diff options
author | Noah Misch | 2014-07-25 22:51:48 +0000 |
---|---|---|
committer | Noah Misch | 2014-07-25 22:51:48 +0000 |
commit | de35a9771004b9d521c9d5882db6be4fba20e80e (patch) | |
tree | a223bba7bc921b2bef51a443fa6d5670fd5c4852 | |
parent | e565ff7553e60b3d13dde410ef96f5256c5525eb (diff) |
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().
-rw-r--r-- | src/backend/port/win32/socket.c | 3 | ||||
-rw-r--r-- | src/backend/port/win32_sema.c | 58 |
2 files changed, 37 insertions, 24 deletions
diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.c index 6a518e5b6d..c981169fe1 100644 --- a/src/backend/port/win32/socket.c +++ b/src/backend/port/win32/socket.c @@ -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; diff --git a/src/backend/port/win32_sema.c b/src/backend/port/win32_sema.c index 43b1123a24..0adc73af7b 100644 --- a/src/backend/port/win32_sema.c +++ b/src/backend/port/win32_sema.c @@ -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; } /* |