summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2023-11-23 18:06:05 +0100
committerLennart Poettering <lennart@poettering.net>2024-01-02 17:57:34 +0100
commita3f3243613b01903f5850a250c793d48d16ebb95 (patch)
tree2adc9a5d60f187b5edb71d805d3196e2093637ff /src
parentMerge pull request #30684 from systemd/update-labeler-configuration (diff)
downloadsystemd-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.h8
-rw-r--r--src/basic/pidref.c39
-rw-r--r--src/basic/pidref.h14
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);