summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2022-06-28 12:58:31 +0000
committerLaurent Bercot <ska@appnovation.com>2022-06-28 12:58:31 +0000
commit28b89edabbd5ee76147a4aa2ccef94ab60d28c0d (patch)
tree25c54dd1c8dd13ca80b3aff7e2a91068f218e9ca /src
parent85315b3e709f65781dd221fd3f13d3a989a748d4 (diff)
downloadexecline-28b89edabbd5ee76147a4aa2ccef94ab60d28c0d.tar.gz
execline-28b89edabbd5ee76147a4aa2ccef94ab60d28c0d.tar.xz
execline-28b89edabbd5ee76147a4aa2ccef94ab60d28c0d.zip
bugfix: make wait -t less borked
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src')
-rw-r--r--src/execline/wait.c73
1 files changed, 47 insertions, 26 deletions
diff --git a/src/execline/wait.c b/src/execline/wait.c
index 1b7516e..c63149a 100644
--- a/src/execline/wait.c
+++ b/src/execline/wait.c
@@ -19,7 +19,7 @@
 
 #include <execline/execline.h>
 
-#define USAGE "wait [ -I | -i ] [ -a | -o ] [ -r | -t timeout ] { pids... }"
+#define USAGE "wait [ -I | -i ] [ -a | -o ] [ -r | -t timeout ] { pids... } [ prog... ]"
 #define dieusage() strerr_dieusage(100, USAGE)
 
 typedef int ac_func (pid_t *, unsigned int *, int *) ;
@@ -41,25 +41,24 @@ static int wait_from_list (pid_t *pids, unsigned int n)
   return wstat == -1 ? -1 : wait_estatus(wstat) ;
 }
 
-static int wait_one (pid_t *pid, int nohang)
+static int wait_one (pid_t *pid)
 {
   int wstat = 0 ;
-  pid_t r = waitpid_nointr(-1, &wstat, nohang ? WNOHANG : 0) ;
-  if (r < 0)
+  *pid = wait(&wstat) ;
+  if (*pid < 0)
   {
     if (errno != ECHILD) strerr_diefu1sys(111, "wait") ;
     else return -1 ;
   }
-  *pid = r ;
   return wait_estatus(wstat) ;
 }
 
-static int wait_one_from_list (pid_t *pids, unsigned int n, pid_t *pid, int nohang)
+static int wait_one_from_list (pid_t *pids, unsigned int n, pid_t *pid)
 {
   for (;;)
   {
     int wstat ;
-    pid_t r = waitpid_nointr(-1, &wstat, nohang ? WNOHANG : 0) ;
+    pid_t r = wait(&wstat) ;
     unsigned int i = 0 ;
     if (r < 0)
     {
@@ -76,18 +75,33 @@ static int wait_one_from_list (pid_t *pids, unsigned int n, pid_t *pid, int noha
   }
 }
 
-static int wait_one_nohang (pid_t *pids, unsigned int *n, pid_t *pid)
+static int wait_one_nohang (pid_t *pids, unsigned int *n, int *wstat)
 {
+  pid_t r = wait_nohang(wstat) ;
+  if (r < 0 && errno != ECHILD) strerr_diefu1sys(111, "wait") ;
   (void)pids ;
   (void)n ;
-  return wait_one(pid, 1) ;
+  return r ;
 }
 
-static int wait_one_from_list_nohang (pid_t *pids, unsigned int *n, pid_t *pid)
+static int wait_one_from_list_nohang (pid_t *pids, unsigned int *n, int *wstat)
 {
-  int r = wait_one_from_list(pids, *n, pid, 1) ;
-  if (r) (*n)-- ;
-  return r ;
+  for (;;)
+  {
+    pid_t r = wait_nohang(wstat) ;
+    unsigned int i = 0 ;
+    if (r <= 0)
+    {
+      if (r == -1 && errno != ECHILD) strerr_diefu1sys(111, "wait") ;
+      else return r ;
+    }
+    for (; i < *n ; i++) if (r == pids[i]) break ;
+    if (i < *n)
+    {
+      pids[i] = pids[--*n] ;
+      return r ;
+    }
+  }
 }
 
 static inline void empty_selfpipe (void)
@@ -101,7 +115,7 @@ static inline void empty_selfpipe (void)
   }
 }
 
