[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. */
- 'select' on MS-Windows returns without waiting for pipes,
Eli Zaretskii <=