chiark / gitweb /
manager: instead of using siginfo_t when reading SIGCHLD PIDs, run waitid() twice...
authorLennart Poettering <lennart@poettering.net>
Tue, 13 Apr 2010 00:05:27 +0000 (02:05 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 13 Apr 2010 00:05:27 +0000 (02:05 +0200)
manager.c

index cf13e25..b78f3c4 100644 (file)
--- a/manager.c
+++ b/manager.c
@@ -1440,26 +1440,53 @@ static int manager_dispatch_sigchld(Manager *m) {
                 Unit *u;
 
                 zero(si);
-                if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG) < 0) {
+
+                /* First we call waitd() for a PID and do not reap the
+                 * zombie. That way we can still access /proc/$PID for
+                 * it while it is a zombie. */
+                if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) {
 
                         if (errno == ECHILD)
                                 break;
 
+                        if (errno == EINTR)
+                                continue;
+
                         return -errno;
                 }
 
-                if (si.si_pid == 0)
+                if (si.si_pid <= 0)
                         break;
 
+                if (si.si_code == CLD_EXITED && si.si_code == CLD_KILLED && si.si_code == CLD_DUMPED) {
+                        char *name = NULL;
+
+                        get_process_name(si.si_pid, &name);
+                        log_debug("Got SIGCHLD for process %llu (%s)", (unsigned long long) si.si_pid, strna(name));
+                        free(name);
+                }
+
+                /* And now, we actually reap the zombie. */
+                if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
+                        if (errno == EINTR)
+                                continue;
+
+                        return -errno;
+                }
+
                 if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED)
                         continue;
 
-                log_debug("child %llu died (code=%s, status=%i)", (long long unsigned) si.si_pid, sigchld_code_to_string(si.si_code), si.si_status);
+                log_debug("Child %llu died (code=%s, status=%i/%s)",
+                          (long long unsigned) si.si_pid,
+                          sigchld_code_to_string(si.si_code),
+                          si.si_status,
+                          strna(si.si_code == CLD_EXITED ? exit_status_to_string(si.si_status) : strsignal(si.si_status)));
 
                 if (!(u = hashmap_remove(m->watch_pids, UINT32_TO_PTR(si.si_pid))))
                         continue;
 
-                log_debug("child %llu belongs to %s", (long long unsigned) si.si_pid, unit_id(u));
+                log_debug("Child %llu belongs to %s", (long long unsigned) si.si_pid, unit_id(u));
 
                 UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
         }
@@ -1495,16 +1522,9 @@ static int manager_process_signal_fd(Manager *m, bool *quit) {
 
                 switch (sfsi.ssi_signo) {
 
-                case SIGCHLD: {
-                        char *name = NULL;
-
-                        get_process_name(sfsi.ssi_pid, &name);
-                        log_debug("Got SIGCHLD for process %llu (%s)", (unsigned long long) sfsi.ssi_pid, strna(name));
-                        free(name);
-
+                case SIGCHLD:
                         sigchld = true;
                         break;
-                }
 
                 case SIGINT:
                 case SIGTERM: