summaryrefslogtreecommitdiff
path: root/src/backend/libpq/be-secure.c
diff options
context:
space:
mode:
authorAndres Freund <andres@anarazel.de>2015-02-03 22:03:48 +0100
committerAndres Freund <andres@anarazel.de>2015-02-03 22:03:48 +0100
commit387da18874afa17156ee3af63766f17efb53c4b9 (patch)
tree642eaff88114b0ac3be59397c3e96a66f93a7ebd /src/backend/libpq/be-secure.c
parent778d498c7d9099c784f14199a319ec2a84d91191 (diff)
Use a nonblocking socket for FE/BE communication and block using latches.
This allows to introduce more elaborate handling of interrupts while reading from a socket. Currently some interrupt handlers have to do significant work from inside signal handlers, and it's very hard to correctly write code to do so. Generic signal handler limitations, combined with the fact that we can't safely jump out of a signal handler while reading from the client have prohibited implementation of features like timeouts for idle-in-transaction. Additionally we use the latch code to wait in a couple places where we previously only had waiting code on windows as other platforms just busy looped. This can increase the number of systemcalls happening during FE/BE communication. Benchmarks so far indicate that the impact isn't very high, and there's room for optimization in the latch code. The chance of cleaning up the usage of latches gives us, seem to outweigh the risk of small performance regressions. This commit theoretically can't used without the next patch in the series, as WaitLatchOrSocket is not defined to be fully signal safe. As we already do that in some cases though, it seems better to keep the commits separate, so they're easier to understand. Author: Andres Freund Reviewed-By: Heikki Linnakangas
Diffstat (limited to 'src/backend/libpq/be-secure.c')
-rw-r--r--src/backend/libpq/be-secure.c77
1 files changed, 76 insertions, 1 deletions
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index c592f850c27..c9a8f6df4fe 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -32,8 +32,10 @@
#endif
#include "libpq/libpq.h"
+#include "miscadmin.h"
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
+#include "storage/proc.h"
char *ssl_cert_file;
@@ -147,7 +149,39 @@ secure_raw_read(Port *port, void *ptr, size_t len)
prepare_for_client_read();
+ /*
+ * Try to read from the socket without blocking. If it succeeds we're
+ * done, otherwise we'll wait for the socket using the latch mechanism.
+ */
+rloop:
+#ifdef WIN32
+ pgwin32_noblock = true;
+#endif
n = recv(port->sock, ptr, len, 0);
+#ifdef WIN32
+ pgwin32_noblock = false;
+#endif
+
+ if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
+ {
+ int w;
+ int save_errno = errno;
+
+ w = WaitLatchOrSocket(MyLatch,
+ WL_SOCKET_READABLE,
+ port->sock, 0);
+
+ if (w & WL_SOCKET_READABLE)
+ {
+ goto rloop;
+ }
+
+ /*
+ * Restore errno, clobbered by WaitLatchOrSocket, so the caller can
+ * react properly.
+ */
+ errno = save_errno;
+ }
client_read_ended();
@@ -170,7 +204,9 @@ secure_write(Port *port, void *ptr, size_t len)
}
else
#endif
+ {
n = secure_raw_write(port, ptr, len);
+ }
return n;
}
@@ -178,5 +214,44 @@ secure_write(Port *port, void *ptr, size_t len)
ssize_t
secure_raw_write(Port *port, const void *ptr, size_t len)
{
- return send(port->sock, ptr, len, 0);
+ ssize_t n;
+
+wloop:
+
+#ifdef WIN32
+ pgwin32_noblock = true;
+#endif
+ n = send(port->sock, ptr, len, 0);
+#ifdef WIN32
+ pgwin32_noblock = false;
+#endif
+
+ if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
+ {
+ int w;
+ int save_errno = errno;
+
+ /*
+ * We probably want to check for latches being set at some point
+ * here. That'd allow us to handle interrupts while blocked on
+ * writes. 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,
+ port->sock, 0);
+
+ if (w & WL_SOCKET_WRITEABLE)
+ {
+ goto wloop;
+ }
+
+ /*
+ * Restore errno, clobbered by WaitLatchOrSocket, so the caller can
+ * react properly.
+ */
+ errno = save_errno;
+ }
+
+ return n;
}