0004-Heavily-WIP-Process-die-interrupts-while-reading-wri.patch

text/x-patch

Filename: 0004-Heavily-WIP-Process-die-interrupts-while-reading-wri.patch
Type: text/x-patch
Part: 3
Message: Re: Escaping from blocked send() reprised.

Patch

Format: unified
Series: patch 0004
File+
src/backend/libpq/be-secure.c 20 3
src/backend/libpq/be-secure-openssl.c 6 1
src/backend/tcop/postgres.c 25 0
src/include/tcop/tcopprot.h 1 0
>From 222254b14be455e750fd84be3a017a3c47d3f384 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Sun, 28 Sep 2014 00:22:39 +0200
Subject: [PATCH 4/4] Heavily-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         | 23 ++++++++++++++++++++---
 src/backend/tcop/postgres.c           | 25 +++++++++++++++++++++++++
 src/include/tcop/tcopprot.h           |  1 +
 4 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 6fc6903..22e2a7b 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -638,7 +638,12 @@ wloop:
 			break;
 		case SSL_ERROR_WANT_READ:
 		case SSL_ERROR_WANT_WRITE:
-			/* XXX: We likely will want to process some interrupts 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(err == SSL_ERROR_WANT_WRITE);
 			if (port->noblock)
 			{
 				errno = EWOULDBLOCK;
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 7b5b30f..6831dd8 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -199,6 +199,7 @@ secure_write(Port *port, void *ptr, size_t len)
 {
 	ssize_t		n;
 
+retry:
 #ifdef USE_SSL
 	if (port->ssl_in_use)
 	{
@@ -210,7 +211,14 @@ secure_write(Port *port, void *ptr, size_t len)
 		n = secure_raw_write(port, ptr, len);
 	}
 
-	/* XXX: We likely will want to process some interrupts here */
+	/* Process interrupts that happened while (or before) writing. */
+	ProcessClientWriteInterrupt(!port->noblock && n < 0);
+
+	/* retry after processing interrupts */
+	if (n < 0 && errno == EINTR)
+	{
+		goto retry;
+	}
 
 	return n;
 }
@@ -236,10 +244,19 @@ wloop:
 		 * don't do anything while (possibly) inside a ssl library.
 		 */
 		w = WaitLatchOrSocket(&MyProc->procLatch,
-							  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 3a6aa1c..ffc7822 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -520,8 +520,33 @@ ProcessClientReadInterrupt(void)
 
 		errno = save_errno;
 	}
+	else if (ProcDiePending)
+	{
+		/*
+		 * We're dying. It's safe (and sane) to handle that now.
+		 */
+		CHECK_FOR_INTERRUPTS();
+	}
 }
 
+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 e4a1a7d..d3db716 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);
-- 
1.8.3.251.g1462b67