summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--manager.c44
1 files changed, 32 insertions, 12 deletions
diff --git a/manager.c b/manager.c
index cf13e254d5..b78f3c4aca 100644
--- 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: