Partially deduplicate interrupt handling for background processes.

Where possible, share signal handler code and main loop interrupt
checking. This saves quite a bit of code and should simplify
maintenance, too.

This commit intends not to change the way anything works, even
though that might allow more code to be unified. It does unify
a bunch of individual variables into a ShutdownRequestPending
flag that has is now used by a bunch of different process types,
though.

Patch by me, reviewed by Andres Freund and Daniel Gustafsson.

Discussion: http://postgr.es/m/CA+TgmoZwDk=BguVDVa+qdA6SBKef=PKbaKDQALTC_9qoz1mJqg@mail.gmail.com
This commit is contained in:
Robert Haas 2019-12-17 13:14:28 -05:00
parent 1e53fe0e70
commit 7dbfea3c45
18 changed files with 191 additions and 399 deletions

View File

@ -18,6 +18,7 @@ OBJS = \
bgwriter.o \
checkpointer.o \
fork_process.o \
interrupt.o \
pgarch.o \
pgstat.o \
postmaster.o \

View File

@ -84,6 +84,7 @@
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "postmaster/fork_process.h"
#include "postmaster/interrupt.h"
#include "postmaster/postmaster.h"
#include "storage/bufmgr.h"
#include "storage/ipc.h"
@ -139,7 +140,6 @@ static bool am_autovacuum_worker = false;
/* Flags set by signal handlers */
static volatile sig_atomic_t got_SIGUSR2 = false;
static volatile sig_atomic_t got_SIGTERM = false;
/* Comparison points for determining whether freeze_max_age is exceeded */
static TransactionId recentXid;
@ -344,7 +344,6 @@ static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
const char *nspname, const char *relname);
static void avl_sigusr2_handler(SIGNAL_ARGS);
static void avl_sigterm_handler(SIGNAL_ARGS);
static void autovac_refresh_stats(void);
@ -450,9 +449,9 @@ AutoVacLauncherMain(int argc, char *argv[])
* backend, so we use the same signal handling. See equivalent code in
* tcop/postgres.c.
*/
pqsignal(SIGHUP, PostgresSigHupHandler);
pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, StatementCancelHandler);
pqsignal(SIGTERM, avl_sigterm_handler);
pqsignal(SIGTERM, SignalHandlerForShutdownRequest);
pqsignal(SIGQUIT, quickdie);
InitializeTimeouts(); /* establishes SIGALRM handler */
@ -553,7 +552,7 @@ AutoVacLauncherMain(int argc, char *argv[])
RESUME_INTERRUPTS();
/* if in shutdown mode, no need for anything further; just go away */
if (got_SIGTERM)
if (ShutdownRequestPending)
AutoVacLauncherShutdown();
/*
@ -605,7 +604,7 @@ AutoVacLauncherMain(int argc, char *argv[])
*/
if (!AutoVacuumingActive())
{
if (!got_SIGTERM)
if (!ShutdownRequestPending)
do_start_worker();
proc_exit(0); /* done */
}
@ -622,7 +621,7 @@ AutoVacLauncherMain(int argc, char *argv[])
rebuild_database_list(InvalidOid);
/* loop until shutdown request */
while (!got_SIGTERM)
while (!ShutdownRequestPending)
{
struct timeval nap;
TimestampTz current_time = 0;
@ -800,7 +799,7 @@ static void
HandleAutoVacLauncherInterrupts(void)
{
/* the normal shutdown case */
if (got_SIGTERM)
if (ShutdownRequestPending)
AutoVacLauncherShutdown();
if (ConfigReloadPending)
@ -1415,18 +1414,6 @@ avl_sigusr2_handler(SIGNAL_ARGS)
errno = save_errno;
}
/* SIGTERM: time to die */
static void
avl_sigterm_handler(SIGNAL_ARGS)
{
int save_errno = errno;
got_SIGTERM = true;
SetLatch(MyLatch);
errno = save_errno;
}
/********************************************************************
* AUTOVACUUM WORKER CODE
@ -1525,7 +1512,7 @@ AutoVacWorkerMain(int argc, char *argv[])
* backend, so we use the same signal handling. See equivalent code in
* tcop/postgres.c.
*/
pqsignal(SIGHUP, PostgresSigHupHandler);
pqsignal(SIGHUP, SignalHandlerForConfigReload);
/*
* SIGINT is used to signal canceling the current table's vacuum; SIGTERM

View File

@ -12,14 +12,13 @@
#include "postgres.h"
#include <unistd.h>
#include "access/parallel.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/atomics.h"
#include "postmaster/bgworker_internals.h"
#include "postmaster/interrupt.h"
#include "postmaster/postmaster.h"
#include "replication/logicallauncher.h"
#include "replication/logicalworker.h"
@ -641,26 +640,6 @@ SanityCheckBackgroundWorker(BackgroundWorker *worker, int elevel)
return true;
}
static void
bgworker_quickdie(SIGNAL_ARGS)
{
/*
* We DO NOT want to run proc_exit() or atexit() callbacks -- we're here
* because shared memory may be corrupted, so we don't want to try to
* clean up our transaction. Just nail the windows shut and get out of
* town. The callbacks wouldn't be safe to run from a signal handler,
* anyway.
*
* Note we do _exit(2) not _exit(0). This is to force the postmaster into
* a system reset cycle if someone sends a manual SIGQUIT to a random
* backend. This is necessary precisely because we don't clean up our
* shared memory state. (The "dead man switch" mechanism in pmsignal.c
* should ensure the postmaster sees this as a crash, too, but no harm in
* being doubly sure.)
*/
_exit(2);
}
/*
* Standard SIGTERM handler for background workers
*/
@ -754,7 +733,7 @@ StartBackgroundWorker(void)
pqsignal(SIGTERM, bgworker_die);
pqsignal(SIGHUP, SIG_IGN);
pqsignal(SIGQUIT, bgworker_quickdie);
pqsignal(SIGQUIT, SignalHandlerForCrashExit);
InitializeTimeouts(); /* establishes SIGALRM handler */
pqsignal(SIGPIPE, SIG_IGN);

