]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pidref: add helpers for waiting for pidref processes
authorLennart Poettering <lennart@poettering.net>
Thu, 23 Nov 2023 17:06:05 +0000 (18:06 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 2 Jan 2024 16:57:34 +0000 (17:57 +0100)
A simple test case is added in a follow-up commit.

src/basic/missing_wait.h [new file with mode: 0644]
src/basic/pidref.c
src/basic/pidref.h

diff --git a/src/basic/missing_wait.h b/src/basic/missing_wait.h
new file mode 100644 (file)
index 0000000..a24779d
--- /dev/null
@@ -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
index cf1c165b605b5ffba9943d61c4a9f6e9b9f47793..972853bbd6b99c7ed6cd76c8ccf50ac49e5ee0d4 100644 (file)
@@ -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);
 }
index a01d4cc85ba078b8f1200895051d9fbd1bccb4fc..0fbffb332064fb4debf95df57e7bef8ec67ec57c 100644 (file)
@@ -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);