Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9f09529

Browse files
committed
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
1 parent 56a7147 commit 9f09529

File tree

8 files changed

+159
-19
lines changed

8 files changed

+159
-19
lines changed

configure

+1-1
Original file line numberDiff line numberDiff line change
@@ -12494,7 +12494,7 @@ $as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h
1249412494
fi
1249512495

1249612496

12497-
for ac_header in atomic.h crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h mbarrier.h poll.h sys/epoll.h sys/ipc.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/sockio.h sys/tas.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h
12497+
for ac_header in atomic.h crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h mbarrier.h poll.h sys/epoll.h sys/ipc.h sys/prctl.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/sockio.h sys/tas.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h
1249812498
do :
1249912499
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
1250012500
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"

configure.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ AC_SUBST(UUID_LIBS)
12601260

12611261
AC_HEADER_STDBOOL
12621262

1263-
AC_CHECK_HEADERS([atomic.h crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h mbarrier.h poll.h sys/epoll.h sys/ipc.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/sockio.h sys/tas.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h])
1263+
AC_CHECK_HEADERS([atomic.h crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h mbarrier.h poll.h sys/epoll.h sys/ipc.h sys/prctl.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/sockio.h sys/tas.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h])
12641264

12651265
# On BSD, test for net/if.h will fail unless sys/socket.h
12661266
# is included first.