View File

@ -34,16 +34,13 @@
*/
#include "postgres.h"
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include "access/xlog.h"
#include "access/xlog_internal.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/bgwriter.h"
#include "postmaster/interrupt.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
#include "storage/condition_variable.h"
@ -86,18 +83,6 @@ int BgWriterDelay = 200;
static TimestampTz last_snapshot_ts;
static XLogRecPtr last_snapshot_lsn = InvalidXLogRecPtr;
/*
* Flags set by interrupt handlers for later service in the main loop.
*/
static volatile sig_atomic_t shutdown_requested = false;
static void HandleBackgroundWriterInterrupts(void);
/* Signal handlers */
static void bg_quickdie(SIGNAL_ARGS);
static void ReqShutdownHandler(SIGNAL_ARGS);
/*
* Main entry point for bgwriter process
@ -116,10 +101,10 @@ BackgroundWriterMain(void)
/*
* Properly accept or ignore signals that might be sent to us.
*/
pqsignal(SIGHUP, PostgresSigHupHandler); /* set flag to read config file */
pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, SIG_IGN);
pqsignal(SIGTERM, ReqShutdownHandler); /* shutdown */
pqsignal(SIGQUIT, bg_quickdie); /* hard crash time */
pqsignal(SIGTERM, SignalHandlerForShutdownRequest);
pqsignal(SIGQUIT, SignalHandlerForCrashExit);
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler);
@ -241,7 +226,7 @@ BackgroundWriterMain(void)
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
HandleBackgroundWriterInterrupts();
HandleMainLoopInterrupts();
/*
* Do one cycle of dirty-buffer writing.
@ -354,71 +339,3 @@ BackgroundWriterMain(void)
prev_hibernate = can_hibernate;
}
}
/*
* Process any new interrupts.
*/
static void
HandleBackgroundWriterInterrupts(void)
{
if (ConfigReloadPending)
{
ConfigReloadPending = false;
ProcessConfigFile(PGC_SIGHUP);
}
if (shutdown_requested)
{
/*
* From here on, elog(ERROR) should end with exit(1), not send
* control back to the sigsetjmp block above
*/
ExitOnAnyError = true;
/* Normal exit from the bgwriter is here */
proc_exit(0); /* done */
}
}
/* --------------------------------
* signal handler routines
* --------------------------------
*/
/*
* bg_quickdie() occurs when signalled SIGQUIT by the postmaster.
*
* Some backend has bought the farm,
* so we need to stop what we're doing and exit.
*/
static void
bg_quickdie(SIGNAL_ARGS)
{
/*
* We DO NOT want to run proc_exit() or atexit() callbacks -- we're here
* because shared memory may be corrupted, so we don't want to try to
* clean up our transaction. Just nail the windows shut and get out of
* town. The callbacks wouldn't be safe to run from a signal handler,
* anyway.
*
* Note we do _exit(2) not _exit(0). This is to force the postmaster into
* a system reset cycle if someone sends a manual SIGQUIT to a random
* backend. This is necessary precisely because we don't clean up our
* shared memory state. (The "dead man switch" mechanism in pmsignal.c
* should ensure the postmaster sees this as a crash, too, but no harm in
* being doubly sure.)
*/
_exit(2);
}
/* SIGTERM: set flag to shutdown and exit */
static void
ReqShutdownHandler(SIGNAL_ARGS)
{
int save_errno = errno;
shutdown_requested = true;
SetLatch(MyLatch);
errno = save_errno;
}

