Commit de35a977 authored by Noah Misch's avatar Noah Misch

Handle WAIT_IO_COMPLETION return from WaitForMultipleObjectsEx().

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().
parent e565ff75
...@@ -623,7 +623,8 @@ pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, c ...@@ -623,7 +623,8 @@ pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, c
return 0; 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(); pgwin32_dispatch_queued_signals();
errno = EINTR; errno = EINTR;
......
...@@ -118,8 +118,10 @@ PGSemaphoreReset(PGSemaphore sema) ...@@ -118,8 +118,10 @@ PGSemaphoreReset(PGSemaphore sema)
void void
PGSemaphoreLock(PGSemaphore sema, bool interruptOK) PGSemaphoreLock(PGSemaphore sema, bool interruptOK)
{ {
DWORD ret;
HANDLE wh[2]; HANDLE wh[2];
bool done = false;
ImmediateInterruptOK = interruptOK;
/* /*
* Note: pgwin32_signal_event should be first to ensure that it will be * Note: pgwin32_signal_event should be first to ensure that it will be
...@@ -135,34 +137,44 @@ PGSemaphoreLock(PGSemaphore sema, bool interruptOK) ...@@ -135,34 +137,44 @@ PGSemaphoreLock(PGSemaphore sema, bool interruptOK)
* no hidden magic about whether the syscall will internally service a * no hidden magic about whether the syscall will internally service a
* signal --- we do that ourselves. * signal --- we do that ourselves.
*/ */
do while (!done)
{ {
ImmediateInterruptOK = interruptOK; DWORD rc;
CHECK_FOR_INTERRUPTS();
ret = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE); CHECK_FOR_INTERRUPTS();
if (ret == WAIT_OBJECT_0) rc = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE);
switch (rc)
{ {
case WAIT_OBJECT_0:
/* Signal event is set - we have a signal to deliver */ /* Signal event is set - we have a signal to deliver */
pgwin32_dispatch_queued_signals(); pgwin32_dispatch_queued_signals();
errno = EINTR; break;
} case WAIT_OBJECT_0 + 1:
else if (ret == WAIT_OBJECT_0 + 1)
{
/* We got it! */ /* We got it! */
errno = 0; 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
/* Otherwise we are in trouble */
errno = EIDRM;
ImmediateInterruptOK = false; ImmediateInterruptOK = false;
} while (errno == EINTR);
if (errno != 0)
ereport(FATAL,
(errmsg("could not lock semaphore: error code %lu", GetLastError())));
} }
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment