Handle child exit status on mainloop context 60/34360/9
authorSangyoon Jang <s89.jang@samsung.com>
Mon, 26 Jan 2015 02:53:39 +0000 (11:53 +0900)
committerSangyoon Jang <s89.jang@samsung.com>
Tue, 27 Jan 2015 08:11:27 +0000 (00:11 -0800)
handle child exit status using pipe
when signal catched, write exit status to pipe and handle it on
mainloop context

Change-Id: I5069cd8352a87df7cb96520c8523db8331229fc4
Signed-off-by: Sangyoon Jang <s89.jang@samsung.com>
server/src/pkgmgr-server.c

index 0fa6580..5987b08 100644 (file)
@@ -89,14 +89,18 @@ is dynamically determined.
 char backend_mode = 63; /*00111111*/
 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;
+
 backend_info *begin;
 extern queue_info_map *start;
 extern int entries;
-int pos = 0;
-/*To store info in case of backend crash*/
-char pname[MAX_PKG_NAME_LEN] = {'\0'};
-char ptype[MAX_PKG_TYPE_LEN] = {'\0'};
-char args[MAX_PKG_ARGS_LEN] = {'\0'};
 
 GMainLoop *mainloop = NULL;
 
@@ -121,7 +125,6 @@ struct appdata {
        OPERATION_TYPE op_type;
 };
 
-
 static int __check_backend_status_for_exit();
 static int __check_queue_status_for_exit();
 static int __check_backend_mode();
@@ -135,13 +138,11 @@ static void response_cb1(void *data, void *event_info);
 static void response_cb2(void *data, void *event_info);
 static int create_popup(struct appdata *ad);
 static void sighandler(int signo);
-static void _wait_backend(pid_t pid);
 static int __get_position_from_pkg_type(char *pkgtype);
 static int __is_efl_tpk_app(char *pkgpath);
 static int __xsystem(const char *argv[]);
 
 gboolean queue_job(void *data);
-gboolean send_fail_signal(void *data);
 gboolean exit_server(void *data);
 
 /* To check whether a particular backend is free/busy*/
@@ -686,7 +687,7 @@ int create_popup(struct appdata *ad)
        return 0;
 }
 
-gboolean send_fail_signal(void *data)
+static void send_fail_signal(char *pname, char *ptype, char *args)
 {
        DBG("send_fail_signal start\n");
        gboolean ret_parse;
@@ -697,7 +698,7 @@ gboolean send_fail_signal(void *data)
        pi = pkgmgr_installer_new();
        if (!pi) {
                DBG("Failure in creating the pkgmgr_installer object");
-               return FALSE;
+               return;
        }
        ret_parse = g_shell_parse_argv(args,
                                       &argcp, &argvp, &gerr);
@@ -705,125 +706,126 @@ gboolean send_fail_signal(void *data)
                DBG("Failed to split args: %s", args);
                DBG("messsage: %s", gerr->message);
                pkgmgr_installer_free(pi);
-               return FALSE;
+               return;
        }
 
        pkgmgr_installer_receive_request(pi, argcp, argvp);
        pkgmgr_installer_send_signal(pi, ptype, pname, "end", "fail");
        pkgmgr_installer_free(pi);
-       return FALSE;
+       return;
 }
 
