mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
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
This commit is contained in:
1 parent
2bacbbecb1
commit
c8f5e6819d
2 files changed
+43
-15
No files matched your search
+14
-3
@@ -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
|
||||
|
||||
+29
-12
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user