return 0;
}
+void fio_clients_terminate(void)
+{
+ struct flist_head *entry;
+ struct fio_client *client;
+
+ flist_for_each(entry, &client_list) {
+ client = flist_entry(entry, struct fio_client, list);
+
+ fio_net_send_simple_cmd(client->fd, FIO_NET_CMD_QUIT, 0);
+ }
+}
+
+static void sig_int(int sig)
+{
+ fio_clients_terminate();
+}
+
+static void client_signal_handler(void)
+{
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = sig_int;
+ act.sa_flags = SA_RESTART;
+ sigaction(SIGINT, &act, NULL);
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = sig_int;
+ act.sa_flags = SA_RESTART;
+ sigaction(SIGTERM, &act, NULL);
+}
+
int fio_clients_connect(void)
{
struct fio_client *client;
struct flist_head *entry, *tmp;
int ret;
+ client_signal_handler();
+
flist_for_each_safe(entry, tmp, &client_list) {
client = flist_entry(entry, struct fio_client, list);
struct io_log *agg_io_log[2];
-#define TERMINATE_ALL (-1)
#define JOB_START_TIMEOUT (5 * 1000)
void td_set_runstate(struct thread_data *td, int runstate)
td->runstate = runstate;
}
-static void terminate_threads(int group_id)
+void fio_terminate_threads(int group_id)
{
struct thread_data *td;
int i;
exit_backend = 1;
fflush(stdout);
exit_value = 128;
- terminate_threads(TERMINATE_ALL);
+ fio_terminate_threads(TERMINATE_ALL);
}
}
act.sa_handler = sig_int;
act.sa_flags = SA_RESTART;
sigaction(SIGTERM, &act, NULL);
+
+ if (is_backend) {
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = sig_int;
+ act.sa_flags = SA_RESTART;
+ sigaction(SIGPIPE, &act, NULL);
+ }
}
/*
if (!in_ramp_time(td) && should_check_rate(td, bytes_done)) {
if (check_min_rate(td, &comp_time, bytes_done)) {
if (exitall_on_terminate)
- terminate_threads(td->groupid);
+ fio_terminate_threads(td->groupid);
td_verror(td, EIO, "check_min_rate");
break;
}
exec_string(td->o.exec_postrun);
if (exitall_on_terminate)
- terminate_threads(td->groupid);
+ fio_terminate_threads(td->groupid);
err:
if (td->error)
}
if (*nr_running == cputhreads && !pending && realthreads)
- terminate_threads(TERMINATE_ALL);
+ fio_terminate_threads(TERMINATE_ALL);
}
static void *gtod_thread_main(void *data)
if (fio_gtod_offload && fio_start_gtod_thread())
return;
+ set_sig_handlers();
+
if (!terse_output) {
log_info("Starting ");
if (nr_thread)
fflush(stdout);
}
- set_sig_handlers();
-
todo = thread_number;
nr_running = 0;
nr_started = 0;
dprint(FD_MUTEX, "wait on startup_mutex\n");
if (fio_mutex_down_timeout(startup_mutex, 10)) {
log_err("fio: job startup hung? exiting.\n");
- terminate_threads(TERMINATE_ALL);
+ fio_terminate_threads(TERMINATE_ALL);
fio_abort = 1;
nr_started--;
break;
while (nr_running) {
reap_threads(&nr_running, &t_rate, &m_rate);
+
+ if (is_backend)
+ fio_server_idle_loop();
+
usleep(10000);
}
};
extern void td_set_runstate(struct thread_data *, int);
+#define TERMINATE_ALL (-1)
+extern void fio_terminate_threads(int);
/*
* Memory helpers
void *pdu = NULL;
do {
+ struct pollfd pfd;
+
+ pfd.fd = sk;
+ pfd.events = POLLIN;
+ ret = 0;
+ do {
+ ret = poll(&pfd, 1, 100);
+ if (ret < 0) {
+ log_err("fio: poll: %s\n", strerror(errno));
+ break;
+ } else if (!ret)
+ continue;
+
+ if (pfd.revents & POLLIN)
+ break;
+ if (pfd.revents & (POLLERR|POLLHUP)) {
+ ret = 1;
+ break;
+ }
+ } while (ret >= 0);
+
+ if (ret < 0)
+ break;
+
ret = fio_recv_data(sk, &cmd, sizeof(cmd));
if (ret)
break;
if (ret) {
free(cmdret);
cmdret = NULL;
- }
-
- if (cmdret)
+ } else if (cmdret)
cmdret->flags &= ~FIO_NET_CMD_F_MORE;
return cmdret;
return ret;
}
-static int send_simple_command(int sk, uint16_t opcode, uint64_t serial)
+int fio_net_send_simple_cmd(int sk, uint16_t opcode, uint64_t serial)
{
struct fio_net_cmd cmd = {
.version = __cpu_to_le16(FIO_SERVER_VER1),
return fio_send_data(sk, &cmd, sizeof(cmd));
}
-/*
- * Send an ack for this command
- */
-static int ack_command(int sk, struct fio_net_cmd *cmd)
-{
-#if 0
- return send_simple_command(sk, FIO_NET_CMD_ACK, cmd->serial);
-#else
- return 0;
-#endif
-}
-
-#if 0
-static int nak_command(int sk, struct fio_net_cmd *cmd)
-{
- return send_simple_command(sk, FIO_NET_CMD_NAK, cmd->serial);
-}
-#endif
-
static int send_quit_command(void)
{
dprint(FD_NET, "server: sending quit\n");
- return send_simple_command(server_fd, FIO_NET_CMD_QUIT, 0);
+ return fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_QUIT, 0);
}
static int handle_cur_job(struct fio_net_cmd *cmd)
switch (cmd->opcode) {
case FIO_NET_CMD_QUIT:
+ fio_terminate_threads(TERMINATE_ALL);
return 1;
case FIO_NET_CMD_EXIT:
exit_backend = 1;
break;
}
- ret = ack_command(sk, cmd);
- if (ret)
- break;
-
ret = handle_command(cmd);
if (ret)
break;
return ret;
}
+void fio_server_idle_loop(void)
+{
+ if (server_fd != -1)
+ handle_connection(server_fd);
+}
+
static int accept_loop(int listen_sk)
{
struct sockaddr addr;
server_fd = sk;
+ printf("handle\n");
+
exitval = handle_connection(sk);
+ printf("out, exit %d\n", exitval);
+
server_fd = -1;
close(sk);
extern int fio_server_text_output(const char *, unsigned int len);
extern int fio_server_log(const char *format, ...);
extern int fio_net_send_cmd(int, uint16_t, const void *, off_t);
+extern int fio_net_send_simple_cmd(int sk, uint16_t opcode, uint64_t serial);
struct thread_stat;
struct group_run_stats;
extern void fio_server_send_ts(struct thread_stat *, struct group_run_stats *);
extern void fio_server_send_gs(struct group_run_stats *);
extern void fio_server_send_status(void);
+extern void fio_server_idle_loop(void);
extern int fio_clients_connect(void);
extern int fio_clients_send_ini(const char *);