In GNU Smalltalk I had a bug where somehow the wineserver would start
reporting ERROR_INVALID_HANDLE for console handles after a
WaitForSingleObject. This patch works around it by not calling
WaitForSingleObject except if really necessary, which is a good idea anyway.
I also save WSAEnumNetworkEvents system calls for console objects, since
they are easily recognizable from other Win32 handles.
Paolo
commit cb81f67209f66d1a4bf189ced17819d492a7ba81
Author: Paolo Bonzini <[email protected]>
Date: Tue Aug 4 18:06:07 2009 +0200
Work around mysterious Wine bug in poll/select.
* lib/poll.c: Do not bother checking for readability
of console handles if not requested. Somehow fixes Wine.
* lib/select.c: Likewise.
diff --git a/ChangeLog b/ChangeLog
index 56e11fa..c54aef5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2009-08-04 Paolo Bonzini <[email protected]>
+
+ Work around mysterious Wine bug in poll/select.
+ * lib/poll.c: Do not bother checking for readability
+ of console handles if not requested. Somehow fixes Wine.
+ * lib/select.c: Likewise.
+
2009-07-25 Paolo Bonzini <[email protected]>
New module pipe-filter.
diff --git a/lib/poll.c b/lib/poll.c
index ed76098..9c72a4a 100644
--- a/lib/poll.c
+++ b/lib/poll.c
@@ -67,6 +67,23 @@
#ifdef WIN32_NATIVE
+#define IsHandleConsole(h) (((long) (h) & 3) == 3)
+
+static BOOL
+IsHandleSocket(HANDLE h)
+{
+ WSANETWORKEVENTS ev;
+
+ if (IsHandleConsole (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;
+}
+
/* Declare data structures for ntdll functions. */
typedef struct _FILE_PIPE_LOCAL_INFORMATION {
ULONG NamedPipeType;
@@ -156,6 +173,9 @@ win32_compute_revents (HANDLE h, int sought)
return happened;
case FILE_TYPE_CHAR:
+ if (!(sought & (POLLIN | POLLRDNORM | POLLPRI | POLLRDBAND)))
+ break;
+
ret = WaitForSingleObject (h, 0);
if (ret == WAIT_OBJECT_0)
{
@@ -439,12 +459,7 @@ poll (pfd, nfd, timeout)
h = (HANDLE) _get_osfhandle (pfd[i].fd);
assert (h != NULL);
-
- /* 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 (IsHandleSocket (h))
{
int requested = FD_CLOSE;
diff --git a/lib/select.c b/lib/select.c
index 8496c15..b3da42d 100644
--- a/lib/select.c
+++ b/lib/select.c
@@ -76,6 +76,23 @@ typedef DWORD (WINAPI *PNtQueryInformationFile)
#define PIPE_BUF 512
#endif
+#define IsHandleConsole(h) (((long) (h) & 3) == 3)
+
+static BOOL
+IsHandleSocket(HANDLE h)
+{
+ WSANETWORKEVENTS ev;
+
+ if (IsHandleConsole (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,8 +155,11 @@ 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)
{
nbuffer = avail = 0;
@@ -285,11 +305,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 (IsHandleSocket (h))
{
int requested = FD_CLOSE;