commit b09f7cf075765519da25dd03d581fd242bddc012
Author: Chris Traverswq <chris.travers@gmail.com>
Date:   Thu Sep 6 12:09:08 2018 +0200

    Fix for race condition between startup process and parallel worker.
    
    The startup process can send a SIGUSR1 signal every 5ms and this can cause
    the parallel worker to never complete the syscall that it continues to retry.
    
    THe fix checks for pending interrupts and addresses program flow accordingly,
    treating an incoming SIGUSR1, SIGTERM, and similar as subject to cleanup similar
    to an ENOSPC.
    
    Thanks to Ildar Musin, Oleksii Kliukin, and Murak Kabilov for review!

diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c
index 77e1bab54b..9a6495c3e0 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -47,6 +47,7 @@
  */
 
 #include "postgres.h"
+#include "miscadmin.h"
 
 #include <fcntl.h>
 #include <unistd.h>
@@ -330,10 +331,26 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
 			shm_unlink(name);
 		errno = save_errno;
 
+		/*
+		 * If we received a query cancel or termination signal, we will have
+		 * EINTR set here. It may not be safe to handle interrupts here of this
+		 * sort so we just continue to the next point where it is.
+		 *
+		 * However, the safety of exceptions here are determined by the elevel
+		 * passed in by the function, so if the elevel is ERROR or higher we
+		 * check for interrupts here if there is an EINTR errno raised by the
+		 * resize operation.  Otherwise we log the failure and move on to the
+		 * next point where interrupts are checked.  This allows for the
+		 * caller to handle cleanup and move to a safe point first.
+		 */
+		if (errno == EINTR && elevel >= ERROR)
+			CHECK_FOR_INTERRUPTS();
+
 		ereport(elevel,
 				(errcode_for_dynamic_shared_memory(),
 				 errmsg("could not resize shared memory segment \"%s\" to %zu bytes: %m",
 						name, request_size)));
+
 		return false;
 	}
 
@@ -419,11 +436,19 @@ dsm_impl_posix_resize(int fd, off_t size)
 #if defined(HAVE_POSIX_FALLOCATE) && defined(__linux__)
 	if (rc == 0)
 	{
-		/* We may get interrupted, if so just retry. */
+		/*
+		 * We may get interrupted, if so just retry unless certain signals are
+		 * sent
+		 *
+		 * In rare cases it is possible for a signal loop to perpetually
+		 * pre-empt this call, so where the signal would cause the query to
+		 * cancel or the process to terminate we exit the loop and return the
+		 * interrupted error to the caller who is now responsible for that.
+		 */
 		do
 		{
 			rc = posix_fallocate(fd, 0, size);
-		} while (rc == EINTR);
+		} while (rc == EINTR && !(ProcDiePending || QueryCancelPending));
 
 		/*
 		 * The caller expects errno to be set, but posix_fallocate() doesn't
