diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6a6959f..b2cf973 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -10210,7 +10210,7 @@ retry: /* * Wait for more WAL to arrive, or timeout to be reached */ - WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT, 5000000L); + WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT, 5000L); ResetLatch(&XLogCtl->recoveryWakeupLatch); } else diff --git a/src/backend/port/unix_latch.c b/src/backend/port/unix_latch.c index 9940a42..0663eb8 100644 --- a/src/backend/port/unix_latch.c +++ b/src/backend/port/unix_latch.c @@ -182,7 +182,7 @@ DisownLatch(volatile Latch *latch) * to wait for. If the latch is already set (and WL_LATCH_SET is given), the * function returns immediately. * - * The 'timeout' is given in microseconds. It must be >= 0 if WL_TIMEOUT + * The 'timeout' is given in milliseconds. It must be >= 0 if WL_TIMEOUT * event is given, otherwise it is ignored. On some platforms, signals cause * the timeout to be restarted, so beware that the function can sleep for * several times longer than the specified timeout. @@ -236,8 +236,9 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, if (wakeEvents & WL_TIMEOUT) { Assert(timeout >= 0); - tv.tv_sec = timeout / 1000000L; - tv.tv_usec = timeout % 1000000L; + tv.tv_sec = timeout / 1000L; + /* tv_usec should be in microseconds */ + tv.tv_usec = (timeout % 1000L) * 1000L; tvp = &tv; } @@ -329,6 +330,11 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, /* * Sets a latch and wakes up anyone waiting on it. Returns quickly if the * latch is already set. + * + * Note that there is a general requirement to call this function within + * signal handlers, to ensure that latch timeout is not invalidated. For + * generic signal handlers that may be registered for multiple processes, + * it will be called with the per-process latch in PGPROC as its argument. */ void SetLatch(volatile Latch *latch) diff --git a/src/backend/port/win32_latch.c b/src/backend/port/win32_latch.c index 8d59ad4..5ee4f40 100644 --- a/src/backend/port/win32_latch.c +++ b/src/backend/port/win32_latch.c @@ -99,23 +99,14 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, SOCKET sock, int numevents; int result = 0; int pmdeath_eventno = 0; - long timeout_ms; Assert(wakeEvents != 0); + Assert(timeout >= 0 || (wakeEvents & WL_TIMEOUT) == 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; @@ -162,7 +153,7 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, SOCKET sock, break; } - rc = WaitForMultipleObjects(numevents, events, FALSE, timeout_ms); + rc = WaitForMultipleObjects(numevents, events, FALSE, (wakeEvents & WL_TIMEOUT)?timeout:INFINITE); if (rc == WAIT_FAILED) elog(ERROR, "WaitForMultipleObjects() failed: error code %d", (int) GetLastError()); diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 2f3fcbf..acfc3b4 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -84,6 +84,7 @@ #include "postmaster/postmaster.h" #include "storage/bufmgr.h" #include "storage/ipc.h" +#include "storage/latch.h" #include "storage/pmsignal.h" #include "storage/proc.h" #include "storage/procsignal.h" @@ -567,38 +568,20 @@ AutoVacLauncherMain(int argc, char *argv[]) /* * Sleep for a while according to schedule. + * Wait on Latch. * - * 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. + * We handle wait time invalidation by calling + * SetLatch() in signal handlers. */ - while (nap.tv_sec > 0 || nap.tv_usec > 0) - { - uint32 sleeptime; - - if (nap.tv_sec > 0) - { - sleeptime = 1000000; - nap.tv_sec--; - } - else - { - sleeptime = nap.tv_usec; - nap.tv_usec = 0; - } - pg_usleep(sleeptime); - - /* - * Emergency bailout if postmaster has died. This is to avoid the - * necessity for manual cleanup of all postmaster children. - */ - if (!PostmasterIsAlive()) - proc_exit(1); - - if (got_SIGTERM || got_SIGHUP || got_SIGUSR2) - break; - } + WaitLatch(&MyProc->waitLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L)); + /* + * Emergency bailout if postmaster has died. This is to avoid the + * necessity for manual cleanup of all postmaster children. + * + * This happens again here because we may have slept for quite a while. + */ + if (!PostmasterIsAlive()) + proc_exit(1); DisableCatchupInterrupt(); @@ -1322,6 +1305,8 @@ static void avl_sighup_handler(SIGNAL_ARGS) { got_SIGHUP = true; + /* let the waiting loop iterate */ + SetLatch(&MyProc->waitLatch); } /* SIGUSR2: a worker is up and running, or just finished, or failed to fork */ @@ -1329,6 +1314,8 @@ static void avl_sigusr2_handler(SIGNAL_ARGS) { got_SIGUSR2 = true; + /* let the waiting loop iterate */ + SetLatch(&MyProc->waitLatch); } /* SIGTERM: time to die */ @@ -1336,6 +1323,8 @@ static void avl_sigterm_handler(SIGNAL_ARGS) { got_SIGTERM = true; + /* let the waiting loop iterate */ + SetLatch(&MyProc->waitLatch); } diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index 2070fbb..8d1dab7 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -409,7 +409,7 @@ pgarch_MainLoop(void) int rc; rc = WaitLatch(&mainloop_latch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - timeout * 1000000L); + timeout * 1000L); if (rc & WL_TIMEOUT) wakened = true; } diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index 32db2bc..4672a52 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, WL_LATCH_SET | WL_TIMEOUT, 60000000L); + WaitLatch(&MyProc->waitLatch, WL_LATCH_SET | WL_TIMEOUT, 60000L); /* 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 63a6304..c1996ca 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -812,7 +812,7 @@ WalSndLoop(void) if (pq_is_send_pending()) wakeEvents |= WL_SOCKET_WRITEABLE; WaitLatchOrSocket(&MyWalSnd->latch, wakeEvents, - MyProcPort->sock, sleeptime * 1000L); + MyProcPort->sock, sleeptime); /* Check for replication timeout */ if (replication_timeout > 0 && diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index 28bcaa7..892941c 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -22,6 +22,7 @@ #include "miscadmin.h" #include "storage/ipc.h" #include "storage/latch.h" +#include "storage/proc.h" #include "storage/procsignal.h" #include "storage/shmem.h" #include "storage/sinval.h" @@ -255,6 +256,9 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) { int save_errno = errno; + if (MyProc) + SetLatch(&MyProc->waitLatch); + if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT)) HandleCatchupInterrupt(); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index f9b3028..8360bd5 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -1613,6 +1613,8 @@ handle_sig_alarm(SIGNAL_ARGS) (void) CheckStatementTimeout(); errno = save_errno; + if (MyProc) + SetLatch(&MyProc->waitLatch); } /* diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index f035a48..ec91f18 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -2643,12 +2643,12 @@ die(SIGNAL_ARGS) InterruptHoldoffCount--; ProcessInterrupts(); } - - /* Interrupt any sync rep wait which is currently in progress. */ - SetLatch(&(MyProc->waitLatch)); } errno = save_errno; + /* set the process latch - we cannot risk invalidating its timeout */ + if (MyProc) + SetLatch(&MyProc->waitLatch); } /* @@ -2684,18 +2684,22 @@ StatementCancelHandler(SIGNAL_ARGS) InterruptHoldoffCount--; ProcessInterrupts(); } - - /* Interrupt any sync rep wait which is currently in progress. */ - SetLatch(&(MyProc->waitLatch)); } errno = save_errno; + /* set the process latch - we cannot risk invalidating its timeout */ + if (MyProc) + SetLatch(&MyProc->waitLatch); } /* signal handler for floating point exception */ void FloatExceptionHandler(SIGNAL_ARGS) { + /* set the process latch - we cannot risk invalidating its timeout */ + if (MyProc) + SetLatch(&MyProc->waitLatch); + ereport(ERROR, (errcode(ERRCODE_FLOATING_POINT_EXCEPTION), errmsg("floating-point exception"), @@ -2709,6 +2713,9 @@ static void SigHupHandler(SIGNAL_ARGS) { got_SIGHUP = true; + /* set the process latch - we cannot risk invalidating its timeout */ + if (MyProc) + SetLatch(&MyProc->waitLatch); } /* diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 09ac3cf..71e41d3 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -126,13 +126,14 @@ struct PGPROC LOCKMASK heldLocks; /* bitmask for lock types already held on this * lock object by this backend */ + Latch waitLatch; /* generic latch for process */ + /* * Info to allow us to wait for synchronous replication, if needed. * waitLSN is InvalidXLogRecPtr if not waiting; set only by user backend. * syncRepState must not be touched except by owning process or WALSender. * syncRepLinks used only while holding SyncRepLock. */ - Latch waitLatch; /* allow us to wait for sync rep */ XLogRecPtr waitLSN; /* waiting for this LSN or higher */ int syncRepState; /* wait state for sync rep */ SHM_QUEUE syncRepLinks; /* list link if process is in syncrep queue */