rbtree.c smalloc.c filehash.c profile.c debug.c lib/rand.c \
lib/num2str.c $(wildcard crc/*.c) engines/cpu.c \
engines/mmap.c engines/sync.c engines/null.c engines/net.c \
- memalign.c
+ memalign.c server.c
ifeq ($(UNAME), Linux)
SOURCE += diskutil.c fifo.c blktrace.c helpers.c cgroup.c trim.c \
fio_unpin_memory();
}
-int main(int argc, char *argv[], char *envp[])
+int exec_run(void)
{
- long ps;
-
- 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 (exec_profile && load_profile(exec_profile))
return 1;
if (!thread_number)
return 0;
+ printf("%d threads\n", thread_number);
+
if (write_bw_log) {
setup_log(&agg_io_log[DDIR_READ]);
setup_log(&agg_io_log[DDIR_WRITE]);
fio_mutex_remove(writeout_mutex);
return exit_value;
}
+
+void reset_fio_state(void)
+{
+ groupid = 0;
+ thread_number = 0;
+ nr_process = 0;
+ nr_thread = 0;
+ done_secs = 0;
+}
+
+int main(int argc, char *argv[], char *envp[])
+{
+ long ps;
+
+ 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;
+
+ return exec_run();
+}
* Init/option functions
*/
extern int __must_check parse_options(int, char **);
+extern int parse_jobs_ini(char *, int, int);
+extern int exec_run(void);
+extern void reset_fio_state(void);
extern int fio_options_parse(struct thread_data *, char **, int);
extern void fio_keywords_init(void);
extern int fio_cmd_option_parse(struct thread_data *, const char *, char *);
#include "filehash.h"
#include "verify.h"
#include "profile.h"
+#include "server.h"
#include "lib/getopt.h"
char *exec_profile = NULL;
int warnings_fatal = 0;
int terse_version = 2;
+int is_backend = 0;
int write_bw_log = 0;
int read_only = 0;
.has_arg = required_argument,
.val = 'V',
},
+ {
+ .name = (char *) "server",
+ .has_arg = no_argument,
+ .val = 'S',
+ },
{
.name = NULL,
},
/*
* This is our [ini] type file parser.
*/
-static int parse_jobs_ini(char *file, int stonewall_flag)
+int parse_jobs_ini(char *file, int is_buf, int stonewall_flag)
{
unsigned int global;
struct thread_data *td;
char **opts;
int i, alloc_opts, num_opts;
- if (!strcmp(file, "-"))
- f = stdin;
- else
- f = fopen(file, "r");
+ if (is_buf)
+ f = NULL;
+ else {
+ if (!strcmp(file, "-"))
+ f = stdin;
+ else
+ f = fopen(file, "r");
- if (!f) {
- perror("fopen job file");
- return 1;
+ if (!f) {
+ perror("fopen job file");
+ return 1;
+ }
}
string = malloc(4096);
* haven't handled.
*/
if (!skip_fgets) {
- p = fgets(string, 4095, f);
+ if (is_buf)
+ p = strsep(&file, "\n");
+ else
+ p = fgets(string, 4095, f);
if (!p)
break;
}
num_opts = 0;
memset(opts, 0, alloc_opts * sizeof(char *));
- while ((p = fgets(string, 4096, f)) != NULL) {
+ while (1) {
+ if (is_buf)
+ p = strsep(&file, "\n");
+ else
+ p = fgets(string, 4096, f);
+ if (!p)
+ break;
+
if (is_empty_or_comment(p))
continue;
free(string);
free(name);
free(opts);
- if (f != stdin)
+ if (!is_buf && f != stdin)
fclose(f);
return ret;
}
exit_val = 1;
}
break;
+ case 'S':
+ is_backend = 1;
+ break;
default:
do_exit++;
exit_val = 1;
if (do_exit)
exit(exit_val);
+ if (is_backend)
+ fio_server();
+
if (td) {
if (!ret)
ret = add_job(td, td->o.name ?: "fio", 0);
for (i = 0; i < job_files; i++) {
if (fill_def_thread())
return 1;
- if (parse_jobs_ini(ini_file[i], i))
+ if (parse_jobs_ini(ini_file[i], 0, i))
return 1;
free(ini_file[i]);
}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "fio.h"
+
+static int net_port = 8765;
+
+static int accept_loop(int listen_sk)
+{
+ struct sockaddr addr;
+ unsigned int len = sizeof(addr);
+ int sk;
+
+again:
+ sk = accept(listen_sk, &addr, &len);
+ printf("got a hit\n");
+ if (sk < 0) {
+ log_err("fio: accept failed\n");
+ return -1;
+ }
+
+ /* read forever */
+ for (;;) {
+ char buf[131072];
+ int ret;
+
+ ret = recv(sk, buf, 4096, 0);
+ if (ret > 0) {
+ parse_jobs_ini(buf, 1, 0);
+ exec_run();
+ reset_fio_state();
+ break;
+ } else if (!ret)
+ break;
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ break;
+ }
+
+ close(sk);
+ printf("closed\n");
+ goto again;
+}
+
+int fio_server(void)
+{
+ struct sockaddr_in saddr_in;
+ struct sockaddr addr;
+ unsigned int len;
+ int sk, opt;
+
+ sk = socket(AF_INET, SOCK_STREAM, 0);
+ if (sk < 0) {
+ log_err("fio: socket\n");
+ return -1;
+ }
+
+ opt = 1;
+ if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
+ log_err("fio: setsockopt\n");
+ return -1;
+ }
+#ifdef SO_REUSEPORT
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) < 0) {
+ td_verror(td, errno, "setsockopt");
+ return 1;
+ }
+#endif
+
+ saddr_in.sin_family = AF_INET;
+ saddr_in.sin_addr.s_addr = htonl(INADDR_ANY);
+ saddr_in.sin_port = htons(net_port);
+
+ if (bind(sk, (struct sockaddr *) &saddr_in, sizeof(saddr_in)) < 0) {
+ perror("bind");
+ log_err("fio: bind\n");
+ return -1;
+ }
+
+ if (listen(sk, 1) < 0) {
+ log_err("fio: listen\n");
+ return -1;
+ }
+
+ len = sizeof(addr);
+ if (getsockname(sk, &addr, &len) < 0) {
+ log_err("fio: getsockname");
+ return -1;
+ }
+
+ return accept_loop(sk);
+}
--- /dev/null
+#ifndef FIO_SERVER_H
+#define FIO_SERVER_H
+
+extern int fio_server(void);
+
+#endif