0006-WIP-Process-die-interrupts-while-reading-writing-fro.patch

text/x-patch

Filename: 0006-WIP-Process-die-interrupts-while-reading-writing-fro.patch
Type: text/x-patch
Part: 5
Message: Re: Escaping from blocked send() reprised.

Patch

Format: unified
Series: patch 0006
File+
src/backend/libpq/be-secure.c 14 16
src/backend/libpq/be-secure-openssl.c 5 2
src/backend/tcop/postgres.c 25 0
src/include/tcop/tcopprot.h 1 0
>From d0887c4db8b38ffb27061e7f7709d0f9e2402392 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Sun, 28 Sep 2014 00:22:39 +0200
Subject: [PATCH 6/6] WIP: Process 'die' interrupts while reading/writing from
 a socket.

Per discussion with Kyotaro HORIGUCHI and Heikki Linnakangas
---
 src/backend/libpq/be-secure-openssl.c |  7 +++++--
 src/backend/libpq/be-secure.c         | 30 ++++++++++++++----------------
 src/backend/tcop/postgres.c           | 25 +++++++++++++++++++++++++
 src/include/tcop/tcopprot.h           |  1 +
 4 files changed, 45 insertions(+), 18 deletions(-)

diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 3a70f43..1fc4c76 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -634,10 +634,13 @@ wloop:
 			/* Don't retry if the socket is in nonblocking mode. */
 			if (port->noblock)
 				break;
+
 			/*
-			 * XXX: We'll, at some later point, likely want to add interrupt
-			 * processing here.
+			 * Check for interrupts here, in addition to secure_write(),
+			 * because a interrupted write in secure_raw_write() will only
+			 * return here, not secure_write().
 			 */
+			ProcessClientWriteInterrupt(true);
 			goto wloop;
 		case SSL_ERROR_SYSCALL:
 			/* leave it to caller to ereport the value of errno */
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 71742a6..cae2955 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -224,16 +224,10 @@ retry:
 		n = secure_raw_write(port, ptr, len);
 	}
 
-	/*
-	 * XXX: We'll, at some later point, likely want to add interrupt
-	 * processing here.
-	 */
+	/* Process interrupts that happened while (or before) writing. */
+	ProcessClientWriteInterrupt(!port->noblock && n < 0);
 
-	/*
-	 * Retry after processing interrupts. This can be triggered even though we
-	 * don't check for latch set's during writing yet, because SSL
-	 * renegotiations might have required reading from the socket.
-	 */
+	/* retry after processing interrupts */
 	if (n < 0 && errno == EINTR)
 	{
 		goto retry;
@@ -262,16 +256,20 @@ wloop:
 		int		w;
 		int		save_errno = errno;
 
-		/*
-		 * XXX: We'll, at some later point, likely want to add interrupt
-		 * processing here.  If set we'd not retry directly, but return. That
-		 * way we don't do anything while (possibly) inside a ssl library.
-		 */
 		w = WaitLatchOrSocket(MyLatch,
-							  WL_SOCKET_WRITEABLE,
+							  WL_LATCH_SET | WL_SOCKET_WRITEABLE,
 							  port->sock, 0);
 
-		if (w & WL_SOCKET_WRITEABLE)
+		if (w & WL_LATCH_SET)
+		{
+			ResetLatch(&MyProc->procLatch);
+			/*
+			 * Force a return, so interrupts can be processed when not
+			 * (possibly) underneath a ssl library.
+			 */
+			errno = EINTR;
+		}
+		else if (w & WL_SOCKET_WRITEABLE)
 		{
 			goto wloop;
 		}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index c4e3a61..0e5b317 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -519,10 +519,35 @@ ProcessClientReadInterrupt(void)
 		if (notifyInterruptPending)
 			ProcessNotifyInterrupt();
 	}
+	else if (ProcDiePending)
+	{
+		/*
+		 * We're dying. It's safe (and sane) to handle that now.
+		 */
+		CHECK_FOR_INTERRUPTS();
+	}
 
 	errno = save_errno;
 }
 
+void
+ProcessClientWriteInterrupt(bool blocked)
+{
+	/*
+	 * We only want to process the interrupt here if socket writes are
+	 * blocking to increase the chance to get an error message to the
+	 * client. If we're not blocked there'll soon be a
+	 * CHECK_FOR_INTERRUPTS(). But if we're blocked we'll never get out of
+	 * that situation if the client has died.
+	 */
+	if (ProcDiePending && blocked)
+	{
+		/*
+		 * We're dying. It's safe (and sane) to handle that now.
+		 */
+		CHECK_FOR_INTERRUPTS();
+	}
+}
 
 /*
  * Do raw parsing (only).
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index fe8c725..fc04a3e 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -68,6 +68,7 @@ extern void FloatExceptionHandler(SIGNAL_ARGS) __attribute__((noreturn));
 extern void RecoveryConflictInterrupt(ProcSignalReason reason); /* called from SIGUSR1
 																 * handler */
 extern void ProcessClientReadInterrupt(void);
+extern void ProcessClientWriteInterrupt(bool blocked);
 
 extern void process_postgres_switches(int argc, char *argv[],
 						  GucContext ctx, const char **dbname);
-- 
2.2.1.212.gc5b9256