]> granicus.if.org Git - postgresql/commitdiff
Back-patch fixes for some issues in our Windows socket code into 9.1.
authorRobert Haas <rhaas@postgresql.org>
Mon, 27 Aug 2012 19:00:08 +0000 (15:00 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 27 Aug 2012 19:00:08 +0000 (15:00 -0400)
This is a backport of commit b85427f2276d02756b558c0024949305ea65aca5.
Per discussion of bug #4958.  Some of these fixes probably need to be
back-patched further, but I'm just doing this much for now.

src/backend/port/win32/socket.c
src/backend/port/win32_latch.c

index b730f8eeda9016626a806de8757ffa1bc8e65b79..9e849271fe67b01d814e9033b3f12019d5fa31d7 100644 (file)
@@ -137,6 +137,7 @@ pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout)
        HANDLE          events[2];
        int                     r;
 
+       /* Create an event object just once and use it on all future calls */
        if (waitevent == INVALID_HANDLE_VALUE)
        {
                waitevent = CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -150,20 +151,19 @@ pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout)
                                (errmsg_internal("could not reset socket waiting event: %i", (int) GetLastError())));
 
        /*
-        * make sure we don't multiplex this kernel event object with a different
-        * socket from a previous call
+        * Track whether socket is UDP or not.  (NB: most likely, this is both
+        * useless and wrong; there is no reason to think that the behavior of
+        * WSAEventSelect is different for TCP and UDP.)
         */
-
        if (current_socket != s)
-       {
-               if (current_socket != -1)
-                       WSAEventSelect(current_socket, waitevent, 0);
                isUDP = isDataGram(s);
-       }
-
        current_socket = s;
 
-       if (WSAEventSelect(s, waitevent, what) == SOCKET_ERROR)
+       /*
+        * Attach event to socket.  NOTE: we must detach it again before returning,
+        * since other bits of code may try to attach other events to the socket.
+        */
+       if (WSAEventSelect(s, waitevent, what) != 0)
        {
                TranslateSocketError();
                return 0;
@@ -196,10 +196,14 @@ pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout)
 
                                r = WSASend(s, &buf, 1, &sent, 0, NULL, NULL);
                                if (r == 0)             /* Completed - means things are fine! */
+                               {
+                                       WSAEventSelect(s, NULL, 0);
                                        return 1;
+                               }
                                else if (WSAGetLastError() != WSAEWOULDBLOCK)
                                {
                                        TranslateSocketError();
+                                       WSAEventSelect(s, NULL, 0);
                                        return 0;
                                }
                        }
@@ -210,6 +214,8 @@ pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout)
        else
                r = WaitForMultipleObjectsEx(2, events, FALSE, timeout, TRUE);
 
+       WSAEventSelect(s, NULL, 0);
+
        if (r == WAIT_OBJECT_0 || r == WAIT_IO_COMPLETION)
        {
                pgwin32_dispatch_queued_signals();
@@ -219,7 +225,10 @@ pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout)
        if (r == WAIT_OBJECT_0 + 1)
                return 1;
        if (r == WAIT_TIMEOUT)
+       {
+               errno = EWOULDBLOCK;
                return 0;
+       }
        ereport(ERROR,
                        (errmsg_internal("unrecognized return value from WaitForMultipleObjects: %i (%i)", r, (int) GetLastError())));
        return 0;
@@ -543,9 +552,12 @@ pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, c
                if (writefds && FD_ISSET(sockets[i], writefds))
                        flags |= FD_WRITE | FD_CLOSE;
 
-               if (WSAEventSelect(sockets[i], events[i], flags) == SOCKET_ERROR)
+               if (WSAEventSelect(sockets[i], events[i], flags) != 0)
                {
                        TranslateSocketError();
+                       /* release already-assigned event objects */
+                       while (--i >= 0)
+                               WSAEventSelect(sockets[i], NULL, 0);
                        for (i = 0; i < numevents; i++)
                                WSACloseEvent(events[i]);
                        return -1;
@@ -565,9 +577,9 @@ pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, c
                for (i = 0; i < numevents; i++)
                {
                        ZeroMemory(&resEvents, sizeof(resEvents));
-                       if (WSAEnumNetworkEvents(sockets[i], events[i], &resEvents) == SOCKET_ERROR)
+                       if (WSAEnumNetworkEvents(sockets[i], events[i], &resEvents) != 0)
                                ereport(FATAL,
-                                               (errmsg_internal("failed to enumerate network events: %i", (int) GetLastError())));
+                                               (errmsg_internal("failed to enumerate network events: %i", (int) WSAGetLastError())));
                        /* Read activity? */
                        if (readfds && FD_ISSET(sockets[i], readfds))
                        {
@@ -594,10 +606,10 @@ pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, c
                }
        }
 
-       /* Clean up all handles */
+       /* Clean up all the event objects */
        for (i = 0; i < numevents; i++)
        {
-               WSAEventSelect(sockets[i], events[i], 0);
+               WSAEventSelect(sockets[i], NULL, 0);
                WSACloseEvent(events[i]);
        }
 
index ccb5771b52bac6123a79af065fdcb3aad4dd1523..bd9c9faf9e5b6b9f29a5da5cd9ed63318b625bad 100644 (file)
@@ -108,10 +108,11 @@ WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, bool forRead,
        numevents = 2;
        if (sock != PGINVALID_SOCKET && (forRead || forWrite))
        {
+               /* Need an event object to represent events on the socket */
                int                     flags = 0;
 
                if (forRead)
-                       flags |= FD_READ;
+                       flags |= (FD_READ | FD_CLOSE);
                if (forWrite)
                        flags |= FD_WRITE;
 
@@ -154,11 +155,10 @@ WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, bool forRead,
                        Assert(sock != PGINVALID_SOCKET);
 
                        ZeroMemory(&resEvents, sizeof(resEvents));
-                       if (WSAEnumNetworkEvents(sock, sockevent, &resEvents) == SOCKET_ERROR)
+                       if (WSAEnumNetworkEvents(sock, sockevent, &resEvents) != 0)
                                ereport(FATAL,
-                                               (errmsg_internal("failed to enumerate network events: %i", (int) GetLastError())));
-
-                       if ((forRead && resEvents.lNetworkEvents & FD_READ) ||
+                                               (errmsg_internal("failed to enumerate network events: %i", (int) WSAGetLastError())));
+                       if ((forRead && resEvents.lNetworkEvents & (FD_READ | FD_CLOSE)) ||
                                (forWrite && resEvents.lNetworkEvents & FD_WRITE))
                                result = 2;
                        break;
@@ -167,10 +167,10 @@ WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, bool forRead,
                        elog(ERROR, "unexpected return code from WaitForMultipleObjects(): %d", (int) rc);
        }
 
-       /* Clean up the handle we created for the socket */
-       if (sock != PGINVALID_SOCKET && (forRead || forWrite))
+       /* Clean up the event object we created for the socket */
+       if (sockevent != WSA_INVALID_EVENT)
        {
-               WSAEventSelect(sock, sockevent, 0);
+               WSAEventSelect(sock, NULL, 0);
                WSACloseEvent(sockevent);
        }