]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Use waitid as the backup method for determining if a process has exited not waitpid
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 28 Aug 2021 15:25:19 +0000 (10:25 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 28 Aug 2021 15:25:19 +0000 (10:25 -0500)
Waitpid reaps the process which would cause an error in the resumption callback.

src/lib/util/event.c

index 006b019be133e935c9921721304d04e7c5bcb911..b37a48a928e3c6e8bfd23ffdf13a5fb0e36b2206 100644 (file)
@@ -1624,9 +1624,17 @@ int _fr_event_pid_wait(NDEBUG_LOCATION_ARGS
 
        EV_SET(&evset, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT | NOTE_EXITSTATUS, 0, ev);
 
+       /*
+        *      This deals with the race where the process exited
+        *      before we could add it to the kqueue.
+        *
+        *      Unless our caller is broken, the process should
+        *      still be available for reaping, so we check
+        *      waitid to see if there is a pending process and
+        *      then call the callback as kqueue would have done.
+        */
        if (unlikely(kevent(el->kq, &evset, 1, NULL, 0, NULL) < 0)) {
-               pid_t child;
-               int status;
+               siginfo_t       info;
 
                talloc_free(ev);
 
@@ -1634,11 +1642,21 @@ int _fr_event_pid_wait(NDEBUG_LOCATION_ARGS
                 *      If the child exited before kevent() was
                 *      called, we need to get its status via
                 *      waitpid().
+                *
+                *      We don't reap the process here to emulate
+                *      what kqueue does (notify but not reap).
                 */
-               child = waitpid(pid, &status, WNOHANG);
-               if (child == pid) {
-                       if (callback) callback(el, pid, status, uctx);
-                       return 0;
+               if (waitid(P_PID, pid, &info, WEXITED | WNOHANG | WNOWAIT) < 0) {
+                       switch (info.si_code) {
+                       case CLD_EXITED:
+                       case CLD_KILLED:
+                       case CLD_DUMPED:
+                               if (callback) callback(el, pid, info.si_status, uctx);
+                               return 0;
+
+                       default:
+                               break;
+                       }
                }
 
                /*