View File

@ -36,10 +36,7 @@
*/
#include "postgres.h"
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include "access/xlog.h"
#include "access/xlog_internal.h"
@ -47,6 +44,7 @@
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/bgwriter.h"
#include "postmaster/interrupt.h"
#include "replication/syncrep.h"
#include "storage/bufmgr.h"
#include "storage/condition_variable.h"
@ -148,11 +146,6 @@ int CheckPointTimeout = 300;
int CheckPointWarning = 30;
double CheckPointCompletionTarget = 0.5;
/*
* Flags set by interrupt handlers for later service in the main loop.
*/
static volatile sig_atomic_t shutdown_requested = false;
/*
* Private state
*/
@ -176,10 +169,7 @@ static bool CompactCheckpointerRequestQueue(void);
static void UpdateSharedMemoryConfig(void);
/* Signal handlers */
static void chkpt_quickdie(SIGNAL_ARGS);
static void ReqCheckpointHandler(SIGNAL_ARGS);
static void ReqShutdownHandler(SIGNAL_ARGS);
/*
@ -204,14 +194,14 @@ CheckpointerMain(void)
* want to wait for the backends to exit, whereupon the postmaster will
* tell us it's okay to shut down (via SIGUSR2).
*/
pqsignal(SIGHUP, PostgresSigHupHandler); /* set flag to read config file */
pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, ReqCheckpointHandler); /* request checkpoint */
pqsignal(SIGTERM, SIG_IGN); /* ignore SIGTERM */
pqsignal(SIGQUIT, chkpt_quickdie); /* hard crash time */
pqsignal(SIGQUIT, SignalHandlerForCrashExit);
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler);
pqsignal(SIGUSR2, ReqShutdownHandler); /* request shutdown */
pqsignal(SIGUSR2, SignalHandlerForShutdownRequest);
/*
* Reset some signals that are accepted by postmaster but not here
@ -551,7 +541,7 @@ HandleCheckpointerInterrupts(void)
*/
UpdateSharedMemoryConfig();
}
if (shutdown_requested)
if (ShutdownRequestPending)
{
/*
* From here on, elog(ERROR) should end with exit(1), not send
@ -679,7 +669,7 @@ CheckpointWriteDelay(int flags, double progress)
* in which case we just try to catch up as quickly as possible.
*/
if (!(flags & CHECKPOINT_IMMEDIATE) &&
!shutdown_requested &&
!ShutdownRequestPending &&
!ImmediateCheckpointRequested() &&
IsCheckpointOnSchedule(progress))
{
@ -807,32 +797,6 @@ IsCheckpointOnSchedule(double progress)
* --------------------------------
*/
/*
* chkpt_quickdie() occurs when signalled SIGQUIT by the postmaster.
*
* Some backend has bought the farm,
* so we need to stop what we're doing and exit.
*/
static void
chkpt_quickdie(SIGNAL_ARGS)
{
/*
* We DO NOT want to run proc_exit() or atexit() callbacks -- we're here
* because shared memory may be corrupted, so we don't want to try to
* clean up our transaction. Just nail the windows shut and get out of
* town. The callbacks wouldn't be safe to run from a signal handler,
* anyway.
*
* Note we do _exit(2) not _exit(0). This is to force the postmaster into
* a system reset cycle if someone sends a manual SIGQUIT to a random
* backend. This is necessary precisely because we don't clean up our
* shared memory state. (The "dead man switch" mechanism in pmsignal.c
* should ensure the postmaster sees this as a crash, too, but no harm in
* being doubly sure.)
*/
_exit(2);
}
/* SIGINT: set flag to run a normal checkpoint right away */
static void
ReqCheckpointHandler(SIGNAL_ARGS)
@ -848,18 +812,6 @@ ReqCheckpointHandler(SIGNAL_ARGS)
errno = save_errno;
}
/* SIGUSR2: set flag to run a shutdown checkpoint and exit */
static void
ReqShutdownHandler(SIGNAL_ARGS)
{
int save_errno = errno;
shutdown_requested = true;
SetLatch(MyLatch);
errno = save_errno;
}
/* --------------------------------
* communication with backends

View File

@ -0,0 +1,108 @@
/*-------------------------------------------------------------------------
*
* interrupt.c
* Interrupt handling routines.
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* src/backend/postmaster/interrupt.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <unistd.h>
#include "miscadmin.h"
#include "postmaster/interrupt.h"
#include "storage/ipc.h"
#include "storage/latch.h"
#include "utils/guc.h"
volatile sig_atomic_t ConfigReloadPending = false;
volatile sig_atomic_t ShutdownRequestPending = false;
/*
* Simple interrupt handler for main loops of background processes.
*/
void
HandleMainLoopInterrupts(void)
{
if (ConfigReloadPending)
{
ConfigReloadPending = false;
ProcessConfigFile(PGC_SIGHUP);
}
if (ShutdownRequestPending)
proc_exit(0);
}
/*
* Simple signal handler for triggering a configuration reload.
*
* Normally, this handler would be used for SIGHUP. The idea is that code
* which uses it would arrange to check the ConfigReloadPending flag at
* convenient places inside main loops, or else call HandleMainLoopInterrupts.
*/
void
SignalHandlerForConfigReload(SIGNAL_ARGS)
{
int save_errno = errno;
ConfigReloadPending = true;
SetLatch(MyLatch);
errno = save_errno;
}
/*
* Simple signal handler for exiting quickly as if due to a crash.
*
* Normally, this would be used for handling SIGQUIT.
*/
void
SignalHandlerForCrashExit(SIGNAL_ARGS)
{
/*
* We DO NOT want to run proc_exit() or atexit() callbacks -- we're here
* because shared memory may be corrupted, so we don't want to try to
* clean up our transaction. Just nail the windows shut and get out of
* town. The callbacks wouldn't be safe to run from a signal handler,
* anyway.
*
* Note we do _exit(2) not _exit(0). This is to force the postmaster into
* a system reset cycle if someone sends a manual SIGQUIT to a random
* backend. This is necessary precisely because we don't clean up our
* shared memory state. (The "dead man switch" mechanism in pmsignal.c
* should ensure the postmaster sees this as a crash, too, but no harm in
* being doubly sure.)
*/
_exit(2);
}
/*
* Simple signal handler for triggering a long-running background process to
* shut down and exit.
*
* Typically, this handler would be used for SIGTERM, but some procesess use
* other signals. In particular, the checkpointer exits on SIGUSR2, the
* stats collector on SIGQUIT, and the WAL writer exits on either SIGINT
* or SIGTERM.
*
* ShutdownRequestPending should be checked at a convenient place within the
* main loop, or else the main loop should call HandleMainLoopInterrupts.
*/
void
SignalHandlerForShutdownRequest(SIGNAL_ARGS)
{
int save_errno = errno;
ShutdownRequestPending = true;
SetLatch(MyLatch);
errno = save_errno;
}

View File

@ -39,6 +39,7 @@
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/fork_process.h"
#include "postmaster/interrupt.h"
#include "postmaster/pgarch.h"
#include "postmaster/postmaster.h"
#include "storage/dsm.h"
@ -83,7 +84,6 @@ static time_t last_sigterm_time = 0;
/*
* Flags set by interrupt handlers for later service in the main loop.
*/
static volatile sig_atomic_t got_SIGTERM = false;
static volatile sig_atomic_t wakened = false;
static volatile sig_atomic_t ready_to_stop = false;
@ -97,7 +97,6 @@ static pid_t pgarch_forkexec(void);
NON_EXEC_STATIC void PgArchiverMain(int argc, char *argv[]) pg_attribute_noreturn();
static void pgarch_exit(SIGNAL_ARGS);
static void ArchSigTermHandler(SIGNAL_ARGS);
static void pgarch_waken(SIGNAL_ARGS);
static void pgarch_waken_stop(SIGNAL_ARGS);
static void pgarch_MainLoop(void);
@ -227,9 +226,9 @@ PgArchiverMain(int argc, char *argv[])
* Ignore all signals usually bound to some action in the postmaster,
* except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT.
*/
pqsignal(SIGHUP, PostgresSigHupHandler);
pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, SIG_IGN);
pqsignal(SIGTERM, ArchSigTermHandler);
pqsignal(SIGTERM, SignalHandlerForShutdownRequest);
pqsignal(SIGQUIT, pgarch_exit);
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
@ -257,24 +256,6 @@ pgarch_exit(SIGNAL_ARGS)
exit(1);
}
/* SIGTERM signal handler for archiver process */
static void
ArchSigTermHandler(SIGNAL_ARGS)
{
int save_errno = errno;
/*
* The postmaster never sends us SIGTERM, so we assume that this means
* that init is trying to shut down the whole system. If we hang around
* too long we'll get SIGKILL'd. Set flag to prevent starting any more
* archive commands.
*/
got_SIGTERM = true;
SetLatch(MyLatch);
errno = save_errno;
}
/* SIGUSR1 signal handler for archiver process */
static void
pgarch_waken(SIGNAL_ARGS)
@ -346,7 +327,7 @@ pgarch_MainLoop(void)
* idea. If more than 60 seconds pass since SIGTERM, exit anyway, so
* that the postmaster can start a new archiver if needed.
*/
if (got_SIGTERM)
if (ShutdownRequestPending)
{
time_t curtime = time(NULL);
@ -434,7 +415,7 @@ pgarch_ArchiverCopyLoop(void)
* command, and the second is to avoid conflicts with another
* archiver spawned by a newer postmaster.
*/
if (got_SIGTERM || !PostmasterIsAlive())
if (ShutdownRequestPending || !PostmasterIsAlive())
return;
/*

View File

@ -49,6 +49,7 @@
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "postmaster/fork_process.h"
#include "postmaster/interrupt.h"
#include "postmaster/postmaster.h"
#include "replication/walsender.h"
#include "storage/backendid.h"
@ -262,9 +263,6 @@ static PgStat_GlobalStats globalStats;
*/
static List *pending_write_requests = NIL;
/* Signal handler flags */
static volatile bool need_exit = false;
/*
* Total time charged to functions so far in the current backend.
* We use this to help separate "self" and "other" time charges.
@ -282,7 +280,6 @@ static pid_t pgstat_forkexec(void);
#endif
NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn();
static void pgstat_exit(SIGNAL_ARGS);
static void pgstat_beshutdown_hook(int code, Datum arg);
static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create);
@ -4432,10 +4429,10 @@ PgstatCollectorMain(int argc, char *argv[])
* except SIGHUP and SIGQUIT. Note we don't need a SIGUSR1 handler to
* support latch operations, because we only use a local latch.
*/
pqsignal(SIGHUP, PostgresSigHupHandler);
pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, SIG_IGN);
pqsignal(SIGTERM, SIG_IGN);
pqsignal(SIGQUIT, pgstat_exit);
pqsignal(SIGQUIT, SignalHandlerForShutdownRequest);
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, SIG_IGN);
@ -4477,14 +4474,14 @@ PgstatCollectorMain(int argc, char *argv[])
/*
* Quit if we get SIGQUIT from the postmaster.
*/
if (need_exit)
if (ShutdownRequestPending)
break;
/*
* Inner loop iterates as long as we keep getting messages, or until
* need_exit becomes set.
* ShutdownRequestPending becomes set.
*/
while (!need_exit)
while (!ShutdownRequestPending)
{
/*
* Reload configuration if we got SIGHUP from the postmaster.
@ -4676,19 +4673,6 @@ PgstatCollectorMain(int argc, char *argv[])
exit(0);
}
/* SIGQUIT signal handler for collector process */
static void
pgstat_exit(SIGNAL_ARGS)
{
int save_errno = errno;
need_exit = true;
SetLatch(MyLatch);
errno = save_errno;
}
/*
* Subroutine to clear stats in a database entry
*

View File

@ -19,13 +19,11 @@
*/
#include "postgres.h"
#include <signal.h>
#include <unistd.h>
#include "access/xlog.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/interrupt.h"
#include "postmaster/startup.h"
#include "storage/ipc.h"
#include "storage/latch.h"
@ -50,7 +48,6 @@ static volatile sig_atomic_t promote_triggered = false;
static volatile sig_atomic_t in_restore_command = false;
/* Signal handlers */
static void startupproc_quickdie(SIGNAL_ARGS);
static void StartupProcTriggerHandler(SIGNAL_ARGS);
static void StartupProcSigHupHandler(SIGNAL_ARGS);
@ -60,33 +57,6 @@ static void StartupProcSigHupHandler(SIGNAL_ARGS);
* --------------------------------
*/
/*
* startupproc_quickdie() occurs when signalled SIGQUIT by the postmaster.
*
* Some backend has bought the farm,
* so we need to stop what we're doing and exit.
*/
static void
startupproc_quickdie(SIGNAL_ARGS)
{
/*
* We DO NOT want to run proc_exit() or atexit() callbacks -- we're here
* because shared memory may be corrupted, so we don't want to try to
* clean up our transaction. Just nail the windows shut and get out of
* town. The callbacks wouldn't be safe to run from a signal handler,
* anyway.
*
* Note we do _exit(2) not _exit(0). This is to force the postmaster into
* a system reset cycle if someone sends a manual SIGQUIT to a random
* backend. This is necessary precisely because we don't clean up our
* shared memory state. (The "dead man switch" mechanism in pmsignal.c
* should ensure the postmaster sees this as a crash, too, but no harm in
* being doubly sure.)
*/
_exit(2);
}
/* SIGUSR2: set flag to finish recovery */
static void
StartupProcTriggerHandler(SIGNAL_ARGS)
@ -167,7 +137,7 @@ StartupProcessMain(void)
pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */
pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */
pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */
pqsignal(SIGQUIT, startupproc_quickdie); /* hard crash time */
pqsignal(SIGQUIT, SignalHandlerForCrashExit);
InitializeTimeouts(); /* establishes SIGALRM handler */
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler);

View File

@ -48,6 +48,7 @@
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/interrupt.h"
#include "postmaster/walwriter.h"
#include "storage/bufmgr.h"
#include "storage/condition_variable.h"
@ -77,17 +78,6 @@ int WalWriterFlushAfter = 128;
#define LOOPS_UNTIL_HIBERNATE 50
#define HIBERNATE_FACTOR 25
/*
* Flags set by interrupt handlers for later service in the main loop.
*/
static volatile sig_atomic_t shutdown_requested = false;
static void HandleWalWriterInterrupts(void);
/* Signal handlers */
static void wal_quickdie(SIGNAL_ARGS);
static void WalShutdownHandler(SIGNAL_ARGS);
/*
* Main entry point for walwriter process
*
@ -108,10 +98,10 @@ WalWriterMain(void)
* We have no particular use for SIGINT at the moment, but seems
* reasonable to treat like SIGTERM.
*/
pqsignal(SIGHUP, PostgresSigHupHandler); /* set flag to read config file */
pqsignal(SIGINT, WalShutdownHandler); /* request shutdown */
pqsignal(SIGTERM, WalShutdownHandler); /* request shutdown */
pqsignal(SIGQUIT, wal_quickdie); /* hard crash time */
pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, SignalHandlerForShutdownRequest);
pqsignal(SIGTERM, SignalHandlerForShutdownRequest);
pqsignal(SIGQUIT, SignalHandlerForCrashExit);
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler);
@ -242,7 +232,7 @@ WalWriterMain(void)
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
HandleWalWriterInterrupts();
HandleMainLoopInterrupts();
/*
* Do what we're here for; then, if XLogBackgroundFlush() found useful
@ -269,65 +259,3 @@ WalWriterMain(void)
WAIT_EVENT_WAL_WRITER_MAIN);
}
}
/*
* Process any new interrupts.
*/
static void
HandleWalWriterInterrupts(void)
{
if (ConfigReloadPending)
{
ConfigReloadPending = false;
ProcessConfigFile(PGC_SIGHUP);
}
if (shutdown_requested)
{
/* Normal exit from the walwriter is here */
proc_exit(0); /* done */
}
}
/* --------------------------------
* signal handler routines
* --------------------------------
*/
/*
* wal_quickdie() occurs when signalled SIGQUIT by the postmaster.
*
* Some backend has bought the farm,
* so we need to stop what we're doing and exit.
*/
static void
wal_quickdie(SIGNAL_ARGS)
{
/*
* We DO NOT want to run proc_exit() or atexit() callbacks -- we're here
* because shared memory may be corrupted, so we don't want to try to
* clean up our transaction. Just nail the windows shut and get out of
* town. The callbacks wouldn't be safe to run from a signal handler,
* anyway.
*
* Note we do _exit(2) not _exit(0). This is to force the postmaster into
* a system reset cycle if someone sends a manual SIGQUIT to a random
* backend. This is necessary precisely because we don't clean up our
* shared memory state. (The "dead man switch" mechanism in pmsignal.c
* should ensure the postmaster sees this as a crash, too, but no harm in
* being doubly sure.)
*/
_exit(2);
}
/* SIGTERM: set flag to exit normally */
static void
WalShutdownHandler(SIGNAL_ARGS)
{
int save_errno = errno;
shutdown_requested = true;
SetLatch(MyLatch);
errno = save_errno;
}

