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 pid_t cmd_pid;
static int command_fds[2] = {-1, -1};
-static int stat_pipe = -1;
static struct gui_args_info conf;
static int loglevel;
static struct gui_command command_list[] = {GUI_COMMANDS {.name = NULL}};
+struct input_task {
+ struct task task;
+};
+
+struct status_task {
+ struct task task;
+ char *buf;
+ int bufsize, loaded;
+ struct timeval next_exec;
+ int fd;
+};
+
+#define COMMAND_BUF_SIZE 32768
+
+struct cmd_task {
+ struct task task;
+ char command_buf[2][COMMAND_BUF_SIZE]; /* stdout/stderr of command */
+ int cbo[2]; /* command buf offsets */
+ unsigned flags[2]; /* passed to for_each_line() */
+};
+
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, struct task *t)
{
- struct timeval atm, diff;
+ struct status_task *st = container_of(t, struct status_task, task);
- 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 */
+ if (st->fd >= 0)
+ return para_fd_set(st->fd, &s->rfds, &s->max_fileno);
+ sched_request_barrier_or_min_delay(&st->next_exec, s);
}
-static void status_post_select(fd_set *rfds)
+static int status_post_select(struct sched *s, struct task *t)
{
- static char *buf;
- static int bufsize, loaded;
+ struct status_task *st = container_of(t, struct status_task, task);
size_t sz;
pid_t pid;
int ret, ret2;
- if (stat_pipe < 0) {
- struct timeval atm;
+ if (st->fd < 0) {
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(&st->next_exec, now, NULL) > 0)
+ return 0;
+ st->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;
+ st->fd = fds[1];
+ return 0;
}
- if (loaded >= bufsize) {
- if (bufsize > 1000 * 1000) {
- loaded = 0;
- return;
+ if (st->loaded >= st->bufsize) {
+ if (st->bufsize > 1000 * 1000) {
+ st->loaded = 0;
+ return 0;
}
- bufsize += bufsize + 1000;
- buf = para_realloc(buf, bufsize);
+ st->bufsize += st->bufsize + 1000;
+ st->buf = para_realloc(st->buf, st->bufsize);
}
- assert(loaded < bufsize);
- ret = read_nonblock(stat_pipe, buf + loaded, bufsize - loaded,
- rfds, &sz);
- loaded += sz;
- ret2 = for_each_stat_item(buf, loaded, update_item);
+ assert(st->loaded < st->bufsize);
+ ret = read_nonblock(st->fd, st->buf + st->loaded,
+ st->bufsize - st->loaded, &s->rfds, &sz);
+ st->loaded += sz;
+ ret2 = for_each_stat_item(st->buf, st->loaded, update_item);
if (ret < 0 || ret2 < 0) {
- loaded = 0;
+ st->loaded = 0;
PARA_NOTICE_LOG("closing stat pipe: %s\n", para_strerror(-ret));
- close(stat_pipe);
- stat_pipe = -1;
+ close(st->fd);
+ st->fd = -1;
clear_all_items();
free(stat_content[SI_BASENAME]);
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;
+ if (sz > 0 && sz < st->loaded)
+ memmove(st->buf, st->buf + st->loaded - sz, sz);
+ st->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
-
static enum cmd_status cmd_status(void)
{
if (command_fds[0] >= 0 || command_fds[1] >= 0)
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, struct task *t)
{
+ struct cmd_task *ct = container_of(t, struct cmd_task, task);
int i, ret;
- static char command_buf[2][COMMAND_BUF_SIZE];
- static int cbo[2]; /* command buf offsets */
- static unsigned flags[2]; /* for for_each_line() */
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);
- cbo[i] += sz;
- sz = cbo[i];
- cbo[i] = for_each_line(flags[i], command_buf[i], cbo[i],
- add_output_line, &i);
- if (sz != cbo[i]) { /* at least one line found */
+ ct->command_buf[i] + ct->cbo[i],
+ COMMAND_BUF_SIZE - 1 - ct->cbo[i], &s->rfds, &sz);
+ ct->cbo[i] += sz;
+ sz = ct->cbo[i];
+ ct->cbo[i] = for_each_line(ct->flags[i], ct->command_buf[i],
+ ct->cbo[i], add_output_line, &i);
+ if (sz != ct->cbo[i]) { /* at least one line found */
wrefresh(bot.win);
- flags[i] = 0;
+ ct->flags[i] = 0;
}
if (ret < 0 || cmd_pid == 0) {
if (ret < 0)
i, para_strerror(-ret));
close(command_fds[i]);
command_fds[i] = -1;
- flags[i] = 0;
- cbo[i] = 0;
+ ct->flags[i] = 0;
+ ct->cbo[i] = 0;
if (command_fds[!i] < 0) /* both fds closed */
- return;
+ return 1;
}
- if (cbo[i] == COMMAND_BUF_SIZE - 1) {
+ if (ct->cbo[i] == COMMAND_BUF_SIZE - 1) {
PARA_NOTICE_LOG("discarding overlong line");
- cbo[i] = 0;
- flags[i] = FELF_DISCARD_FIRST;
+ ct->cbo[i] = 0;
+ ct->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,
+ },
+ .fd = -1
+ };
+ 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;
}