summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/execline/wait.c125
1 files changed, 101 insertions, 24 deletions
diff --git a/src/execline/wait.c b/src/execline/wait.c
index 4d550c9..764d503 100644
--- a/src/execline/wait.c
+++ b/src/execline/wait.c
@@ -2,61 +2,138 @@
#include <sys/types.h>
#include <sys/wait.h>
-#include <skalibs/sgetopt.h>
+#include <errno.h>
+#include <skalibs/uint64.h>
#include <skalibs/uint.h>
+#include <skalibs/sgetopt.h>
#include <skalibs/strerr2.h>
+#include <skalibs/tai.h>
#include <skalibs/djbunix.h>
+#include <skalibs/selfpipe.h>
+#include <skalibs/iopause.h>
#include <execline/execline.h>
-#define USAGE "wait [ -r ] { pids... }"
+#define USAGE "wait [ -I | -i ] [ -r | -t timeout ] { pids... }"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+typedef int actfunc_t (pid_t *, unsigned int *) ;
+typedef actfunc_t *actfunc_t_ref ;
+
+static inline void waitall (void)
+{
+ pid_t r = 1 ;
+ while (r > 0) r = wait(0) ;
+ if (r < 0 && errno != ECHILD) strerr_diefu1sys(111, "wait") ;
+}
+
+static int waitany (pid_t *dummytab, unsigned int *dummyn)
+{
+ pid_t r = 1 ;
+ while (r > 0) r = wait_nohang(0) ;
+ if (!r) return 1 ;
+ if (errno != ECHILD) strerr_diefu1sys(111, "wait") ;
+ (void)dummytab ;
+ (void)dummyn ;
+ return 0 ;
+}
+
+static int waitintab (pid_t *tab, unsigned int *n)
+{
+ unsigned int i = 0 ;
+ for (; i < *n ; i++)
+ {
+ pid_t r = waitpid(tab[i], 0, WNOHANG) ;
+ if (r)
+ {
+ if (r < 0 && errno != ECHILD) strerr_diefu1sys(111, "waitpid") ;
+ tab[i--] = tab[--(*n)] ;
+ }
+ }
+ return !!*n ;
+}
+
+static inline void handle_signals (void)
+{
+ for (;;) switch (selfpipe_read())
+ {
+ case -1 : strerr_diefu1sys(111, "read selfpipe") ;
+ case 0 : return ;
+ case SIGCHLD : break ;
+ default: strerr_dief1x(101, "internal inconsistency. Please submit a bug-report.") ;
+ }
+}
-static unsigned int waitall (void)
+static inline void mainloop (tain_t *deadline, int insist, actfunc_t_ref f, pid_t *tab, unsigned int *n)
{
- register unsigned int n = 0 ;
- int wstat ;
- while (wait(&wstat) > 0) n++ ;
- return n ;
+ iopause_fd x = { .events = IOPAUSE_READ } ;
+ x.fd = selfpipe_init() ;
+ if (x.fd < 0) strerr_diefu1sys(111, "create selfpipe") ;
+ if (selfpipe_trap(SIGCHLD) < 0) strerr_diefu1sys(111, "trap SIGCHLD") ;
+ tain_now_g() ;
+ tain_add_g(deadline, deadline) ;
+ while ((*f)(tab, n))
+ {
+ register int r = iopause_g(&x, 1, deadline) ;
+ if (r < 0) strerr_diefu1sys(111, "iopause") ;
+ else if (!r)
+ {
+ if (!insist) break ;
+ errno = ETIMEDOUT ;
+ strerr_diefu1sys(1, "wait") ;
+ }
+ else handle_signals() ;
+ }
+ selfpipe_finish() ;
}
int main (int argc, char const **argv, char const *const *envp)
{
+ tain_t tto ;
int argc1 ;
- int flagreap = 0 ;
+ int hastimeout = 0 ;
+ int insist = 0 ;
PROG = "wait" ;
{
subgetopt_t l = SUBGETOPT_ZERO ;
+ unsigned int t = 0 ;
for (;;)
{
- register int opt = subgetopt_r(argc, argv, "r", &l) ;
+ register int opt = subgetopt_r(argc, argv, "iIrt:", &l) ;
if (opt == -1) break ;
switch (opt)
{
- case 'r' : flagreap = 1 ; break ;
- default : strerr_dieusage(100, USAGE) ;
+ case 'i' : insist = 1 ; break ;
+ case 'I' : insist = 0 ; break ;
+ case 'r' : t = 0 ; hastimeout = 1 ; break ;
+ case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; hastimeout = 1 ; break ;
+ default : dieusage() ;
}
}
argc -= l.ind ; argv += l.ind ;
+ if (hastimeout) tain_from_millisecs(&tto, t) ;
+ else tto = tain_infinite_relative ;
}
argc1 = el_semicolon(argv) ;
if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ;
- if (!argc1) flagreap ? wait_reap() : waitall() ;
+ if (!argc1 && !hastimeout) waitall() ;
else
{
- pid_t tab[argc1] ;
- register unsigned int i = 0 ;
- for (; i < (unsigned int)argc1 ; i++)
- {
- unsigned int pid ;
- if (!uint0_scan(argv[i], &pid)) strerr_dieusage(100, USAGE) ;
- tab[i] = pid ;
- }
- if (flagreap)
+ actfunc_t_ref f = argc1 ? &waitintab : &waitany ;
+ unsigned int n = argc1 ? (unsigned int)argc1 : 1 ;
+ pid_t tab[n] ;
+ if (argc1)
{
- if (waitn_reap(tab, argc1) < 0)
- strerr_diefu1sys(111, "waitn_reap") ;
+ register unsigned int i = 0 ;
+ for (; i < n ; i++)
+ {
+ uint64_t pid ;
+ if (!uint640_scan(argv[i], &pid)) strerr_dieusage(100, USAGE) ;
+ tab[i] = (pid_t)pid ;
+ }
}
- else if (!waitn(tab, argc1)) strerr_diefu1sys(111, "waitn") ;
+ mainloop(&tto, insist, f, tab, &n) ;
}
+
pathexec0_run(argv + argc1 + 1, envp) ;
strerr_dieexec(111, argv[argc1 + 1]) ;
}