]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pidref: add pidref_set_parent() for race-freely getting pidref on ppid
authorLennart Poettering <lennart@poettering.net>
Fri, 1 Dec 2023 16:14:33 +0000 (17:14 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 13 Dec 2023 17:00:14 +0000 (18:00 +0100)
src/basic/pidref.c
src/basic/pidref.h

index 69b5cad575973887a21f07b1b9b16e0200a0bb31..d3821c1f544204f192b4ca9a2ece35c4feedbef6 100644 (file)
@@ -106,6 +106,38 @@ int pidref_set_pidfd_consume(PidRef *pidref, int fd) {
         return r;
 }
 
+int pidref_set_parent(PidRef *ret) {
+        _cleanup_(pidref_done) PidRef parent = PIDREF_NULL;
+        pid_t ppid;
+        int r;
+
+        assert(ret);
+
+        /* Acquires a pidref to our parent process. Deals with the fact that parent processes might exit, and
+         * we get reparented to other processes, with our old parent's PID already being recycled. */
+
+        ppid = getppid();
+        for (;;) {
+                r = pidref_set_pid(&parent, ppid);
+                if (r < 0)
+                        return r;
+
+                if (parent.fd < 0) /* If pidfds are not available, then we are done */
+                        break;
+
+                pid_t now_ppid = getppid();
+                if (now_ppid == ppid) /* If our ppid is still the same, then we are done */
+                        break;
+
+                /* Otherwise let's try again with the new ppid */
+                ppid = now_ppid;
+                pidref_done(&parent);
+        }
+
+        *ret = TAKE_PIDREF(parent);
+        return 0;
+}
+
 void pidref_done(PidRef *pidref) {
         assert(pidref);
 
index dada069357def5f23ecd97b793010a9750cc6be6..a01d4cc85ba078b8f1200895051d9fbd1bccb4fc 100644 (file)
@@ -38,7 +38,7 @@ int pidref_set_pidstr(PidRef *pidref, const char *pid);
 int pidref_set_pidfd(PidRef *pidref, int fd);
 int pidref_set_pidfd_take(PidRef *pidref, int fd); /* takes ownership of the passed pidfd on success*/
 int pidref_set_pidfd_consume(PidRef *pidref, int fd); /* takes ownership of the passed pidfd in both success and failure */
-
+int pidref_set_parent(PidRef *ret);
 static inline int pidref_set_self(PidRef *pidref) {
         return pidref_set_pid(pidref, 0);
 }