[PATCH] s6-uevent-spawner: Fix possibly delaying uevents

From: Olivier Brunel <jjk_at_jjacky.com>
Date: Sun, 14 Jun 2015 14:37:41 +0200

Because of the buffered IO, the possible scenario could occur:
- netlink uevents (plural) occur, i.e. data ready on stdin
- iopause triggered, handle_stdin() called. The first uevent is processed, child
  launched, we're waiting for a signal
- SIGCHLD occurs, we're back to iopausing on stdin again, only it's not ready
  yet; Because we've read it all already and still have unprocessed data
  (uevents) on our own internal buffer (buffer_0)

This could lead to e.g. plug an USB drive, and see only half the uevents be
processed. Generate a new uevent, and see all the "old" uevents then be
processed, and maybe the new ones too, maybe only part of them. Rince, repeat.

We now call handle_stdin() if the buffer isn't empty, so it'll process any such
"buffered" uevents, knowing that it will read if needed (and we can pretty much
assume the data will be there in this case).

Signed-off-by: Olivier Brunel <jjk_at_jjacky.com>
---
 src/minutils/s6-uevent-spawner.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/src/minutils/s6-uevent-spawner.c b/src/minutils/s6-uevent-spawner.c
index 40f088e..f7e2456 100644
--- a/src/minutils/s6-uevent-spawner.c
+++ b/src/minutils/s6-uevent-spawner.c
_at_@ -219,17 +219,24 @@ int main (int argc, char const *const *argv, char const *const *envp)
 
   while (cont || pid)
   {
-    register int r = iopause_g(x, 1 + (!pid && cont), &deadline) ;
-    if (r < 0) strerr_diefu1sys(111, "iopause") ;
-    else if (!r) handle_timeout() ;
+    register int ready = !pid && cont ;
+
+    if (ready && !buffer_isempty(buffer_0))
+      handle_stdin(&sa, linevar, argv, envp) ;
     else
     {
-      if (x[0].revents & IOPAUSE_EXCEPT)
-        strerr_diefu1x(111, "iopause: trouble with selfpipe") ;
-      if (x[0].revents & IOPAUSE_READ)
-        handle_signals() ;
-      else if (!pid && cont && (x[1].revents & IOPAUSE_READ))
-        handle_stdin(&sa, linevar, argv, envp) ;
+      register int r = iopause_g(x, 1 + ready, &deadline) ;
+      if (r < 0) strerr_diefu1sys(111, "iopause") ;
+      else if (!r) handle_timeout() ;
+      else
+      {
+        if (x[0].revents & IOPAUSE_EXCEPT)
+          strerr_diefu1x(111, "iopause: trouble with selfpipe") ;
+        if (x[0].revents & IOPAUSE_READ)
+          handle_signals() ;
+        else if (ready && (x[1].revents & IOPAUSE_READ))
+          handle_stdin(&sa, linevar, argv, envp) ;
+      }
     }
   }
   if (verbosity >= 2) strerr_warni1x("exiting") ;
-- 
2.4.3
Received on Sun Jun 14 2015 - 12:37:41 UTC

This archive was generated by hypermail 2.3.0 : Sun May 09 2021 - 19:38:49 UTC