diff options
Diffstat (limited to 'src/basic/process-util.c')
-rw-r--r-- | src/basic/process-util.c | 72 |
1 files changed, 61 insertions, 11 deletions
diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 611fd2339..2494ba6af 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -26,7 +26,6 @@ #include <signal.h> #include <stdbool.h> #include <stdio.h> -#include <stdio_ext.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> @@ -131,8 +130,6 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return -errno; } - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - if (max_length == 1) { /* If there's only room for one byte, return the empty string */ @@ -411,8 +408,6 @@ int is_kernel_thread(pid_t pid) { return -errno; } - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - count = fread(&c, 1, 1, f); eof = feof(f); fclose(f); @@ -497,8 +492,6 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) { return -errno; } - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - FOREACH_LINE(line, f, return -errno) { char *l; @@ -577,8 +570,6 @@ int get_process_environ(pid_t pid, char **env) { return -errno; } - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - while ((c = fgetc(f)) != EOF) { if (!GREEDY_REALLOC(outcome, allocated, sz + 5)) return -ENOMEM; @@ -714,6 +705,67 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod return -EPROTO; } +/* + * Return values: + * < 0 : wait_for_terminate_with_timeout() failed to get the state of the + * process, the process timed out, the process was terminated by a + * signal, or failed for an unknown reason. + * >=0 : The process terminated normally with no failures. + * + * Success is indicated by a return value of zero, a timeout is indicated + * by ETIMEDOUT, and all other child failure states are indicated by error + * is indicated by a non-zero value. + */ +int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) { + sigset_t mask; + int r; + usec_t until; + + assert_se(sigemptyset(&mask) == 0); + assert_se(sigaddset(&mask, SIGCHLD) == 0); + + /* Drop into a sigtimewait-based timeout. Waiting for the + * pid to exit. */ + until = now(CLOCK_MONOTONIC) + timeout; + for (;;) { + usec_t n; + siginfo_t status = {}; + struct timespec ts; + + n = now(CLOCK_MONOTONIC); + if (n >= until) + break; + + r = sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)) < 0 ? -errno : 0; + /* Assuming we woke due to the child exiting. */ + if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) { + if (status.si_pid == pid) { + /* This is the correct child.*/ + if (status.si_code == CLD_EXITED) + return (status.si_status == 0) ? 0 : -EPROTO; + else + return -EPROTO; + } + } + /* Not the child, check for errors and proceed appropriately */ + if (r < 0) { + switch (r) { + case -EAGAIN: + /* Timed out, child is likely hung. */ + return -ETIMEDOUT; + case -EINTR: + /* Received a different signal and should retry */ + continue; + default: + /* Return any unexpected errors */ + return r; + } + } + } + + return -EPROTO; +} + #if 0 /// UNNEEDED by elogind void sigkill_wait(pid_t pid) { assert(pid > 1); @@ -766,8 +818,6 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { return -errno; } - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - l = strlen(field); r = 0; |