From 59f71a0d0b56b2df48db4bf1738aece5551f7a47 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Wed, 14 Jan 2015 18:45:22 +0100 Subject: [PATCH] Add a default local latch for use in signal handlers. To do so, move InitializeLatchSupport() into the new common process initialization functions, and add a new global variable MyLatch. MyLatch is usable as soon InitPostmasterChild() has been called (i.e. very early during startup). Initially it points to a process local latch that exists in all processes. InitProcess/InitAuxiliaryProcess then replaces that local latch with PGPROC->procLatch. During shutdown the reverse happens. This is primarily advantageous for two reasons: For one it simplifies dealing with the shared process latch, especially in signal handlers, because instead of having to check for MyProc, MyLatch can be used unconditionally. For another, a later patch that makes FEs/BE communication use latches, now can rely on the existence of a latch, even before having gone through InitProcess. Discussion: 20140927191243.GD5423@alap3.anarazel.de --- src/backend/postmaster/autovacuum.c | 13 +++----- src/backend/postmaster/bgworker.c | 4 +-- src/backend/postmaster/bgwriter.c | 12 +++---- src/backend/postmaster/checkpointer.c | 13 +++----- src/backend/postmaster/pgarch.c | 21 ++++-------- src/backend/postmaster/pgstat.c | 19 ++++------- src/backend/postmaster/syslogger.c | 21 ++++-------- src/backend/postmaster/walwriter.c | 10 +++--- src/backend/replication/syncrep.c | 4 +-- src/backend/storage/ipc/procsignal.c | 4 +-- src/backend/storage/ipc/shm_mq.c | 12 +++---- src/backend/storage/lmgr/proc.c | 42 ++++++++++-------------- src/backend/tcop/postgres.c | 12 +++---- src/backend/utils/adt/misc.c | 4 +-- src/backend/utils/init/globals.c | 9 +++++ src/backend/utils/init/miscinit.c | 37 +++++++++++++++++++++ src/backend/utils/misc/timeout.c | 6 ++-- src/include/miscadmin.h | 4 +++ src/include/storage/latch.h | 2 +- src/test/modules/test_shm_mq/setup.c | 4 +-- src/test/modules/test_shm_mq/test.c | 4 +-- src/test/modules/test_shm_mq/worker.c | 3 +- src/test/modules/worker_spi/worker_spi.c | 10 +++--- 23 files changed, 136 insertions(+), 134 deletions(-) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index a26eee25d4..02f871ce22 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -589,11 +589,11 @@ 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). */ - rc = WaitLatch(&MyProc->procLatch, + rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L)); - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); DisableCatchupInterrupt(); @@ -1341,8 +1341,7 @@ avl_sighup_handler(SIGNAL_ARGS) int save_errno = errno; got_SIGHUP = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -1354,8 +1353,7 @@ avl_sigusr2_handler(SIGNAL_ARGS) int save_errno = errno; got_SIGUSR2 = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -1367,8 +1365,7 @@ avl_sigterm_handler(SIGNAL_ARGS) int save_errno = errno; got_SIGTERM = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 6673f5ba62..267b916327 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -942,7 +942,7 @@ WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp) if (status != BGWH_NOT_YET_STARTED) break; - rc = WaitLatch(&MyProc->procLatch, + rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0); if (rc & WL_POSTMASTER_DEATH) @@ -951,7 +951,7 @@ WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp) break; } - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); } } PG_CATCH(); diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index f138eb7473..b6cf65d495 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -248,7 +248,7 @@ BackgroundWriterMain(void) int rc; /* Clear any already-pending wakeups */ - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); if (got_SIGHUP) { @@ -336,7 +336,7 @@ BackgroundWriterMain(void) * down with latch events that are likely to happen frequently during * normal operation. */ - rc = WaitLatch(&MyProc->procLatch, + rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, BgWriterDelay /* ms */ ); @@ -363,7 +363,7 @@ BackgroundWriterMain(void) /* Ask for notification at next buffer allocation */ StrategyNotifyBgWriter(MyProc->pgprocno); /* Sleep ... */ - rc = WaitLatch(&MyProc->procLatch, + rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, BgWriterDelay * HIBERNATE_FACTOR); /* Reset the notification request in case we timed out */ @@ -426,8 +426,7 @@ BgSigHupHandler(SIGNAL_ARGS) int save_errno = errno; got_SIGHUP = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -439,8 +438,7 @@ ReqShutdownHandler(SIGNAL_ARGS) int save_errno = errno; shutdown_requested = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index 3c9c216c6f..237be121dd 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -360,7 +360,7 @@ CheckpointerMain(void) int rc; /* Clear any already-pending wakeups */ - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); /* * Process any requests or signals received recently. @@ -559,7 +559,7 @@ CheckpointerMain(void) cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs); } - rc = WaitLatch(&MyProc->procLatch, + rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, cur_timeout * 1000L /* convert to ms */ ); @@ -832,8 +832,7 @@ ChkptSigHupHandler(SIGNAL_ARGS) int save_errno = errno; got_SIGHUP = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -845,8 +844,7 @@ ReqCheckpointHandler(SIGNAL_ARGS) int save_errno = errno; checkpoint_requested = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -869,8 +867,7 @@ ReqShutdownHandler(SIGNAL_ARGS) int save_errno = errno; shutdown_requested = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index 78dec3a4c6..9b689af915 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -78,11 +78,6 @@ 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 used by signal handlers to wake up the sleep in the main loop. - */ -static Latch mainloop_latch; - /* ---------- * Local function forward declarations * ---------- @@ -220,10 +215,6 @@ pgarch_forkexec(void) NON_EXEC_STATIC void PgArchiverMain(int argc, char *argv[]) { - InitializeLatchSupport(); /* needed for latch waits */ - - InitLatch(&mainloop_latch); /* initialize latch used in main loop */ - /* * Ignore all signals usually bound to some action in the postmaster, * except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT. @@ -269,7 +260,7 @@ ArchSigHupHandler(SIGNAL_ARGS) /* set flag to re-read config file at next convenient time */ got_SIGHUP = true; - SetLatch(&mainloop_latch); + SetLatch(MyLatch); errno = save_errno; } @@ -287,7 +278,7 @@ ArchSigTermHandler(SIGNAL_ARGS) * archive commands. */ got_SIGTERM = true; - SetLatch(&mainloop_latch); + SetLatch(MyLatch); errno = save_errno; } @@ -300,7 +291,7 @@ pgarch_waken(SIGNAL_ARGS) /* set flag that there is work to be done */ wakened = true; - SetLatch(&mainloop_latch); + SetLatch(MyLatch); errno = save_errno; } @@ -313,7 +304,7 @@ pgarch_waken_stop(SIGNAL_ARGS) /* set flag to do a final cycle and shut down afterwards */ ready_to_stop = true; - SetLatch(&mainloop_latch); + SetLatch(MyLatch); errno = save_errno; } @@ -344,7 +335,7 @@ pgarch_MainLoop(void) */ do { - ResetLatch(&mainloop_latch); + ResetLatch(MyLatch); /* When we get SIGUSR2, we do one more archive cycle, then exit */ time_to_stop = ready_to_stop; @@ -397,7 +388,7 @@ pgarch_MainLoop(void) { int rc; - rc = WaitLatch(&mainloop_latch, + rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, timeout * 1000L); if (rc & WL_TIMEOUT) diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index fa87660bae..0cf498866a 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -130,8 +130,6 @@ PgStat_MsgBgWriter BgWriterStats; */ NON_EXEC_STATIC pgsocket pgStatSock = PGINVALID_SOCKET; -static Latch pgStatLatch; - static struct sockaddr_storage pgStatAddr; static time_t last_pgstat_start_time; @@ -3151,15 +3149,10 @@ PgstatCollectorMain(int argc, char *argv[]) PgStat_Msg msg; int wr; - InitializeLatchSupport(); /* needed for latch waits */ - - /* Initialize private latch for use by signal handlers */ - InitLatch(&pgStatLatch); - /* * Ignore all signals usually bound to some action in the postmaster, * except SIGHUP and SIGQUIT. Note we don't need a SIGUSR1 handler to - * support latch operations, because pgStatLatch is local not shared. + * support latch operations, because we only use a local latch. */ pqsignal(SIGHUP, pgstat_sighup_handler); pqsignal(SIGINT, SIG_IGN); @@ -3205,7 +3198,7 @@ PgstatCollectorMain(int argc, char *argv[]) for (;;) { /* Clear any already-pending wakeups */ - ResetLatch(&pgStatLatch); + ResetLatch(MyLatch); /* * Quit if we get SIGQUIT from the postmaster. @@ -3363,7 +3356,7 @@ PgstatCollectorMain(int argc, char *argv[]) /* Sleep until there's something to do */ #ifndef WIN32 - wr = WaitLatchOrSocket(&pgStatLatch, + wr = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_SOCKET_READABLE, pgStatSock, -1L); @@ -3379,7 +3372,7 @@ PgstatCollectorMain(int argc, char *argv[]) * to not provoke "pgstat wait timeout" complaints from * backend_read_statsfile. */ - wr = WaitLatchOrSocket(&pgStatLatch, + wr = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_SOCKET_READABLE | WL_TIMEOUT, pgStatSock, 2 * 1000L /* msec */ ); @@ -3409,7 +3402,7 @@ pgstat_exit(SIGNAL_ARGS) int save_errno = errno; need_exit = true; - SetLatch(&pgStatLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -3421,7 +3414,7 @@ pgstat_sighup_handler(SIGNAL_ARGS) int save_errno = errno; got_SIGHUP = true; - SetLatch(&pgStatLatch); + SetLatch(MyLatch); errno = save_errno; } diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index d127fb5771..41b8dbb6c2 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -85,7 +85,6 @@ static FILE *csvlogFile = NULL; NON_EXEC_STATIC pg_time_t first_syslogger_file_time = 0; static char *last_file_name = NULL; static char *last_csv_file_name = NULL; -static Latch sysLoggerLatch; /* * Buffers for saving partial messages from different backends. @@ -231,12 +230,6 @@ SysLoggerMain(int argc, char *argv[]) syslogPipe[1] = 0; #endif - InitializeLatchSupport(); /* needed for latch waits */ - - - /* Initialize private latch for use by signal handlers */ - InitLatch(&sysLoggerLatch); - /* * Properly accept or ignore signals the postmaster might send us * @@ -302,7 +295,7 @@ SysLoggerMain(int argc, char *argv[]) #endif /* Clear any already-pending wakeups */ - ResetLatch(&sysLoggerLatch); + ResetLatch(MyLatch); /* * Process any requests or signals received recently. @@ -428,7 +421,7 @@ SysLoggerMain(int argc, char *argv[]) * Sleep until there's something to do */ #ifndef WIN32 - rc = WaitLatchOrSocket(&sysLoggerLatch, + rc = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags, syslogPipe[0], cur_timeout); @@ -480,7 +473,7 @@ SysLoggerMain(int argc, char *argv[]) */ LeaveCriticalSection(&sysloggerSection); - (void) WaitLatch(&sysLoggerLatch, + (void) WaitLatch(MyLatch, WL_LATCH_SET | cur_flags, cur_timeout); @@ -1061,7 +1054,7 @@ pipeThread(void *arg) { if (ftell(syslogFile) >= Log_RotationSize * 1024L || (csvlogFile != NULL && ftell(csvlogFile) >= Log_RotationSize * 1024L)) - SetLatch(&sysLoggerLatch); + SetLatch(MyLatch); } LeaveCriticalSection(&sysloggerSection); } @@ -1073,7 +1066,7 @@ pipeThread(void *arg) flush_pipe_input(logbuffer, &bytes_in_logbuffer); /* set the latch to waken the main thread, which will quit */ - SetLatch(&sysLoggerLatch); + SetLatch(MyLatch); LeaveCriticalSection(&sysloggerSection); _endthread(); @@ -1353,7 +1346,7 @@ sigHupHandler(SIGNAL_ARGS) int save_errno = errno; got_SIGHUP = true; - SetLatch(&sysLoggerLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -1365,7 +1358,7 @@ sigUsr1Handler(SIGNAL_ARGS) int save_errno = errno; rotation_requested = true; - SetLatch(&sysLoggerLatch); + SetLatch(MyLatch); errno = save_errno; } diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 044c30665e..a44b5a80eb 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -252,7 +252,7 @@ WalWriterMain(void) } /* Clear any already-pending wakeups */ - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); /* * Process any requests or signals received recently. @@ -287,7 +287,7 @@ WalWriterMain(void) else cur_timeout = WalWriterDelay * HIBERNATE_FACTOR; - rc = WaitLatch(&MyProc->procLatch, + rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, cur_timeout); @@ -345,8 +345,7 @@ WalSigHupHandler(SIGNAL_ARGS) int save_errno = errno; got_SIGHUP = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -358,8 +357,7 @@ WalShutdownHandler(SIGNAL_ARGS) int save_errno = errno; shutdown_requested = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index b2b3a81f54..ec594cf3df 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -162,7 +162,7 @@ SyncRepWaitForLSN(XLogRecPtr XactCommitLSN) int syncRepState; /* Must reset the latch before testing state. */ - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); /* * Try checking the state without the lock first. There's no @@ -235,7 +235,7 @@ SyncRepWaitForLSN(XLogRecPtr XactCommitLSN) * Wait on latch. Any condition that should wake us up will set the * latch, so no need for timeout. */ - WaitLatch(&MyProc->procLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1); + WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1); } /* diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index cf09418766..48573bef60 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -292,8 +292,8 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN)) RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); - if (set_latch_on_sigusr1 && MyProc != NULL) - SetLatch(&MyProc->procLatch); + if (set_latch_on_sigusr1) + SetLatch(MyLatch); latch_sigusr1_handler(); diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c index 7c41400d21..d42a8d1ae4 100644 --- a/src/backend/storage/ipc/shm_mq.c +++ b/src/backend/storage/ipc/shm_mq.c @@ -827,13 +827,13 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data, * at top of loop, because setting an already-set latch is much * cheaper than setting one that has been reset. */ - WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0); /* An interrupt may have occurred while we were waiting. */ CHECK_FOR_INTERRUPTS(); /* Reset the latch so we don't spin. */ - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); } else { @@ -924,13 +924,13 @@ shm_mq_receive_bytes(shm_mq *mq, Size bytes_needed, bool nowait, * loop, because setting an already-set latch is much cheaper than * setting one that has been reset. */ - WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0); /* An interrupt may have occurred while we were waiting. */ CHECK_FOR_INTERRUPTS(); /* Reset the latch so we don't spin. */ - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); } } @@ -991,13 +991,13 @@ shm_mq_wait_internal(volatile shm_mq *mq, PGPROC *volatile * ptr, } /* Wait to be signalled. */ - WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0); /* An interrupt may have occurred while we were waiting. */ CHECK_FOR_INTERRUPTS(); /* Reset the latch so we don't spin. */ - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); } } PG_CATCH(); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 777c60b64d..65e8afe457 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -290,13 +290,6 @@ InitProcess(void) if (MyProc != NULL) elog(ERROR, "you already exist"); - /* - * Initialize process-local latch support. This could fail if the kernel - * is low on resources, and if so we want to exit cleanly before acquiring - * any shared-memory resources. - */ - InitializeLatchSupport(); - /* * Try to get a proc struct from the free list. If this fails, we must be * out of PGPROC structures (not to mention semaphores). @@ -391,10 +384,12 @@ InitProcess(void) SHMQueueElemInit(&(MyProc->syncRepLinks)); /* - * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch. - * Note that there's no particular need to do ResetLatch here. + * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch + * on it. That allows us to repoint the process latch, which so far + * points to process local one, to the shared one. */ OwnLatch(&MyProc->procLatch); + SwitchToSharedLatch(); /* * We might be reusing a semaphore that belonged to a failed process. So @@ -474,13 +469,6 @@ InitAuxiliaryProcess(void) if (MyProc != NULL) elog(ERROR, "you already exist"); - /* - * Initialize process-local latch support. This could fail if the kernel - * is low on resources, and if so we want to exit cleanly before acquiring - * any shared-memory resources. - */ - InitializeLatchSupport(); - /* * We use the ProcStructLock to protect assignment and releasing of * AuxiliaryProcs entries. @@ -547,10 +535,12 @@ InitAuxiliaryProcess(void) #endif /* - * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch. - * Note that there's no particular need to do ResetLatch here. + * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch + * on it. That allows us to repoint the process latch, which so far + * points to process local one, to the shared one. */ OwnLatch(&MyProc->procLatch); + SwitchToSharedLatch(); /* * We might be reusing a semaphore that belonged to a failed process. So @@ -800,10 +790,12 @@ ProcKill(int code, Datum arg) ReplicationSlotRelease(); /* - * Clear MyProc first; then disown the process latch. This is so that - * signal handlers won't try to clear the process latch after it's no - * longer ours. + * Reset MyLatch to the process local one. This is so that signal + * handlers et al can continue using the latch after the shared latch + * isn't ours anymore. After that clear MyProc and disown the shared + * latch. */ + SwitchBackToLocalLatch(); proc = MyProc; MyProc = NULL; DisownLatch(&proc->procLatch); @@ -867,10 +859,12 @@ AuxiliaryProcKill(int code, Datum arg) LWLockReleaseAll(); /* - * Clear MyProc first; then disown the process latch. This is so that - * signal handlers won't try to clear the process latch after it's no - * longer ours. + * Reset MyLatch to the process local one. This is so that signal + * handlers et al can continue using the latch after the shared latch + * isn't ours anymore. After that clear MyProc and disown the shared + * latch. */ + SwitchBackToLocalLatch(); proc = MyProc; MyProc = NULL; DisownLatch(&proc->procLatch); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index f805368899..8f743536cf 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -2607,8 +2607,7 @@ die(SIGNAL_ARGS) } /* If we're still here, waken anything waiting on the process latch */ - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -2649,8 +2648,7 @@ StatementCancelHandler(SIGNAL_ARGS) } /* If we're still here, waken anything waiting on the process latch */ - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -2675,8 +2673,7 @@ SigHupHandler(SIGNAL_ARGS) int save_errno = errno; got_SIGHUP = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -2814,8 +2811,7 @@ RecoveryConflictInterrupt(ProcSignalReason reason) * waiting on that latch, expecting to get interrupted by query cancels et * al., would also need to set set_latch_on_sigusr1. */ - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index ed5a795bb0..29f7c3badf 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -413,10 +413,10 @@ pg_sleep(PG_FUNCTION_ARGS) else break; - (void) WaitLatch(&MyProc->procLatch, + (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT, delay_ms); - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); } PG_RETURN_VOID(); diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index dc5c8d684a..c35867bcfe 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -40,6 +40,15 @@ struct Port *MyProcPort; long MyCancelKey; int MyPMChildSlot; +/* + * MyLatch points to the latch that should be used for signal handling by the + * current process. It will either point to a process local latch if the + * current process does not have a PGPROC entry in that moment, or to + * PGPROC->procLatch if it has. Thus it can always be used in signal handlers, + * without checking for its existence. + */ +struct Latch *MyLatch; + /* * DataDir is the absolute path to the top level of the PGDATA directory tree. * Except during early startup, this is also the server's working directory; diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 414b05e3b8..4646e0938e 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -39,6 +39,7 @@ #include "postmaster/postmaster.h" #include "storage/fd.h" #include "storage/ipc.h" +#include "storage/latch.h" #include "storage/pg_shmem.h" #include "storage/proc.h" #include "storage/procarray.h" @@ -55,6 +56,7 @@ ProcessingMode Mode = InitProcessing; /* List of lock files to be removed at proc exit */ static List *lock_files = NIL; +static Latch LocalLatchData; /* ---------------------------------------------------------------- * ignoring system indexes support stuff @@ -189,6 +191,11 @@ InitPostmasterChild(void) /* We don't want the postmaster's proc_exit() handlers */ on_exit_reset(); + /* Initialize process-local latch support */ + InitializeLatchSupport(); + MyLatch = &LocalLatchData; + InitLatch(MyLatch); + /* * If possible, make this process a group leader, so that the postmaster * can signal any child processes too. Not all processes will have @@ -215,6 +222,11 @@ InitStandaloneProcess(const char *argv0) MyStartTime = time(NULL); /* set our start time in case we call elog */ + /* Initialize process-local latch support */ + InitializeLatchSupport(); + MyLatch = &LocalLatchData; + InitLatch(MyLatch); + /* Compute paths, no postmaster to inherit from */ if (my_exec_path[0] == '\0') { @@ -227,6 +239,31 @@ InitStandaloneProcess(const char *argv0) get_pkglib_path(my_exec_path, pkglib_path); } +void +SwitchToSharedLatch(void) +{ + Assert(MyLatch == &LocalLatchData); + Assert(MyProc != NULL); + + MyLatch = &MyProc->procLatch; + /* + * Set the shared latch as the local one might have been set. This + * shouldn't normally be necessary as code is supposed to check the + * condition before waiting for the latch, but a bit care can't hurt. + */ + SetLatch(MyLatch); +} + +void +SwitchBackToLocalLatch(void) +{ + Assert(MyLatch != &LocalLatchData); + Assert(MyProc != NULL && MyLatch == &MyProc->procLatch); + + MyLatch = &LocalLatchData; + SetLatch(MyLatch); +} + /* * GetUserId - get the current effective user ID. * diff --git a/src/backend/utils/misc/timeout.c b/src/backend/utils/misc/timeout.c index 1dec4928af..ce4bc13ec3 100644 --- a/src/backend/utils/misc/timeout.c +++ b/src/backend/utils/misc/timeout.c @@ -284,11 +284,9 @@ handle_sig_alarm(SIGNAL_ARGS) /* * SIGALRM is always cause for waking anything waiting on the process - * latch. Cope with MyProc not being there, as the startup process also - * uses this signal handler. + * latch. */ - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); /* * Fire any pending timeouts, but only if we're enabled to do so. diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index b94a94499b..6e33a17212 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -148,6 +148,7 @@ extern int max_worker_processes; extern PGDLLIMPORT int MyProcPid; extern PGDLLIMPORT pg_time_t MyStartTime; extern PGDLLIMPORT struct Port *MyProcPort; +extern PGDLLIMPORT struct Latch *MyLatch; extern long MyCancelKey; extern int MyPMChildSlot; @@ -302,6 +303,9 @@ extern void SetCurrentRoleId(Oid roleid, bool is_superuser); extern void SetDataDir(const char *dir); extern void ChangeToDataDir(void); +extern void SwitchToSharedLatch(void); +extern void SwitchBackToLocalLatch(void); + /* in utils/misc/superuser.c */ extern bool superuser(void); /* current user is superuser */ extern bool superuser_arg(Oid roleid); /* given user is superuser */ diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index f1577b0095..28fc684d24 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -85,7 +85,7 @@ * the public functions. It is defined here to allow embedding Latches as * part of bigger structs. */ -typedef struct +typedef struct Latch { sig_atomic_t is_set; bool is_shared; diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c index b049cff2d0..195099095d 100644 --- a/src/test/modules/test_shm_mq/setup.c +++ b/src/test/modules/test_shm_mq/setup.c @@ -285,13 +285,13 @@ wait_for_workers_to_become_ready(worker_state *wstate, } /* Wait to be signalled. */ - WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0); /* An interrupt may have occurred while we were waiting. */ CHECK_FOR_INTERRUPTS(); /* Reset the latch so we don't spin. */ - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); } } PG_CATCH(); diff --git a/src/test/modules/test_shm_mq/test.c b/src/test/modules/test_shm_mq/test.c index 6428fcf51c..732376daff 100644 --- a/src/test/modules/test_shm_mq/test.c +++ b/src/test/modules/test_shm_mq/test.c @@ -230,9 +230,9 @@ test_shm_mq_pipelined(PG_FUNCTION_ARGS) * have read or written data and therefore there may now be work * for us to do. */ - WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0); CHECK_FOR_INTERRUPTS(); - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); } } diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c index dec058b55e..a9d9e0e255 100644 --- a/src/test/modules/test_shm_mq/worker.c +++ b/src/test/modules/test_shm_mq/worker.c @@ -211,8 +211,7 @@ handle_sigterm(SIGNAL_ARGS) { int save_errno = errno; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); if (!proc_exit_inprogress) { diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c index ac0f59c988..94d3857364 100644 --- a/src/test/modules/worker_spi/worker_spi.c +++ b/src/test/modules/worker_spi/worker_spi.c @@ -74,8 +74,7 @@ worker_spi_sigterm(SIGNAL_ARGS) int save_errno = errno; got_sigterm = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -91,8 +90,7 @@ worker_spi_sighup(SIGNAL_ARGS) int save_errno = errno; got_sighup = true; - if (MyProc) - SetLatch(&MyProc->procLatch); + SetLatch(MyLatch); errno = save_errno; } @@ -227,10 +225,10 @@ worker_spi_main(Datum main_arg) * necessary, but is awakened if postmaster dies. That way the * background process goes away immediately in an emergency. */ - rc = WaitLatch(&MyProc->procLatch, + rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, worker_spi_naptime * 1000L); - ResetLatch(&MyProc->procLatch); + ResetLatch(MyLatch); /* emergency bailout if postmaster has died */ if (rc & WL_POSTMASTER_DEATH) -- 2.40.0