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
+}
/*
* 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,
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
* 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
/*
{
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)
{
#endif
}
+#ifdef WIN32
PG_SETMASK(&UnBlockSig);
+#endif
errno = save_errno;
}
{
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",
break;
}
+#ifdef WIN32
PG_SETMASK(&UnBlockSig);
+#endif
errno = save_errno;
}
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")));
PostmasterStateMachine();
/* Done with signal handler */
+#ifdef WIN32
PG_SETMASK(&UnBlockSig);
+#endif
errno = save_errno;
}
{
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))
signal_child(StartupPID, SIGUSR2);
}
+#ifdef WIN32
PG_SETMASK(&UnBlockSig);
+#endif
errno = save_errno;
}