-static int wait_with_timeout (pid_t *pids, unsigned int n, pid_t *pid, ac_func_ref f, tain *tto, int justone, int strict)
+static int wait_with_timeout (pid_t *pids, unsigned int n, pid_t *returned, ac_func_ref f, tain *tto, int justone, int strict)
 {
   iopause_fd x = { .fd = selfpipe_init(), .events = IOPAUSE_READ } ;
   pid_t special = pids[n-1] ;
@@ -115,23 +129,30 @@ static int wait_with_timeout (pid_t *pids, unsigned int n, pid_t *pid, ac_func_r
     int r ;
     for (;;)
     {
-      r = (*f)(pids, &n, pid) ;
-      if (!r) break ;
-      if (r < 0) { selfpipe_finish() ; return e ; }
-      if (justone) { selfpipe_finish() ; return r ; }
-      if (*pid == special) e = r ;
+      int wstat ;
+      pid_t pid = (*f)(pids, &n, &wstat) ;
+      if (!pid) break ;
+      if (pid < 0) goto endloop ;
+      if (justone || pid == special)
+      {
+        *returned = pid ;
+        e = wait_estatus(wstat) ;
+      }
+      if (justone || !n) goto endloop ;
     }
-
     r = iopause_g(&x, 1, tto) ;
     if (r < 0) strerr_diefu1sys(111, "iopause") ;
     else if (!r)
     {
-      if (!strict) { selfpipe_finish() ; return -1 ; }
+      if (!strict) { e = -1 ; break ; }
       errno = ETIMEDOUT ;
       strerr_diefu1sys(99, "wait") ;
     }
     else empty_selfpipe() ;
   }
+ endloop:
+  selfpipe_finish() ;
+  return e ;
 }
 
 int main (int argc, char const **argv)
@@ -143,7 +164,7 @@ int main (int argc, char const **argv)
   int justone = 0 ;
   int hasblock ;
   int e ;
-  pid_t pid ;
+  pid_t pid = -1 ;
   PROG = "wait" ;
 #ifdef EXECLINE_PEDANTIC_POSIX
   setlocale(LC_ALL, "") ;  /* but of course, dear POSIX */
@@ -193,15 +214,15 @@ int main (int argc, char const **argv)
          wait_with_timeout(pids, n, &pid, argc1 ? &wait_one_from_list_nohang : &wait_one_nohang, &tto, justone, insist) :
          justone ?
            argc1 ?
-             wait_one_from_list(pids, n, &pid, 0) :  /* wait -o -- 2 3 4 / wait -o -- { 2 3 4 } */
-             wait_one(&pid, 0) :  /* wait -o / wait -o { } */
+             wait_one_from_list(pids, n, &pid) :  /* wait -o -- 2 3 4 / wait -o -- { 2 3 4 } */
+             wait_one(&pid) :  /* wait -o / wait -o { } */
            argc1 ?
              wait_from_list(pids, n) :  /* wait 2 3 4 / wait { 2 3 4 }*/
              wait_all() ; /* wait / wait { } */
   }
   if (!hasblock) return e >= 0 ? e : 127 ;
   if (!justone) xexec0(argv + argc1 + 1) ;
-  if (e < 0) xmexec_n(argv + argc1 + 1, "?\0!", 4, 2) ;
+  if (e < 0) xmexec0_n(argv + argc1 + 1, "?\0!", 4, 2) ;
 
   {
     char fmt[4 + UINT_FMT + PID_FMT] = "?=" ;
@@ -209,6 +230,6 @@ int main (int argc, char const **argv)
     m += uint_fmt(fmt + m, (unsigned int)e) ; fmt[m++] = 0 ;
     fmt[m++] = '!' ; fmt[m++] = '=' ;
     m += pid_fmt(fmt + m, pid) ; fmt[m++] = 0 ;
-    xmexec_n(argv + argc1 + 1, fmt, m, 2) ;
+    xmexec0_n(argv + argc1 + 1, fmt, m, 2) ;
   }
 }