* WL_POSTMASTER_DEATH event would be painful. Re-checking doesn't
* cost much.
*/
- if (!PostmasterIsAlive())
+ if (!PostmasterIsAliveInternal())
{
occurred_events->fd = PGINVALID_SOCKET;
occurred_events->events = WL_POSTMASTER_DEATH;
* WL_POSTMASTER_DEATH event would be painful. Re-checking doesn't
* cost much.
*/
- if (!PostmasterIsAlive())
+ if (!PostmasterIsAliveInternal())
{
occurred_events->fd = PGINVALID_SOCKET;
occurred_events->events = WL_POSTMASTER_DEATH;
* even though there is no known reason to think that the event could
* be falsely set on Windows.
*/
- if (!PostmasterIsAlive())
+ if (!PostmasterIsAliveInternal())
{
occurred_events->fd = PGINVALID_SOCKET;
occurred_events->events = WL_POSTMASTER_DEATH;
#include <signal.h>
#include <unistd.h>
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
#include "miscadmin.h"
#include "postmaster/postmaster.h"
#include "replication/walsender.h"
NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL;
+/*
+ * Signal handler to be notified if postmaster dies.
+ */
+#ifdef USE_POSTMASTER_DEATH_SIGNAL
+volatile sig_atomic_t postmaster_possibly_dead = false;
+
+static void
+postmaster_death_handler(int signo)
+{
+ postmaster_possibly_dead = true;
+}
+
+/*
+ * The available signals depend on the OS. SIGUSR1 and SIGUSR2 are already
+ * used for other things, so choose another one.
+ *
+ * Currently, we assume that we can always find a signal to use. That
+ * seems like a reasonable assumption for all platforms that are modern
+ * enough to have a parent-death signaling mechanism.
+ */
+#if defined(SIGINFO)
+#define POSTMASTER_DEATH_SIGNAL SIGINFO
+#elif defined(SIGPWR)
+#define POSTMASTER_DEATH_SIGNAL SIGPWR
+#else
+#error "cannot find a signal to use for postmaster death"
+#endif
+
+#endif /* USE_POSTMASTER_DEATH_SIGNAL */
/*
* PMSignalShmemSize
/*
- * PostmasterIsAlive - check whether postmaster process is still alive
+ * PostmasterIsAliveInternal - check whether postmaster process is still alive
+ *
+ * This is the slow path of PostmasterIsAlive(), where the caller has already
+ * checked 'postmaster_possibly_dead'. (On platforms that don't support
+ * a signal for parent death, PostmasterIsAlive() is just an alias for this.)
*/
bool
-PostmasterIsAlive(void)
+PostmasterIsAliveInternal(void)
{
-#ifndef WIN32
- char c;
- ssize_t rc;
+#ifdef USE_POSTMASTER_DEATH_SIGNAL
+ /*
+ * Reset the flag before checking, so that we don't miss a signal if
+ * postmaster dies right after the check. If postmaster was indeed dead,
+ * we'll re-arm it before returning to caller.
+ */
+ postmaster_possibly_dead = false;
+#endif
- rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1);
- if (rc < 0)
+#ifndef WIN32
{
- if (errno == EAGAIN || errno == EWOULDBLOCK)
+ char c;
+ ssize_t rc;
+
+ rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1);
+
+ /*
+ * In the usual case, the postmaster is still alive, and there is no
+ * data in the pipe.
+ */
+ if (rc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
return true;
else
- elog(FATAL, "read on postmaster death monitoring pipe failed: %m");
+ {
+ /*
+ * Postmaster is dead, or something went wrong with the read()
+ * call.
+ */
+
+#ifdef USE_POSTMASTER_DEATH_SIGNAL
+ postmaster_possibly_dead = true;
+#endif
+
+ if (rc < 0)
+ elog(FATAL, "read on postmaster death monitoring pipe failed: %m");
+ else if (rc > 0)
+ elog(FATAL, "unexpected data in postmaster death monitoring pipe");
+
+ return false;
+ }
}
- else if (rc > 0)
- elog(FATAL, "unexpected data in postmaster death monitoring pipe");
- return false;
#else /* WIN32 */
- return (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT);
+ if (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT)
+ return true;
+ else
+ {
+#ifdef USE_POSTMASTER_DEATH_SIGNAL
+ postmaster_possibly_dead = true;
+#endif
+ return false;
+ }
#endif /* WIN32 */
}
+
+/*
+ * PostmasterDeathSignalInit - request signal on postmaster death if possible
+ */
+void
+PostmasterDeathSignalInit(void)
+{
+#ifdef USE_POSTMASTER_DEATH_SIGNAL
+ int signum = POSTMASTER_DEATH_SIGNAL;
+
+ /* Register our signal handler. */
+ pqsignal(signum, postmaster_death_handler);
+
+ /* Request a signal on parent exit. */
+#if defined(PR_SET_PDEATHSIG)
+ if (prctl(PR_SET_PDEATHSIG, signum) < 0)
+ elog(ERROR, "could not request parent death signal: %m");
+#else
+#error "USE_POSTMASTER_DEATH_SIGNAL set, but there is no mechanism to request the signal"
+#endif
+
+ /*
+ * Just in case the parent was gone already and we missed it, we'd better
+ * check the slow way on the first call.
+ */
+ postmaster_possibly_dead = true;
+#endif /* USE_POSTMASTER_DEATH_SIGNAL */
+}
#ifndef PMSIGNAL_H
#define PMSIGNAL_H
+#ifdef HAVE_SYS_PRCTL_H
+#include "sys/prctl.h"
+#endif
+
/*
* Reasons for signaling the postmaster. We can cope with simultaneous
* signals for different reasons. If the same reason is signaled multiple
extern void MarkPostmasterChildActive(void);
extern void MarkPostmasterChildInactive(void);
extern void MarkPostmasterChildWalSender(void);
-extern bool PostmasterIsAlive(void);
+extern bool PostmasterIsAliveInternal(void);
+extern void PostmasterDeathSignalInit(void);
+
+
+/*
+ * Do we have a way to ask for a signal on parent death?
+ *
+ * If we do, pmsignal.c will set up a signal handler, that sets a flag when
+ * the parent dies. Checking the flag first makes PostmasterIsAlive() a lot
+ * cheaper in usual case that the postmaster is alive.
+ */
+#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_PDEATHSIG)
+#define USE_POSTMASTER_DEATH_SIGNAL
+#endif
+
+#ifdef USE_POSTMASTER_DEATH_SIGNAL
+extern volatile sig_atomic_t postmaster_possibly_dead;
+
+static inline bool
+PostmasterIsAlive(void)
+{
+ if (likely(!postmaster_possibly_dead))
+ return true;
+ return PostmasterIsAliveInternal();
+}
+#else
+#define PostmasterIsAlive() PostmasterIsAliveInternal()
+#endif
#endif /* PMSIGNAL_H */