diff options
author | Lennart Poettering <lennart@poettering.net> | 2010-04-13 02:05:27 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2010-04-13 02:05:27 +0200 |
commit | 4112df163517478207526e0d3e7278ab1acf1f9f (patch) | |
tree | bcca7673aa52e52d423bf83c30c9bafe15b9642c | |
parent | 8d0e8067af90e2a05d2051e7fdbe0b7f847dd167 (diff) |
manager: instead of using siginfo_t when reading SIGCHLD PIDs, run waitid() twice to avoid dropped signals
-rw-r--r-- | manager.c | 44 |
1 files changed, 32 insertions, 12 deletions
@@ -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: |