diff --git a/src/backend/port/unix_latch.c b/src/backend/port/unix_latch.c index 335e9f66afb52163470ee9b69119b7fa16d2bc1c..bbd1810ea530547c75255f02c5be44c559cc03de 100644 --- a/src/backend/port/unix_latch.c +++ b/src/backend/port/unix_latch.c @@ -60,11 +60,41 @@ static volatile sig_atomic_t waiting = false; static int selfpipe_readfd = -1; static int selfpipe_writefd = -1; -/* private function prototypes */ -static void initSelfPipe(void); -static void drainSelfPipe(void); +/* Private function prototypes */ static void sendSelfPipeByte(void); +static void drainSelfPipe(void); + + +/* + * Initialize the process-local latch infrastructure. + * + * This must be called once during startup of any process that can wait on + * latches, before it issues any InitLatch() or OwnLatch() calls. + */ +void +InitializeLatchSupport(void) +{ + int pipefd[2]; + + Assert(selfpipe_readfd == -1); + + /* + * Set up the self-pipe that allows a signal handler to wake up the + * select() in WaitLatch. Make the write-end non-blocking, so that + * SetLatch won't block if the event has already been set many times + * filling the kernel buffer. Make the read-end non-blocking too, so that + * we can easily clear the pipe by reading until EAGAIN or EWOULDBLOCK. + */ + if (pipe(pipefd) < 0) + elog(FATAL, "pipe() failed: %m"); + if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) < 0) + elog(FATAL, "fcntl() failed on read-end of self-pipe: %m"); + if (fcntl(pipefd[1], F_SETFL, O_NONBLOCK) < 0) + elog(FATAL, "fcntl() failed on write-end of self-pipe: %m"); + selfpipe_readfd = pipefd[0]; + selfpipe_writefd = pipefd[1]; +} /* * Initialize a backend-local latch. @@ -72,9 +102,8 @@ static void sendSelfPipeByte(void); void InitLatch(volatile Latch *latch) { - /* Initialize the self-pipe if this is our first latch in the process */ - if (selfpipe_readfd == -1) - initSelfPipe(); + /* Assert InitializeLatchSupport has been called in this process */ + Assert(selfpipe_readfd >= 0); latch->is_set = false; latch->owner_pid = MyProcPid; @@ -116,11 +145,10 @@ InitSharedLatch(volatile Latch *latch) void OwnLatch(volatile Latch *latch) { - Assert(latch->is_shared); + /* Assert InitializeLatchSupport has been called in this process */ + Assert(selfpipe_readfd >= 0); - /* Initialize the self-pipe if this is our first latch in this process */ - if (selfpipe_readfd == -1) - initSelfPipe(); + Assert(latch->is_shared); /* sanity check */ if (latch->owner_pid != 0) @@ -514,30 +542,6 @@ latch_sigusr1_handler(void) sendSelfPipeByte(); } -/* initialize the self-pipe */ -static void -initSelfPipe(void) -{ - int pipefd[2]; - - /* - * Set up the self-pipe that allows a signal handler to wake up the - * select() in WaitLatch. Make the write-end non-blocking, so that - * SetLatch won't block if the event has already been set many times - * filling the kernel buffer. Make the read-end non-blocking too, so that - * we can easily clear the pipe by reading until EAGAIN or EWOULDBLOCK. - */ - if (pipe(pipefd) < 0) - elog(FATAL, "pipe() failed: %m"); - if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) < 0) - elog(FATAL, "fcntl() failed on read-end of self-pipe: %m"); - if (fcntl(pipefd[1], F_SETFL, O_NONBLOCK) < 0) - elog(FATAL, "fcntl() failed on write-end of self-pipe: %m"); - - selfpipe_readfd = pipefd[0]; - selfpipe_writefd = pipefd[1]; -} - /* Send one byte to the self-pipe, to wake up WaitLatch */ static void sendSelfPipeByte(void) diff --git a/src/backend/port/win32_latch.c b/src/backend/port/win32_latch.c index 1f1ed33dc2d358ce27d7d769f4e6849d7d2d810d..0c089fc7ecc80b4c5fff806866ea6b8b46700ded 100644 --- a/src/backend/port/win32_latch.c +++ b/src/backend/port/win32_latch.c @@ -30,6 +30,12 @@ #include "storage/shmem.h" +void +InitializeLatchSupport(void) +{ + /* currently, nothing to do here for Windows */ +} + void InitLatch(volatile Latch *latch) { diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index d5d8be0587d663631e27886da66cdae71f8448db..a6c0aea3d6a957ee4f4a1652b82987f1d1aeae9f 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -234,8 +234,6 @@ PgArchiverMain(int argc, char *argv[]) MyProcPid = getpid(); /* reset MyProcPid */ - InitLatch(&mainloop_latch); /* initialize latch used in main loop */ - MyStartTime = time(NULL); /* record Start Time for logging */ /* @@ -247,6 +245,10 @@ PgArchiverMain(int argc, char *argv[]) elog(FATAL, "setsid() failed: %m"); #endif + InitializeLatchSupport(); /* needed for latch waits */ + + InitLatch(&mainloop_latch); /* initialize latch used in main loop */ + /* * Ignore all signals usually bound to some action in the postmaster, * except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT. diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 8389d5c4ae932a24d22a8d3fe20920a2bdede7c8..be3adf16d922039a636b59842f7b1b3f1440707d 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -3022,6 +3022,8 @@ PgstatCollectorMain(int argc, char *argv[]) elog(FATAL, "setsid() failed: %m"); #endif + InitializeLatchSupport(); /* needed for latch waits */ + /* Initialize private latch for use by signal handlers */ InitLatch(&pgStatLatch); diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index 0febf64d87f2b337b70e4c9e49d4399b6aa03c0e..cccec743b0d28922964acd5b597ed74548588856 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -251,6 +251,8 @@ SysLoggerMain(int argc, char *argv[]) elog(FATAL, "setsid() failed: %m"); #endif + InitializeLatchSupport(); /* needed for latch waits */ + /* Initialize private latch for use by signal handlers */ InitLatch(&sysLoggerLatch); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 677042962a0e9e5723dc1fcf81d0cbb2f44446c2..5ae1506038cc59ebea9d6a7cee3ccebd3adc9819 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -279,6 +279,13 @@ InitProcess(void) if (MyProc != NULL) elog(ERROR, "you already exist"); + /* + * Initialize process-local latch support. This could fail if the kernel + * is low on resources, and if so we want to exit cleanly before acquiring + * any shared-memory resources. + */ + InitializeLatchSupport(); + /* * Try to get a proc struct from the free list. If this fails, we must be * out of PGPROC structures (not to mention semaphores). @@ -451,6 +458,13 @@ InitAuxiliaryProcess(void) if (MyProc != NULL) elog(ERROR, "you already exist"); + /* + * Initialize process-local latch support. This could fail if the kernel + * is low on resources, and if so we want to exit cleanly before acquiring + * any shared-memory resources. + */ + InitializeLatchSupport(); + /* * We use the ProcStructLock to protect assignment and releasing of * AuxiliaryProcs entries. diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 71fb4868a000ccdd1afc6dd38bbbc8102c07f87f..f5c7fe1ca5ee9d0ee9706035f0b13f7a02bc1968 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -111,6 +111,7 @@ typedef struct /* * prototypes for functions in latch.c */ +extern void InitializeLatchSupport(void); extern void InitLatch(volatile Latch *latch); extern void InitSharedLatch(volatile Latch *latch); extern void OwnLatch(volatile Latch *latch);