Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F112019427
D9697.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D9697.diff
View Options
Index: head/bin/pwait/Makefile
===================================================================
--- head/bin/pwait/Makefile
+++ head/bin/pwait/Makefile
@@ -1,6 +1,10 @@
# $FreeBSD$
+.include <src.opts.mk>
+
PACKAGE=runtime
PROG= pwait
+SUBDIR.${MK_TESTS}+= tests
+
.include <bsd.prog.mk>
Index: head/bin/pwait/pwait.1
===================================================================
--- head/bin/pwait/pwait.1
+++ head/bin/pwait/pwait.1
@@ -32,7 +32,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 1, 2009
+.Dd March 7, 2017
.Dt PWAIT 1
.Os
.Sh NAME
@@ -40,6 +40,7 @@
.Nd wait for processes to terminate
.Sh SYNOPSIS
.Nm
+.Op Fl t Ar duration
.Op Fl v
.Ar pid
\&...
@@ -50,13 +51,36 @@
.Pp
The following option is available:
.Bl -tag -width indent
+.It Fl t Ar duration
+If any process is still running after
+.Ar duration ,
+.Nm
+will exit.
+The
+.Ar duration
+value can be integer or decimal numbers.
+Values without unit symbols are interpreted as seconds.
+.Pp
+Supported unit symbols are:
+.Bl -tag -width indent -compact
+.It s
+seconds
+.It m
+minutes
+.It h
+hours
+.El
.It Fl v
Print the exit status when each process terminates.
.El
-.Sh DIAGNOSTICS
+.Sh EXIT STATUS
The
.Nm
-utility returns 0 on success, and >0 if an error occurs.
+utility exits 0 on success, and >0 if an error occurs.
+.Pp
+If the
+.Fl t
+flag is specified and a timeout occurs, the exit status will be 124.
.Pp
Invalid pids elicit a warning message but are otherwise ignored.
.Sh SEE ALSO
Index: head/bin/pwait/pwait.c
===================================================================
--- head/bin/pwait/pwait.c
+++ head/bin/pwait/pwait.c
@@ -53,7 +53,7 @@
usage(void)
{
- fprintf(stderr, "usage: pwait [-v] pid ...\n");
+ fprintf(stderr, "usage: pwait [-t timeout] [-v] pid ...\n");
exit(EX_USAGE);
}
@@ -63,15 +63,46 @@
int
main(int argc, char *argv[])
{
+ struct itimerval itv;
int kq;
struct kevent *e;
- int verbose = 0;
+ int tflag, verbose;
int opt, nleft, n, i, duplicate, status;
long pid;
char *s, *end;
+ double timeout;
- while ((opt = getopt(argc, argv, "v")) != -1) {
+ tflag = verbose = 0;
+ memset(&itv, 0, sizeof(itv));
+ while ((opt = getopt(argc, argv, "t:v")) != -1) {
switch (opt) {
+ case 't':
+ tflag = 1;
+ errno = 0;
+ timeout = strtod(optarg, &end);
+ if (end == optarg || errno == ERANGE ||
+ timeout < 0)
+ errx(EX_DATAERR, "timeout value");
+ switch(*end) {
+ case 0:
+ case 's':
+ break;
+ case 'h':
+ timeout *= 60;
+ /* FALLTHROUGH */
+ case 'm':
+ timeout *= 60;
+ break;
+ default:
+ errx(EX_DATAERR, "timeout unit");
+ }
+ if (timeout > 100000000L)
+ errx(EX_DATAERR, "timeout value");
+ itv.it_value.tv_sec = (time_t)timeout;
+ timeout -= (time_t)timeout;
+ itv.it_value.tv_usec =
+ (suseconds_t)(timeout * 1000000UL);
+ break;
case 'v':
verbose = 1;
break;
@@ -91,7 +122,7 @@
if (kq == -1)
err(1, "kqueue");
- e = malloc(argc * sizeof(struct kevent));
+ e = malloc((argc + tflag) * sizeof(struct kevent));
if (e == NULL)
err(1, "malloc");
nleft = 0;
@@ -119,12 +150,30 @@
}
}
+ if (tflag) {
+ /*
+ * Explicitly detect SIGALRM so that an exit status of 124
+ * can be returned rather than 142.
+ */
+ EV_SET(e + nleft, SIGALRM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
+ if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1)
+ err(EX_OSERR, "kevent");
+ /* Ignore SIGALRM to not interrupt kevent(2). */
+ signal(SIGALRM, SIG_IGN);
+ if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
+ err(EX_OSERR, "setitimer");
+ }
while (nleft > 0) {
- n = kevent(kq, NULL, 0, e, nleft, NULL);
+ n = kevent(kq, NULL, 0, e, nleft + tflag, NULL);
if (n == -1)
err(1, "kevent");
- if (verbose)
- for (i = 0; i < n; i++) {
+ for (i = 0; i < n; i++) {
+ if (e[i].filter == EVFILT_SIGNAL) {
+ if (verbose)
+ printf("timeout\n");
+ return (124);
+ }
+ if (verbose) {
status = e[i].data;
if (WIFEXITED(status))
printf("%ld: exited with status %d.\n",
@@ -138,7 +187,8 @@
printf("%ld: terminated.\n",
(long)e[i].ident);
}
- nleft -= n;
+ --nleft;
+ }
}
exit(EX_OK);
Index: head/bin/pwait/tests/Makefile
===================================================================
--- head/bin/pwait/tests/Makefile
+++ head/bin/pwait/tests/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+ATF_TESTS_SH= pwait
+
+.include <bsd.test.mk>
Index: head/bin/pwait/tests/Makefile.depend
===================================================================
--- head/bin/pwait/tests/Makefile.depend
+++ head/bin/pwait/tests/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
Index: head/bin/pwait/tests/pwait.sh
===================================================================
--- head/bin/pwait/tests/pwait.sh
+++ head/bin/pwait/tests/pwait.sh
@@ -0,0 +1,242 @@
+# $FreeBSD$
+
+atf_test_case basic
+basic_head()
+{
+ atf_set "descr" "Basic tests on pwait(1) utility"
+}
+
+basic_body()
+{
+ sleep 1 &
+ p1=$!
+
+ sleep 5 &
+ p5=$!
+
+ sleep 10 &
+ p10=$!
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:0 \
+ -x timeout --preserve-status 15 pwait $p1 $p5 $p10
+
+ atf_check \
+ -o empty \
+ -e inline:"kill: $p1: No such process\n" \
+ -s exit:1 \
+ -x kill -0 $p1
+
+ atf_check \
+ -o empty \
+ -e inline:"kill: $p5: No such process\n" \
+ -s exit:1 \
+ -x kill -0 $p5
+
+ atf_check \
+ -o empty \
+ -e inline:"kill: $p10: No such process\n" \
+ -s exit:1 \
+ -x kill -0 $p10
+
+}
+
+basic_cleanup()
+{
+ kill $p1 $p5 $p10 >/dev/null 2>&1
+ wait $p1 $p5 $p10 >/dev/null 2>&1
+}
+
+atf_test_case time_unit
+time_unit_head()
+{
+ atf_set "descr" "Test parsing the timeout unit and value"
+}
+
+time_unit_body()
+{
+ init=1
+
+ atf_check \
+ -o empty \
+ -e inline:"pwait: timeout unit\n" \
+ -s exit:65 \
+ -x timeout --preserve-status 2 pwait -t 1d $init
+
+ atf_check \
+ -o empty \
+ -e inline:"pwait: timeout unit\n" \
+ -s exit:65 \
+ -x timeout --preserve-status 2 pwait -t 1d $init
+
+ atf_check \
+ -o empty \
+ -e inline:"pwait: timeout value\n" \
+ -s exit:65 \
+ -x timeout --preserve-status 2 pwait -t -1 $init
+
+ atf_check \
+ -o empty \
+ -e inline:"pwait: timeout value\n" \
+ -s exit:65 \
+ -x timeout --preserve-status 2 pwait -t 100000001 $init
+
+ # These long duration cases are expected to timeout from the
+ # timeout utility rather than pwait -t.
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:143 \
+ -x timeout --preserve-status 2 pwait -t 100000000 $init
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:143 \
+ -x timeout --preserve-status 2 pwait -t 1h $init
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:143 \
+ -x timeout --preserve-status 2 pwait -t 1.5h $init
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:143 \
+ -x timeout --preserve-status 2 pwait -t 1m $init
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:143 \
+ -x timeout --preserve-status 2 pwait -t 1.5m $init
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:143 \
+ -x timeout --preserve-status 2 pwait -t 0 $init
+
+ # The rest are fast enough that pwait -t is expected to trigger
+ # the timeout.
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:124 \
+ -x timeout --preserve-status 2 pwait -t 1s $init
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:124 \
+ -x timeout --preserve-status 2 pwait -t 1.5s $init
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:124 \
+ -x timeout --preserve-status 2 pwait -t 1 $init
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:124 \
+ -x timeout --preserve-status 2 pwait -t 1.5 $init
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:124 \
+ -x timeout --preserve-status 2 pwait -t 0.5 $init
+}
+
+atf_test_case timeout_trigger_timeout
+timeout_trigger_timeout_head()
+{
+ atf_set "descr" "Test that exceeding the timeout is detected"
+}
+
+timeout_trigger_timeout_body()
+{
+ sleep 10 &
+ p10=$!
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:124 \
+ -x timeout --preserve-status 6.5 pwait -t 5 $p10
+}
+
+timeout_trigger_timeout_cleanup()
+{
+ kill $p10 >/dev/null 2>&1
+ wait $p10 >/dev/null 2>&1
+}
+
+atf_test_case timeout_no_timeout
+timeout_no_timeout_head()
+{
+ atf_set "descr" "Test that not exceeding the timeout continues to wait"
+}
+
+timeout_no_timeout_body()
+{
+ sleep 10 &
+ p10=$!
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:0 \
+ -x timeout --preserve-status 11.5 pwait -t 12 $p10
+}
+
+timeout_no_timeout_cleanup()
+{
+ kill $p10 >/dev/null 2>&1
+ wait $p10 >/dev/null 2>&1
+}
+
+atf_test_case timeout_many
+timeout_many_head()
+{
+ atf_set "descr" "Test timeout on many processes"
+}
+
+timeout_many_body()
+{
+ sleep 1 &
+ p1=$!
+
+ sleep 5 &
+ p5=$!
+
+ sleep 10 &
+ p10=$!
+
+ atf_check \
+ -o empty \
+ -e empty \
+ -s exit:124 \
+ -x timeout --preserve-status 7.5 pwait -t 6 $p1 $p5 $p10
+}
+
+timeout_many_cleanup()
+{
+ kill $p1 $p5 $p10 >/dev/null 2>&1
+ wait $p1 $p5 $p10 >/dev/null 2>&1
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case basic
+ atf_add_test_case time_unit
+ atf_add_test_case timeout_trigger_timeout
+ atf_add_test_case timeout_no_timeout
+ atf_add_test_case timeout_many
+}
Index: head/etc/mtree/BSD.tests.dist
===================================================================
--- head/etc/mtree/BSD.tests.dist
+++ head/etc/mtree/BSD.tests.dist
@@ -640,6 +640,8 @@
..
printf
..
+ pwait
+ ..
sdiff
..
sed
Index: head/targets/pseudo/tests/Makefile.depend
===================================================================
--- head/targets/pseudo/tests/Makefile.depend
+++ head/targets/pseudo/tests/Makefile.depend
@@ -307,6 +307,7 @@
usr.bin/mkimg/tests \
usr.bin/ncal/tests \
usr.bin/printf/tests \
+ usr.bin/pwait/tests \
usr.bin/sdiff/tests \
usr.bin/sed/tests \
usr.bin/sed/tests/regress.multitest.out \
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 12, 4:02 PM (10 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17122339
Default Alt Text
D9697.diff (9 KB)
Attached To
Mode
D9697: pwait: Add a -t flag to specify a timeout in seconds before exiting.
Attached
Detach File
Event Timeline
Log In to Comment