View File

@ -30,6 +30,7 @@
#include "pgstat.h"
#include "postmaster/bgworker.h"
#include "postmaster/fork_process.h"
#include "postmaster/interrupt.h"
#include "postmaster/postmaster.h"
#include "replication/logicallauncher.h"
#include "replication/logicalworker.h"
@ -955,7 +956,7 @@ ApplyLauncherMain(Datum main_arg)
LogicalRepCtx->launcher_pid = MyProcPid;
/* Establish signal handlers. */
pqsignal(SIGTERM, PostgresSigHupHandler);
pqsignal(SIGTERM, SignalHandlerForConfigReload);
pqsignal(SIGTERM, die);
BackgroundWorkerUnblockSignals();

View File

@ -45,6 +45,7 @@
#include "parser/parse_relation.h"
#include "pgstat.h"
#include "postmaster/bgworker.h"
#include "postmaster/interrupt.h"
#include "postmaster/postmaster.h"
#include "postmaster/walwriter.h"
#include "replication/decode.h"
@ -1575,7 +1576,7 @@ ApplyWorkerMain(Datum main_arg)
logicalrep_worker_attach(worker_slot);
/* Setup signal handling */
pqsignal(SIGHUP, PostgresSigHupHandler);
pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGTERM, die);
BackgroundWorkerUnblockSignals();

