diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2011-07-08 18:27:49 +0300 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2011-07-08 18:44:07 +0300 |
commit | 89fd72cbf26f5d2e3d86ab19c1ead73ab8fac0fe (patch) | |
tree | fa0605f7ec1ff3a798b1c22fd847185158288a8b /src/backend/port/win32_latch.c | |
parent | 9598afa3b0f7a7fdcf3740173346950b2bd5942c (diff) | |
download | postgresql-89fd72cbf26f5d2e3d86ab19c1ead73ab8fac0fe.tar.gz postgresql-89fd72cbf26f5d2e3d86ab19c1ead73ab8fac0fe.zip |
Introduce a pipe between postmaster and each backend, which can be used to
detect postmaster death. Postmaster keeps the write-end of the pipe open,
so when it dies, children get EOF in the read-end. That can conveniently
be waited for in select(), which allows eliminating some of the polling
loops that check for postmaster death. This patch doesn't yet change all
the loops to use the new mechanism, expect a follow-on patch to do that.
This changes the interface to WaitLatch, so that it takes as argument a
bitmask of events that it waits for. Possible events are latch set, timeout,
postmaster death, and socket becoming readable or writeable.
The pipe method behaves slightly differently from the kill() method
previously used in PostmasterIsAlive() in the case that postmaster has died,
but its parent has not yet read its exit code with waitpid(). The pipe
returns EOF as soon as the process dies, but kill() continues to return
true until waitpid() has been called (IOW while the process is a zombie).
Because of that, change PostmasterIsAlive() to use the pipe too, otherwise
WaitLatch() would return immediately with WL_POSTMASTER_DEATH, while
PostmasterIsAlive() would claim it's still alive. That could easily lead to
busy-waiting while postmaster is in zombie state.
Peter Geoghegan with further changes by me, reviewed by Fujii Masao and
Florian Pflug.
Diffstat (limited to 'src/backend/port/win32_latch.c')
-rw-r--r-- | src/backend/port/win32_latch.c | 98 |
1 files changed, 71 insertions, 27 deletions
diff --git a/src/backend/port/win32_latch.c b/src/backend/port/win32_latch.c index 4bcf7b7a8f3..ef61b0184d1 100644 --- a/src/backend/port/win32_latch.c +++ b/src/backend/port/win32_latch.c @@ -23,6 +23,7 @@ #include <unistd.h> #include "miscadmin.h" +#include "postmaster/postmaster.h" #include "replication/walsender.h" #include "storage/latch.h" #include "storage/shmem.h" @@ -81,43 +82,67 @@ DisownLatch(volatile Latch *latch) latch->owner_pid = 0; } -bool -WaitLatch(volatile Latch *latch, long timeout) +int +WaitLatch(volatile Latch *latch, int wakeEvents, long timeout) { - return WaitLatchOrSocket(latch, PGINVALID_SOCKET, false, false, timeout) > 0; + return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout); } int -WaitLatchOrSocket(volatile Latch *latch, SOCKET sock, bool forRead, - bool forWrite, long timeout) +WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, SOCKET sock, + long timeout) { DWORD rc; - HANDLE events[3]; + HANDLE events[4]; HANDLE latchevent; - HANDLE sockevent = WSA_INVALID_EVENT; /* silence compiler */ + HANDLE sockevent = WSA_INVALID_EVENT; int numevents; int result = 0; + int pmdeath_eventno; + long timeout_ms; + + Assert(wakeEvents != 0); + + /* Ignore WL_SOCKET_* events if no valid socket is given */ + if (sock == PGINVALID_SOCKET) + wakeEvents &= ~(WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE); + + /* Convert timeout to milliseconds for WaitForMultipleObjects() */ + if (wakeEvents & WL_TIMEOUT) + { + Assert(timeout >= 0); + timeout_ms = timeout / 1000; + } + else + timeout_ms = INFINITE; + /* Construct an array of event handles for WaitforMultipleObjects() */ latchevent = latch->event; events[0] = latchevent; events[1] = pgwin32_signal_event; numevents = 2; - if (sock != PGINVALID_SOCKET && (forRead || forWrite)) + if (((wakeEvents & WL_SOCKET_READABLE) || + (wakeEvents & WL_SOCKET_WRITEABLE))) { int flags = 0; - if (forRead) + if (wakeEvents & WL_SOCKET_READABLE) flags |= FD_READ; - if (forWrite) + if (wakeEvents & WL_SOCKET_WRITEABLE) flags |= FD_WRITE; sockevent = WSACreateEvent(); WSAEventSelect(sock, sockevent, flags); events[numevents++] = sockevent; } + if (wakeEvents & WL_POSTMASTER_DEATH) + { + pmdeath_eventno = numevents; + events[numevents++] = PostmasterHandle; + } - for (;;) + do { /* * Reset the event, and check if the latch is set already. If someone @@ -127,45 +152,64 @@ WaitLatchOrSocket(volatile Latch *latch, SOCKET sock, bool forRead, */ if (!ResetEvent(latchevent)) elog(ERROR, "ResetEvent failed: error code %d", (int) GetLastError()); - if (latch->is_set) + if (latch->is_set && (wakeEvents & WL_LATCH_SET)) { - result = 1; + result |= WL_LATCH_SET; + /* + * Leave loop immediately, avoid blocking again. We don't attempt + * to report any other events that might also be satisfied. + */ break; } - rc = WaitForMultipleObjects(numevents, events, FALSE, - (timeout >= 0) ? (timeout / 1000) : INFINITE); + rc = WaitForMultipleObjects(numevents, events, FALSE, timeout_ms); + if (rc == WAIT_FAILED) elog(ERROR, "WaitForMultipleObjects() failed: error code %d", (int) GetLastError()); + + /* Participate in Windows signal emulation */ + else if (rc == WAIT_OBJECT_0 + 1) + pgwin32_dispatch_queued_signals(); + + else if ((wakeEvents & WL_POSTMASTER_DEATH) && + rc == WAIT_OBJECT_0 + pmdeath_eventno) + { + /* Postmaster died */ + result |= WL_POSTMASTER_DEATH; + } else if (rc == WAIT_TIMEOUT) { - result = 0; - break; + result |= WL_TIMEOUT; } - else if (rc == WAIT_OBJECT_0 + 1) - pgwin32_dispatch_queued_signals(); - else if (rc == WAIT_OBJECT_0 + 2) + else if ((wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) != 0 && + rc == WAIT_OBJECT_0 + 2) /* socket is at event slot 2 */ { WSANETWORKEVENTS resEvents; - Assert(sock != PGINVALID_SOCKET); - ZeroMemory(&resEvents, sizeof(resEvents)); if (WSAEnumNetworkEvents(sock, sockevent, &resEvents) == SOCKET_ERROR) ereport(FATAL, (errmsg_internal("failed to enumerate network events: %i", (int) GetLastError()))); - if ((forRead && resEvents.lNetworkEvents & FD_READ) || - (forWrite && resEvents.lNetworkEvents & FD_WRITE)) - result = 2; - break; + if ((wakeEvents & WL_SOCKET_READABLE) && + (resEvents.lNetworkEvents & FD_READ)) + { + result |= WL_SOCKET_READABLE; + } + if ((wakeEvents & WL_SOCKET_WRITEABLE) && + (resEvents.lNetworkEvents & FD_WRITE)) + { + result |= WL_SOCKET_WRITEABLE; + } } + /* Otherwise it must be the latch event */ else if (rc != WAIT_OBJECT_0) elog(ERROR, "unexpected return code from WaitForMultipleObjects(): %d", (int) rc); } + while(result == 0); /* Clean up the handle we created for the socket */ - if (sock != PGINVALID_SOCKET && (forRead || forWrite)) + if (sockevent != WSA_INVALID_EVENT) { WSAEventSelect(sock, sockevent, 0); WSACloseEvent(sockevent); |