Centralize setup of SIGQUIT handling for postmaster child processes.

We decided that the policy established in commit 7634bd4f6 for
the bgwriter, checkpointer, walwriter, and walreceiver processes,
namely that they should accept SIGQUIT at all times, really ought
to apply uniformly to all postmaster children.  Therefore, get
rid of the duplicative and inconsistent per-process code for
establishing that signal handler and removing SIGQUIT from BlockSig.
Instead, make InitPostmasterChild do it.

The handler set up by InitPostmasterChild is SignalHandlerForCrashExit,
which just summarily does _exit(2).  In interactive backends, we
almost immediately replace that with quickdie, since we would prefer
to try to tell the client that we're dying.  However, this patch is
changing the behavior of autovacuum (both launcher and workers), as
well as walsenders.  Those processes formerly also used quickdie,
but AFAICS that was just mindless copy-and-paste: they don't have
any interactive client that's likely to benefit from being told this.

The stats collector continues to be an outlier, in that it thinks
SIGQUIT means normal exit.  That should probably be changed for
consistency, but there's another patch set where that's being
dealt with, so I didn't do so here.

Discussion: https://postgr.es/m/644875.1599933441@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2020-09-16 16:04:36 -04:00
parent 2000b6c10a
commit 44fc6e259b
12 changed files with 51 additions and 49 deletions

View File

@ -454,8 +454,8 @@ AutoVacLauncherMain(int argc, char *argv[])
pqsignal(SIGHUP, SignalHandlerForConfigReload); pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, StatementCancelHandler); pqsignal(SIGINT, StatementCancelHandler);
pqsignal(SIGTERM, SignalHandlerForShutdownRequest); pqsignal(SIGTERM, SignalHandlerForShutdownRequest);
/* SIGQUIT handler was already set up by InitPostmasterChild */
pqsignal(SIGQUIT, quickdie);
InitializeTimeouts(); /* establishes SIGALRM handler */ InitializeTimeouts(); /* establishes SIGALRM handler */
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
@ -498,9 +498,10 @@ AutoVacLauncherMain(int argc, char *argv[])
* *
* Note that we use sigsetjmp(..., 1), so that the prevailing signal mask * Note that we use sigsetjmp(..., 1), so that the prevailing signal mask
* (to wit, BlockSig) will be restored when longjmp'ing to here. Thus, * (to wit, BlockSig) will be restored when longjmp'ing to here. Thus,
* signals will be blocked until we complete error recovery. It might * signals other than SIGQUIT will be blocked until we complete error
* seem that this policy makes the HOLD_INTERRUPTS() call redundant, but * recovery. It might seem that this policy makes the HOLD_INTERRUPTS()
* it is not since InterruptPending might be set already. * call redundant, but it is not since InterruptPending might be set
* already.
*/ */
if (sigsetjmp(local_sigjmp_buf, 1) != 0) if (sigsetjmp(local_sigjmp_buf, 1) != 0)
{ {
@ -1531,7 +1532,8 @@ AutoVacWorkerMain(int argc, char *argv[])
*/ */
pqsignal(SIGINT, StatementCancelHandler); pqsignal(SIGINT, StatementCancelHandler);
pqsignal(SIGTERM, die); pqsignal(SIGTERM, die);
pqsignal(SIGQUIT, quickdie); /* SIGQUIT handler was already set up by InitPostmasterChild */
InitializeTimeouts(); /* establishes SIGALRM handler */ InitializeTimeouts(); /* establishes SIGALRM handler */
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
@ -1562,9 +1564,9 @@ AutoVacWorkerMain(int argc, char *argv[])
* *
* Note that we use sigsetjmp(..., 1), so that the prevailing signal mask * Note that we use sigsetjmp(..., 1), so that the prevailing signal mask
* (to wit, BlockSig) will be restored when longjmp'ing to here. Thus, * (to wit, BlockSig) will be restored when longjmp'ing to here. Thus,
* signals will be blocked until we exit. It might seem that this policy * signals other than SIGQUIT will be blocked until we exit. It might
* makes the HOLD_INTERRUPTS() call redundant, but it is not since * seem that this policy makes the HOLD_INTERRUPTS() call redundant, but
* InterruptPending might be set already. * it is not since InterruptPending might be set already.
*/ */
if (sigsetjmp(local_sigjmp_buf, 1) != 0) if (sigsetjmp(local_sigjmp_buf, 1) != 0)
{ {

View File

@ -731,9 +731,9 @@ StartBackgroundWorker(void)
pqsignal(SIGFPE, SIG_IGN); pqsignal(SIGFPE, SIG_IGN);
} }
pqsignal(SIGTERM, bgworker_die); pqsignal(SIGTERM, bgworker_die);
/* SIGQUIT handler was already set up by InitPostmasterChild */
pqsignal(SIGHUP, SIG_IGN); pqsignal(SIGHUP, SIG_IGN);
pqsignal(SIGQUIT, SignalHandlerForCrashExit);
InitializeTimeouts(); /* establishes SIGALRM handler */ InitializeTimeouts(); /* establishes SIGALRM handler */
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);

View File

@ -104,7 +104,7 @@ BackgroundWriterMain(void)
pqsignal(SIGHUP, SignalHandlerForConfigReload); pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, SIG_IGN); pqsignal(SIGINT, SIG_IGN);
pqsignal(SIGTERM, SignalHandlerForShutdownRequest); pqsignal(SIGTERM, SignalHandlerForShutdownRequest);
pqsignal(SIGQUIT, SignalHandlerForCrashExit); /* SIGQUIT handler was already set up by InitPostmasterChild */
pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR1, procsignal_sigusr1_handler);
@ -115,10 +115,6 @@ BackgroundWriterMain(void)
*/ */
pqsignal(SIGCHLD, SIG_DFL); pqsignal(SIGCHLD, SIG_DFL);
/* We allow SIGQUIT (SignalHandlerForCrashExit) at all times */
sigdelset(&BlockSig, SIGQUIT);
PG_SETMASK(&BlockSig);
/* /*
* We just started, assume there has been either a shutdown or * We just started, assume there has been either a shutdown or
* end-of-recovery snapshot. * end-of-recovery snapshot.

View File

@ -198,7 +198,7 @@ CheckpointerMain(void)
pqsignal(SIGHUP, SignalHandlerForConfigReload); pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, ReqCheckpointHandler); /* request checkpoint */ pqsignal(SIGINT, ReqCheckpointHandler); /* request checkpoint */
pqsignal(SIGTERM, SIG_IGN); /* ignore SIGTERM */ pqsignal(SIGTERM, SIG_IGN); /* ignore SIGTERM */
pqsignal(SIGQUIT, SignalHandlerForCrashExit); /* SIGQUIT handler was already set up by InitPostmasterChild */
pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR1, procsignal_sigusr1_handler);
@ -209,10 +209,6 @@ CheckpointerMain(void)
*/ */
pqsignal(SIGCHLD, SIG_DFL); pqsignal(SIGCHLD, SIG_DFL);
/* We allow SIGQUIT (SignalHandlerForCrashExit) at all times */
sigdelset(&BlockSig, SIGQUIT);
PG_SETMASK(&BlockSig);
/* /*
* Initialize so that first time-driven event happens at the correct time. * Initialize so that first time-driven event happens at the correct time.
*/ */

