Merge branch 'master' into gfio
authorJens Axboe <axboe@kernel.dk>
Fri, 24 Feb 2012 07:28:55 +0000 (08:28 +0100)
committerJens Axboe <axboe@kernel.dk>
Fri, 24 Feb 2012 07:28:55 +0000 (08:28 +0100)
13 files changed:
Makefile
client.c
client.h [new file with mode: 0644]
endian_check.c [new file with mode: 0644]
endian_check.h [new file with mode: 0644]
eta.c
fio.c
fio.h
fio_initialization.c [new file with mode: 0644]
fio_initialization.h [new file with mode: 0644]
gfio.c [new file with mode: 0644]
server.c
server.h

index 673107f0d1dffb9a9c58719ba52fab2e865d60e2..a1270276bbda0f1dae4ae5c8a1c2ee77f46a2bff 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,12 +9,16 @@ PROGS = fio
 SCRIPTS = fio_generate_plots
 UNAME  := $(shell uname)
 
-SOURCE := gettime.c fio.c ioengines.c init.c stat.c log.c time.c filesetup.c \
+GTKCFLAGS = `pkg-config gtk+-2.0 --cflags`
+GTKLDFLAGS = `pkg-config gtk+-2.0 gthread-2.0 --libs`
+
+SOURCE := gettime.c ioengines.c init.c stat.c log.c time.c filesetup.c \
                eta.c verify.c memory.c io_u.c parse.c mutex.c options.c \
                rbtree.c smalloc.c filehash.c profile.c debug.c lib/rand.c \
                lib/num2str.c lib/ieee754.c $(wildcard crc/*.c) engines/cpu.c \
                engines/mmap.c engines/sync.c engines/null.c engines/net.c \
-               memalign.c server.c client.c iolog.c backend.c libfio.c flow.c
+               memalign.c server.c client.c iolog.c backend.c libfio.c flow.c \
+               endian_check.c fio_initialization.c
 
 ifeq ($(UNAME), Linux)
   SOURCE += diskutil.c fifo.c blktrace.c helpers.c cgroup.c trim.c \
@@ -63,7 +67,12 @@ ifneq (,$(findstring CYGWIN,$(UNAME)))
   CC     = x86_64-w64-mingw32-gcc
 endif
 
+FIO_SOURCE = $(SOURCE) fio.c
+GFIO_SOURCE = $(SOURCE) gfio.c
+
 OBJS = $(SOURCE:.c=.o)
+FIO_OBJS = $(OBJS) fio.o
+GFIO_OBJS = $(OBJS) gfio.o
 
 T_SMALLOC_OBJS = t/stest.o
 T_SMALLOC_OBJS += mutex.o smalloc.o t/log.o
@@ -104,8 +113,8 @@ t/stest: $(T_SMALLOC_OBJS)
 t/ieee754: $(T_IEEE_OBJS)
        $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_IEEE_OBJS) $(LIBS) $(LDFLAGS)
 
-fio: $(OBJS)
-       $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
+fio: $(FIO_OBJS)
+       $(QUIET_CC)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(FIO_OBJS) $(LIBS) $(LDFLAGS)
 
 .depend: $(SOURCE)
        $(QUIET_DEP)$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(SOURCE) 1> .depend
@@ -128,3 +137,9 @@ install: $(PROGS) $(SCRIPTS)
 ifneq ($(wildcard .depend),)
 include .depend
 endif
+
+gfio:  $(OBJS) gfio.c
+       $(CC) ${CPPFLAGS} ${CFLAGS} ${GTKCFLAGS} ${LDFLAGS} ${GTKLDFLAGS} -pthread -o gfio $(OBJS) gfio.c $(LIBS) ${LDFLAGS}
+
+
+
index 8c85d2b5c6a673f433f2930fbb41c6a70e8b354b..e109b93fcc86e4db88cdc2edf9d06a745e22f17e 100644 (file)
--- a/client.c
+++ b/client.c
 #include <signal.h>
 
 #include "fio.h"
+#include "client.h"
 #include "server.h"
 #include "flist.h"
 #include "hash.h"
 
+extern void (*update_thread_status)(char *status_message, double perc);
+
 struct client_eta {
        struct jobs_eta eta;
        unsigned int pending;
@@ -59,6 +62,37 @@ struct fio_client {
        char **argv;
 };
 
+static void fio_client_text_op(struct fio_client *client,
+               FILE *f, __u16 pdu_len, const char *buf)
+{
+       const char *name;
+       int fio_unused ret;
+
+       name = client->name ? client->name : client->hostname;
+
+       if (!client->skip_newline)
+               fprintf(f, "<%s> ", name);
+       ret = fwrite(buf, pdu_len, 1, f);
+       fflush(f);
+       client->skip_newline = strchr(buf, '\n') == NULL;
+}
+
+static void handle_du(struct fio_client *client, struct fio_net_cmd *cmd);
+static void handle_ts(struct fio_net_cmd *cmd);
+static void handle_gs(struct fio_net_cmd *cmd);
+static void handle_eta(struct fio_client *client, struct fio_net_cmd *cmd);
+static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd);
+
+struct client_ops fio_client_ops = {
+       fio_client_text_op,
+       handle_du,
+       handle_ts,
+       handle_gs,
+       handle_eta,
+       handle_probe,
+       NULL, /* status display, if NULL, printf is used */
+};
+
 static struct timeval eta_tv;
 
 enum {
@@ -85,7 +119,7 @@ static int sum_stat_nr;
 #define FIO_CLIENT_HASH_MASK   (FIO_CLIENT_HASH_SZ - 1)
 static struct flist_head client_hash[FIO_CLIENT_HASH_SZ];
 
-static int handle_client(struct fio_client *client);
+static int handle_client(struct fio_client *client, struct client_ops *ops);
 static void dec_jobs_eta(struct client_eta *eta);
 
 static void fio_client_add_hash(struct fio_client *client)
@@ -819,7 +853,7 @@ static void handle_stop(struct fio_client *client, struct fio_net_cmd *cmd)
                log_info("client <%s>: exited with error %d\n", client->hostname, client->error);
 }
 
