On 26 May 2011 11:22, Heikki Linnakangas <heikki.linnakan...@enterprisedb.com> wrote: > The Unix-stuff looks good to me at a first glance.
Good. > There's one reference left to "life sign" in comments. (FWIW, I don't have a > problem with that terminology myself) Should have caught that one. Removed. > Looking at the MSDN docs again, can't you simply include PostmasterHandle in > the WaitForMultipleObjects() call to have it return when the process dies? > It should be possible to mix different kind of handles in one call, > including process handles. Does it not work as advertised? Uh, I might have done that, had I been aware of PostmasterHandle. I tried various convoluted ways to make it do what ReadFile() did for me, before finally biting the bullet and just using ReadFile() in a separate thread. I've tried adding PostmasterHandle though, and it works well - it appears to behave exactly the same as my original implementation. This simplifies things considerably. Now, on win32, things are actually simpler than on Unix. >> You'll see that it takes about a second for the archiver to exit. All >> processes exit. > > Hmm, shouldn't the archiver exit almost instantaneously now that there's no > polling anymore? Actually, just one "lagger" process sometimes remains that takes maybe as long as a second, a bit longer than the others. I assumed that it was the archiver, but I was probably wrong. I also didn't see that very consistently. Attached revision doesn't use any threads or pipes on win32. It's far neater there. I'm still seeing that "lagger" process (which is an overstatement) at times, so I guess it is normal. On Windows, there is no detailed PS output, so I actually don't know what the lagger process is, and no easy way to determine that immediately occurs to me. -- Peter Geoghegan http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training and Services
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index e71090f..b1d38f5 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -10150,7 +10150,7 @@ retry: /* * Wait for more WAL to arrive, or timeout to be reached */ - WaitLatch(&XLogCtl->recoveryWakeupLatch, 5000000L); + WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT, 5000000L); ResetLatch(&XLogCtl->recoveryWakeupLatch); } else diff --git a/src/backend/port/unix_latch.c b/src/backend/port/unix_latch.c index 6dae7c9..fa1d382 100644 --- a/src/backend/port/unix_latch.c +++ b/src/backend/port/unix_latch.c @@ -94,6 +94,7 @@ #include "miscadmin.h" #include "storage/latch.h" +#include "storage/pmsignal.h" #include "storage/shmem.h" /* Are we currently in WaitLatch? The signal handler would like to know. */ @@ -108,6 +109,15 @@ static void initSelfPipe(void); static void drainSelfPipe(void); static void sendSelfPipeByte(void); +/* + * Constants that represent which of a pair of fds given + * to pipe() is watched and owned in the context of + * dealing with postmaster death + */ +#define POSTMASTER_FD_WATCH 0 +#define POSTMASTER_FD_OWN 1 + +extern int postmaster_alive_fds[2]; /* * Initialize a backend-local latch. @@ -188,22 +198,22 @@ DisownLatch(volatile Latch *latch) * backend-local latch initialized with InitLatch, or a shared latch * associated with the current process by calling OwnLatch. * - * Returns 'true' if the latch was set, or 'false' if timeout was reached. + * Returns bit field indicating which condition(s) caused the wake-up. */ -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); } /* * Like WaitLatch, but will also return when there's data available in - * 'sock' for reading or writing. Returns 0 if timeout was reached, - * 1 if the latch was set, 2 if the socket became readable or writable. + * 'sock' for reading or writing. + * + * Returns bit field indicating which condition(s) caused the wake-up. */ int -WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, bool forRead, - bool forWrite, long timeout) +WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, long timeout) { struct timeval tv, *tvp = NULL; @@ -211,12 +221,13 @@ WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, bool forRead, fd_set output_mask; int rc; int result = 0; + bool found = false; if (latch->owner_pid != MyProcPid) elog(ERROR, "cannot wait on a latch owned by another process"); /* Initialize timeout */ - if (timeout >= 0) + if (timeout >= 0 && (wakeEvents & WL_TIMEOUT)) { tv.tv_sec = timeout / 1000000L; tv.tv_usec = timeout % 1000000L; @@ -224,7 +235,7 @@ WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, bool forRead, } waiting = true; - for (;;) + do { int hifd; @@ -235,16 +246,30 @@ WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, bool forRead, * do that), and the select() will return immediately. */ drainSelfPipe(); - if (latch->is_set) - { - result = 1; - break; + if (latch->is_set && (wakeEvents & WL_LATCH_SET)) + { + result |= WL_LATCH_SET; + found = true; + /* Leave loop immediately, avoid blocking again. + * Since latch is set, no other factor could have + * coincided that could make us wake up + * independently of the latch being set, so no + * need to worry about having missed something. + */ + break; } FD_ZERO(&input_mask); FD_SET(selfpipe_readfd, &input_mask); + + if (wakeEvents & WL_POSTMASTER_DEATH) + { + FD_SET(postmaster_alive_fds[POSTMASTER_FD_WATCH], &input_mask); + if (postmaster_alive_fds[POSTMASTER_FD_WATCH] > hifd) + hifd = postmaster_alive_fds[POSTMASTER_FD_WATCH]; + } hifd = selfpipe_readfd; - if (sock != PGINVALID_SOCKET && forRead) + if (sock != PGINVALID_SOCKET && (wakeEvents & WL_SOCKET_READABLE)) { FD_SET(sock, &input_mask); if (sock > hifd) @@ -252,7 +277,7 @@ WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, bool forRead, } FD_ZERO(&output_mask); - if (sock != PGINVALID_SOCKET && forWrite) + if (sock != PGINVALID_SOCKET && (wakeEvents & WL_SOCKET_WRITEABLE)) { FD_SET(sock, &output_mask); if (sock > hifd) @@ -268,20 +293,35 @@ WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, bool forRead, (errcode_for_socket_access(), errmsg("select() failed: %m"))); } - if (rc == 0) + if (rc == 0 && (wakeEvents & WL_TIMEOUT)) { /* timeout exceeded */ - result = 0; - break; + result |= WL_TIMEOUT; + found = true; } - if (sock != PGINVALID_SOCKET && - ((forRead && FD_ISSET(sock, &input_mask)) || - (forWrite && FD_ISSET(sock, &output_mask)))) + if (sock != PGINVALID_SOCKET) { - result = 2; - break; /* data available in socket */ + if ((wakeEvents & WL_SOCKET_READABLE ) && FD_ISSET(sock, &input_mask)) + { + result |= WL_SOCKET_READABLE; + found = true; /* data available in socket */ + } + if ((wakeEvents & WL_SOCKET_WRITEABLE) && FD_ISSET(sock, &output_mask)) + { + result |= WL_SOCKET_WRITEABLE; + found = true; + } } + if ((wakeEvents & WL_POSTMASTER_DEATH) && + FD_ISSET(postmaster_alive_fds[POSTMASTER_FD_WATCH], &input_mask) && + !PostmasterIsAlive(true)) + { + result |= WL_POSTMASTER_DEATH; + found = true; + } } + while(!found); + waiting = false; return result; @@ -430,3 +470,99 @@ drainSelfPipe(void) elog(ERROR, "unexpected EOF on self-pipe"); } } + +/* + * Called once from the postmaster, so that child processes can subsequently + * monitor if their parent is dead. We open up an anoymous pipe, and have child + * processes block on a select() call that examines if the read file descriptor + * is ready for reading. They do so through a latch. + * + * Child processes are responsible for releasing the death watch handler, so + * that only the postmaster holds it, and a select() on the fd returns upon the + * one and only holder (the postmaster) dying. + * + * This is a trick that obviates the need for auxiliary backends to have tight + * polling loops where they check if the postmaster is alive. We do this because + * that pattern results in an excessive number of wakeups per second when idle. + */ +void +InitPostmasterDeathWatchHandle(void) +{ + int flags; + + /* + * Create pipe. The postmaster is deemed dead if + * no process has the writing end (POSTMASTER_FD_OWN) open. + * + */ + Assert(MyProcPid == PostmasterPid); + if (pipe(postmaster_alive_fds)) + { + ereport(FATAL, + (errcode_for_socket_access(), + errmsg( "pipe() call failed to create pipe to monitor postmaster death: %s", strerror(errno)))); + } + + flags = fcntl(postmaster_alive_fds[POSTMASTER_FD_WATCH], F_GETFL); + if (flags < 0) + { + ereport(FATAL, + (errcode_for_socket_access(), + errmsg("Failed to set the postmaster death watching fd's flags: %s", strerror(errno)))); + } + + /* + * Set FNONBLOCK to allow checking for the fd's presence with a read() call + * and FASYNC to deliver a signal to our process group if the descriptor vanishes + */ + flags |= FNONBLOCK | FASYNC; + if (fcntl(postmaster_alive_fds[POSTMASTER_FD_WATCH], F_SETFL, flags)) + { + ereport(FATAL, + (errcode_for_socket_access(), + errmsg("Failed to set the postmaster death watching fd's flags: %s", strerror(errno)))); + } + + /* Send SIGIO signal to the whole process group */ + if (fcntl(postmaster_alive_fds[POSTMASTER_FD_WATCH], F_SETOWN, -getpgrp())) + { + ereport(FATAL, + (errcode_for_socket_access(), + errmsg("Failed to set the postmaster's watching end's notification: %s", strerror(errno)))); + } +} + +/* + * Release postmaster death watch handle. + * + * Important: This must be called immediately after a process + * forks from the postmaster. Otherwise, latch clients will + * not wake up on postmaster death, even if they have requested + * to. + * + * Even some hypothetical backend that doesn't care about postmaster + * death has a responsibility to call this function - otherwise, + * some other latch client backend could wait in vain to be informed + * of postmaster death, because the irresponsible backend held open + * the ownership file descriptor and outlived the postmaster. + * + * We call the function within the fork machinery to handle all cases, + * so new backends need not bother with this themselves + */ +void +ReleasePostmasterDeathWatchHandle(void) +{ + /* MyProcPid won't have been set yet */ + Assert(PostmasterPid != getpid()); + /* Please don't ask twice */ + Assert(postmaster_alive_fds[POSTMASTER_FD_OWN] != -1); + /* Release parent's ownership fd - only postmaster should hold it */ + if (close(postmaster_alive_fds[ POSTMASTER_FD_OWN])) + { + ereport(FATAL, + (errcode_for_socket_access(), + errmsg("Failed to close file descriptor associated with Postmaster death in child process %d", MyProcPid))); + } + postmaster_alive_fds[POSTMASTER_FD_OWN] = -1; +} + diff --git a/src/backend/port/win32_latch.c b/src/backend/port/win32_latch.c index 3509302..ad5d914 100644 --- a/src/backend/port/win32_latch.c +++ b/src/backend/port/win32_latch.c @@ -25,8 +25,10 @@ #include "miscadmin.h" #include "replication/walsender.h" #include "storage/latch.h" +#include "storage/pmsignal.h" #include "storage/shmem.h" +extern HANDLE PostmasterHandle; void InitLatch(volatile Latch *latch) @@ -81,35 +83,35 @@ 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 */ int numevents; int result = 0; + bool found = false; latchevent = latch->event; events[0] = latchevent; events[1] = pgwin32_signal_event; numevents = 2; - if (sock != PGINVALID_SOCKET && (forRead || forWrite)) + if (sock != PGINVALID_SOCKET && ((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(); @@ -117,7 +119,12 @@ WaitLatchOrSocket(volatile Latch *latch, SOCKET sock, bool forRead, events[numevents++] = sockevent; } - for (;;) + if (wakeEvents & WL_POSTMASTER_DEATH) + { + events[numevents++] = PostmasterHandle; + } + + do { /* * Reset the event, and check if the latch is set already. If someone @@ -129,22 +136,37 @@ WaitLatchOrSocket(volatile Latch *latch, SOCKET sock, bool forRead, elog(ERROR, "ResetEvent failed: error code %d", (int) GetLastError()); if (latch->is_set) { - result = 1; + result |= WL_LATCH_SET; + found = true; + /* Leave loop immediately, avoid blocking again. + * Since latch is set, no other factor could have + * coincided that could make us wake up + * independently of the latch being set, so no + * need to worry about having missed something. + */ break; } - rc = WaitForMultipleObjects(numevents, events, FALSE, (timeout >= 0) ? (timeout / 1000) : INFINITE); - if (rc == WAIT_FAILED) + + if ( (wakeEvents & WL_POSTMASTER_DEATH) && + !PostmasterIsAlive(true)) + { + /* Postmaster died */ + result |= WL_POSTMASTER_DEATH; + found = true; + } + else if (rc == WAIT_FAILED) elog(ERROR, "WaitForMultipleObjects() failed: error code %d", (int) GetLastError()); else if (rc == WAIT_TIMEOUT) { - result = 0; - break; + result |= WL_TIMEOUT; + found = true; } else if (rc == WAIT_OBJECT_0 + 1) pgwin32_dispatch_queued_signals(); - else if (rc == WAIT_OBJECT_0 + 2) + else if (rc == WAIT_OBJECT_0 + 2 && + ((wakeEvents & WL_SOCKET_READABLE) || (wakeEvents & WL_SOCKET_WRITEABLE))) { WSANETWORKEVENTS resEvents; @@ -155,17 +177,24 @@ WaitLatchOrSocket(volatile Latch *latch, SOCKET sock, bool forRead, 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; + found = true; + } + if ((wakeEvents & WL_SOCKET_WRITEABLE) && (resEvents.lNetworkEvents & FD_WRITE)) + { + result |= WL_SOCKET_WRITEABLE; + found = true; + } } else if (rc != WAIT_OBJECT_0) elog(ERROR, "unexpected return code from WaitForMultipleObjects(): %d", (int) rc); } + while(!found); /* Clean up the handle we created for the socket */ - if (sock != PGINVALID_SOCKET && (forRead || forWrite)) + if (sock != PGINVALID_SOCKET && ((wakeEvents & WL_SOCKET_READABLE) || (wakeEvents & WL_SOCKET_WRITEABLE))) { WSAEventSelect(sock, sockevent, 0); WSACloseEvent(sockevent); diff --git a/src/backend/postmaster/fork_process.c b/src/backend/postmaster/fork_process.c index b2fe9a1..6e2f37a 100644 --- a/src/backend/postmaster/fork_process.c +++ b/src/backend/postmaster/fork_process.c @@ -11,6 +11,7 @@ */ #include "postgres.h" #include "postmaster/fork_process.h" +#include "storage/latch.h" #include <fcntl.h> #include <time.h> @@ -61,6 +62,7 @@ fork_process(void) #ifdef LINUX_PROFILE setitimer(ITIMER_PROF, &prof_itimer, NULL); #endif + ReleasePostmasterDeathWatchHandle(); /* * By default, Linux tends to kill the postmaster in out-of-memory diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index b40375a..1548a3b 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -40,6 +40,7 @@ #include "postmaster/postmaster.h" #include "storage/fd.h" #include "storage/ipc.h" +#include "storage/latch.h" #include "storage/pg_shmem.h" #include "storage/pmsignal.h" #include "utils/guc.h" @@ -87,6 +88,12 @@ static volatile sig_atomic_t got_SIGTERM = false; static volatile sig_atomic_t wakened = false; static volatile sig_atomic_t ready_to_stop = false; +/* + * Latch that archiver loop waits on until it is awakened by + * signals, each of which there is a handler for + */ +static volatile Latch mainloop_latch; + /* ---------- * Local function forward declarations * ---------- @@ -228,6 +235,8 @@ PgArchiverMain(int argc, char *argv[]) MyProcPid = getpid(); /* reset MyProcPid */ + InitLatch(&mainloop_latch); /* initialise latch used in main loop, now that we are a subprocess */ + MyStartTime = time(NULL); /* record Start Time for logging */ /* @@ -282,6 +291,8 @@ ArchSigHupHandler(SIGNAL_ARGS) { /* set flag to re-read config file at next convenient time */ got_SIGHUP = true; + /* Let the waiting loop iterate */ + SetLatch(&mainloop_latch); } /* SIGTERM signal handler for archiver process */ @@ -295,6 +306,8 @@ ArchSigTermHandler(SIGNAL_ARGS) * archive commands. */ got_SIGTERM = true; + /* Let the waiting loop iterate */ + SetLatch(&mainloop_latch); } /* SIGUSR1 signal handler for archiver process */ @@ -303,6 +316,8 @@ pgarch_waken(SIGNAL_ARGS) { /* set flag that there is work to be done */ wakened = true; + /* Let the waiting loop iterate */ + SetLatch(&mainloop_latch); } /* SIGUSR2 signal handler for archiver process */ @@ -311,6 +326,8 @@ pgarch_waken_stop(SIGNAL_ARGS) { /* set flag to do a final cycle and shut down afterwards */ ready_to_stop = true; + /* Let the waiting loop iterate */ + SetLatch(&mainloop_latch); } /* @@ -334,6 +351,13 @@ pgarch_MainLoop(void) do { + /* + * There shouldn't be anything for the archiver to do except to wait + * on a latch ... however, the archiver exists to protect our data, + * so she wakes up occasionally to allow herself to be proactive. + */ + ResetLatch(&mainloop_latch); + /* When we get SIGUSR2, we do one more archive cycle, then exit */ time_to_stop = ready_to_stop; @@ -370,26 +394,28 @@ pgarch_MainLoop(void) last_copy_time = time(NULL); } - /* - * There shouldn't be anything for the archiver to do except to wait - * for a signal ... however, the archiver exists to protect our data, - * so she wakes up occasionally to allow herself to be proactive. + /* + * Wait on latch, until various signals are received, or + * until a poll will be forced by PGARCH_AUTOWAKE_INTERVAL + * having passed since last_copy_time, or on the postmaster's + * untimely demise. * - * On some platforms, signals won't interrupt the sleep. To ensure we - * respond reasonably promptly when someone signals us, break down the - * sleep into 1-second increments, and check for interrupts after each - * nap. + * The caveat about signals resetting the timeout of + * WaitLatch()/select() on some platforms can be safely disregarded, + * because we handle all expected signals, and all handlers + * call SetLatch() where that matters anyway */ - while (!(wakened || ready_to_stop || got_SIGHUP || - !PostmasterIsAlive(true))) - { - time_t curtime; - pg_usleep(1000000L); + if (!time_to_stop) /* Don't wait during last iteration */ + { + time_t curtime = time(NULL); + unsigned int timeout_secs = (unsigned int) PGARCH_AUTOWAKE_INTERVAL - + (unsigned int) (curtime - last_copy_time); + WaitLatch(&mainloop_latch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, timeout_secs * 1000000L); curtime = time(NULL); if ((unsigned int) (curtime - last_copy_time) >= (unsigned int) PGARCH_AUTOWAKE_INTERVAL) - wakened = true; + wakened = true; /* wakened by timeout - this wasn't a SIGHUP, etc */ } /* diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 1e2aa9f..dd2335e 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -356,6 +356,7 @@ static void RandomSalt(char *md5Salt); static void signal_child(pid_t pid, int signal); static bool SignalSomeChildren(int signal, int targets); + #define SignalChildren(sig) SignalSomeChildren(sig, BACKEND_TYPE_ALL) /* @@ -443,6 +444,7 @@ typedef struct HANDLE syslogPipe[2]; #else int syslogPipe[2]; + int postmaster_alive_fds[2]; #endif char my_exec_path[MAXPGPATH]; char pkglib_path[MAXPGPATH]; @@ -472,6 +474,15 @@ static void ShmemBackendArrayRemove(Backend *bn); #define EXIT_STATUS_0(st) ((st) == 0) #define EXIT_STATUS_1(st) (WIFEXITED(st) && WEXITSTATUS(st) == 1) +/* + * 2 file descriptors that monitoring if postmaster is alive. + * First is POSTMASTER_FD_WATCH, second is POSTMASTER_FD_OWN. + * (macros defined in unix_latch.c) + */ +#ifndef WIN32 +int postmaster_alive_fds[2]; +#endif + /* * Postmaster main entry point @@ -491,6 +502,15 @@ PostmasterMain(int argc, char *argv[]) IsPostmasterEnvironment = true; +#ifndef WIN32 + /* + * Initialise mechanism that allows waiting latch clients + * to wake on postmaster death, to finish their + * remaining business + */ + InitPostmasterDeathWatchHandle(); +#endif + /* * for security, no dir or file created can be group or other accessible */ @@ -4753,6 +4773,9 @@ save_backend_variables(BackendParameters *param, Port *port, memcpy(¶m->syslogPipe, &syslogPipe, sizeof(syslogPipe)); +#ifndef WIN32 + memcpy(¶m->postmaster_alive_fds, &postmaster_alive_fds, sizeof(postmaster_alive_fds)); +#endif strlcpy(param->my_exec_path, my_exec_path, MAXPGPATH); strlcpy(param->pkglib_path, pkglib_path, MAXPGPATH); @@ -4968,6 +4991,10 @@ restore_backend_variables(BackendParameters *param, Port *port) memcpy(&syslogPipe, ¶m->syslogPipe, sizeof(syslogPipe)); +#ifndef WIN32 + memcpy(&postmaster_alive_fds, ¶m->postmaster_alive_fds, sizeof(postmaster_alive_fds)); +#endif + strlcpy(my_exec_path, param->my_exec_path, MAXPGPATH); strlcpy(pkglib_path, param->pkglib_path, MAXPGPATH); diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index 1d4df8a..efda804 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -171,7 +171,7 @@ SyncRepWaitForLSN(XLogRecPtr XactCommitLSN) * postmaster death regularly while waiting. Note that timeout here * does not necessarily release from loop. */ - WaitLatch(&MyProc->waitLatch, 60000000L); + WaitLatch(&MyProc->waitLatch, WL_LATCH_SET | WL_TIMEOUT, 60000000L); /* Must reset the latch before testing state. */ ResetLatch(&MyProc->waitLatch); diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 470e6d1..27cc350 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -805,8 +805,9 @@ WalSndLoop(void) } /* Sleep */ - WaitLatchOrSocket(&MyWalSnd->latch, MyProcPort->sock, - true, pq_is_send_pending(), + WaitLatchOrSocket(&MyWalSnd->latch, + WL_LATCH_SET | WL_SOCKET_READABLE | (pq_is_send_pending()? WL_SOCKET_WRITEABLE:0) | WL_TIMEOUT, + MyProcPort->sock, sleeptime * 1000L); /* Check for replication timeout */ diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 03ec071..5464dbc 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -38,9 +38,8 @@ extern void InitLatch(volatile Latch *latch); extern void InitSharedLatch(volatile Latch *latch); extern void OwnLatch(volatile Latch *latch); extern void DisownLatch(volatile Latch *latch); -extern bool WaitLatch(volatile Latch *latch, long timeout); -extern int WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, - bool forRead, bool forWrite, long timeout); +extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout); +extern int WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, long timeout); extern void SetLatch(volatile Latch *latch); extern void ResetLatch(volatile Latch *latch); @@ -52,8 +51,25 @@ extern void ResetLatch(volatile Latch *latch); */ #ifndef WIN32 extern void latch_sigusr1_handler(void); +/* + * On unix, it is necessary to Init monitoring + * of postmaster being alive + */ +extern void InitPostmasterDeathWatchHandle(void); +/* + * It is also necessary to call ReleasePostmasterDeathWatchHandle() + * after forking from PM for the Unix implementation + */ +extern void ReleasePostmasterDeathWatchHandle(void); #else #define latch_sigusr1_handler() #endif +/* Bitmasks for events that may wake-up WaitLatch() clients */ +#define WL_LATCH_SET (1 << 0) +#define WL_SOCKET_READABLE (1 << 1) +#define WL_SOCKET_WRITEABLE (1 << 2) +#define WL_TIMEOUT (1 << 3) +#define WL_POSTMASTER_DEATH (1 << 4) + #endif /* LATCH_H */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers