Use signalfd to handle SIGCHLD 43/119243/1
authorSangyoon Jang <s89.jang@samsung.com>
Thu, 16 Mar 2017 06:14:07 +0000 (15:14 +0900)
committerSangyoon Jang <s89.jang@samsung.com>
Thu, 16 Mar 2017 06:14:07 +0000 (15:14 +0900)
Change-Id: I6e6327508e074919d7347afdafdb13fa9555c13b
Signed-off-by: Sangyoon Jang <s89.jang@samsung.com>
src/pkgmgr-server.c

index cf55a28..38334d9 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/signalfd.h>
 #include <signal.h>
 #include <grp.h>
 #include <fcntl.h>
@@ -82,14 +83,8 @@ is dynamically determined.
 static char backend_busy = 0;
 extern int num_of_backends;
 
-struct signal_info_t {
-       pid_t pid;
-       int status;
-};
-
-static int pipe_sig[2];
-static GIOChannel *pipe_io;
-static guint pipe_wid;
+static GIOChannel *sio;
+static guint swid;
 static GHashTable *backend_info_table;
 static GMainLoop *mainloop;
 
@@ -98,7 +93,6 @@ static int __check_queue_status_for_exit(void);
 static int __is_backend_busy(int position);
 static void __set_backend_busy(int position);
 static void __set_backend_free(int position);
-static void sighandler(int signo);
 
 gboolean exit_server(void *data);
 
@@ -179,39 +173,42 @@ static int __setup_size_info_io(struct backend_job *job)
        return 0;
 }
 
-static gboolean pipe_io_handler(GIOChannel *io, GIOCondition cond,
+static gboolean __signal_handler(GIOChannel *io, GIOCondition cond,
                gpointer data)
 {
        GError *err = NULL;
        GIOStatus s;
        gsize len;
-       struct signal_info_t info;
+       struct signalfd_siginfo fdsi;
        struct backend_job *job;
+       pid_t pid;
+       int status;
 
-       s = g_io_channel_read_chars(io, (gchar *)&info,
-                       sizeof(struct signal_info_t), &len, &err);
-       if (s != G_IO_STATUS_NORMAL) {
-               ERR("Signal pipe read failed: %s", err->message);
+       s = g_io_channel_read_chars(io, (gchar *)&fdsi,
+                       sizeof(struct signalfd_siginfo), &len, &err);
+       if (s != G_IO_STATUS_NORMAL || len != sizeof(struct signalfd_siginfo)) {
+               ERR("Signal read failed");
                g_error_free(err);
                return TRUE;
        }
 
+       pid = waitpid(-1, &status, WNOHANG);
        job = (struct backend_job *)g_hash_table_lookup(backend_info_table,
-                       (gconstpointer)info.pid);
+                       (gconstpointer)pid);
        if (job == NULL) {
                ERR("Unknown child exit");
                return -1;
        }
 
        __set_backend_free(job->backend_slot);
-       if (WIFSIGNALED(info.status)) {
+       if (WIFSIGNALED(status)) {
                _send_fail_signal(job);
-               DBG("backend[%s] exit with signal[%d]", job->backend_type,
-                               WTERMSIG(info.status));
-       } else if (WEXITSTATUS(info.status)) {
-               DBG("backend[%s] exit with error", job->backend_type);
+               DBG("backend[%s][%d] exit with signal[%d]", job->backend_type,
+                               pid, WTERMSIG(status));
+       } else if (WEXITSTATUS(status)) {
+               DBG("backend[%s][%d] exit with error", job->backend_type, pid);
        } else {
-               DBG("backend[%s] exit", job->backend_type);
+               DBG("backend[%s][%d] exit", job->backend_type, pid);
        }
 
        if (job->extra) {
@@ -222,7 +219,7 @@ static gboolean pipe_io_handler(GIOChannel *io, GIOCondition cond,
                }
        }
 
-       g_hash_table_remove(backend_info_table, (gconstpointer)info.pid);
+       g_hash_table_remove(backend_info_table, (gconstpointer)pid);
        g_idle_add(queue_job, NULL);
 
        return TRUE;
@@ -234,60 +231,42 @@ static int __init_backend_info(void)
                        g_direct_equal, NULL,
                        (GDestroyNotify)_free_backend_job);
 
-       if (pipe(pipe_sig)) {
-               ERR("create pipe failed");
-               return -1;
-       }
-
-       pipe_io = g_io_channel_unix_new(pipe_sig[0]);
-       g_io_channel_set_encoding(pipe_io, NULL, NULL);
-       g_io_channel_set_buffered(pipe_io, FALSE);
-       pipe_wid = g_io_add_watch(pipe_io, G_IO_IN, pipe_io_handler, NULL);
-
        return 0;
 }
 
 static void __fini_backend_info(void)
 {
-       g_source_remove(pipe_wid);
-       g_io_channel_unref(pipe_io);
-       close(pipe_sig[0]);
-       close(pipe_sig[1]);
-
        /*Free backend info */
        g_hash_table_destroy(backend_info_table);
 }
 
-static void sighandler(int signo)
-{
-       struct signal_info_t info;
-       char buf[1024] = {0, };
-
-       info.pid = waitpid(-1, &info.status, WNOHANG);
-       if (write(pipe_sig[1], &info, sizeof(struct signal_info_t)) < 0)
-               ERR("failed to write result: %s",
-                               strerror_r(errno, buf, sizeof(buf)));
-}
-
 static int __register_signal_handler(void)
 {
-       static int sig_reg = 0;
-       struct sigaction act;
+       sigset_t mask;
+       int sfd;
 
-       if (sig_reg)
-               return 0;
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGCHLD);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
+               ERR("sigprocmask failed");
+               return -1;
+       }
 
-       act.sa_handler = sighandler;
-       sigemptyset(&act.sa_mask);
-       act.sa_flags = SA_NOCLDSTOP;
-       if (sigaction(SIGCHLD, &act, NULL) < 0) {
-               ERR("signal: SIGCHLD failed");
+       sfd = signalfd(-1, &mask, SFD_NONBLOCK);
+       if (sfd == -1) {
+               ERR("signalfd failed");
                return -1;
        }
 
+       sio = g_io_channel_unix_new(sfd);
+       g_io_channel_set_close_on_unref(sio, TRUE);
+       g_io_channel_set_encoding(sio, NULL, NULL);
+       g_io_channel_set_buffered(sio, FALSE);
+       swid = g_io_add_watch(sio, G_IO_IN, __signal_handler, NULL);
+
        g_timeout_add_seconds(2, exit_server, NULL);
 
-       sig_reg = 1;
        return 0;
 }
 
@@ -1691,6 +1670,11 @@ int main(int argc, char *argv[])
 
        DBG("server start");
 
+       if (__register_signal_handler()) {
+               ERR("failed to register signal handler");
+               return -1;
+       }
+
        r = _init_backend_queue();
        if (r) {
                DBG("Queue Initialization Failed");
@@ -1709,11 +1693,6 @@ int main(int argc, char *argv[])
                return -1;
        }
 
-       if (__register_signal_handler()) {
-               ERR("failed to register signal handler");
-               return -1;
-       }
-
 #if !GLIB_CHECK_VERSION(2, 35, 0)
        g_type_init();
 #endif
@@ -1732,6 +1711,9 @@ int main(int argc, char *argv[])
        __fini_backend_info();
        _fini_backend_queue();
 
+       g_source_remove(swid);
+       g_io_channel_unref(sio);
+
        DBG("package manager server terminated.");
 
        return 0;