Skip to content

Commit 4d4005c

Browse files
committed
Split up process latch initialization for more-fail-soft behavior.
In the previous coding, new backend processes would attempt to create their self-pipe during the OwnLatch call in InitProcess. However, pipe creation could fail if the kernel is short of resources; and the system does not recover gracefully from a FATAL error right there, since we have armed the dead-man switch for this process and not yet set up the on_shmem_exit callback that would disarm it. The postmaster then forces an unnecessary database-wide crash and restart, as reported by Sean Chittenden. There are various ways we could rearrange the code to fix this, but the simplest and sanest seems to be to split out creation of the self-pipe into a new function InitializeLatchSupport, which must be called from a place where failure is allowed. For most processes that gets called in InitProcess or InitAuxiliaryProcess, but processes that don't call either but still use latches need their own calls. Back-patch to 9.1, which has only a part of the latch logic that 9.2 and HEAD have, but nonetheless includes this bug.
1 parent 0fbd443 commit 4d4005c

File tree

7 files changed

+67
-36
lines changed

7 files changed

+67
-36
lines changed

src/backend/port/unix_latch.c

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,50 @@ static volatile sig_atomic_t waiting = false;
6060
static int selfpipe_readfd = -1;
6161
static int selfpipe_writefd = -1;
6262

63-
/* private function prototypes */
64-
static void initSelfPipe(void);
65-
static void drainSelfPipe(void);
63+
/* Private function prototypes */
6664
static void sendSelfPipeByte(void);
65+
static void drainSelfPipe(void);
66+
67+
68+
/*
69+
* Initialize the process-local latch infrastructure.
70+
*
71+
* This must be called once during startup of any process that can wait on
72+
* latches, before it issues any InitLatch() or OwnLatch() calls.
73+
*/
74+
void
75+
InitializeLatchSupport(void)
76+
{
77+
int pipefd[2];
78+
79+
Assert(selfpipe_readfd == -1);
80+
81+
/*
82+
* Set up the self-pipe that allows a signal handler to wake up the
83+
* select() in WaitLatch. Make the write-end non-blocking, so that
84+
* SetLatch won't block if the event has already been set many times
85+
* filling the kernel buffer. Make the read-end non-blocking too, so that
86+
* we can easily clear the pipe by reading until EAGAIN or EWOULDBLOCK.
87+
*/
88+
if (pipe(pipefd) < 0)
89+
elog(FATAL, "pipe() failed: %m");
90+
if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) < 0)
91+
elog(FATAL, "fcntl() failed on read-end of self-pipe: %m");
92+
if (fcntl(pipefd[1], F_SETFL, O_NONBLOCK) < 0)
93+
elog(FATAL, "fcntl() failed on write-end of self-pipe: %m");
6794

95+
selfpipe_readfd = pipefd[0];
96+
selfpipe_writefd = pipefd[1];
97+
}
6898

6999
/*
70100
* Initialize a backend-local latch.
71101
*/
72102
void
73103
InitLatch(volatile Latch *latch)
74104
{
75-
/* Initialize the self-pipe if this is our first latch in the process */
76-
if (selfpipe_readfd == -1)
77-
initSelfPipe();
105+
/* Assert InitializeLatchSupport has been called in this process */
106+
Assert(selfpipe_readfd >= 0);
78107

79108
latch->is_set = false;
80109
latch->owner_pid = MyProcPid;
@@ -116,11 +145,10 @@ InitSharedLatch(volatile Latch *latch)
116145
void
117146
OwnLatch(volatile Latch *latch)
118147
{
119-
Assert(latch->is_shared);
148+
/* Assert InitializeLatchSupport has been called in this process */
149+
Assert(selfpipe_readfd >= 0);
120150

121-
/* Initialize the self-pipe if this is our first latch in this process */
122-
if (selfpipe_readfd == -1)
123-
initSelfPipe();
151+
Assert(latch->is_shared);
124152

125153
/* sanity check */
126154
if (latch->owner_pid != 0)
@@ -511,30 +539,6 @@ latch_sigusr1_handler(void)
511539
sendSelfPipeByte();
512540
}
513541

514-
/* initialize the self-pipe */
515-
static void
516-
initSelfPipe(void)
517-
{
518-
int pipefd[2];
519-
520-
/*
521-
* Set up the self-pipe that allows a signal handler to wake up the
522-
* select() in WaitLatch. Make the write-end non-blocking, so that
523-
* SetLatch won't block if the event has already been set many times
524-
* filling the kernel buffer. Make the read-end non-blocking too, so that
525-
* we can easily clear the pipe by reading until EAGAIN or EWOULDBLOCK.
526-
*/
527-
if (pipe(pipefd) < 0)
528-
elog(FATAL, "pipe() failed: %m");
529-
if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) < 0)
530-
elog(FATAL, "fcntl() failed on read-end of self-pipe: %m");
531-
if (fcntl(pipefd[1], F_SETFL, O_NONBLOCK) < 0)
532-
elog(FATAL, "fcntl() failed on write-end of self-pipe: %m");
533-
534-
selfpipe_readfd = pipefd[0];
535-
selfpipe_writefd = pipefd[1];
536-
}
537-
538542
/* Send one byte to the self-pipe, to wake up WaitLatch */
539543
static void
540544
sendSelfPipeByte(void)

