summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/libpq/pqsignal.c49
-rw-r--r--src/backend/postmaster/postmaster.c87
-rw-r--r--src/include/libpq/pqsignal.h3
-rw-r--r--src/include/port.h5
-rw-r--r--src/port/pqsignal.c29
5 files changed, 116 insertions, 57 deletions
diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c
index 68c32bb60d..4f47eaf2e3 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 2f04950879..e1822c7923 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;
}
diff --git a/src/include/libpq/pqsignal.h b/src/include/libpq/pqsignal.h
index d0e3b9e479..46bc3a8895 100644
--- a/src/include/libpq/pqsignal.h
+++ b/src/include/libpq/pqsignal.h
@@ -36,4 +36,7 @@ extern sigset_t UnBlockSig,
extern void pqinitmask(void);
+/* pqsigfunc is declared in src/include/port.h */
+extern pqsigfunc pqsignal_pm(int signo, pqsigfunc func);
+
#endif /* PQSIGNAL_H */
diff --git a/src/include/port.h b/src/include/port.h
index b5c03d912b..ebcee1c55c 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -524,11 +524,6 @@ extern int pg_mkdir_p(char *path, int omode);
/* port/pqsignal.c */
typedef void (*pqsigfunc) (int signo);
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
-#ifndef WIN32
-extern pqsigfunc pqsignal_no_restart(int signo, pqsigfunc func);
-#else
-#define pqsignal_no_restart(signo, func) pqsignal(signo, func)
-#endif
/* port/quotes.c */
extern char *escape_single_quotes_ascii(const char *src);
diff --git a/src/port/pqsignal.c b/src/port/pqsignal.c
index ecb9ca261f..814d616399 100644
--- a/src/port/pqsignal.c
+++ b/src/port/pqsignal.c
@@ -58,33 +58,4 @@ pqsignal(int signo, pqsigfunc func)
#endif
}
-/*
- * Set up a signal handler, without SA_RESTART, for signal "signo"
- *
- * Returns the previous handler.
- *
- * On Windows, this would be identical to pqsignal(), so don't bother.
- */
-#ifndef WIN32
-
-pqsigfunc
-pqsignal_no_restart(int signo, pqsigfunc func)
-{
- struct sigaction act,
- oact;
-
- act.sa_handler = func;
- sigemptyset(&act.sa_mask);
- 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;
-}
-
-#endif /* !WIN32 */
-
#endif /* !defined(WIN32) || defined(FRONTEND) */