View File

@ -228,7 +228,7 @@ PgArchiverMain(int argc, char *argv[])
pqsignal(SIGHUP, SignalHandlerForConfigReload); pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, SIG_IGN); pqsignal(SIGINT, SIG_IGN);
pqsignal(SIGTERM, SignalHandlerForShutdownRequest); pqsignal(SIGTERM, SignalHandlerForShutdownRequest);
pqsignal(SIGQUIT, SignalHandlerForCrashExit); /* SIGQUIT handler was already set up by InitPostmasterChild */
pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, pgarch_waken); pqsignal(SIGUSR1, pgarch_waken);

View File

@ -4355,7 +4355,7 @@ BackendInitialize(Port *port)
* cleaned up. * cleaned up.
*/ */
pqsignal(SIGTERM, process_startup_packet_die); pqsignal(SIGTERM, process_startup_packet_die);
pqsignal(SIGQUIT, SignalHandlerForCrashExit); /* SIGQUIT handler was already set up by InitPostmasterChild */
InitializeTimeouts(); /* establishes SIGALRM handler */ InitializeTimeouts(); /* establishes SIGALRM handler */
PG_SETMASK(&StartupBlockSig); PG_SETMASK(&StartupBlockSig);
@ -4435,7 +4435,7 @@ BackendInitialize(Port *port)
status = ProcessStartupPacket(port, false, false); status = ProcessStartupPacket(port, false, false);
/* /*
* Disable the timeout, and prevent SIGTERM/SIGQUIT again. * Disable the timeout, and prevent SIGTERM again.
*/ */
disable_timeout(STARTUP_PACKET_TIMEOUT, false); disable_timeout(STARTUP_PACKET_TIMEOUT, false);
PG_SETMASK(&BlockSig); PG_SETMASK(&BlockSig);
@ -4983,10 +4983,6 @@ SubPostmasterMain(int argc, char *argv[])
if (strcmp(argv[1], "--forkavworker") == 0) if (strcmp(argv[1], "--forkavworker") == 0)
AutovacuumWorkerIAm(); AutovacuumWorkerIAm();
/* In EXEC_BACKEND case we will not have inherited these settings */
pqinitmask();
PG_SETMASK(&BlockSig);
/* Read in remaining GUC variables */ /* Read in remaining GUC variables */
read_nondefault_variables(); read_nondefault_variables();

