From 1de79f8154baedfde3175319b11ca6a79921fec9 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Tue, 21 Jan 2020 12:17:09 +1300 Subject: [PATCH 1/3] Add WaitMyLatch() to replace many WaitLatch() calls. WaitLatch() sets up and tears down a WaitEventSet every time. A common case is waiting for your own latch, optionally with a timeout, and automatic exit on postmaster death. Provide a function that does that, with a reused WaitEventSet. This avoids many system calls on some builds. --- src/backend/access/transam/parallel.c | 7 ++--- src/backend/executor/nodeGather.c | 3 +- src/backend/postmaster/autovacuum.c | 6 ++-- src/backend/postmaster/bgwriter.c | 10 ++----- src/backend/postmaster/checkpointer.c | 6 ++-- src/backend/postmaster/pgarch.c | 5 +--- src/backend/postmaster/walwriter.c | 5 +--- src/backend/replication/basebackup.c | 6 ++-- src/backend/replication/logical/launcher.c | 17 +++-------- src/backend/replication/logical/tablesync.c | 8 ++---- src/backend/storage/ipc/latch.c | 32 +++++++++++++++++++++ src/backend/storage/ipc/procsignal.c | 5 +--- src/backend/storage/lmgr/proc.c | 7 ++--- src/backend/utils/adt/misc.c | 5 +--- src/include/storage/latch.h | 1 + 15 files changed, 58 insertions(+), 65 deletions(-) diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index df06e7d174..e951ae75b9 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -705,9 +705,7 @@ WaitForParallelWorkersToAttach(ParallelContext *pcxt) * might also get set for some other reason, but if so we'll * just end up waiting for the same worker again. */ - rc = WaitLatch(MyLatch, - WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, - -1, WAIT_EVENT_BGWORKER_STARTUP); + rc = WaitMyLatch(-1, WAIT_EVENT_BGWORKER_STARTUP); if (rc & WL_LATCH_SET) ResetLatch(MyLatch); @@ -825,8 +823,7 @@ WaitForParallelWorkersToFinish(ParallelContext *pcxt) } } - (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, -1, - WAIT_EVENT_PARALLEL_FINISH); + (void) WaitMyLatch(-1, WAIT_EVENT_PARALLEL_FINISH); ResetLatch(MyLatch); } diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index 6b8ed867d5..57d82eae8f 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -383,8 +383,7 @@ gather_readnext(GatherState *gatherstate) return NULL; /* Nothing to do except wait for developments. */ - (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0, - WAIT_EVENT_EXECUTE_GATHER); + (void) WaitMyLatch(-1, WAIT_EVENT_EXECUTE_GATHER); ResetLatch(MyLatch); nvisited = 0; } diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 6d1f28c327..b5c3142bed 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -641,10 +641,8 @@ AutoVacLauncherMain(int argc, char *argv[]) * Wait until naptime expires or we get some type of signal (all the * signal handlers will wake us by calling SetLatch). */ - (void) WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L), - WAIT_EVENT_AUTOVACUUM_MAIN); + (void) WaitMyLatch((nap.tv_sec * 1000L) + (nap.tv_usec / 1000L), + WAIT_EVENT_AUTOVACUUM_MAIN); ResetLatch(MyLatch); diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 069e27e427..85c1c6891c 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -301,9 +301,7 @@ BackgroundWriterMain(void) * down with latch events that are likely to happen frequently during * normal operation. */ - rc = WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - BgWriterDelay /* ms */ , WAIT_EVENT_BGWRITER_MAIN); + rc = WaitMyLatch(BgWriterDelay /* ms */ , WAIT_EVENT_BGWRITER_MAIN); /* * If no latch event and BgBufferSync says nothing's happening, extend @@ -328,10 +326,8 @@ BackgroundWriterMain(void) /* Ask for notification at next buffer allocation */ StrategyNotifyBgWriter(MyProc->pgprocno); /* Sleep ... */ - (void) WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - BgWriterDelay * HIBERNATE_FACTOR, - WAIT_EVENT_BGWRITER_HIBERNATE); + (void) WaitMyLatch(BgWriterDelay * HIBERNATE_FACTOR, + WAIT_EVENT_BGWRITER_HIBERNATE); /* Reset the notification request in case we timed out */ StrategyNotifyBgWriter(-1); } diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index e354a78725..b87dd03856 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -511,10 +511,8 @@ CheckpointerMain(void) cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs); } - (void) WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - cur_timeout * 1000L /* convert to ms */ , - WAIT_EVENT_CHECKPOINTER_MAIN); + (void) WaitMyLatch(cur_timeout * 1000L /* convert to ms */ , + WAIT_EVENT_CHECKPOINTER_MAIN); } } diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index 3ca30badb2..4833c1c343 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -361,10 +361,7 @@ pgarch_MainLoop(void) { int rc; - rc = WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - timeout * 1000L, - WAIT_EVENT_ARCHIVER_MAIN); + rc = WaitMyLatch(timeout * 1000L, WAIT_EVENT_ARCHIVER_MAIN); if (rc & WL_TIMEOUT) wakened = true; if (rc & WL_POSTMASTER_DEATH) diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 45a2757969..c9ac4eb742 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -253,9 +253,6 @@ WalWriterMain(void) else cur_timeout = WalWriterDelay * HIBERNATE_FACTOR; - (void) WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - cur_timeout, - WAIT_EVENT_WAL_WRITER_MAIN); + (void) WaitMyLatch(cur_timeout, WAIT_EVENT_WAL_WRITER_MAIN); } } diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index dea8aab45e..0f1b54746d 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -1705,10 +1705,8 @@ throttle(size_t increment) * (TAR_SEND_SIZE / throttling_sample * elapsed_min_unit) should be * the maximum time to sleep. Thus the cast to long is safe. */ - wait_result = WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - (long) (sleep / 1000), - WAIT_EVENT_BASE_BACKUP_THROTTLE); + wait_result = WaitMyLatch((long) (sleep / 1000), + WAIT_EVENT_BASE_BACKUP_THROTTLE); if (wait_result & WL_LATCH_SET) CHECK_FOR_INTERRUPTS(); diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c index aec885e987..13e811384d 100644 --- a/src/backend/replication/logical/launcher.c +++ b/src/backend/replication/logical/launcher.c @@ -211,9 +211,7 @@ WaitForReplicationWorkerAttach(LogicalRepWorker *worker, * We need timeout because we generally don't get notified via latch * about the worker attach. But we don't expect to have to wait long. */ - rc = WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - 10L, WAIT_EVENT_BGWORKER_STARTUP); + rc = WaitMyLatch(10L, WAIT_EVENT_BGWORKER_STARTUP); if (rc & WL_LATCH_SET) { @@ -482,9 +480,7 @@ logicalrep_worker_stop(Oid subid, Oid relid) LWLockRelease(LogicalRepWorkerLock); /* Wait a bit --- we don't expect to have to wait long. */ - rc = WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - 10L, WAIT_EVENT_BGWORKER_STARTUP); + rc = WaitMyLatch(10L, WAIT_EVENT_BGWORKER_STARTUP); if (rc & WL_LATCH_SET) { @@ -526,9 +522,7 @@ logicalrep_worker_stop(Oid subid, Oid relid) LWLockRelease(LogicalRepWorkerLock); /* Wait a bit --- we don't expect to have to wait long. */ - rc = WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - 10L, WAIT_EVENT_BGWORKER_SHUTDOWN); + rc = WaitMyLatch(10L, WAIT_EVENT_BGWORKER_SHUTDOWN); if (rc & WL_LATCH_SET) { @@ -1034,10 +1028,7 @@ ApplyLauncherMain(Datum main_arg) } /* Wait for more work. */ - rc = WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - wait_time, - WAIT_EVENT_LOGICAL_LAUNCHER_MAIN); + rc = WaitMyLatch(wait_time, WAIT_EVENT_LOGICAL_LAUNCHER_MAIN); if (rc & WL_LATCH_SET) { diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index f8183cd488..44d8c275cc 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -185,9 +185,7 @@ wait_for_relation_state_change(Oid relid, char expected_state) if (!worker) return false; - (void) WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE); + (void) WaitMyLatch(1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE); ResetLatch(MyLatch); } @@ -238,9 +236,7 @@ wait_for_worker_state_change(char expected_state) * Wait. We expect to get a latch signal back from the apply worker, * but use a timeout in case it dies without sending one. */ - rc = WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE); + rc = WaitMyLatch(1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE); if (rc & WL_LATCH_SET) ResetLatch(MyLatch); diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c index d677ffbda7..27fc3df920 100644 --- a/src/backend/storage/ipc/latch.c +++ b/src/backend/storage/ipc/latch.c @@ -52,6 +52,7 @@ #include "storage/latch.h" #include "storage/pmsignal.h" #include "storage/shmem.h" +#include "utils/memutils.h" /* * Select the fd readiness primitive to use. Normally the "most modern" @@ -420,6 +421,37 @@ WaitLatchOrSocket(Latch *latch, int wakeEvents, pgsocket sock, return ret; } +/* + * For callers with the common requirement to wait for their own latch or a + * timeout (or -1 for no timeout), with automatic exit on postmaster death, + * this variant reuses a WaitEventSet. On builds where that allocates kernel + * resources, this approach avoids building them up and tearing them down + * every time. + */ +int +WaitMyLatch(long timeout, uint32 wait_event_info) +{ + static WaitEventSet *set; + WaitEvent event; + + /* Create on demand. */ + if (set == NULL) + { + WaitEventSet *wes; + + wes = CreateWaitEventSet(TopMemoryContext, 2); + AddWaitEventToSet(wes, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch, NULL); + AddWaitEventToSet(wes, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET, NULL, + NULL); + set = wes; + } + + if (WaitEventSetWait(set, timeout, &event, 1, wait_event_info) == 0) + return WL_TIMEOUT; + else + return event.events; +} + /* * Sets a latch and wakes up anyone waiting on it. * diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index 65d3946386..024cbc9cf9 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -395,10 +395,7 @@ WaitForProcSignalBarrier(uint64 generation) CHECK_FOR_INTERRUPTS(); - events = - WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - timeout, WAIT_EVENT_PROC_SIGNAL_BARRIER); + events = WaitMyLatch(timeout, WAIT_EVENT_PROC_SIGNAL_BARRIER); ResetLatch(MyLatch); oldval = pg_atomic_read_u64(&slot->pss_barrierGeneration); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 32df8c85a1..0789c30b9b 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -1283,8 +1283,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) } else { - (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0, - PG_WAIT_LOCK | locallock->tag.lock.locktag_type); + (void) WaitMyLatch(-1, + PG_WAIT_LOCK | locallock->tag.lock.locktag_type); ResetLatch(MyLatch); /* check for deadlocks first, as that's probably log-worthy */ if (got_deadlock_timeout) @@ -1793,8 +1793,7 @@ CheckDeadLockAlert(void) void ProcWaitForSignal(uint32 wait_event_info) { - (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0, - wait_event_info); + (void) WaitMyLatch(-1, wait_event_info); ResetLatch(MyLatch); CHECK_FOR_INTERRUPTS(); } diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 323e36b81c..6937c143b7 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -378,10 +378,7 @@ pg_sleep(PG_FUNCTION_ARGS) else break; - (void) WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, - delay_ms, - WAIT_EVENT_PG_SLEEP); + (void) WaitMyLatch(delay_ms, WAIT_EVENT_PG_SLEEP); ResetLatch(MyLatch); } diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 46ae56cae3..d6fd154dc6 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -176,6 +176,7 @@ extern int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info); extern int WaitLatchOrSocket(Latch *latch, int wakeEvents, pgsocket sock, long timeout, uint32 wait_event_info); +extern int WaitMyLatch(long timeout, uint32 wait_event_info); /* * Unix implementation uses SIGUSR1 for inter-process signaling. -- 2.20.1