View File

@ -43,7 +43,6 @@
*/
#include "postgres.h"
#include <signal.h>
#include <unistd.h>
#include "access/htup_details.h"
@ -58,6 +57,7 @@
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/interrupt.h"
#include "replication/walreceiver.h"
#include "replication/walsender.h"
#include "storage/ipc.h"
@ -127,7 +127,6 @@ static void ProcessWalSndrMessage(XLogRecPtr walEnd, TimestampTz sendTime);
/* Signal handlers */
static void WalRcvSigHupHandler(SIGNAL_ARGS);
static void WalRcvShutdownHandler(SIGNAL_ARGS);
static void WalRcvQuickDieHandler(SIGNAL_ARGS);
/*
@ -249,7 +248,7 @@ WalReceiverMain(void)
pqsignal(SIGHUP, WalRcvSigHupHandler); /* set flag to read config file */
pqsignal(SIGINT, SIG_IGN);
pqsignal(SIGTERM, WalRcvShutdownHandler); /* request shutdown */
pqsignal(SIGQUIT, WalRcvQuickDieHandler); /* hard crash time */
pqsignal(SIGQUIT, SignalHandlerForCrashExit);
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler);
@ -780,32 +779,6 @@ WalRcvShutdownHandler(SIGNAL_ARGS)
errno = save_errno;
}
/*
* WalRcvQuickDieHandler() occurs when signalled SIGQUIT by the postmaster.
*
* Some backend has bought the farm, so we need to stop what we're doing and
* exit.
*/
static void
WalRcvQuickDieHandler(SIGNAL_ARGS)
{
/*
* We DO NOT want to run proc_exit() or atexit() callbacks -- we're here
* because shared memory may be corrupted, so we don't want to try to
* clean up our transaction. Just nail the windows shut and get out of
* town. The callbacks wouldn't be safe to run from a signal handler,
* anyway.
*
* Note we use _exit(2) not _exit(0). This is to force the postmaster
* into a system reset cycle if someone sends a manual SIGQUIT to a random
* backend. This is necessary precisely because we don't clean up our
* shared memory state. (The "dead man switch" mechanism in pmsignal.c
* should ensure the postmaster sees this as a crash, too, but no harm in
* being doubly sure.)
*/
_exit(2);
}
/*
* Accept the message from XLOG stream, and process it.
*/