-static int handle_client(struct fio_client *client)
+static int handle_client(struct fio_client *client, struct client_ops *ops)
 {
        struct fio_net_cmd *cmd;
 
@@ -839,39 +873,30 @@ static int handle_client(struct fio_client *client)
                break;
        case FIO_NET_CMD_TEXT: {
                const char *buf = (const char *) cmd->payload;
-               const char *name;
-               int fio_unused ret;
-
-               name = client->name ? client->name : client->hostname;
-
-               if (!client->skip_newline)
-                       fprintf(f_out, "<%s> ", name);
-               ret = fwrite(buf, cmd->pdu_len, 1, f_out);
-               fflush(f_out);
-               client->skip_newline = strchr(buf, '\n') == NULL;
+               ops->text_op(client, f_out, cmd->pdu_len, buf);
                free(cmd);
                break;
                }
        case FIO_NET_CMD_DU:
-               handle_du(client, cmd);
+               ops->disk_util(client, cmd);
                free(cmd);
                break;
        case FIO_NET_CMD_TS:
-               handle_ts(cmd);
+               ops->thread_status(cmd);
                free(cmd);
                break;
        case FIO_NET_CMD_GS:
-               handle_gs(cmd);
+               ops->group_stats(cmd);
                free(cmd);
                break;
        case FIO_NET_CMD_ETA:
                remove_reply_cmd(client, cmd);
-               handle_eta(client, cmd);
+               ops->eta(client, cmd);
                free(cmd);
                break;
        case FIO_NET_CMD_PROBE:
                remove_reply_cmd(client, cmd);
-               handle_probe(client, cmd);
+               ops->probe(client, cmd);
                free(cmd);
                break;
        case FIO_NET_CMD_RUN:
@@ -980,7 +1005,7 @@ static int fio_client_timed_out(void)
        return ret;
 }
 
