]> granicus.if.org Git - postgresql/commitdiff
Split up process latch initialization for more-fail-soft behavior.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 15 Oct 2012 03:00:01 +0000 (23:00 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 15 Oct 2012 03:00:01 +0000 (23:00 -0400)
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.

src/backend/port/unix_latch.c
src/backend/port/win32_latch.c
src/backend/postmaster/pgarch.c
src/backend/postmaster/pgstat.c
src/backend/postmaster/syslogger.c
src/backend/storage/lmgr/proc.c
src/include/storage/latch.h

index 65b2fc56e0361cf76c0e8d4f7b8e3ed602cee5a0..343bf5e536b7519d6f290af330cdedb9c0f336ca 100644 (file)
@@ -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)
@@ -511,30 +539,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)
index eb46dcad1ba360d84ba2ba614b920965e2f32524..eaa30c4a501c3a07e0d1e551b888aa9d63853fb9 100644 (file)
 #include "storage/shmem.h"
 
 
+void
+InitializeLatchSupport(void)
+{
+       /* currently, nothing to do here for Windows */
+}
+
 void
 InitLatch(volatile Latch *latch)
 {
index 5c43cdde653b7e04f506e20738b1ee9e6293a531..d87618f762186882b19f694c8460a7d394bee179 100644 (file)
@@ -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.
index 73d5b2e39c88ed0f29f4927e3de709930b406595..7684e11a9ae4235399e6cf04384081e5a73695ca 100644 (file)
@@ -3021,6 +3021,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);
 
index 98e0bfbf6155f97511c05e1bbd9386c98d496028..eeba40b928a0951883838515cea1a611ef08c562 100644 (file)
@@ -250,6 +250,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);
 
index 8593713e78f663f628e494f2cb2b19699ffb3202..1dda2f81c30c8e4b7eb1c3737f2fb9a3b35ef864 100644 (file)
@@ -291,6 +291,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).
@@ -464,6 +471,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.
index 71fb4868a000ccdd1afc6dd38bbbc8102c07f87f..f5c7fe1ca5ee9d0ee9706035f0b13f7a02bc1968 100644 (file)
@@ -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);