-static void _wait_backend(pid_t pid)
+static gboolean pipe_io_handler(GIOChannel *io, GIOCondition cond, gpointer data)
 {
-       int status;
-       pid_t cpid;
-       int i = 0;
-       backend_info *ptr = NULL;
-       ptr = begin;
-       cpid = waitpid(pid, &status, 0);
-       if (cpid != pid)
-               ERR("WaitBackend Faillure %d",cpid);
-       else if (WIFEXITED(status)) {
-                       DBG("child NORMAL exit [%d]\n", cpid);
-                       for(i = 0; i < num_of_backends; i++)
-                       {
-                               if (cpid == (ptr + i)->pid) {
-                                       __set_backend_free(i);
-                                       __set_backend_mode(i);
-                                       __unset_recovery_mode((ptr + i)->pkgid, (ptr + i)->pkgtype);
-                                       ERR(" STATUS = %d \n",(WEXITSTATUS (status)));
-                                       if (WEXITSTATUS (status) != 0) {
-                                               strncpy(pname, (ptr + i)->pkgid, MAX_PKG_NAME_LEN-1);
-                                               strncpy(ptype, (ptr + i)->pkgtype, MAX_PKG_TYPE_LEN-1);
-                                               strncpy(args, (ptr + i)->args, MAX_PKG_ARGS_LEN-1);
-                                               g_idle_add(send_fail_signal, NULL);
-                                       }
-                                       break;
-                               }
-                               else
-                                       DBG("PID of registered backend is  [%d]\n", (ptr + i)->pid);
+       int x;
+       GError *err = NULL;
+       GIOStatus s;
+       gsize len;
+       struct signal_info_t info;
+       backend_info *ptr = begin;
+
+       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);
+               g_error_free(err);
+               return TRUE;
+       }
+
+       for (x = 0; x < num_of_backends; x++, ptr++) {
+               if (ptr && ptr->pid == info.pid)
+                       break;
+       }
 
-                       }
-               }
-       else if (WIFSIGNALED(status)) {
-                       DBG("child SIGNALED exit [%d]\n", cpid);
-                       /*get the pkgid and pkgtype to send fail signal*/
-                       for(i = 0; i < num_of_backends; i++)
-                       {
-                               if (cpid == (ptr + i)->pid) {
-                                       __set_backend_free(i);
-                                       __set_backend_mode(i);
-                                       __unset_recovery_mode((ptr + i)->pkgid, (ptr + i)->pkgtype);
-                                       strncpy(pname, (ptr + i)->pkgid, MAX_PKG_NAME_LEN-1);
-                                       strncpy(ptype, (ptr + i)->pkgtype, MAX_PKG_TYPE_LEN-1);
-                                       strncpy(args, (ptr + i)->args, MAX_PKG_ARGS_LEN-1);
-                                       g_idle_add(send_fail_signal, NULL);
-                                       break;
-                               }
-                       }
-               }
+       if (x == num_of_backends) {
+               ERR("Unknown child exit");
+               return -1;
+       }
+
+       __set_backend_free(x);
+       __set_backend_mode(x);
+       __unset_recovery_mode(ptr->pkgid, ptr->pkgtype);
+       if (WIFSIGNALED(info.status) || WEXITSTATUS(info.status)) {
+               send_fail_signal(ptr->pkgid, ptr->pkgtype, ptr->args);
+               DBG("backend[%s] exit with error", ptr->pkgtype);
+       } else {
+               DBG("backend[%s] exit", ptr->pkgtype);
+       }
+
+       return TRUE;
 }
 