src/backend/port/win32_latch.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030
#include "storage/shmem.h"
3131

3232

33+
void
34+
InitializeLatchSupport(void)
35+
{
36+
/* currently, nothing to do here for Windows */
37+
}
38+
3339
void
3440
InitLatch(volatile Latch *latch)
3541
{

src/backend/postmaster/pgarch.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,6 @@ PgArchiverMain(int argc, char *argv[])
234234

235235
MyProcPid = getpid(); /* reset MyProcPid */
236236

237-
InitLatch(&mainloop_latch); /* initialize latch used in main loop */
238-
239237
MyStartTime = time(NULL); /* record Start Time for logging */
240238

241239
/*
@@ -247,6 +245,10 @@ PgArchiverMain(int argc, char *argv[])
247245
elog(FATAL, "setsid() failed: %m");
248246
#endif
249247

248+
InitializeLatchSupport(); /* needed for latch waits */
249+
250+
InitLatch(&mainloop_latch); /* initialize latch used in main loop */
251+
250252
/*
251253
* Ignore all signals usually bound to some action in the postmaster,
252254
* except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT.

src/backend/postmaster/pgstat.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3021,6 +3021,8 @@ PgstatCollectorMain(int argc, char *argv[])
30213021
elog(FATAL, "setsid() failed: %m");
30223022
#endif
30233023

3024+
InitializeLatchSupport(); /* needed for latch waits */
3025+
30243026
/* Initialize private latch for use by signal handlers */
30253027
InitLatch(&pgStatLatch);
30263028

src/backend/postmaster/syslogger.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ SysLoggerMain(int argc, char *argv[])
250250
elog(FATAL, "setsid() failed: %m");
251251
#endif
252252

253+
InitializeLatchSupport(); /* needed for latch waits */
254+
253255
/* Initialize private latch for use by signal handlers */
254256
InitLatch(&sysLoggerLatch);
255257

src/backend/storage/lmgr/proc.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,13 @@ InitProcess(void)
291291
if (MyProc != NULL)
292292
elog(ERROR, "you already exist");
293293

294+
/*
295+
* Initialize process-local latch support. This could fail if the kernel
296+
* is low on resources, and if so we want to exit cleanly before acquiring
297+
* any shared-memory resources.
298+
*/
299+
InitializeLatchSupport();
300+
294301
/*
295302
* Try to get a proc struct from the free list. If this fails, we must be
296303
* out of PGPROC structures (not to mention semaphores).
@@ -464,6 +471,13 @@ InitAuxiliaryProcess(void)
464471
if (MyProc != NULL)
465472
elog(ERROR, "you already exist");
466473

474+
/*
475+
* Initialize process-local latch support. This could fail if the kernel
476+
* is low on resources, and if so we want to exit cleanly before acquiring
477+
* any shared-memory resources.
478+
*/
479+
InitializeLatchSupport();
480+
467481
/*
468482
* We use the ProcStructLock to protect assignment and releasing of
469483
* AuxiliaryProcs entries.

src/include/storage/latch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ typedef struct
111111
/*
112112
* prototypes for functions in latch.c
113113
*/
114+
extern void InitializeLatchSupport(void);
114115
extern void InitLatch(volatile Latch *latch);
115116
extern void InitSharedLatch(volatile Latch *latch);
116117
extern void OwnLatch(volatile Latch *latch);

0 commit comments

Comments
 (0)