View File

@ -175,7 +175,7 @@ StartupProcessMain(void)
pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */ pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */
pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */ pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */
pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */ pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */
pqsignal(SIGQUIT, SignalHandlerForCrashExit); /* SIGQUIT handler was already set up by InitPostmasterChild */
InitializeTimeouts(); /* establishes SIGALRM handler */ InitializeTimeouts(); /* establishes SIGALRM handler */
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR1, procsignal_sigusr1_handler);

View File

@ -101,7 +101,7 @@ WalWriterMain(void)
pqsignal(SIGHUP, SignalHandlerForConfigReload); pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, SignalHandlerForShutdownRequest); pqsignal(SIGINT, SignalHandlerForShutdownRequest);
pqsignal(SIGTERM, SignalHandlerForShutdownRequest); pqsignal(SIGTERM, SignalHandlerForShutdownRequest);
pqsignal(SIGQUIT, SignalHandlerForCrashExit); /* SIGQUIT handler was already set up by InitPostmasterChild */
pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR1, procsignal_sigusr1_handler);
@ -112,10 +112,6 @@ WalWriterMain(void)
*/ */
pqsignal(SIGCHLD, SIG_DFL); pqsignal(SIGCHLD, SIG_DFL);
/* We allow SIGQUIT (SignalHandlerForCrashExit) at all times */
sigdelset(&BlockSig, SIGQUIT);
PG_SETMASK(&BlockSig);
/* /*
* Create a memory context that we will do all our work in. We do this so * Create a memory context that we will do all our work in. We do this so
* that we can reset the context during error recovery and thereby avoid * that we can reset the context during error recovery and thereby avoid

View File

@ -270,7 +270,7 @@ WalReceiverMain(void)
pqsignal(SIGHUP, WalRcvSigHupHandler); /* set flag to read config file */ pqsignal(SIGHUP, WalRcvSigHupHandler); /* set flag to read config file */
pqsignal(SIGINT, SIG_IGN); pqsignal(SIGINT, SIG_IGN);
pqsignal(SIGTERM, WalRcvShutdownHandler); /* request shutdown */ pqsignal(SIGTERM, WalRcvShutdownHandler); /* request shutdown */
pqsignal(SIGQUIT, SignalHandlerForCrashExit); /* SIGQUIT handler was already set up by InitPostmasterChild */
pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR1, procsignal_sigusr1_handler);
@ -279,10 +279,6 @@ WalReceiverMain(void)
/* Reset some signals that are accepted by postmaster but not here */ /* Reset some signals that are accepted by postmaster but not here */
pqsignal(SIGCHLD, SIG_DFL); pqsignal(SIGCHLD, SIG_DFL);
/* We allow SIGQUIT (SignalHandlerForCrashExit) at all times */
sigdelset(&BlockSig, SIGQUIT);
PG_SETMASK(&BlockSig);
/* Load the libpq-specific functions */ /* Load the libpq-specific functions */
load_file("libpqwalreceiver", false); load_file("libpqwalreceiver", false);
if (WalReceiverFunctions == NULL) if (WalReceiverFunctions == NULL)

View File

