From c1cf4c743597a776fbbd50a276a4177ad4e5a34b Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Wed, 18 Apr 2018 00:59:39 +0100 Subject: [PATCH 1/2] 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. Author: Thomas Munro, based on a suggestion from Andres Freund Discussion: https://postgr.es/m/7261eb39-0369-f2f4-1bb5-62f3b6083b5e%40iki.fi https://postgr.es/m/20180411002643.6buofht4ranhei7k%40alap3.anarazel.de --- configure | 40 +++++++++++++++++++++++++++ configure.in | 22 +++++++++++++++ src/backend/postmaster/postmaster.c | 2 ++ src/backend/storage/ipc/latch.c | 6 ++-- src/backend/storage/ipc/pmsignal.c | 55 ++++++++++++++++++++++++++++++++++++- src/include/c.h | 11 ++++++++ src/include/pg_config.h.in | 3 ++ src/include/storage/pmsignal.h | 17 +++++++++++- 8 files changed, 151 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 56f18dfbc26..29ba38ee174 100755 --- a/configure +++ b/configure @@ -9717,6 +9717,46 @@ program to use during the build." "$LINENO" 5 fi fi +# +# Signals to detect parent process death +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for parent death signal support" >&5 +$as_echo_n "checking for parent death signal support... " >&6; } + +# Linux has prctl(PR_SET_PDEATHSIG, ...) +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main () +{ + +#ifndef PR_SET_PDEATHSIG +#error PR_SET_PDEATHSIG not defined +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + HAVE_PR_SET_PDEATHSIG=1 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test x"$HAVE_PR_SET_PDEATHSIG" = "x1"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: PR_SET_PDEATHSIG" >&5 +$as_echo "PR_SET_PDEATHSIG" >&6; } + +$as_echo "#define HAVE_PR_SET_PDEATHSIG 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + # # Pthreads # diff --git a/configure.in b/configure.in index da02a56ec66..31dda503628 100644 --- a/configure.in +++ b/configure.in @@ -1022,6 +1022,28 @@ program to use during the build.]) fi fi +# +# Signals to detect parent process death +# +AC_MSG_CHECKING([for parent death signal support]) + +# Linux has prctl(PR_SET_PDEATHSIG, ...) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include +], [ +#ifndef PR_SET_PDEATHSIG +#error PR_SET_PDEATHSIG not defined +#endif +])], [HAVE_PR_SET_PDEATHSIG=1]) + +if test x"$HAVE_PR_SET_PDEATHSIG" = "x1"; then + AC_MSG_RESULT(PR_SET_PDEATHSIG) + AC_DEFINE(HAVE_PR_SET_PDEATHSIG, 1, + [Define to 1 if the system supports PR_SET_PDEATHSIG]) +else + AC_MSG_RESULT(no) +fi + # # Pthreads # diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index d948369f3ea..c3ef7ee38ca 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -2484,6 +2484,8 @@ ClosePostmasterPorts(bool am_syslogger) if (bonjour_sdref) close(DNSServiceRefSockFD(bonjour_sdref)); #endif + + PostmasterDeathInit(); } diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c index e6706f7fb80..f6dda9cc9ac 100644 --- a/src/backend/storage/ipc/latch.c +++ b/src/backend/storage/ipc/latch.c @@ -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; diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c index be61858fc67..c415b8b5dbb 100644 --- a/src/backend/storage/ipc/pmsignal.c +++ b/src/backend/storage/ipc/pmsignal.c @@ -23,6 +23,9 @@ #include "storage/pmsignal.h" #include "storage/shmem.h" +#if defined(HAVE_PR_SET_PDEATHSIG) +#include +#endif /* * The postmaster is signaled by its children by sending SIGUSR1. The @@ -71,6 +74,28 @@ struct PMSignalData NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL; +#ifdef USE_POSTMASTER_DEATH_SIGNAL +sig_atomic_t postmaster_possibly_dead = false; + +static void +postmaster_death_handler(int signo) +{ + postmaster_possibly_dead = true; +} + +/* + * The available signals depends on the OS and architecture. SIGUSR1 and + * SIGUSR2 are already used for other things, so choose another one. + */ +#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 /* * PMSignalShmemSize @@ -269,7 +294,7 @@ MarkPostmasterChildInactive(void) * PostmasterIsAlive - check whether postmaster process is still alive */ bool -PostmasterIsAlive(void) +PostmasterIsAliveInternal(void) { #ifndef WIN32 char c; @@ -291,3 +316,31 @@ PostmasterIsAlive(void) return (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT); #endif /* WIN32 */ } + +/* + * PostmasterDeathInit - request signal on postmaster death if possible + */ +void +PostmasterDeathInit(void) +{ +#ifdef USE_POSTMASTER_DEATH_SIGNAL + int signum; + + /* Register our signal handler. */ + signum = POSTMASTER_DEATH_SIGNAL; + pqsignal(signum, postmaster_death_handler); + + /* Request a signal on parent exit. */ +#ifdef HAVE_PR_SET_PDEATHSIG + if (prctl(PR_SET_PDEATHSIG, signum) < 0) + elog(ERROR, "could not request parent death signal: %m"); +#endif + + /* + * Just in case the parent was gone already and we missed it, we'd + * better check the slow way. + */ + if (!PostmasterIsAliveInternal()) + postmaster_possibly_dead = true; +#endif +} diff --git a/src/include/c.h b/src/include/c.h index 95e9aeded9d..116c2a24814 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -1155,6 +1155,17 @@ extern int fdatasync(int fildes); #define NON_EXEC_STATIC static #endif +/* + * Do we have a way to ask for a signal on parent death? Build with + * NO_POSTMASTER_DEATH_SIGNAL defined to inhibit the use of death signals on + * platforms that support it, for testing purposes. + */ +#ifndef NO_POSTMASTER_DEATH_SIGNAL +#if defined(HAVE_PR_SET_PDEATHSIG) +#define USE_POSTMASTER_DEATH_SIGNAL +#endif +#endif + /* /port compatibility functions */ #include "port.h" diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index f3620231a71..5454f0d4807 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -428,6 +428,9 @@ /* Define to 1 if the assembler supports PPC's LWARX mutex hint bit. */ #undef HAVE_PPC_LWARX_MUTEX_HINT +/* Define to 1 if the system supports PR_SET_PDEATHSIG */ +#undef HAVE_PR_SET_PDEATHSIG + /* Define to 1 if you have the `pstat' function. */ #undef HAVE_PSTAT diff --git a/src/include/storage/pmsignal.h b/src/include/storage/pmsignal.h index bec162cc16d..6667853bdc3 100644 --- a/src/include/storage/pmsignal.h +++ b/src/include/storage/pmsignal.h @@ -51,6 +51,21 @@ extern bool IsPostmasterChildWalSender(int slot); extern void MarkPostmasterChildActive(void); extern void MarkPostmasterChildInactive(void); extern void MarkPostmasterChildWalSender(void); -extern bool PostmasterIsAlive(void); +extern bool PostmasterIsAliveInternal(void); +extern void PostmasterDeathInit(void); + +#ifdef USE_POSTMASTER_DEATH_SIGNAL +extern sig_atomic_t postmaster_possibly_dead; +#endif + +static inline bool +PostmasterIsAlive(void) +{ +#ifdef USE_POSTMASTER_DEATH_SIGNAL + if (likely(!postmaster_possibly_dead)) + return true; +#endif + return PostmasterIsAliveInternal(); +} #endif /* PMSIGNAL_H */ -- 2.16.2