Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 Jul 2026 10:17:17 +0000
From:      Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav <des@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: c8f5e6819d4d - main - pwait: Optionally wait until process is reaped
Message-ID:  <6a67302d.1f998.2405cd66@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by des:

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

commit c8f5e6819d4d81906c4a1641b5c9f02d8730481c
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-07-27 10:15:31 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
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) {


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a67302d.1f998.2405cd66>