diff options
Diffstat (limited to 'gl/select.c')
-rw-r--r-- | gl/select.c | 67 |
1 files changed, 56 insertions, 11 deletions
diff --git a/gl/select.c b/gl/select.c index 82e438c116..bb6952ebf5 100644 --- a/gl/select.c +++ b/gl/select.c @@ -21,6 +21,7 @@ #include <config.h> #include <alloca.h> +#include <assert.h> #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ /* Native Win32. */ @@ -76,6 +77,23 @@ typedef DWORD (WINAPI *PNtQueryInformationFile) #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 @@ -138,19 +156,37 @@ win32_poll_handle (HANDLE h, int fd, struct bitset *rbits, struct bitset *wbits, 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) @@ -199,7 +235,7 @@ rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds, 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; @@ -227,7 +263,10 @@ rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds, 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)); @@ -236,6 +275,11 @@ rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds, 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)); } @@ -246,6 +290,11 @@ rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds, 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)); } @@ -285,11 +334,7 @@ rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds, 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; |