diff options
author | Lennart Poettering <lennart@poettering.net> | 2023-11-23 18:06:05 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2024-01-02 17:57:34 +0100 |
commit | a3f3243613b01903f5850a250c793d48d16ebb95 (patch) | |
tree | 2adc9a5d60f187b5edb71d805d3196e2093637ff /src | |
parent | Merge pull request #30684 from systemd/update-labeler-configuration (diff) | |
download | systemd-a3f3243613b01903f5850a250c793d48d16ebb95.tar.xz systemd-a3f3243613b01903f5850a250c793d48d16ebb95.zip |
pidref: add helpers for waiting for pidref processes
A simple test case is added in a follow-up commit.
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/missing_wait.h | 8 | ||||
-rw-r--r-- | src/basic/pidref.c | 39 | ||||
-rw-r--r-- | src/basic/pidref.h | 14 |
3 files changed, 60 insertions, 1 deletions
diff --git a/src/basic/missing_wait.h b/src/basic/missing_wait.h new file mode 100644 index 0000000000..a24779d977 --- /dev/null +++ b/src/basic/missing_wait.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <sys/wait.h> + +#ifndef P_PIDFD +#define P_PIDFD 3 +#endif diff --git a/src/basic/pidref.c b/src/basic/pidref.c index cf1c165b60..972853bbd6 100644 --- a/src/basic/pidref.c +++ b/src/basic/pidref.c @@ -3,6 +3,7 @@ #include "errno-util.h" #include "fd-util.h" #include "missing_syscall.h" +#include "missing_wait.h" #include "parse-util.h" #include "pidref.h" #include "process-util.h" @@ -302,6 +303,44 @@ bool pidref_is_self(const PidRef *pidref) { return pidref->pid == getpid_cached(); } +int pidref_wait(const PidRef *pidref, siginfo_t *ret, int options) { + int r; + + if (!pidref_is_set(pidref)) + return -ESRCH; + + if (pidref->pid == 1 || pidref->pid == getpid_cached()) + return -ECHILD; + + siginfo_t si = {}; + + if (pidref->fd >= 0) { + r = RET_NERRNO(waitid(P_PIDFD, pidref->fd, &si, options)); + if (r >= 0) { + if (ret) + *ret = si; + return r; + } + if (r != -EINVAL) /* P_PIDFD was added in kernel 5.4 only */ + return r; + } + + r = RET_NERRNO(waitid(P_PID, pidref->pid, &si, options)); + if (r >= 0 && ret) + *ret = si; + return r; +} + +int pidref_wait_for_terminate(const PidRef *pidref, siginfo_t *ret) { + int r; + + for (;;) { + r = pidref_wait(pidref, ret, WEXITED); + if (r != -EINTR) + return r; + } +} + static void pidref_hash_func(const PidRef *pidref, struct siphash *state) { siphash24_compress_typesafe(pidref->pid, state); } diff --git a/src/basic/pidref.h b/src/basic/pidref.h index a01d4cc85b..0fbffb3320 100644 --- a/src/basic/pidref.h +++ b/src/basic/pidref.h @@ -55,7 +55,19 @@ int pidref_new_from_pid(pid_t pid, PidRef **ret); int pidref_kill(const PidRef *pidref, int sig); int pidref_kill_and_sigcont(const PidRef *pidref, int sig); -int pidref_sigqueue(const PidRef *pidfref, int sig, int value); +int pidref_sigqueue(const PidRef *pidref, int sig, int value); + +int pidref_wait(const PidRef *pidref, siginfo_t *siginfo, int options); +int pidref_wait_for_terminate(const PidRef *pidref, siginfo_t *ret); + +static inline void pidref_done_sigkill_wait(PidRef *pidref) { + if (!pidref_is_set(pidref)) + return; + + (void) pidref_kill(pidref, SIGKILL); + (void) pidref_wait_for_terminate(pidref, NULL); + pidref_done(pidref); +} int pidref_verify(const PidRef *pidref); |