[HACKERS] [PATCH 2/2] [libpq] Try to avoid manually masking SIGPIPEs on every send()

2009-06-10 Thread Jeremy Kerr
Currently, libpq will wrap each send() call on the connection with
two system calls to mask SIGPIPEs. This results in 3 syscalls instead
of one, and (on Linux) can lead to high contention on the signal
mask locks in threaded apps.

We have a couple of other methods to avoid SIGPIPEs:
sockopt(SO_NOSIGPIPE) and the MSG_NOSIGNAL flag to send().

This change attempts to use these if they're available at compile-
and run-time. If not, we drop back to manipulating the signal mask as
before.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
 src/interfaces/libpq/fe-connect.c |   39 +
 src/interfaces/libpq/fe-secure.c  |   83 +-
 src/interfaces/libpq/libpq-int.h  |2 
 3 files changed, 106 insertions(+), 18 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c 
b/src/interfaces/libpq/fe-connect.c
index 7f4ae4c..8265268 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1085,6 +1085,7 @@ keep_going:   
/* We will come back to here until there is
while (conn-addr_cur != NULL)
{
struct addrinfo *addr_cur = 
conn-addr_cur;
+   int optval;
 
/* Remember current address for 
possible error msg */
memcpy(conn-raddr.addr, 
addr_cur-ai_addr,
@@ -1149,6 +1150,44 @@ keep_going:  
/* We will come back to here until there is
}
 #endif   /* F_SETFD */
 
+   /* We have three methods of blocking 
sigpipe during
+* send() calls to this socket:
+*
+*  - setsockopt(sock, SO_NOSIGPIPE)
+*  - send(sock, ..., MSG_NOSIGNAL)
+*  - setting the signal mask to 
SIG_IGN during send()
+*
+* The first two reduce the number of 
syscalls (for the
+* third, we require three syscalls to 
implement a send()),
+* so use them if they're available. 
Their availability is
+* flagged in the following members of 
PGconn:
+*
+* conn-sigpipe_so - we 
have set up SO_NOSIGPIPE
+* conn-sigpipe_flag   - we're 
specifying MSG_NOSIGNAL
+*
+* If we can use SO_NOSIGPIPE, then set 
sigpipe_so here and
+* we don't need to care about anything 
else. Otherwise,
+* try MSG_NOSIGNAL by setting 
sigpipe_flag. If we get an
+* error with MSG_NOSIGNAL, we clear 
the flag and revert
+* to manual masking.
+*/
+   conn-sigpipe_so = false;
+#ifdef MSG_NOSIGNAL
+   conn-sigpipe_flag = true;
+#else /* !MSG_NOSIGNAL */
+   conn-sigpipe_flag = false;
+#endif /* MSG_NOSIGNAL */
+
+#ifdef SO_NOSIGPIPE
+   if (!setsockopt(conn-sock, SOL_SOCKET, 
SO_NOSIGPIPE,
+   (char *)optval, 
sizeof(optval)))
+   {
+   conn-sigpipe_so = true;
+   conn-sigpipe_flag = false;
+   }
+#endif /* SO_NOSIGPIPE */
+
+
/*
 * Start/make connection.  This should 
not block, since we
 * are in nonblock mode.  If it does, 
well, too bad.
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index 13c97ac..949cd0f 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -122,6 +122,18 @@ static long win32_ssl_create_mutex = 0;
  */
 
 #ifndef WIN32
+
+static inline int sigpipe_masked(PGconn *conn)
+{
+   /* If we're on an SSL connection, we can only use SO_NOSIGPIPE masking.
+* Otherwise, we can handle SO_NOSIGPIPE or the MSG_NOSIGNAL flag */
+#ifdef USE_SSL
+   if (conn-ssl)
+   return conn-sigpipe_so;
+#endif
+   return conn-sigpipe_so || conn-sigpipe_flag;
+}
+
 #ifdef 

Re: [HACKERS] [PATCH 2/2] [libpq] Try to avoid manually masking SIGPIPEs on every send()

2009-06-10 Thread Jeremy Kerr
Marko,

 optval seems used without initialization.

Dang, I was checking for the SO_NOSIGPIPE flag, and didn't check for 
optval. New patch coming...

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers