bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

'select' on MS-Windows returns without waiting for pipes


From: Eli Zaretskii
Subject: 'select' on MS-Windows returns without waiting for pipes
Date: Sun, 08 Jun 2014 18:32:43 +0300

The gnulib implementation of 'select' for MS-Windows returns
immediately with a zero value when it is called to wait for input from
an anonymous pipe (e.g., a pipe created by a call to 'pipe' or
'pipe2').  This was discussed here in this thread:

  http://lists.gnu.org/archive/html/bug-gnulib/2011-06/msg00008.html

I bumped into this independently today while running the Guile's test
suite on MS-Windows.  Guile uses 'select', among other places, in its
implementation of 'sleep' and 'usleep' primitives.  It calls 'select'
with a file descriptor of a signal delivery pipe, which is written to
(by another thread) when Guile is interrupted by a signal.  But due to
the above-mentioned problem, these two functions never sleep, and
instead return immediately.

I suggest the following changes to work around the issue.  These
changes also zero out the 'timeout' argument if the timeout period
expires with no data or signal available; this seems to be what some
programs (Guile among them) expect.

Thanks.

--- lib/select.c~       2014-02-15 01:00:33 +0200
+++ lib/select.c        2014-06-08 17:58:07 +0300
@@ -252,6 +252,7 @@ rpl_select (int nfds, fd_set *rfds, fd_s
   DWORD ret, wait_timeout, nhandles, nsock, nbuffer;
   MSG msg;
   int i, fd, rc;
+  clock_t tend;
 
   if (nfds > FD_SETSIZE)
     nfds = FD_SETSIZE;
@@ -388,6 +389,10 @@ rpl_select (int nfds, fd_set *rfds, fd_s
   /* Place a sentinel at the end of the array.  */
   handle_array[nhandles] = NULL;
 
+  /* When will the waiting period expire?  */
+  if (wait_timeout != INFINITE)
+    tend = clock () + wait_timeout;
+
 restart:
   if (wait_timeout == 0 || nsock == 0)
     rc = 0;
@@ -408,6 +413,13 @@ restart:
         wait_timeout = 0;
     }
 
+  /* How much is left to wait?  */
+  if (wait_timeout != INFINITE)
+    {
+      wait_timeout = tend - clock ();
+      if (wait_timeout < 0)
+       wait_timeout = 0;
+    }
   for (;;)
     {
       ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
@@ -453,7 +465,16 @@ restart:
             }
         }
 
-      if (rc == 0 && wait_timeout == INFINITE)
+      if (rc == 0
+         && (wait_timeout == INFINITE
+         /* If NHANDLES > 1, but no bits are set, it means we've
+            been told incorrectly that some handle was signaled.
+            This happens with anonymous pipes, which always cause
+            MsgWaitForMultipleObjects to exit immediately, but no
+            data is found ready to be read by windows_poll_handle.
+            To avoid a total failure (whereby we return zero and
+            don't wait at all), let's poll in a more busy loop.  */
+             || (wait_timeout != 0 && nhandles > 1)))
         {
           /* Sleep 1 millisecond to avoid busy wait and retry with the
              original fd_sets.  */
@@ -463,6 +484,8 @@ restart:
           SleepEx (1, TRUE);
           goto restart;
         }
+      if (timeout && wait_timeout == 0 && rc == 0)
+       timeout->tv_sec = timeout->tv_usec = 0;
     }
 
   /* Now fill in the results.  */





reply via email to

[Prev in Thread] Current Thread [Next in Thread]