@ -3041,7 +3041,7 @@ WalSndSignals(void)
pqsignal(SIGHUP, SignalHandlerForConfigReload); pqsignal(SIGHUP, SignalHandlerForConfigReload);
pqsignal(SIGINT, StatementCancelHandler); /* query cancel */ pqsignal(SIGINT, StatementCancelHandler); /* query cancel */
pqsignal(SIGTERM, die); /* request shutdown */ pqsignal(SIGTERM, die); /* request shutdown */
pqsignal(SIGQUIT, quickdie); /* hard crash time */ /* SIGQUIT handler was already set up by InitPostmasterChild */
InitializeTimeouts(); /* establishes SIGALRM handler */ InitializeTimeouts(); /* establishes SIGALRM handler */
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR1, procsignal_sigusr1_handler);

View File

@ -3820,7 +3820,8 @@ PostgresMain(int argc, char *argv[],
} }
/* /*
* Set up signal handlers and masks. * Set up signal handlers. (InitPostmasterChild or InitStandaloneProcess
* has already set up BlockSig and made that the active signal mask.)
* *
* Note that postmaster blocked all signals before forking child process, * Note that postmaster blocked all signals before forking child process,
* so there is no race condition whereby we might receive a signal before * so there is no race condition whereby we might receive a signal before
@ -3842,6 +3843,9 @@ PostgresMain(int argc, char *argv[],
pqsignal(SIGTERM, die); /* cancel current query and exit */ pqsignal(SIGTERM, die); /* cancel current query and exit */
/* /*
* In a postmaster child backend, replace SignalHandlerForCrashExit
* with quickdie, so we can tell the client we're dying.
*
* In a standalone backend, SIGQUIT can be generated from the keyboard * In a standalone backend, SIGQUIT can be generated from the keyboard
* easily, while SIGTERM cannot, so we make both signals do die() * easily, while SIGTERM cannot, so we make both signals do die()
* rather than quickdie(). * rather than quickdie().
@ -3871,16 +3875,6 @@ PostgresMain(int argc, char *argv[],
* platforms */ * platforms */
} }
pqinitmask();
if (IsUnderPostmaster)
{
/* We allow SIGQUIT (quickdie) at all times */
sigdelset(&BlockSig, SIGQUIT);
}
PG_SETMASK(&BlockSig); /* block everything except SIGQUIT */
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
/* /*

View File

@ -32,10 +32,12 @@
#include "catalog/pg_authid.h" #include "catalog/pg_authid.h"
#include "common/file_perm.h" #include "common/file_perm.h"
#include "libpq/libpq.h" #include "libpq/libpq.h"
#include "libpq/pqsignal.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "pgstat.h" #include "pgstat.h"
#include "postmaster/autovacuum.h" #include "postmaster/autovacuum.h"
#include "postmaster/interrupt.h"
#include "postmaster/postmaster.h" #include "postmaster/postmaster.h"
#include "storage/fd.h" #include "storage/fd.h"
#include "storage/ipc.h" #include "storage/ipc.h"
@ -133,6 +135,23 @@ InitPostmasterChild(void)
elog(FATAL, "setsid() failed: %m"); elog(FATAL, "setsid() failed: %m");
#endif #endif
/* In EXEC_BACKEND case we will not have inherited BlockSig etc values */
#ifdef EXEC_BACKEND
pqinitmask();
#endif
/*
* Every postmaster child process is expected to respond promptly to
* SIGQUIT at all times. Therefore we centrally remove SIGQUIT from
* BlockSig and install a suitable signal handler. (Client-facing
* processes may choose to replace this default choice of handler with
* quickdie().) All other blockable signals remain blocked for now.
*/
pqsignal(SIGQUIT, SignalHandlerForCrashExit);
sigdelset(&BlockSig, SIGQUIT);
PG_SETMASK(&BlockSig);
/* Request a signal if the postmaster dies, if possible. */ /* Request a signal if the postmaster dies, if possible. */
PostmasterDeathSignalInit(); PostmasterDeathSignalInit();
} }
@ -155,6 +174,13 @@ InitStandaloneProcess(const char *argv0)
InitLatch(MyLatch); InitLatch(MyLatch);
InitializeLatchWaitSet(); InitializeLatchWaitSet();
/*
* For consistency with InitPostmasterChild, initialize signal mask here.
* But we don't unblock SIGQUIT or provide a default handler for it.
*/
pqinitmask();
PG_SETMASK(&BlockSig);
/* Compute paths, no postmaster to inherit from */ /* Compute paths, no postmaster to inherit from */
if (my_exec_path[0] == '\0') if (my_exec_path[0] == '\0')
{ {