1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-07 00:36:50 +03:00

Use signals for postmaster death on Linux.

Linux provides a way to ask for a signal when your parent process dies.
Use that to make PostmasterIsAlive() very cheap.

Based on a suggestion from Andres Freund.

Author: Thomas Munro, Heikki Linnakangas
Reviewed-By: Michael Paquier
Discussion: https://postgr.es/m/7261eb39-0369-f2f4-1bb5-62f3b6083b5e%40iki.fi
Discussion: https://postgr.es/m/20180411002643.6buofht4ranhei7k%40alap3.anarazel.de
This commit is contained in:
Thomas Munro
2018-07-11 12:40:58 +12:00
parent 56a7147213
commit 9f09529952
8 changed files with 160 additions and 20 deletions

View File

@ -1112,7 +1112,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
* 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;
@ -1230,7 +1230,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
* 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;
@ -1390,7 +1390,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
* 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;

View File

@ -17,6 +17,10 @@
#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"
@ -71,6 +75,35 @@ struct PMSignalData
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
@ -266,28 +299,94 @@ MarkPostmasterChildInactive(void)
/*
* 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");
}
else if (rc > 0)
elog(FATAL, "unexpected data in postmaster death monitoring pipe");
{
/*
* 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;
}
}
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 */
}