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. */