diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/libpq/pqsignal.c | 49 | ||||
-rw-r--r-- | src/backend/postmaster/postmaster.c | 87 |
2 files changed, 113 insertions, 23 deletions
diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c index 68c32bb60d7..4f47eaf2e3a 100644 --- a/src/backend/libpq/pqsignal.c +++ b/src/backend/libpq/pqsignal.c @@ -95,3 +95,52 @@ pqinitmask(void) sigdelset(&StartupBlockSig, SIGALRM); #endif } + +/* + * Set up a postmaster signal handler for signal "signo" + * + * Returns the previous handler. + * + * This is used only in the postmaster, which has its own odd approach to + * signal handling. For signals with handlers, we block all signals for the + * duration of signal handler execution. We also do not set the SA_RESTART + * flag; this should be safe given the tiny range of code in which the + * postmaster ever unblocks signals. + * + * pqinitmask() must have been invoked previously. + * + * On Windows, this function is just an alias for pqsignal() + * (and note that it's calling the code in src/backend/port/win32/signal.c, + * not src/port/pqsignal.c). On that platform, the postmaster's signal + * handlers still have to block signals for themselves. + */ +pqsigfunc +pqsignal_pm(int signo, pqsigfunc func) +{ +#ifndef WIN32 + struct sigaction act, + oact; + + act.sa_handler = func; + if (func == SIG_IGN || func == SIG_DFL) + { + /* in these cases, act the same as pqsignal() */ + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + } + else + { + act.sa_mask = BlockSig; + act.sa_flags = 0; + } +#ifdef SA_NOCLDSTOP + if (signo == SIGCHLD) + act.sa_flags |= SA_NOCLDSTOP; +#endif + if (sigaction(signo, &act, &oact) < 0) + return SIG_ERR; + return oact.sa_handler; +#else /* WIN32 */ + return pqsignal(signo, func); +#endif +} diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 2f049508791..e1822c79230 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -618,14 +618,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, @@ -637,18 +648,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 @@ -658,15 +667,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 /* @@ -2655,7 +2664,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) { @@ -2715,7 +2730,9 @@ SIGHUP_handler(SIGNAL_ARGS) #endif } +#ifdef WIN32 PG_SETMASK(&UnBlockSig); +#endif errno = save_errno; } @@ -2729,7 +2746,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", @@ -2858,7 +2881,9 @@ pmdie(SIGNAL_ARGS) break; } +#ifdef WIN32 PG_SETMASK(&UnBlockSig); +#endif errno = save_errno; } @@ -2873,7 +2898,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"))); @@ -3176,7 +3207,9 @@ reaper(SIGNAL_ARGS) PostmasterStateMachine(); /* Done with signal handler */ +#ifdef WIN32 PG_SETMASK(&UnBlockSig); +#endif errno = save_errno; } @@ -5110,7 +5143,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)) @@ -5270,7 +5309,9 @@ sigusr1_handler(SIGNAL_ARGS) signal_child(StartupPID, SIGUSR2); } +#ifdef WIN32 PG_SETMASK(&UnBlockSig); +#endif errno = save_errno; } |