Handle WAIT_IO_COMPLETION return from WaitForMultipleObjectsEx().
authorNoah Misch <noah@leadboat.com>
Fri, 25 Jul 2014 22:51:48 +0000 (18:51 -0400)
committerNoah Misch <noah@leadboat.com>
Fri, 25 Jul 2014 22:51:48 +0000 (18:51 -0400)
This return code is possible wherever we pass bAlertable = TRUE; it
arises when Windows caused the current thread to run an "I/O completion
routine" or an "asynchronous procedure call".  PostgreSQL does not
provoke either of those Windows facilities, hence this bug remaining
largely unnoticed, but other local code might do so.  Due to a shortage
of complaints, no back-patch for now.

Per report from Shiv Shivaraju Gowda, this bug can cause
PGSemaphoreLock() to PANIC.  The bug can also cause select() to report
timeout expiration too early, which might confuse pgstat_init() and
CheckRADIUSAuth().

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

index 6a518e5b6d9c1c5cfdf5c2322aa5366ec7956e62..c981169fe1f8c9dcd6f875000074819a746197cd 100644 (file)
@@ -623,7 +623,8 @@ pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, c
                return 0;
        }
 
-       if (r == WAIT_OBJECT_0 + numevents)
+       /* Signal-like events. */
+       if (r == WAIT_OBJECT_0 + numevents || r == WAIT_IO_COMPLETION)
        {
                pgwin32_dispatch_queued_signals();
                errno = EINTR;
index 43b1123a24ee0fad91a421db9c4fd02779e6cc7f..0adc73af7b167a8562fb4575c836e8dd78665be1 100644 (file)
@@ -118,8 +118,10 @@ PGSemaphoreReset(PGSemaphore sema)
 void
 PGSemaphoreLock(PGSemaphore sema, bool interruptOK)
 {
-       DWORD           ret;
        HANDLE          wh[2];
+       bool            done = false;
+
+       ImmediateInterruptOK = interruptOK;
 
        /*
         * Note: pgwin32_signal_event should be first to ensure that it will be
@@ -135,34 +137,44 @@ PGSemaphoreLock(PGSemaphore sema, bool interruptOK)
         * no hidden magic about whether the syscall will internally service a
         * signal --- we do that ourselves.
         */
-       do
+       while (!done)
        {
-               ImmediateInterruptOK = interruptOK;
-               CHECK_FOR_INTERRUPTS();
+               DWORD           rc;
 
-               ret = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE);
+               CHECK_FOR_INTERRUPTS();
 
-               if (ret == WAIT_OBJECT_0)
+               rc = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE);
+               switch (rc)
                {
-                       /* Signal event is set - we have a signal to deliver */
-                       pgwin32_dispatch_queued_signals();
-                       errno = EINTR;
+                       case WAIT_OBJECT_0:
+                               /* Signal event is set - we have a signal to deliver */
+                               pgwin32_dispatch_queued_signals();
+                               break;
+                       case WAIT_OBJECT_0 + 1:
+                               /* We got it! */
+                               done = true;
+                               break;
+                       case WAIT_IO_COMPLETION:
+                               /*
+                                * The system interrupted the wait to execute an I/O
+                                * completion routine or asynchronous procedure call in this
+                                * thread.  PostgreSQL does not provoke either of these, but
+                                * atypical loaded DLLs or even other processes might do so.
+                                * Now, resume waiting.
+                                */
+                               break;
+                       case WAIT_FAILED:
+                               ereport(FATAL,
+                                               (errmsg("could not lock semaphore: error code %lu",
+                                                               GetLastError())));
+                               break;
+                       default:
+                               elog(FATAL, "unexpected return code from WaitForMultipleObjectsEx(): %lu", rc);
+                               break;
                }
-               else if (ret == WAIT_OBJECT_0 + 1)
-               {
-                       /* We got it! */
-                       errno = 0;
-               }
-               else
-                       /* Otherwise we are in trouble */
-                       errno = EIDRM;
-
-               ImmediateInterruptOK = false;
-       } while (errno == EINTR);
+       }
 
-       if (errno != 0)
-               ereport(FATAL,
-               (errmsg("could not lock semaphore: error code %lu", GetLastError())));
+       ImmediateInterruptOK = false;
 }
 
 /*