diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2019-10-13 15:48:26 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2019-10-13 15:48:26 -0400 |
commit | 9abb2bfc046070b22e3be28173a0736da31cab5a (patch) | |
tree | 436d534545df7601feb65f98c37221e68982b255 /src/backend/postmaster/postmaster.c | |
parent | f38291e927fa8c04eb772e6a17a3dd44da2b69e8 (diff) |
In the postmaster, rely on the signal infrastructure to block signals.
POSIX sigaction(2) can be told to block a set of signals while a
signal handler executes. Make use of that instead of manually
blocking and unblocking signals in the postmaster's signal handlers.
This should save a few cycles, and it also prevents recursive
invocation of signal handlers when many signals arrive in close
succession. We have seen buildfarm failures that seem to be due to
postmaster stack overflow caused by such recursion (exacerbated by
a Linux PPC64 kernel bug).
This doesn't change anything about the way that it works on Windows.
Somebody might consider adjusting port/win32/signal.c to let it work
similarly, but I'm not in a position to do that.
For the moment, just apply to HEAD. Possibly we should consider
back-patching this, but it'd be good to let it age awhile first.
Discussion: https://postgr.es/m/14878.1570820201@sss.pgh.pa.us
Diffstat (limited to 'src/backend/postmaster/postmaster.c')
-rw-r--r-- | src/backend/postmaster/postmaster.c | 87 |
1 files changed, 64 insertions, 23 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 85f15a5666e..5f303591652 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -606,14 +606,25 @@ PostmasterMain(int argc, char *argv[]) /* * Set up signal handlers for the postmaster process. * - * In the postmaster, we want to install non-ignored handlers *without* - * SA_RESTART. This is because they'll be blocked at all times except - * when ServerLoop is waiting for something to happen, and during that - * window, we want signals to exit the select(2) wait so that ServerLoop - * can respond if anything interesting happened. On some platforms, - * signals marked SA_RESTART would not cause the select() wait to end. - * Child processes will generally want SA_RESTART, but we expect them to - * set up their own handlers before unblocking signals. + * In the postmaster, we use pqsignal_pm() rather than pqsignal() (which + * is used by all child processes and client processes). That has a + * couple of special behaviors: + * + * 1. Except on Windows, we tell sigaction() to block all signals for the + * duration of the signal handler. This is faster than our old approach + * of blocking/unblocking explicitly in the signal handler, and it should + * also prevent excessive stack consumption if signals arrive quickly. + * + * 2. We do not set the SA_RESTART flag. This is because signals will be + * blocked at all times except when ServerLoop is waiting for something to + * happen, and during that window, we want signals to exit the select(2) + * wait so that ServerLoop can respond if anything interesting happened. + * On some platforms, signals marked SA_RESTART would not cause the + * select() wait to end. + * + * Child processes will generally want SA_RESTART, so pqsignal() sets that + * flag. We expect children to set up their own handlers before + * unblocking signals. * * CAUTION: when changing this list, check for side-effects on the signal * handling setup of child processes. See tcop/postgres.c, @@ -625,18 +636,16 @@ PostmasterMain(int argc, char *argv[]) pqinitmask(); PG_SETMASK(&BlockSig); - pqsignal_no_restart(SIGHUP, SIGHUP_handler); /* reread config file and - * have children do same */ - pqsignal_no_restart(SIGINT, pmdie); /* send SIGTERM and shut down */ - pqsignal_no_restart(SIGQUIT, pmdie); /* send SIGQUIT and die */ - pqsignal_no_restart(SIGTERM, pmdie); /* wait for children and shut down */ - pqsignal(SIGALRM, SIG_IGN); /* ignored */ - pqsignal(SIGPIPE, SIG_IGN); /* ignored */ - pqsignal_no_restart(SIGUSR1, sigusr1_handler); /* message from child - * process */ - pqsignal_no_restart(SIGUSR2, dummy_handler); /* unused, reserve for - * children */ - pqsignal_no_restart(SIGCHLD, reaper); /* handle child termination */ + pqsignal_pm(SIGHUP, SIGHUP_handler); /* reread config file and have + * children do same */ + pqsignal_pm(SIGINT, pmdie); /* send SIGTERM and shut down */ + pqsignal_pm(SIGQUIT, pmdie); /* send SIGQUIT and die */ + pqsignal_pm(SIGTERM, pmdie); /* wait for children and shut down */ + pqsignal_pm(SIGALRM, SIG_IGN); /* ignored */ + pqsignal_pm(SIGPIPE, SIG_IGN); /* ignored */ + pqsignal_pm(SIGUSR1, sigusr1_handler); /* message from child process */ + pqsignal_pm(SIGUSR2, dummy_handler); /* unused, reserve for children */ + pqsignal_pm(SIGCHLD, reaper); /* handle child termination */ /* * No other place in Postgres should touch SIGTTIN/SIGTTOU handling. We @@ -646,15 +655,15 @@ PostmasterMain(int argc, char *argv[]) * child processes should just allow the inherited settings to stand. */ #ifdef SIGTTIN - pqsignal(SIGTTIN, SIG_IGN); /* ignored */ + pqsignal_pm(SIGTTIN, SIG_IGN); /* ignored */ #endif #ifdef SIGTTOU - pqsignal(SIGTTOU, SIG_IGN); /* ignored */ + pqsignal_pm(SIGTTOU, SIG_IGN); /* ignored */ #endif /* ignore SIGXFSZ, so that ulimit violations work like disk full */ #ifdef SIGXFSZ - pqsignal(SIGXFSZ, SIG_IGN); /* ignored */ + pqsignal_pm(SIGXFSZ, SIG_IGN); /* ignored */ #endif /* @@ -2640,7 +2649,13 @@ SIGHUP_handler(SIGNAL_ARGS) { int save_errno = errno; + /* + * We rely on the signal mechanism to have blocked all signals ... except + * on Windows, which lacks sigaction(), so we have to do it manually. + */ +#ifdef WIN32 PG_SETMASK(&BlockSig); +#endif if (Shutdown <= SmartShutdown) { @@ -2700,7 +2715,9 @@ SIGHUP_handler(SIGNAL_ARGS) #endif } +#ifdef WIN32 PG_SETMASK(&UnBlockSig); +#endif errno = save_errno; } @@ -2714,7 +2731,13 @@ pmdie(SIGNAL_ARGS) { int save_errno = errno; + /* + * We rely on the signal mechanism to have blocked all signals ... except + * on Windows, which lacks sigaction(), so we have to do it manually. + */ +#ifdef WIN32 PG_SETMASK(&BlockSig); +#endif ereport(DEBUG2, (errmsg_internal("postmaster received signal %d", @@ -2880,7 +2903,9 @@ pmdie(SIGNAL_ARGS) break; } +#ifdef WIN32 PG_SETMASK(&UnBlockSig); +#endif errno = save_errno; } @@ -2895,7 +2920,13 @@ reaper(SIGNAL_ARGS) int pid; /* process id of dead child process */ int exitstatus; /* its exit status */ + /* + * We rely on the signal mechanism to have blocked all signals ... except + * on Windows, which lacks sigaction(), so we have to do it manually. + */ +#ifdef WIN32 PG_SETMASK(&BlockSig); +#endif ereport(DEBUG4, (errmsg_internal("reaping dead processes"))); @@ -3212,7 +3243,9 @@ reaper(SIGNAL_ARGS) PostmasterStateMachine(); /* Done with signal handler */ +#ifdef WIN32 PG_SETMASK(&UnBlockSig); +#endif errno = save_errno; } @@ -5114,7 +5147,13 @@ sigusr1_handler(SIGNAL_ARGS) { int save_errno = errno; + /* + * We rely on the signal mechanism to have blocked all signals ... except + * on Windows, which lacks sigaction(), so we have to do it manually. + */ +#ifdef WIN32 PG_SETMASK(&BlockSig); +#endif /* Process background worker state change. */ if (CheckPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE)) @@ -5272,7 +5311,9 @@ sigusr1_handler(SIGNAL_ARGS) signal_child(StartupPID, SIGUSR2); } +#ifdef WIN32 PG_SETMASK(&UnBlockSig); +#endif errno = save_errno; } |