The branch main has been updated by des:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=c8f5e6819d4d81906c4a1641b5c9f02d8730481c

commit c8f5e6819d4d81906c4a1641b5c9f02d8730481c
Author:     Dag-Erling Smørgrav <[email protected]>
AuthorDate: 2026-07-27 10:15:31 +0000
Commit:     Dag-Erling Smørgrav <[email protected]>
CommitDate: 2026-07-27 10:15:31 +0000

    pwait: Optionally wait until process is reaped
    
    If the new -r option is specified, wait until the target process not
    only terminates but is reaped.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Sponsored by:   NetApp, Inc.
    Reviewed by:    kib, markj
    Differential Revision:  https://reviews.freebsd.org/D58314
---
 bin/pwait/pwait.1 | 17 ++++++++++++++---
 bin/pwait/pwait.c | 41 +++++++++++++++++++++++++++++------------
 2 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/bin/pwait/pwait.1 b/bin/pwait/pwait.1
index d92b829b1d6a..2776d3439a31 100644
--- a/bin/pwait/pwait.1
+++ b/bin/pwait/pwait.1
@@ -30,7 +30,7 @@
 .\" USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 .\" OF SUCH DAMAGE.
 .\"
-.Dd October 22, 2025
+.Dd July 22, 2026
 .Dt PWAIT 1
 .Os
 .Sh NAME
@@ -39,7 +39,7 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl t Ar duration
-.Op Fl opv
+.Op Fl oprv
 .Ar pid
 \&...
 .Sh DESCRIPTION
@@ -53,6 +53,17 @@ The following option is available:
 Exit when any of the given processes has terminated.
 .It Fl p
 On exit, print a list of processes that have not terminated.
+.It Fl r
+Do not exit until target processes have not only terminated, but been
+reaped by a call to the
+.Xr wait 2
+family of functions.
+Without this flag, target processes may still exist as zombies when
+.Nm
+exits.
+Beware of deadlocks if a target process's reaper (usually its parent)
+is directly or indirectly blocked by
+.Nm .
 .It Fl t Ar duration
 If any process is still running after
 .Ar duration ,
@@ -127,8 +138,8 @@ $ sleep 30 & sleep 40 &
 [2] 1675
 $ pwait -v -t 60 1674 1675
 1674: exited with status 0.
-1675: exited with status 0.
 [1]-  Done                    sleep 30
+1675: exited with status 0.
 [2]+  Done                    sleep 40
 $ echo $?
 0
diff --git a/bin/pwait/pwait.c b/bin/pwait/pwait.c
index 7f134036f1b9..36c6644f5474 100644
--- a/bin/pwait/pwait.c
+++ b/bin/pwait/pwait.c
@@ -40,6 +40,7 @@
 #include <sys/tree.h>
 #include <sys/wait.h>
 
+#include <assert.h>
 #include <err.h>
 #include <errno.h>
 #include <signal.h>
@@ -68,7 +69,7 @@ RB_GENERATE_STATIC(pidtree, pid, entry, pidcmp);
 static void
 usage(void)
 {
-       fprintf(stderr, "usage: pwait [-t timeout] [-opv] pid ...\n");
+       fprintf(stderr, "usage: pwait [-oprv] [-t timeout] pid ...\n");
        exit(EX_USAGE);
 }
 
@@ -86,16 +87,17 @@ main(int argc, char *argv[])
        size_t sz;
        long pid;
        pid_t mypid;
-       int i, kq, n, ndone, nleft, opt, pid_max, ret, status;
-       bool oflag, pflag, tflag, verbose;
+       int i, kq, n, ndone, nleft, notes, opt, pid_max, ret, status;
+       bool oflag, pflag, rflag, tflag, verbose;
 
        oflag = false;
        pflag = false;
+       rflag = false;
        tflag = false;
        verbose = false;
        memset(&itv, 0, sizeof(itv));
 
-       while ((opt = getopt(argc, argv, "opt:v")) != -1) {
+       while ((opt = getopt(argc, argv, "oprt:v")) != -1) {
                switch (opt) {
                case 'o':
                        oflag = true;
@@ -103,6 +105,9 @@ main(int argc, char *argv[])
                case 'p':
                        pflag = true;
                        break;
+               case 'r':
+                       rflag = true;
+                       break;
                case 't':
                        tflag = true;
                        errno = 0;
@@ -165,6 +170,9 @@ main(int argc, char *argv[])
        }
        ndone = nleft = 0;
        mypid = getpid();
+       notes = rflag ? NOTE_REAP : NOTE_EXIT;
+       if (verbose)
+               notes |= NOTE_EXIT;
        for (n = 0; n < argc; n++) {
                s = argv[n];
                /* Undocumented Solaris compat */
@@ -190,7 +198,7 @@ main(int argc, char *argv[])
                        free(p);
                        continue;
                }
-               EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+               EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, notes, 0, NULL);
                if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) {
                        if (errno != ESRCH)
                                err(EX_OSERR, "kevent()");
@@ -230,9 +238,11 @@ main(int argc, char *argv[])
                                        printf("timeout\n");
                                }
                                ret = 124;
+                               continue;
                        }
+                       assert(e[i].filter == EVFILT_PROC);
                        pid = e[i].ident;
-                       if (verbose) {
+                       if ((e[i].fflags & NOTE_EXIT) && verbose) {
                                status = e[i].data;
                                if (WIFEXITED(status)) {
                                        printf("%ld: exited with status %d.\n",
@@ -244,13 +254,20 @@ main(int argc, char *argv[])
                                        printf("%ld: terminated.\n", pid);
                                }
                        }
-                       k.pid = pid;
-                       if ((p = RB_FIND(pidtree, &pids, &k)) != NULL) {
-                               RB_REMOVE(pidtree, &pids, p);
-                               free(p);
-                               ndone++;
+                       if ((e[i].fflags & NOTE_REAP) && verbose) {
+                               printf("%ld: reaped.\n", pid);
+                       }
+                       if ((e[i].fflags & NOTE_REAP) ||
+                           (!rflag && (e[i].fflags & NOTE_EXIT))) {
+                               /* this process is done */
+                               k.pid = pid;
+                               if ((p = RB_FIND(pidtree, &pids, &k)) != NULL) {
+                                       RB_REMOVE(pidtree, &pids, p);
+                                       free(p);
+                                       ndone++;
+                               }
+                               --nleft;
                        }
-                       --nleft;
                }
        }
        if (pflag) {

Reply via email to