#include <config.h>
#include <alloca.h>
+#include <assert.h>
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
/* Native Win32. */
#define PIPE_BUF 512
#endif
+#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
+
+static BOOL
+IsSocketHandle(HANDLE h)
+{
+ WSANETWORKEVENTS ev;
+
+ if (IsConsoleHandle (h))
+ return FALSE;
+
+ /* Under Wine, it seems that getsockopt returns 0 for pipes too.
+ WSAEnumNetworkEvents instead distinguishes the two correctly. */
+ ev.lNetworkEvents = 0xDEADBEEF;
+ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+ return ev.lNetworkEvents != 0xDEADBEEF;
+}
+
/* Compute output fd_sets for libc descriptor FD (whose Win32 handle is H). */
static int
break;
case FILE_TYPE_CHAR:
- ret = WaitForSingleObject (h, 0);
write = TRUE;
+ if (!(rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
+ break;
+
+ ret = WaitForSingleObject (h, 0);
if (ret == WAIT_OBJECT_0)
{
+ if (!IsConsoleHandle (h))
+ {
+ read = TRUE;
+ break;
+ }
+
nbuffer = avail = 0;
bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
- if (!bRet || nbuffer == 0)
- except = TRUE;
+
+ /* Screen buffers handles are filtered earlier. */
+ assert (bRet);
+ if (nbuffer == 0)
+ {
+ except = TRUE;
+ break;
+ }
irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
if (!bRet || avail == 0)
- except = TRUE;
+ {
+ except = TRUE;
+ break;
+ }
for (i = 0; i < avail; i++)
if (irbuffer[i].EventType == KEY_EVENT)
fd_set handle_rfds, handle_wfds, handle_xfds;
struct bitset rbits, wbits, xbits;
unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
- DWORD ret, wait_timeout, nhandles, nsock;
+ DWORD ret, wait_timeout, nhandles, nsock, nbuffer;
MSG msg;
int i, fd, rc;
nhandles = 1;
nsock = 0;
- /* Copy descriptors to bitsets. */
+ /* Copy descriptors to bitsets. At the same time, eliminate
+ bits in the "wrong" direction for console input buffers
+ and screen buffers, because screen buffers are waitable
+ and they will block until a character is available. */
memset (&rbits, 0, sizeof (rbits));
memset (&wbits, 0, sizeof (wbits));
memset (&xbits, 0, sizeof (xbits));
for (i = 0; i < rfds->fd_count; i++)
{
fd = rfds->fd_array[i];
+ h = (HANDLE) _get_osfhandle (fd);
+ if (IsConsoleHandle (h)
+ && !GetNumberOfConsoleInputEvents (h, &nbuffer))
+ continue;
+
rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
}
for (i = 0; i < wfds->fd_count; i++)
{
fd = wfds->fd_array[i];
+ h = (HANDLE) _get_osfhandle (fd);
+ if (IsConsoleHandle (h)
+ && GetNumberOfConsoleInputEvents (h, &nbuffer))
+ continue;
+
wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
}
return -1;
}
- /* Under Wine, it seems that getsockopt returns 0 for pipes too.
- WSAEnumNetworkEvents instead distinguishes the two correctly. */
- ev.lNetworkEvents = 0xDEADBEEF;
- WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
- if (ev.lNetworkEvents != 0xDEADBEEF)
+ if (IsSocketHandle (h))
{
int requested = FD_CLOSE;