src/backend/storage/ipc/latch.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
11121112
* WL_POSTMASTER_DEATH event would be painful. Re-checking doesn't
11131113
* cost much.
11141114
*/
1115-
if (!PostmasterIsAlive())
1115+
if (!PostmasterIsAliveInternal())
11161116
{
11171117
occurred_events->fd = PGINVALID_SOCKET;
11181118
occurred_events->events = WL_POSTMASTER_DEATH;
@@ -1230,7 +1230,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
12301230
* WL_POSTMASTER_DEATH event would be painful. Re-checking doesn't
12311231
* cost much.
12321232
*/
1233-
if (!PostmasterIsAlive())
1233+
if (!PostmasterIsAliveInternal())
12341234
{
12351235
occurred_events->fd = PGINVALID_SOCKET;
12361236
occurred_events->events = WL_POSTMASTER_DEATH;
@@ -1390,7 +1390,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
13901390
* even though there is no known reason to think that the event could
13911391
* be falsely set on Windows.
13921392
*/
1393-
if (!PostmasterIsAlive())
1393+
if (!PostmasterIsAliveInternal())
13941394
{
13951395
occurred_events->fd = PGINVALID_SOCKET;
13961396
occurred_events->events = WL_POSTMASTER_DEATH;

src/backend/storage/ipc/pmsignal.c

+112-13
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#include <signal.h>
1818
#include <unistd.h>
1919

20+
#ifdef HAVE_SYS_PRCTL_H
21+
#include <sys/prctl.h>
22+
#endif
23+
2024
#include "miscadmin.h"
2125
#include "postmaster/postmaster.h"
2226
#include "replication/walsender.h"
@@ -71,6 +75,35 @@ struct PMSignalData
7175

7276
NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL;
7377

78+
/*
79+
* Signal handler to be notified if postmaster dies.
80+
*/
81+
#ifdef USE_POSTMASTER_DEATH_SIGNAL
82+
volatile sig_atomic_t postmaster_possibly_dead = false;
83+
84+
static void
85+
postmaster_death_handler(int signo)
86+
{
87+
postmaster_possibly_dead = true;
88+
}
89+
90+
/*
91+
* The available signals depend on the OS. SIGUSR1 and SIGUSR2 are already
92+
* used for other things, so choose another one.
93+
*
94+
* Currently, we assume that we can always find a signal to use. That
95+
* seems like a reasonable assumption for all platforms that are modern
96+
* enough to have a parent-death signaling mechanism.
97+
*/
98+
#if defined(SIGINFO)
99+
#define POSTMASTER_DEATH_SIGNAL SIGINFO
100+
#elif defined(SIGPWR)
101+
#define POSTMASTER_DEATH_SIGNAL SIGPWR
102+
#else
103+
#error "cannot find a signal to use for postmaster death"
104+
#endif
105+
106+
#endif /* USE_POSTMASTER_DEATH_SIGNAL */
74107

75108
/*
76109
* PMSignalShmemSize
@@ -266,28 +299,94 @@ MarkPostmasterChildInactive(void)
266299

267300

268301
/*
269-
* PostmasterIsAlive - check whether postmaster process is still alive
302+
* PostmasterIsAliveInternal - check whether postmaster process is still alive
303+
*
304+
* This is the slow path of PostmasterIsAlive(), where the caller has already
305+
* checked 'postmaster_possibly_dead'. (On platforms that don't support
306+
* a signal for parent death, PostmasterIsAlive() is just an alias for this.)
270307
*/
271308
bool
272-
PostmasterIsAlive(void)
309+
PostmasterIsAliveInternal(void)
273310
{
274-
#ifndef WIN32
275-
char c;
276-
ssize_t rc;
311+
#ifdef USE_POSTMASTER_DEATH_SIGNAL
312+
/*
313+
* Reset the flag before checking, so that we don't miss a signal if
314+
* postmaster dies right after the check. If postmaster was indeed dead,
315+
* we'll re-arm it before returning to caller.
316+
*/
317+
postmaster_possibly_dead = false;
318+
#endif
277319

278-
rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1);
279-
if (rc < 0)
320+
#ifndef WIN32
280321
{
281-
if (errno == EAGAIN || errno == EWOULDBLOCK)
322+
char c;
323+
ssize_t rc;
324+
325+
rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1);
326+
327+
/*
328+
* In the usual case, the postmaster is still alive, and there is no
329+
* data in the pipe.
330+
*/
331+
if (rc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
282332
return true;
283333
else
284-
elog(FATAL, "read on postmaster death monitoring pipe failed: %m");
334+
{
335+
/*
336+
* Postmaster is dead, or something went wrong with the read()
337+
* call.
338+
*/
339+
340+
#ifdef USE_POSTMASTER_DEATH_SIGNAL
341+
postmaster_possibly_dead = true;
342+
#endif
343+
344+
if (rc < 0)
345+
elog(FATAL, "read on postmaster death monitoring pipe failed: %m");
346+
else if (rc > 0)
347+
elog(FATAL, "unexpected data in postmaster death monitoring pipe");
348+
349+
return false;
350+
}
285351
}
286-
else if (rc > 0)
287-
elog(FATAL, "unexpected data in postmaster death monitoring pipe");
288352

289-
return false;
290353
#else /* WIN32 */
291-
return (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT);
354+
if (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT)
355+
return true;
356+
else
357+
{
358+
#ifdef USE_POSTMASTER_DEATH_SIGNAL
359+
postmaster_possibly_dead = true;
360+
#endif
361+
return false;
362+
}
292363
#endif /* WIN32 */
293364
}
365+
366+
/*
367+
* PostmasterDeathSignalInit - request signal on postmaster death if possible
368+
*/
369+
void
370+
PostmasterDeathSignalInit(void)
371+
{
372+
#ifdef USE_POSTMASTER_DEATH_SIGNAL
373+
int signum = POSTMASTER_DEATH_SIGNAL;
374+
375+
/* Register our signal handler. */
376+
pqsignal(signum, postmaster_death_handler);
377+
378+
/* Request a signal on parent exit. */
379+
#if defined(PR_SET_PDEATHSIG)
380+
if (prctl(PR_SET_PDEATHSIG, signum) < 0)
381+
elog(ERROR, "could not request parent death signal: %m");
382+
#else
383+
#error "USE_POSTMASTER_DEATH_SIGNAL set, but there is no mechanism to request the signal"
384+
#endif
385+
386+
/*
387+
* Just in case the parent was gone already and we missed it, we'd better
388+
* check the slow way on the first call.
389+
*/
390+
postmaster_possibly_dead = true;
391+
#endif /* USE_POSTMASTER_DEATH_SIGNAL */
392+
}

src/backend/utils/init/miscinit.c

+4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "storage/ipc.h"
4444
#include "storage/latch.h"
4545
#include "storage/pg_shmem.h"
46+
#include "storage/pmsignal.h"
4647
#include "storage/proc.h"
4748
#include "storage/procarray.h"
4849
#include "utils/builtins.h"
@@ -304,6 +305,9 @@ InitPostmasterChild(void)
304305
if (setsid() < 0)
305306
elog(FATAL, "setsid() failed: %m");
306307
#endif
308+
309+
/* Request a signal if the postmaster dies, if possible. */
310+
PostmasterDeathSignalInit();
307311
}
308312

309313
/*

src/include/pg_config.h.in

+3
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,9 @@
600600
/* Define to 1 if you have the <sys/ipc.h> header file. */
601601
#undef HAVE_SYS_IPC_H
602602

603+
/* Define to 1 if you have the <sys/prctl.h> header file. */
604+
#undef HAVE_SYS_PRCTL_H
605+
603606
/* Define to 1 if you have the <sys/pstat.h> header file. */
604607
#undef HAVE_SYS_PSTAT_H
605608

src/include/pg_config.h.win32

+3
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,9 @@
482482
/* Define to 1 if you have the <sys/ipc.h> header file. */
483483
/* #undef HAVE_SYS_IPC_H */
484484

485+
/* Define to 1 if you have the <sys/prctl.h> header file. */
486+
/* #undef HAVE_SYS_PRCTL_H */
487+
485488
/* Define to 1 if you have the <sys/pstat.h> header file. */
486489
/* #undef HAVE_SYS_PSTAT_H */
487490

src/include/storage/pmsignal.h

+32-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
#ifndef PMSIGNAL_H
1515
#define PMSIGNAL_H
1616

17+
#ifdef HAVE_SYS_PRCTL_H
18+
#include "sys/prctl.h"
19+
#endif
20+
1721
/*
1822
* Reasons for signaling the postmaster. We can cope with simultaneous
1923
* signals for different reasons. If the same reason is signaled multiple
@@ -51,6 +55,33 @@ extern bool IsPostmasterChildWalSender(int slot);
5155
extern void MarkPostmasterChildActive(void);
5256
extern void MarkPostmasterChildInactive(void);
5357
extern void MarkPostmasterChildWalSender(void);
54-
extern bool PostmasterIsAlive(void);
58+
extern bool PostmasterIsAliveInternal(void);
59+
extern void PostmasterDeathSignalInit(void);
60+
61+
62+
/*
63+
* Do we have a way to ask for a signal on parent death?
64+
*
65+
* If we do, pmsignal.c will set up a signal handler, that sets a flag when
66+
* the parent dies. Checking the flag first makes PostmasterIsAlive() a lot
67+
* cheaper in usual case that the postmaster is alive.
68+
*/
69+
#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_PDEATHSIG)
70+
#define USE_POSTMASTER_DEATH_SIGNAL
71+
#endif
72+
73+
#ifdef USE_POSTMASTER_DEATH_SIGNAL
74+
extern volatile sig_atomic_t postmaster_possibly_dead;
75+
76+
static inline bool
77+
PostmasterIsAlive(void)
78+
{
79+
if (likely(!postmaster_possibly_dead))
80+
return true;
81+
return PostmasterIsAliveInternal();
82+
}
83+
#else
84+
#define PostmasterIsAlive() PostmasterIsAliveInternal()
85+
#endif
5586

5687
#endif /* PMSIGNAL_H */

0 commit comments

Comments
 (0)