gui: Call waitpid() from exec and status task.
authorAndre Noll <maan@systemlinux.org>
Mon, 27 Jan 2014 10:35:08 +0000 (11:35 +0100)
committerAndre Noll <maan@systemlinux.org>
Sun, 4 May 2014 13:48:55 +0000 (15:48 +0200)
This commit changes signal_post_select() to not call waitpid() via
para_reap_child() any more. Instead it notifies all tasks using the
new error code E_GUI_SIGCHLD. The exec task and the status task honor
this notification and call waitpid() for their "own" pid to check
whether the executing process or the stat process has terminated and
to obtain the exit status.

Although neither task cares deeply about the exit code, the menu
commands, which will be implemented in subsequent patches, will
care. So it's good to have the option to get this information.

error.h
gui.c

diff --git a/error.h b/error.h
index 301e2ca..0f542a8 100644 (file)
--- a/error.h
+++ b/error.h
@@ -16,7 +16,6 @@ DEFINE_ERRLIST_OBJECT_ENUM;
 #define TIME_ERRORS
 #define CLOSE_ON_FORK_ERRORS
 #define DAEMON_ERRORS
-#define GUI_ERRORS
 #define GUI_THEME_ERRORS
 #define RINGBUFFER_ERRORS
 #define SCORE_ERRORS
@@ -87,6 +86,8 @@ extern const char **para_errlist[];
        PARA_ERROR(FLACDEC_DECODER_INIT, "could not init stream decoder"), \
        PARA_ERROR(FLACDEC_EOF, "flacdec encountered end of file condition"), \
 
+#define GUI_ERRORS \
+       PARA_ERROR(GUI_SIGCHLD, "received SIGCHLD"), \
 
 #define FLAC_AFH_ERRORS \
        PARA_ERROR(FLAC_CHAIN_ALLOC, "could not create metadata chain"), \
diff --git a/gui.c b/gui.c
index 9b7c2f9..db291c2 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -129,6 +129,7 @@ struct input_task {
 
 struct status_task {
        struct task task;
+       pid_t pid;
        char *buf;
        int bufsize, loaded;
        struct timeval next_exec;
@@ -601,24 +602,37 @@ static void status_pre_select(struct sched *s, struct task *t)
        struct status_task *st = container_of(t, struct status_task, task);
 
        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);
+               para_fd_set(st->fd, &s->rfds, &s->max_fileno);
+       if (task_get_notification(t) < 0)
+               return sched_min_delay(s);
+       if (st->fd < 0)
+               sched_request_barrier_or_min_delay(&st->next_exec, s);
 }
 
 static int status_post_select(struct sched *s, struct task *t)
 {
        struct status_task *st = container_of(t, struct status_task, task);
        size_t sz;
-       pid_t pid;
        int ret, ret2;
 
+       ret = task_get_notification(t);
+       if (ret == -E_GUI_SIGCHLD && st->pid > 0) {
+               int exit_status;
+               if (waitpid(st->pid, &exit_status, WNOHANG) == st->pid) {
+                       st->pid = 0;
+                       PARA_ERROR_LOG("stat command exit status: %d",
+                               exit_status);
+               }
+       }
        if (st->fd < 0) {
                int fds[3] = {0, 1, 0};
+               if (st->pid > 0)
+                       return 0;
                /* Avoid busy loop */
                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);
+               ret = para_exec_cmdline_pid(&st->pid, conf.stat_cmd_arg, fds);
                if (ret < 0)
                        return 0;
                ret = mark_fd_nonblocking(fds[1]);
@@ -781,23 +795,6 @@ static void init_curses(void)
        // noecho(); /* don't echo input */
 }
 
-static void check_sigchld(void)
-{
-       int ret;
-       pid_t pid;
-
-reap_next_child:
-       ret = para_reap_child(&pid);
-       if (ret <= 0)
-               return;
-       if (pid == exec_pid) {
-               exec_pid = 0;
-               init_curses();
-               print_in_bar(COLOR_MSG, " ");
-       }
-       goto reap_next_child;
-}
-
 /*
  * This sucker modifies its first argument. *handler and *arg are
  * pointers to 0-terminated strings (inside line). Crap.
@@ -928,7 +925,7 @@ static int signal_post_select(struct sched *s, __a_unused struct task *t)
                reread_conf();
                return 1;
        case SIGCHLD:
-               check_sigchld();
+               task_notify_all(s, E_GUI_SIGCHLD);
                return 1;
        }
        return 1;
@@ -943,26 +940,31 @@ static enum exec_status exec_status(void)
        return EXEC_IDLE;
 }
 
-static void exec_pre_select(struct sched *s, __a_unused struct task *t)
+static void exec_pre_select(struct sched *s, struct task *t)
 {
-       enum exec_status es = exec_status();
-
-       if (es != EXEC_DCMD)
-               return;
        if (exec_fds[0] >= 0)
                para_fd_set(exec_fds[0], &s->rfds, &s->max_fileno);
        if (exec_fds[1] >= 0)
                para_fd_set(exec_fds[1], &s->rfds, &s->max_fileno);
+       if (task_get_notification(t) < 0)
+               sched_min_delay(s);
 }
 
 static int exec_post_select(struct sched *s, struct task *t)
 {
        struct exec_task *ct = container_of(t, struct exec_task, task);
        int i, ret;
-       enum exec_status es = exec_status();
 
-       if (es != EXEC_DCMD)
-               return 0;
+       ret = task_get_notification(t);
+       if (ret == -E_GUI_SIGCHLD && exec_pid > 0) {
+               int exit_status;
+               if (waitpid(exec_pid, &exit_status, WNOHANG) == exec_pid) {
+                       exec_pid = 0;
+                       init_curses();
+                       PARA_INFO_LOG("command exit status: %d", exit_status);
+                       print_in_bar(COLOR_MSG, " ");
+               }
+       }
        for (i = 0; i < 2; i++) {
                size_t sz;
                if (exec_fds[i] < 0)