-int fio_handle_clients(void)
+int fio_handle_clients(struct client_ops *ops)
 {
        struct pollfd *pfds;
        int i, ret = 0, retval = 0;
@@ -993,6 +1018,9 @@ int fio_handle_clients(void)
        init_thread_stat(&client_ts);
        init_group_run_stat(&client_gs);
 
+       /* Used by eta.c:display_thread_status() */
+       update_thread_status = ops->thread_status_display;
+
        while (!exit_backend && nr_clients) {
                struct flist_head *entry, *tmp;
                struct fio_client *client;
@@ -1048,7 +1076,7 @@ int fio_handle_clients(void)
                                log_err("fio: unknown client fd %d\n", pfds[i].fd);
                                continue;
                        }
-                       if (!handle_client(client)) {
+                       if (!handle_client(client, ops)) {
                                log_info("client: host=%s disconnected\n",
                                                client->hostname);
                                remove_client(client);
diff --git a/client.h b/client.h
new file mode 100644 (file)
index 0000000..150d133
--- /dev/null
+++ b/client.h
@@ -0,0 +1,35 @@
+#ifndef CLIENT_H
+#define CLIENT_H
+
+struct fio_client;
+struct fio_net_cmd;
+
+typedef void (*client_text_op_func)(struct fio_client *client,
+               FILE *f, __u16 pdu_len, const char *buf);
+
+typedef void (*client_disk_util_op_func)(struct fio_client *client, struct fio_net_cmd *cmd);
+
+typedef void (*client_thread_status_op)(struct fio_net_cmd *cmd);
+
+typedef void (*client_group_stats_op)(struct fio_net_cmd *cmd);
+
+typedef void (*client_eta_op)(struct fio_client *client, struct fio_net_cmd *cmd);
+
+typedef void (*client_probe_op)(struct fio_client *client, struct fio_net_cmd *cmd);
+
+typedef void (*client_thread_status_display_op)(char *status_message, double perc);
+
+struct client_ops {
+       client_text_op_func text_op;
+       client_disk_util_op_func disk_util;
+       client_thread_status_op thread_status;
+       client_group_stats_op group_stats;
+       client_eta_op eta; 
+       client_probe_op probe;
+       client_thread_status_display_op thread_status_display;
+};
+
+extern struct client_ops fio_client_ops;
+
+#endif
+
diff --git a/endian_check.c b/endian_check.c
new file mode 100644 (file)
index 0000000..c6fc3e2
--- /dev/null
@@ -0,0 +1,33 @@
+#include <stdint.h>
+#include "os/os.h"
+
+int endian_check(void)
+{
+       union {
+               uint8_t c[8];
+               uint64_t v;
+       } u;
+       int le = 0, be = 0;
+
+       u.v = 0x12;
+       if (u.c[7] == 0x12)
+               be = 1;
+       else if (u.c[0] == 0x12)
+               le = 1;
+
+#if defined(FIO_LITTLE_ENDIAN)
+       if (be)
+               return 1;
+#elif defined(FIO_BIG_ENDIAN)
+       if (le)
+               return 1;
+#else
+       return 1;
+#endif
+
+       if (!le && !be)
+               return 1;
+
+       return 0;
+}
+
diff --git a/endian_check.h b/endian_check.h
new file mode 100644 (file)
index 0000000..2e06c3b
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef ENDIAN_CHECK_H
+#define ENDIAN_CHECK_H
+
+int endian_check(void);
+
+#endif 
diff --git a/eta.c b/eta.c
index 6118d1af21b5afccee8c9f106bc4cbd93b557c61..64c02fe2d3690e9ff3421d94d233fc01d2bcf903 100644 (file)
--- a/eta.c
+++ b/eta.c
@@ -7,6 +7,8 @@
 
 #include "fio.h"
 
+void (*update_thread_status)(char *status_message, double perc) = NULL;
+
 static char run_str[REAL_MAX_JOBS + 1];
 
 /*
@@ -411,8 +413,12 @@ void display_thread_status(struct jobs_eta *je)
        }
        p += sprintf(p, "\r");
 
-       printf("%s", output);
-       fflush(stdout);
+       if (update_thread_status) {
+               update_thread_status(output, perc);
+       } else {
+               printf("%s", output);
+               fflush(stdout);
+       }
 }
 
 void print_thread_status(void)
diff --git a/fio.c b/fio.c
index be60c5ff64bce2a3b24760bf668ce477ba2a84c5..52ed944a8b226b1fffe0cf38bc276ab012e42e31 100644 (file)
--- a/fio.c
+++ b/fio.c
 #include "profile.h"
 #include "lib/rand.h"
 #include "memalign.h"
+#include "client.h"
 #include "server.h"
-
-unsigned long page_mask;
-unsigned long page_size;
-
-static int endian_check(void)
-{
-       union {
-               uint8_t c[8];
-               uint64_t v;
-       } u;
-       int le = 0, be = 0;
-
-       u.v = 0x12;
-       if (u.c[7] == 0x12)
-               be = 1;
-       else if (u.c[0] == 0x12)
-               le = 1;
-
-#if defined(FIO_LITTLE_ENDIAN)
-       if (be)
-               return 1;
-#elif defined(FIO_BIG_ENDIAN)
-       if (le)
-               return 1;
-#else
-       return 1;
-#endif
-
-       if (!le && !be)
-               return 1;
-
-       return 0;
-}
+#include "fio_initialization.h"
 
 int main(int argc, char *argv[], char *envp[])
 {
-       long ps;
-
-       if (endian_check()) {
-               log_err("fio: endianness settings appear wrong.\n");
-               log_err("fio: please report this to fio@vger.kernel.org\n");
+       if (initialize_fio(envp))
                return 1;
-       }
-
-       arch_init(envp);
-
-       sinit();
-
-       /*
-        * We need locale for number printing, if it isn't set then just
-        * go with the US format.
-        */
-       if (!getenv("LC_NUMERIC"))
-               setlocale(LC_NUMERIC, "en_US");
-
-       ps = sysconf(_SC_PAGESIZE);
-       if (ps < 0) {
-               log_err("Failed to get page size\n");
-               return 1;
-       }
-
-       page_size = ps;
-       page_mask = ps - 1;
-
-       fio_keywords_init();
 
        if (parse_options(argc, argv))
                return 1;
 
        if (nr_clients)
-               return fio_handle_clients();
+               return fio_handle_clients(&fio_client_ops);
        else
                return fio_backend();
 }
diff --git a/fio.h b/fio.h
index 5c912d0aab89da4c3b8c0510e5220107e083a067..3efda51acf6ad37be6cc27ab7c20f966b81f87d7 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -36,6 +36,7 @@ struct thread_data;
 #include "gettime.h"
 #include "lib/getopt.h"
 #include "lib/rand.h"
+#include "client.h"
 #include "server.h"
 #include "stat.h"
 #include "flow.h"
diff --git a/fio_initialization.c b/fio_initialization.c
new file mode 100644 (file)
index 0000000..8bd3374
--- /dev/null
@@ -0,0 +1,43 @@
+#include <locale.h>
+
+#include "endian_check.h"
+#include "smalloc.h"
+#include "fio.h"
+
+
+unsigned long page_mask;
+unsigned long page_size;
+
+int initialize_fio(char *envp[])
+{
+       long ps;
+
+       if (endian_check()) {
+               log_err("fio: endianness settings appear wrong.\n");
+               log_err("fio: please report this to fio@vger.kernel.org\n");
+               return 1;
+       }
+
+       arch_init(envp);
+
+       sinit();
+
+       /*
+        * We need locale for number printing, if it isn't set then just
+        * go with the US format.
+        */
+       if (!getenv("LC_NUMERIC"))
+               setlocale(LC_NUMERIC, "en_US");
+
+       ps = sysconf(_SC_PAGESIZE);
+       if (ps < 0) {
+               log_err("Failed to get page size\n");
+               return 1;
+       }
+
+       page_size = ps;
+       page_mask = ps - 1;
+
+       fio_keywords_init();
+       return 0;
+}
diff --git a/fio_initialization.h b/fio_initialization.h
new file mode 100644 (file)
index 0000000..877cd44
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef FIO_INITIALIZATION
+#define FIO_INITIALIZATION
+
+extern unsigned long page_mask;
+extern unsigned long page_size;
+extern int initialize_fio(char *envp[]);
+
+#endif
diff --git a/gfio.c b/gfio.c
new file mode 100644 (file)
index 0000000..852214e
--- /dev/null
+++ b/gfio.c
@@ -0,0 +1,361 @@
+/*
+ * gfio - gui front end for fio - the flexible io tester
+ *
+ * Copyright (C) 2012 Stephen M. Cameron <stephenmcameron@gmail.com> 
+ *
+ * The license below covers all files distributed with fio unless otherwise
+ * noted in the file itself.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <locale.h>
+#include <malloc.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "fio_initialization.h"
+#include "fio.h"
+
+#define ARRAYSIZE(x) (sizeof((x)) / (sizeof((x)[0])))
+
+typedef void (*clickfunction)(GtkWidget *widget, gpointer data);
+
+static void quit_clicked(GtkWidget *widget, gpointer data);
+static void start_job_clicked(GtkWidget *widget, gpointer data);
+
+static struct button_spec {
+       const char *buttontext;
+       clickfunction f;
+       const char *tooltiptext;
+} buttonspeclist[] = {
+#define START_JOB_BUTTON 0
+       { "Start Job",
+               start_job_clicked,
+               "Send current fio job to fio server to be executed" },
+#define QUIT_BUTTON 1
+       { "Quit", quit_clicked, "Quit gfio" },
+};
+
+struct gui {
+       int argc;
+       char **argv;
+       GtkWidget *window;
+       GtkWidget *vbox;
+       GtkWidget *topvbox;
+       GtkWidget *topalign;
+       GtkWidget *bottomalign;
+       GtkWidget *thread_status_pb;
+       GtkWidget *buttonbox;
+       GtkWidget *button[ARRAYSIZE(buttonspeclist)];
+       GtkWidget *hostname_hbox;
+       GtkWidget *hostname_label;
+       GtkWidget *hostname_entry;
+       GtkWidget *port_label;
+       GtkWidget *port_entry;
+       GtkWidget *hostname_combo_box; /* ipv4, ipv6 or socket */
+       GtkWidget *jobfile_hbox;
+       GtkWidget *jobfile_label;
+       GtkWidget *jobfile_entry;
+       GtkWidget *scrolled_window;
+       GtkWidget *textview;
+       GtkTextBuffer *text;
+       pthread_t t;
+} ui;
+
+static void gfio_text_op(struct fio_client *client,
+                FILE *f, __u16 pdu_len, const char *buf)
+{
+       GtkTextBuffer *buffer;
+       GtkTextIter end;
+
+       buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui.textview));
+       gdk_threads_enter();
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert(buffer, &end, buf, -1);
+       gdk_threads_leave();
+       gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ui.textview),
+                                       &end, 0.0, FALSE, 0.0,0.0);
+}
+
+static void gfio_disk_util_op(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+       printf("gfio_disk_util_op called\n");
+       fio_client_ops.disk_util(client, cmd);
+}
+
+static void gfio_thread_status_op(struct fio_net_cmd *cmd)
+{
+       printf("gfio_thread_status_op called\n");
+       fio_client_ops.thread_status(cmd);
+}
+
+static void gfio_group_stats_op(struct fio_net_cmd *cmd)
+{
+       printf("gfio_group_stats_op called\n");
+       fio_client_ops.group_stats(cmd);
+}
+
+static void gfio_eta_op(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+       fio_client_ops.eta(client, cmd);
+}
+
+static void gfio_probe_op(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+       printf("gfio_probe_op called\n");
+       fio_client_ops.probe(client, cmd);
+}
+
+static void gfio_update_thread_status(char *status_message, double perc)
+{
+       static char message[100];
+       const char *m = message;
+
+       strncpy(message, status_message, sizeof(message) - 1);
+       gtk_progress_bar_set_text(
+               GTK_PROGRESS_BAR(ui.thread_status_pb), m);
+       gtk_progress_bar_set_fraction(
+               GTK_PROGRESS_BAR(ui.thread_status_pb), perc / 100.0);
+       gdk_threads_enter();
+       gtk_widget_queue_draw(ui.window);
+       gdk_threads_leave();
+}
+
+struct client_ops gfio_client_ops = {
+       gfio_text_op,
+       gfio_disk_util_op,
+       gfio_thread_status_op,
+       gfio_group_stats_op,
+       gfio_eta_op,
+       gfio_probe_op,
+       gfio_update_thread_status,
+};
+
+static void quit_clicked(__attribute__((unused)) GtkWidget *widget,
+                __attribute__((unused)) gpointer data)
+{
+        gtk_main_quit();
+}
+
+static void add_arg(char **argv, int index, const char *value)
+{
+       argv[index] = malloc(strlen(value) + 1);
+       strcpy(argv[index], value);
+}
+
+static void free_args(int argc, char **argv)
+{
+       int i;
+
+       for (i = 0; i < argc; i++)
+               free(argv[i]);
+       free(argv);
+}
+
+static void *job_thread(void *arg)
+{
+       struct gui *ui = arg;
+
+       fio_handle_clients(&gfio_client_ops);
+       gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
+       free_args(ui->argc, ui->argv);
+       return NULL;
+}
+
+static void construct_options(struct gui *ui, int *argc, char ***argv)
+{
+       const char *hostname, *hostname_type, *port, *jobfile;
+       char newarg[200];
+       
+       hostname_type = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(ui->hostname_combo_box)->entry));
+       hostname = gtk_entry_get_text(GTK_ENTRY(ui->hostname_entry));
+       port = gtk_entry_get_text(GTK_ENTRY(ui->port_entry));
+       jobfile = gtk_entry_get_text(GTK_ENTRY(ui->jobfile_entry));
+
+       *argc = 3;
+       *argv = malloc(*argc * sizeof(**argv));         
+       add_arg(*argv, 0,  "gfio");
+       snprintf(newarg, sizeof(newarg) - 1, "--client=%s", hostname);
+       add_arg(*argv, 1, newarg);
+       add_arg(*argv, 2, jobfile);
+}
+
+static void start_job_thread(pthread_t *t, struct gui *ui)
+{
+       construct_options(ui, &ui->argc, &ui->argv);
+       if (parse_options(ui->argc, ui->argv)) {
+               printf("Yeah, I didn't really like those options too much.\n");
+               free_args(ui->argc, ui->argv);
+               gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 1);
+               return;
+       }
+       pthread_create(t, NULL, job_thread, ui);
+}
+
+static void start_job_clicked(__attribute__((unused)) GtkWidget *widget,
+                gpointer data)
+{
+       struct gui *ui = data;
+
+       printf("Start job button was clicked.\n");
+       gtk_widget_set_sensitive(ui->button[START_JOB_BUTTON], 0);
+       start_job_thread(&ui->t, ui);
+}
+
+static void add_button(struct gui *ui, int i, GtkWidget *buttonbox,
+                       struct button_spec *buttonspec)
+{
+       ui->button[i] = gtk_button_new_with_label(buttonspec->buttontext);
+       g_signal_connect(ui->button[i], "clicked", G_CALLBACK (buttonspec->f), ui);
+       gtk_box_pack_start(GTK_BOX (ui->buttonbox), ui->button[i], TRUE, TRUE, 0);
+       gtk_widget_set_tooltip_text(ui->button[i], buttonspeclist[i].tooltiptext);
+}
+
+static void add_buttons(struct gui *ui,
+                               struct button_spec *buttonlist,
+                               int nbuttons)
+{
+       int i;
+
+       for (i = 0; i < nbuttons; i++)
+               add_button(ui, i, ui->buttonbox, &buttonlist[i]);
+}
+
+static void init_ui(int *argc, char **argv[], struct gui *ui)
+{
+       GList *hostname_type_list = NULL;
+       char portnum[20];
+
+       /* Magical g*thread incantation, you just need this thread stuff.
+        * Without it, the update that happens in gfio_update_thread_status
+        * doesn't really happen in a timely fashion, you need expose events
+        */
+       if (!g_thread_supported ())
+               g_thread_init(NULL);
+       gdk_threads_init();
+
+       gtk_init(argc, argv);
+       
+       ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+        gtk_window_set_title(GTK_WINDOW(ui->window), "fio");
+       gtk_window_set_default_size(GTK_WINDOW(ui->window), 700, 500);
+
+       g_signal_connect(ui->window, "delete-event", G_CALLBACK (quit_clicked), NULL);
+       g_signal_connect(ui->window, "destroy", G_CALLBACK (quit_clicked), NULL);
+
+       ui->vbox = gtk_vbox_new(FALSE, 0);
+       gtk_container_add(GTK_CONTAINER (ui->window), ui->vbox);
+
+       /*
+        * Set up alignments for widgets at the top of ui, 
+        * align top left, expand horizontally but not vertically
+        */
+       ui->topalign = gtk_alignment_new(0, 0, 1, 0);
+       ui->topvbox = gtk_vbox_new(FALSE, 0);
+       gtk_container_add(GTK_CONTAINER(ui->topalign), ui->topvbox);
+       gtk_box_pack_start(GTK_BOX(ui->vbox), ui->topalign, FALSE, FALSE, 0);
+
+       /*
+        * Set up hostname label + entry, port label + entry,
+        */
+       ui->hostname_hbox = gtk_hbox_new(FALSE, 0);
+       ui->hostname_label = gtk_label_new("Host:");
+       ui->hostname_entry = gtk_entry_new();
+       gtk_entry_set_text(GTK_ENTRY(ui->hostname_entry), "localhost");
+       ui->port_label = gtk_label_new("Port:");
+       ui->port_entry = gtk_entry_new();
+       snprintf(portnum, sizeof(portnum) - 1, "%d", FIO_NET_PORT);
+       gtk_entry_set_text(GTK_ENTRY(ui->port_entry), (gchar *) portnum);
+
+       /*
+        * Set up combo box for address type
+        */
+       ui->hostname_combo_box = gtk_combo_new();
+       gtk_entry_set_text(GTK_ENTRY (GTK_COMBO(ui->hostname_combo_box)->entry), "IPv4");
+       hostname_type_list = g_list_append(hostname_type_list, (gpointer) "IPv4"); 
+       hostname_type_list = g_list_append(hostname_type_list, (gpointer) "local socket"); 
+       hostname_type_list = g_list_append(hostname_type_list, (gpointer) "IPv6"); 
+       gtk_combo_set_popdown_strings (GTK_COMBO (ui->hostname_combo_box), hostname_type_list);
+       g_list_free(hostname_type_list);
+
+       gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->hostname_label);
+       gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->hostname_entry);
+       gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->port_label);
+       gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->port_entry);
+       gtk_container_add(GTK_CONTAINER (ui->hostname_hbox), ui->hostname_combo_box);
+       gtk_container_add(GTK_CONTAINER (ui->topvbox), ui->hostname_hbox);
+
+       /*
+        * Set up jobfile text entry (temporary until gui really works)
+        */
+       ui->jobfile_hbox = gtk_hbox_new(FALSE, 0);
+       ui->jobfile_label = gtk_label_new("Job file:");
+       ui->jobfile_entry = gtk_entry_new();
+       gtk_container_add(GTK_CONTAINER (ui->jobfile_hbox), ui->jobfile_label);
+       gtk_container_add(GTK_CONTAINER (ui->jobfile_hbox), ui->jobfile_entry);
+       gtk_container_add(GTK_CONTAINER (ui->topvbox), ui->jobfile_hbox);
+
+       /*
+        * Set up thread status progress bar
+        */
+       ui->thread_status_pb = gtk_progress_bar_new();
+       gtk_progress_bar_set_fraction(
+               GTK_PROGRESS_BAR(ui->thread_status_pb), 0.0);
+       gtk_progress_bar_set_text(
+               GTK_PROGRESS_BAR(ui->thread_status_pb), "No jobs running");
+       gtk_container_add(GTK_CONTAINER (ui->topvbox), ui->thread_status_pb);
+
+       /*
+        * Add a text box for text op messages 
+        */
+       ui->textview = gtk_text_view_new();
+       ui->text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui->textview));
+       gtk_text_buffer_set_text(ui->text, "", -1);
+       gtk_text_view_set_editable(GTK_TEXT_VIEW(ui->textview), FALSE);
+       gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ui->textview), FALSE);
+       ui->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui->scrolled_window),
+                                       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+       gtk_container_add(GTK_CONTAINER(ui->scrolled_window), ui->textview);
+       gtk_box_pack_start(GTK_BOX(ui->vbox), ui->scrolled_window,
+                       TRUE, TRUE, 0);
+
+       /*
+        * Set up alignments for widgets at the bottom of ui, 
+        * align bottom left, expand horizontally but not vertically
+        */
+       ui->bottomalign = gtk_alignment_new(0, 1, 1, 0);
+       ui->buttonbox = gtk_hbox_new(FALSE, 0);
+       gtk_container_add(GTK_CONTAINER(ui->bottomalign), ui->buttonbox);
+       gtk_box_pack_start(GTK_BOX(ui->vbox), ui->bottomalign,
+                                       FALSE, FALSE, 0);
+
+       add_buttons(ui, buttonspeclist, ARRAYSIZE(buttonspeclist));
+       gtk_widget_show_all(ui->window);
+}
+
+int main(int argc, char *argv[], char *envp[])
+{
+       if (initialize_fio(envp))
+               return 1;
+
+       init_ui(&argc, &argv, &ui);
+
+       gdk_threads_enter();
+       gtk_main();
+       gdk_threads_leave();
+       return 0;
+}
index 84b106e805a4bd178a189ebb556c384fba307a04..2e8682c999cc395f0af45ab67723d40459735484 100644 (file)
--- a/server.c
+++ b/server.c
@@ -24,7 +24,7 @@
 
 #include "fio_version.h"
 
-int fio_net_port = 8765;
+int fio_net_port = FIO_NET_PORT;
 
 int exit_backend = 0;
 
index 27da94f23c69e00ed089af87de833b84a612f9f2..2be61733534836b2d787e0ac8ec8c9ce60baf4b0 100644 (file)
--- a/server.h
+++ b/server.h
@@ -10,6 +10,8 @@
 #include "os/os.h"
 #include "diskutil.h"
 
+#define FIO_NET_PORT 8765
+
 /*
  * On-wire encoding is little endian
  */
@@ -123,7 +125,7 @@ extern void fio_server_idle_loop(void);
 
 extern int fio_clients_connect(void);
 extern int fio_clients_send_ini(const char *);
-extern int fio_handle_clients(void);
+extern int fio_handle_clients(struct client_ops *ops);
 extern int fio_client_add(const char *, void **);
 extern void fio_client_add_cmd_option(void *, const char *);