View File

@ -66,6 +66,7 @@
#include "miscadmin.h"
#include "nodes/replnodes.h"
#include "pgstat.h"
#include "postmaster/interrupt.h"
#include "replication/basebackup.h"
#include "replication/decode.h"
#include "replication/logical.h"
@ -2969,8 +2970,7 @@ void
WalSndSignals(void)
{
/* Set up signal handlers */
pqsignal(SIGHUP, PostgresSigHupHandler); /* set flag to read config
* file */
pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, StatementCancelHandler); /* query cancel */
pqsignal(SIGTERM, die); /* request shutdown */
pqsignal(SIGQUIT, quickdie); /* hard crash time */

View File

@ -58,6 +58,7 @@
#include "pg_trace.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "postmaster/interrupt.h"
#include "postmaster/postmaster.h"
#include "replication/logicallauncher.h"
#include "replication/logicalworker.h"
@ -2861,24 +2862,6 @@ FloatExceptionHandler(SIGNAL_ARGS)
"invalid operation, such as division by zero.")));
}
/*
* SIGHUP: set flag to re-read config file at next convenient time.
*
* Sets the ConfigReloadPending flag, which should be checked at convenient
* places inside main loops. (Better than doing the reading in the signal
* handler, ey?)
*/
void
PostgresSigHupHandler(SIGNAL_ARGS)
{
int save_errno = errno;
ConfigReloadPending = true;
SetLatch(MyLatch);
errno = save_errno;
}
/*
* RecoveryConflictInterrupt: out-of-line portion of recovery conflict
* handling following receipt of SIGUSR1. Designed to be similar to die()
@ -3827,8 +3810,7 @@ PostgresMain(int argc, char *argv[],
WalSndSignals();
else
{
pqsignal(SIGHUP, PostgresSigHupHandler); /* set flag to read config
* file */
pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, StatementCancelHandler); /* cancel current query */
pqsignal(SIGTERM, die); /* cancel current query and exit */

