INIT_GUI_ERRLISTS;
static char *stat_content[NUM_STAT_ITEMS];
-static int signal_pipe;
-
static struct gui_window {
WINDOW *win;
} top, bot, sb, in, sep;
static struct gui_command command_list[] = {GUI_COMMANDS {.name = NULL}};
+struct input_task {
+ struct task task;
+};
+
+struct status_task {
+ struct task task;
+};
+
+struct cmd_task {
+ struct task task;
+};
+
static int find_cmd_byname(char *name)
{
int i;
}
__printf_2_3 void (*para_log)(int, const char*, ...) = curses_log;
-static void setup_signal_handling(void)
-{
- signal_pipe = para_signal_init();
- para_install_sighandler(SIGINT);
- para_install_sighandler(SIGTERM);
- para_install_sighandler(SIGCHLD);
- para_install_sighandler(SIGWINCH);
- para_install_sighandler(SIGUSR1);
-}
-
static void shutdown_curses(void)
{
def_prog_mode();
static struct timeval next_exec;
-static void status_pre_select(fd_set *rfds, int *max_fileno, struct timeval *tv)
+static void status_pre_select(struct sched *s, __a_unused struct task *t)
{
- struct timeval atm, diff;
-
if (stat_pipe >= 0)
- return para_fd_set(stat_pipe, rfds, max_fileno);
- gettimeofday(&atm, NULL);
- if (tv_diff(&next_exec, &atm, &diff) > 0) {
- *tv = diff;
- return;
- }
- tv->tv_sec = tv->tv_usec = 0; /* min delay */
+ return para_fd_set(stat_pipe, &s->rfds, &s->max_fileno);
+ sched_request_barrier_or_min_delay(&next_exec, s);
}
-static void status_post_select(fd_set *rfds)
+static int status_post_select(struct sched *s, __a_unused struct task *t)
{
static char *buf;
static int bufsize, loaded;
int ret, ret2;
if (stat_pipe < 0) {
- struct timeval atm;
int fds[3] = {0, 1, 0};
/* Avoid busy loop */
- gettimeofday(&atm, NULL);
- if (tv_diff(&next_exec, &atm, NULL) > 0)
- return;
- next_exec.tv_sec = atm.tv_sec + 2;
+ if (tv_diff(&next_exec, now, NULL) > 0)
+ return 0;
+ next_exec.tv_sec = now->tv_sec + 2;
ret = para_exec_cmdline_pid(&pid, conf.stat_cmd_arg, fds);
if (ret < 0)
- return;
+ return 0;
ret = mark_fd_nonblocking(fds[1]);
if (ret < 0) {
close(fds[1]);
- return;
+ return 0;
}
stat_pipe = fds[1];
- return;
+ return 0;
}
if (loaded >= bufsize) {
if (bufsize > 1000 * 1000) {
loaded = 0;
- return;
+ return 0;
}
bufsize += bufsize + 1000;
buf = para_realloc(buf, bufsize);
}
assert(loaded < bufsize);
ret = read_nonblock(stat_pipe, buf + loaded, bufsize - loaded,
- rfds, &sz);
+ &s->rfds, &sz);
loaded += sz;
ret2 = for_each_stat_item(buf, loaded, update_item);
if (ret < 0 || ret2 < 0) {
stat_content[SI_BASENAME] =
para_strdup("stat command terminated!?");
print_all_items();
- return;
+ return 0;
}
sz = ret2; /* what is left */
if (sz > 0 && sz < loaded)
memmove(buf, buf + loaded - sz, sz);
loaded = sz;
+ return 0;
}
/*
/*
* React to various signal-related events
*/
-static void signal_post_select(fd_set *rfds)
+static int signal_post_select(struct sched *s, __a_unused struct task *t)
{
- int ret = para_next_signal(rfds);
+ int ret = para_next_signal(&s->rfds);
+
if (ret <= 0)
- return;
+ return 0;
switch (ret) {
case SIGTERM:
die(EXIT_FAILURE, "only the good die young (caught SIGTERM)\n");
- return;
+ return 1;
case SIGWINCH:
if (curses_active()) {
shutdown_curses();
init_curses();
redraw_bot_win();
}
- return;
+ return 1;
case SIGINT:
PARA_WARNING_LOG("caught SIGINT, reset\n");
/* Nothing to do. SIGINT killed our child which gets noticed
* by do_select and resets everything.
*/
- return;
+ return 1;
case SIGUSR1:
PARA_NOTICE_LOG("got SIGUSR1, rereading configuration\n");
reread_conf();
- return;
+ return 1;
case SIGCHLD:
check_sigchld();
- return;
+ return 1;
}
+ return 1;
}
#define COMMAND_BUF_SIZE 32768
return CMDS_IDLE;
}
-static void command_pre_select(fd_set *rfds, int *max_fileno)
+static void command_pre_select(struct sched *s, __a_unused struct task *t)
{
enum cmd_status cmds = cmd_status();
if (cmds != CMDS_DCMD)
return;
if (command_fds[0] >= 0)
- para_fd_set(command_fds[0], rfds, max_fileno);
+ para_fd_set(command_fds[0], &s->rfds, &s->max_fileno);
if (command_fds[1] >= 0)
- para_fd_set(command_fds[1], rfds, max_fileno);
+ para_fd_set(command_fds[1], &s->rfds, &s->max_fileno);
}
-static void command_post_select(fd_set *rfds)
+static int command_post_select(struct sched *s, __a_unused struct task *t)
{
int i, ret;
static char command_buf[2][COMMAND_BUF_SIZE];
enum cmd_status cmds = cmd_status();
if (cmds != CMDS_DCMD)
- return;
+ return 0;
for (i = 0; i < 2; i++) {
size_t sz;
if (command_fds[i] < 0)
continue;
ret = read_nonblock(command_fds[i],
command_buf[i] + cbo[i],
- COMMAND_BUF_SIZE - 1 - cbo[i], rfds, &sz);
+ COMMAND_BUF_SIZE - 1 - cbo[i], &s->rfds, &sz);
cbo[i] += sz;
sz = cbo[i];
cbo[i] = for_each_line(flags[i], command_buf[i], cbo[i],
flags[i] = 0;
cbo[i] = 0;
if (command_fds[!i] < 0) /* both fds closed */
- return;
+ return 1;
}
if (cbo[i] == COMMAND_BUF_SIZE - 1) {
PARA_NOTICE_LOG("discarding overlong line");
flags[i] = FELF_DISCARD_FIRST;
}
}
+ return 0;
}
-static void input_pre_select(fd_set *rfds, int *max_fileno)
+static void input_pre_select(struct sched *s, __a_unused struct task *t)
{
enum cmd_status cmds = cmd_status();
if (cmds != CMDS_XCMD)
- para_fd_set(STDIN_FILENO, rfds, max_fileno);
+ para_fd_set(STDIN_FILENO, &s->rfds, &s->max_fileno);
}
/* read from command pipe and print data to bot window */
km_keyname(c));
}
-static void input_post_select(void)
+static int input_post_select(__a_unused struct sched *s, __a_unused struct task *t)
{
int ret;
enum cmd_status cmds = cmd_status();
if (cmds == CMDS_XCMD)
- return;
+ return 0;
ret = wgetch(top.win);
if (ret == ERR || ret == KEY_RESIZE)
- return;
- if (cmds == CMDS_IDLE)
- return handle_command(ret);
+ return 0;
+ if (cmds == CMDS_IDLE) {
+ handle_command(ret);
+ return 0;
+ }
if (cmd_pid != 0)
kill(cmd_pid, SIGTERM);
+ return 0;
}
-static void signal_pre_select(fd_set *rfds, int *max_fileno)
+static void signal_pre_select(struct sched *s, struct task *t)
{
- para_fd_set(signal_pipe, rfds, max_fileno);
-}
-
-/*
- * This is the core select loop. It checks the following fds:
- *
- * - signal pipe
- * - stdin
- * - stdout/stderr of display or internal commands
- */
-__noreturn static void do_select(void)
-{
- fd_set rfds;
- int ret, max_fileno;
- struct timeval tv;
-
-repeat:
- tv.tv_sec = conf.timeout_arg / 1000;
- tv.tv_usec = (conf.timeout_arg % 1000) * 1000;
- FD_ZERO(&rfds);
- max_fileno = 0;
- status_pre_select(&rfds, &max_fileno, &tv);
- signal_pre_select(&rfds, &max_fileno);
- command_pre_select(&rfds, &max_fileno);
- input_pre_select(&rfds, &max_fileno);
- ret = para_select(max_fileno + 1, &rfds, NULL, &tv);
- if (ret <= 0)
- goto repeat; /* skip fd checks */
- signal_post_select(&rfds);
- command_post_select(&rfds);
- status_post_select(&rfds);
- input_post_select();
- goto repeat;
+ struct signal_task *st = container_of(t, struct signal_task, task);
+ para_fd_set(st->fd, &s->rfds, &s->max_fileno);
}
static void print_scroll_msg(void)
exit(0);
}
+static int setup_tasks_and_schedule(void)
+{
+ struct sched sched = {
+ .default_timeout = {
+ .tv_sec = conf.timeout_arg / 1000,
+ .tv_usec = (conf.timeout_arg % 1000) * 1000,
+ },
+ };
+ struct cmd_task cmd_task = {
+ .task = {
+ .status = "cmd",
+ .pre_select = command_pre_select,
+ .post_select = command_post_select,
+ },
+ };
+ struct status_task status_task = {
+ .task = {
+ .status = "status",
+ .pre_select = status_pre_select,
+ .post_select = status_post_select,
+ },
+ };
+ struct input_task input_task = {
+ .task = {
+ .status = "input",
+ .pre_select = input_pre_select,
+ .post_select = input_post_select,
+ },
+ };
+ struct signal_task signal_task = {
+ .task = {
+ .status = "signal",
+ .pre_select = signal_pre_select,
+ .post_select = signal_post_select,
+ },
+ };
+ signal_task.fd = para_signal_init();
+ para_install_sighandler(SIGINT);
+ para_install_sighandler(SIGTERM);
+ para_install_sighandler(SIGCHLD);
+ para_install_sighandler(SIGWINCH);
+ para_install_sighandler(SIGUSR1);
+
+ register_task(&sched, &cmd_task.task);
+ register_task(&sched, &status_task.task);
+ register_task(&sched, &input_task.task);
+ register_task(&sched, &signal_task.task);
+ return schedule(&sched);
+}
+
int main(int argc, char *argv[])
{
gui_cmdline_parser(argc, argv, &conf); /* exits on errors */
if (conf.help_given || conf.detailed_help_given)
print_help_and_die();
parse_config_file_or_die(false /* override */);
- setup_signal_handling();
bot_win_rb = ringbuffer_new(RINGBUFFER_SIZE);
setlocale(LC_CTYPE, "");
initscr(); /* needed only once, always successful */
init_curses();
- do_select();
+ return setup_tasks_and_schedule() < 0? EXIT_FAILURE : EXIT_SUCCESS;
}