+static int __init_backend_info(void)
+{
+       backend_info *ptr;
+
+       /*Allocate memory for holding pid, pkgtype and pkgid*/
+       ptr = (backend_info*)calloc(num_of_backends, sizeof(backend_info));
+       if (ptr == NULL) {
+               DBG("Malloc Failed\n");
+               return -1;
+       }
+       begin = ptr;
+
+       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 */
+       free(begin);
+}
 
 static void sighandler(int signo)
 {
-       int status;
-       pid_t cpid;
-       int i = 0;
-       backend_info *ptr = NULL;
-       ptr = begin;
+       struct signal_info_t info;
 
-       while ((cpid = waitpid(-1, &status, WNOHANG)) > 0) {
-               DBG("child exit [%d]\n", cpid);
-               if (WIFEXITED(status)) {
-                       DBG("child NORMAL exit [%d]\n", cpid);
-                       for(i = 0; i < num_of_backends; i++)
-                       {
-                               if (cpid == (ptr + i)->pid) {
-                                       __set_backend_free(i);
-                                       __set_backend_mode(i);
-                                       __unset_recovery_mode((ptr + i)->pkgid, (ptr + i)->pkgtype);
-
-                                       if (WEXITSTATUS (status) != 0) {
-                                               strncpy(pname, (ptr + i)->pkgid, MAX_PKG_NAME_LEN-1);
-                                               strncpy(ptype, (ptr + i)->pkgtype, MAX_PKG_TYPE_LEN-1);
-                                               strncpy(args, (ptr + i)->args, MAX_PKG_ARGS_LEN-1);
-                                               g_idle_add(send_fail_signal, NULL);
-                                       }
-                                       break;
-                               }
-                               else
-                                       DBG("PID of registered backend is  [%d]\n", (ptr + i)->pid);
+       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(errno));
+}
 
-                       }
-               }
-               else if (WIFSIGNALED(status)) {
-                       DBG("child SIGNALED exit [%d]\n", cpid);
-                       /*get the pkgid and pkgtype to send fail signal*/
-                       for(i = 0; i < num_of_backends; i++)
-                       {
-                               if (cpid == (ptr + i)->pid) {
-                                       __set_backend_free(i);
-                                       __set_backend_mode(i);
-                                       __unset_recovery_mode((ptr + i)->pkgid, (ptr + i)->pkgtype);
-                                       strncpy(pname, (ptr + i)->pkgid, MAX_PKG_NAME_LEN-1);
-                                       strncpy(ptype, (ptr + i)->pkgtype, MAX_PKG_TYPE_LEN-1);
-                                       strncpy(args, (ptr + i)->args, MAX_PKG_ARGS_LEN-1);
-                                       g_idle_add(send_fail_signal, NULL);
-                                       break;
-                               }
-                       }
-               }
+static int __register_signal_handler(void)
+{
+       static int sig_reg = 0;
+       struct sigaction act;
+
+       if (sig_reg)
+               return 0;
+
+       act.sa_handler = sighandler;
+       sigemptyset(&act.sa_mask);
+       act.sa_flags = SA_NOCLDSTOP;
+       if (sigaction(SIGCHLD, &act, NULL) < 0) {
+               ERR("signal: SIGCHLD failed\n");
+               return -1;
        }
 
+       if (g_timeout_add_seconds(2, exit_server, NULL))
+               DBG("g_timeout_add_seconds() Added to Main Loop");
+
+       sig_reg = 1;
+       return 0;
 }
 
 void req_cb(void *cb_data, uid_t uid, const char *req_id, const int req_type,
            const char *pkg_type, const char *pkgid, const char *args,
            const char *cookie, int *ret)
 {
-       static int sig_reg = 0;
        int err = -1;
        int p = 0;
        int cookie_result = 0;
@@ -859,21 +861,11 @@ void req_cb(void *cb_data, uid_t uid, const char *req_id, const int req_type,
         * if UID != Regular USER & UID != GLOBAL USER  == TRUE ==> NOT GRANTED
         * if RUID == Regular USER & UID != RUID == True ==> NOT GRANTED
         *  */
-       if (sig_reg == 0) {
-               struct sigaction act;
-
-               act.sa_handler = sighandler;
-               sigemptyset(&act.sa_mask);
-               act.sa_flags = SA_NOCLDSTOP;
-
-               if (sigaction(SIGCHLD, &act, NULL) < 0) {
-                       DBG("signal: SIGCHLD failed\n");
-               } else
-                       DBG("signal: SIGCHLD succeed\n");
-               if (g_timeout_add_seconds(2, exit_server, NULL))
-                       DBG("g_timeout_add_seconds() Added to Main Loop");
 
-               sig_reg = 1;
+       if (__register_signal_handler()) {
+               ERR("failed to register signal handler");
+               *ret = COMM_RET_ERROR;
+               goto err;
        }
 
        DBG("req_type=(%d) drawing_popup=(%d) backend_flag=(%d)\n", req_type,
@@ -1745,7 +1737,6 @@ pop:
 
        default:        /* parent */
                DBG("parent exit\n");
-               _wait_backend((ptr + x)->pid);
                _save_queue_status(item, "done");
                break;
        }
@@ -1835,7 +1826,6 @@ int main(int argc, char *argv[])
        pid_t pid;
        char *backend_cmd = NULL;
        char *backend_name = NULL;
-       backend_info *ptr = NULL;
        int r;
 
        DBG("server start");
@@ -1892,14 +1882,11 @@ int main(int argc, char *argv[])
                return -1;
        }
 
-       /*Allocate memory for holding pid, pkgtype and pkgid*/
-       ptr = (backend_info*)calloc(num_of_backends, sizeof(backend_info));
-       if (ptr == NULL) {
-               DBG("Malloc Failed\n");
+       r = __init_backend_info();
+       if (r) {
+               DBG("backend info init failed");
                return -1;
        }
-       memset(ptr, '\0', num_of_backends * sizeof(backend_info));
-       begin = ptr;
 
        g_type_init();
        mainloop = g_main_loop_new(NULL, FALSE);
@@ -1922,11 +1909,7 @@ int main(int argc, char *argv[])
 
        DBG("Quit main loop.");
        _pm_queue_final();
-       /*Free backend info */
-       if (begin) {
-               free(begin);
-               begin = NULL;
-       }
+       __fini_backend_info();
 
        DBG("package manager server terminated.");