static void test_pid_to_ptr(void) { assert_se(PTR_TO_PID(NULL) == 0); assert_se(PID_TO_PTR(0) == NULL); assert_se(PTR_TO_PID(PID_TO_PTR(1)) == 1); assert_se(PTR_TO_PID(PID_TO_PTR(2)) == 2); assert_se(PTR_TO_PID(PID_TO_PTR(-1)) == -1); assert_se(PTR_TO_PID(PID_TO_PTR(-2)) == -2); assert_se(PTR_TO_PID(PID_TO_PTR(INT16_MAX)) == INT16_MAX); assert_se(PTR_TO_PID(PID_TO_PTR(INT16_MIN)) == INT16_MIN); #if SIZEOF_PID_T >= 4 assert_se(PTR_TO_PID(PID_TO_PTR(INT32_MAX)) == INT32_MAX); assert_se(PTR_TO_PID(PID_TO_PTR(INT32_MIN)) == INT32_MIN); #endif }
static void wait_for_children(Set *pids, sigset_t *mask) { usec_t until; assert(mask); if (set_isempty(pids)) return; until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC; for (;;) { struct timespec ts; int k; usec_t n; void *p; Iterator i; /* First, let the kernel inform us about killed * children. Most processes will probably be our * children, but some are not (might be our * grandchildren instead...). */ for (;;) { pid_t pid; pid = waitpid(-1, NULL, WNOHANG); if (pid == 0) break; if (pid < 0) { if (errno == ECHILD) break; log_error_errno(errno, "waitpid() failed: %m"); return; } (void) set_remove(pids, PID_TO_PTR(pid)); } /* Now explicitly check who might be remaining, who * might not be our child. */ SET_FOREACH(p, pids, i) { /* We misuse getpgid as a check whether a * process still exists. */ if (getpgid(PTR_TO_PID(p)) >= 0) continue; if (errno != ESRCH) continue; set_remove(pids, p); } if (set_isempty(pids)) return; n = now(CLOCK_MONOTONIC); if (n >= until) return; timespec_store(&ts, until - n); k = sigtimedwait(mask, NULL, &ts); if (k != SIGCHLD) { if (k < 0 && errno != EAGAIN) { log_error_errno(errno, "sigtimedwait() failed: %m"); return; } if (k >= 0) log_warning("sigtimedwait() returned unexpected signal."); } } }