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;
 

Reply via email to