View File

@ -32,7 +32,6 @@ volatile sig_atomic_t QueryCancelPending = false;
volatile sig_atomic_t ProcDiePending = false;
volatile sig_atomic_t ClientConnectionLost = false;
volatile sig_atomic_t IdleInTransactionSessionTimeoutPending = false;
volatile sig_atomic_t ConfigReloadPending = false;
volatile uint32 InterruptHoldoffCount = 0;
volatile uint32 QueryCancelHoldoffCount = 0;
volatile uint32 CritSectionCount = 0;

View File

@ -82,7 +82,6 @@ extern PGDLLIMPORT volatile sig_atomic_t InterruptPending;
extern PGDLLIMPORT volatile sig_atomic_t QueryCancelPending;
extern PGDLLIMPORT volatile sig_atomic_t ProcDiePending;
extern PGDLLIMPORT volatile sig_atomic_t IdleInTransactionSessionTimeoutPending;
extern PGDLLIMPORT volatile sig_atomic_t ConfigReloadPending;
extern PGDLLIMPORT volatile sig_atomic_t ClientConnectionLost;
@ -279,8 +278,6 @@ extern void restore_stack_base(pg_stack_base_t base);
extern void check_stack_depth(void);
extern bool stack_is_too_deep(void);
extern void PostgresSigHupHandler(SIGNAL_ARGS);
/* in tcop/utility.c */
extern void PreventCommandIfReadOnly(const char *cmdname);
extern void PreventCommandIfParallelMode(const char *cmdname);

View File

@ -0,0 +1,32 @@
/*-------------------------------------------------------------------------
*
* interrupt.h
* Interrupt handling routines.
*
* Responses to interrupts are fairly varied and many types of backends
* have their own implementations, but we provide a few generic things
* here to facilitate code reuse.
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* src/include/postmaster/interrupt.h
*
*-------------------------------------------------------------------------
*/
#ifndef INTERRUPT_H
#define INTERRUPT_H
#include <signal.h>
extern PGDLLIMPORT volatile sig_atomic_t ConfigReloadPending;
extern PGDLLIMPORT volatile sig_atomic_t ShutdownRequestPending;
extern void HandleMainLoopInterrupts(void);
extern void SignalHandlerForConfigReload(SIGNAL_ARGS);
extern void SignalHandlerForCrashExit(SIGNAL_ARGS);
extern void SignalHandlerForShutdownRequest(SIGNAL_ARGS);
#endif