diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2012-11-08 20:04:54 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2012-11-08 20:04:54 -0500 |
commit | 8354ce92165ee969510e975d30a69f875e3ffcd9 (patch) | |
tree | 9bea765b5ebaf07de3d0d382236236bf0a1f13d7 /src/backend/port/win32_latch.c | |
parent | 03787f63921e37c123ceff712ed405c5172e765d (diff) | |
download | postgresql-8354ce92165ee969510e975d30a69f875e3ffcd9.tar.gz postgresql-8354ce92165ee969510e975d30a69f875e3ffcd9.zip |
Fix WaitLatch() to return promptly when the requested timeout expires.
If the sleep is interrupted by a signal, we must recompute the remaining
time to wait; otherwise, a steady stream of non-wait-terminating interrupts
could delay return from WaitLatch indefinitely. This has been shown to be
a problem for the autovacuum launcher, and there may well be other places
now or in the future with similar issues. So we'd better make the function
robust, even though this'll add at least one gettimeofday call per wait.
Back-patch to 9.2. We might eventually need to fix 9.1 as well, but the
code is quite different there, and the usage of WaitLatch in 9.1 is so
limited that it's not clearly important to do so.
Reported and diagnosed by Jeff Janes, though I rewrote his patch rather
heavily.
Diffstat (limited to 'src/backend/port/win32_latch.c')
-rw-r--r-- | src/backend/port/win32_latch.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/src/backend/port/win32_latch.c b/src/backend/port/win32_latch.c index eaa30c4a501..377bdce84f7 100644 --- a/src/backend/port/win32_latch.c +++ b/src/backend/port/win32_latch.c @@ -24,6 +24,7 @@ #include <unistd.h> #include "miscadmin.h" +#include "portability/instr_time.h" #include "postmaster/postmaster.h" #include "storage/latch.h" #include "storage/pmsignal.h" @@ -100,6 +101,9 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, long timeout) { DWORD rc; + instr_time start_time, + cur_time; + long cur_timeout; HANDLE events[4]; HANDLE latchevent; HANDLE sockevent = WSA_INVALID_EVENT; @@ -118,11 +122,19 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, if ((wakeEvents & WL_LATCH_SET) && latch->owner_pid != MyProcPid) elog(ERROR, "cannot wait on a latch owned by another process"); - /* Convert timeout to form used by WaitForMultipleObjects() */ + /* + * Initialize timeout if requested. We must record the current time so + * that we can determine the remaining timeout if WaitForMultipleObjects + * is interrupted. + */ if (wakeEvents & WL_TIMEOUT) + { + INSTR_TIME_SET_CURRENT(start_time); Assert(timeout >= 0); + cur_timeout = timeout; + } else - timeout = INFINITE; + cur_timeout = INFINITE; /* * Construct an array of event handles for WaitforMultipleObjects(). @@ -187,7 +199,7 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, break; } - rc = WaitForMultipleObjects(numevents, events, FALSE, timeout); + rc = WaitForMultipleObjects(numevents, events, FALSE, cur_timeout); if (rc == WAIT_FAILED) elog(ERROR, "WaitForMultipleObjects() failed: error code %lu", @@ -203,7 +215,11 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, } else if (rc == WAIT_OBJECT_0 + 1) { - /* Latch is set, we'll handle that on next iteration of loop */ + /* + * Latch is set. We'll handle that on next iteration of loop, but + * let's not waste the cycles to update cur_timeout below. + */ + continue; } else if ((wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) && rc == WAIT_OBJECT_0 + 2) /* socket is at event slot 2 */ @@ -240,8 +256,17 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, } else elog(ERROR, "unexpected return code from WaitForMultipleObjects(): %lu", rc); - } - while (result == 0); + + /* If we're not done, update cur_timeout for next iteration */ + if (result == 0 && cur_timeout != INFINITE) + { + INSTR_TIME_SET_CURRENT(cur_time); + INSTR_TIME_SUBTRACT(cur_time, start_time); + cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time); + if (cur_timeout < 0) + cur_timeout = 0; + } + } while (result == 0); /* Clean up the event object we created for the socket */ if (sockevent != WSA_INVALID_EVENT) |