Skip to content

Commit 0150dbd

Browse files
committed
Allow libpq to do thread-safe SIGPIPE handling. This allows it to
ignore SIGPIPE from send() in libpq, but terminate on any other SIGPIPE, unless the user installs their own signal handler. This is a minor fix because the only time you get SIGPIPE from libpq's send() is when the backend dies.
1 parent acc5754 commit 0150dbd

File tree

9 files changed

+167
-12
lines changed

9 files changed

+167
-12
lines changed

doc/src/sgml/libpq.sgml

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.144 2003/12/13 23:59:06 neilc Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.145 2004/01/09 02:02:43 momjian Exp $
33
-->
44

55
<chapter id="libpq">
@@ -3587,7 +3587,7 @@ thread-enabled applications.
35873587
One restriction is that no two threads attempt to manipulate the same
35883588
<structname>PGconn</> object at the same time. In particular, you cannot
35893589
issue concurrent commands from different threads through the same
3590-
connection object. (If you need to run concurrent commands, start up
3590+
connection object. (If you need to run concurrent commands, use
35913591
multiple connections.)
35923592
</para>
35933593

@@ -3612,6 +3612,25 @@ not thread-safe.<indexterm><primary>crypt</><secondary>thread
36123612
safety</></> It is better to use the <literal>md5</literal> method,
36133613
which is thread-safe on all platforms.
36143614
</para>
3615+
3616+
<para>
3617+
<application>libpq</application> must ignore <literal>SIGPIPE</> signals
3618+
generated internally by <function>send()</> calls to backend processes.
3619+
When <productname>PostgreSQL</> is configured without
3620+
<literal>--enable-thread-safety</>, <application>libpq</> sets
3621+
<literal>SIGPIPE</> to <literal>SIG_IGN</> before each
3622+
<function>send()</> call and restores the original signal handler after
3623+
completion. When <literal>--enable-thread-safety</> is used,
3624+
<application>libpq</> installs its own <literal>SIGPIPE</> handler
3625+
before the first database connection if no custom <literal>SIGPIPE</>
3626+
handler has been installed previously. This handler uses thread-local
3627+
storage to determine if a <literal>SIGPIPE</> signal has been generated
3628+
by an internal <function>send()</>. If an application wants to install
3629+
its own <literal>SIGPIPE</> signal handler, it should call
3630+
<function>PQinSend()</> to determine if it should ignore the
3631+
<literal>SIGPIPE</> signal. This function is available in both
3632+
thread-safe and non-thread-safe versions of <application>libpq</>.
3633+
</para>
36153634
</sect1>
36163635

36173636

src/backend/nodes/read.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/nodes/read.c,v 1.37 2004/01/07 21:12:56 tgl Exp $
12+
* $PostgreSQL: pgsql/src/backend/nodes/read.c,v 1.38 2004/01/09 02:02:43 momjian Exp $
1313
*
1414
* HISTORY
1515
* AUTHOR DATE MAJOR EVENT
@@ -22,6 +22,7 @@
2222
#include <ctype.h>
2323
#include <errno.h>
2424

25+
#include "nodes/value.h"
2526
#include "nodes/pg_list.h"
2627
#include "nodes/readfuncs.h"
2728
#include "nodes/value.h"

src/interfaces/libpq/fe-connect.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.266 2004/01/07 18:56:29 neilc Exp $
11+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.267 2004/01/09 02:02:43 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -43,6 +43,10 @@
4343
#include <arpa/inet.h>
4444
#endif
4545

46+
#ifdef ENABLE_THREAD_SAFETY
47+
#include <pthread.h>
48+
#endif
49+
4650
#include "libpq/ip.h"
4751
#include "mb/pg_wchar.h"
4852

@@ -66,7 +70,6 @@ long ioctlsocket_ret=1;
6670
#define DefaultSSLMode "disable"
6771
#endif
6872

69-
7073
/* ----------
7174
* Definition of the conninfo parameters and their fallback resources.
7275
*
@@ -198,6 +201,7 @@ static char *pwdfMatchesString(char *buf, char *token);
198201
static char *PasswordFromFile(char *hostname, char *port, char *dbname,
199202
char *username);
200203

204+
201205
/*
202206
* Connecting to a Database
203207
*
@@ -881,6 +885,12 @@ connectDBStart(PGconn *conn)
881885
struct addrinfo hint;
882886
const char *node = NULL;
883887
int ret;
888+
#ifdef ENABLE_THREAD_SAFETY
889+
static pthread_once_t check_sigpipe_once = PTHREAD_ONCE_INIT;
890+
891+
/* Check only on first connection request */
892+
pthread_once(&check_sigpipe_once, check_sigpipe_handler);
893+
#endif
884894

885895
if (!conn)
886896
return 0;
@@ -3158,3 +3168,4 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
31583168

31593169
#undef LINELEN
31603170
}
3171+

src/interfaces/libpq/fe-print.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* didn't really belong there.
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.49 2003/11/29 19:52:12 pgsql Exp $
13+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.50 2004/01/09 02:02:43 momjian Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -90,8 +90,10 @@ PQprint(FILE *fout,
9090
int fs_len = strlen(po->fieldSep);
9191
int total_line_length = 0;
9292
int usePipe = 0;
93-
pqsigfunc oldsigpipehandler = NULL;
9493
char *pagerenv;
94+
#if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
95+
pqsigfunc oldsigpipehandler = NULL;
96+
#endif
9597

9698
#ifdef TIOCGWINSZ
9799
struct winsize screen_size;
@@ -189,8 +191,12 @@ PQprint(FILE *fout,
189191
if (fout)
190192
{
191193
usePipe = 1;
194+
#ifdef ENABLE_THREAD_SAFETY
195+
pthread_setspecific(thread_in_send, "t");
196+
#else
192197
#ifndef WIN32
193198
oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN);
199+
#endif
194200
#endif
195201
}
196202
else
@@ -306,7 +312,13 @@ PQprint(FILE *fout,
306312
_pclose(fout);
307313
#else
308314
pclose(fout);
315+
#endif
316+
#ifdef ENABLE_THREAD_SAFETY
317+
pthread_setspecific(thread_in_send, "f");
318+
#else
319+
#ifndef WIN32
309320
pqsignal(SIGPIPE, oldsigpipehandler);
321+
#endif
310322
#endif
311323
}
312324
if (po->html3 && !po->expanded)

src/interfaces/libpq/fe-secure.c

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.34 2003/12/18 22:49:26 tgl Exp $
14+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.35 2004/01/09 02:02:43 momjian Exp $
1515
*
1616
* NOTES
1717
* The client *requires* a valid server certificate. Since
@@ -106,6 +106,10 @@
106106
#include <arpa/inet.h>
107107
#endif
108108

109+
#ifdef ENABLE_THREAD_SAFETY
110+
#include <pthread.h>
111+
#endif
112+
109113
#ifndef HAVE_STRDUP
110114
#include "strdup.h"
111115
#endif
@@ -142,6 +146,11 @@ static const char *SSLerrmessage(void);
142146
static SSL_CTX *SSL_context = NULL;
143147
#endif
144148

149+
#ifdef ENABLE_THREAD_SAFETY
150+
static void sigpipe_handler_ignore_send(int signo);
151+
pthread_key_t thread_in_send;
152+
#endif
153+
145154
/* ------------------------------------------------------------ */
146155
/* Hardcoded values */
147156
/* ------------------------------------------------------------ */
@@ -347,9 +356,13 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
347356
{
348357
ssize_t n;
349358

359+
#ifdef ENABLE_THREAD_SAFETY
360+
pthread_setspecific(thread_in_send, "t");
361+
#else
350362
#ifndef WIN32
351363
pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
352364
#endif
365+
#endif
353366

354367
#ifdef USE_SSL
355368
if (conn->ssl)
@@ -407,8 +420,12 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
407420
#endif
408421
n = send(conn->sock, ptr, len, 0);
409422

423+
#ifdef ENABLE_THREAD_SAFETY
424+
pthread_setspecific(thread_in_send, "f");
425+
#else
410426
#ifndef WIN32
411427
pqsignal(SIGPIPE, oldsighandler);
428+
#endif
412429
#endif
413430

414431
return n;
@@ -1048,3 +1065,59 @@ PQgetssl(PGconn *conn)
10481065
}
10491066

10501067
#endif /* USE_SSL */
1068+
1069+
1070+
#ifdef ENABLE_THREAD_SAFETY
1071+
/*
1072+
* Check SIGPIPE handler and perhaps install our own.
1073+
*/
1074+
void
1075+
check_sigpipe_handler(void)
1076+
{
1077+
pqsigfunc pipehandler;
1078+
1079+
/*
1080+
* If the app hasn't set a SIGPIPE handler, define our own
1081+
* that ignores SIGPIPE on libpq send() and does SIG_DFL
1082+
* for other SIGPIPE cases.
1083+
*/
1084+
pipehandler = pqsignalinquire(SIGPIPE);
1085+
if (pipehandler == SIG_DFL) /* not set by application */
1086+
{
1087+
/*
1088+
* Create key first because the signal handler might be called
1089+
* right after being installed.
1090+
*/
1091+
pthread_key_create(&thread_in_send, NULL);
1092+
pqsignal(SIGPIPE, sigpipe_handler_ignore_send);
1093+
}
1094+
}
1095+
1096+
/*
1097+
* Threaded SIGPIPE signal handler
1098+
*/
1099+
void
1100+
sigpipe_handler_ignore_send(int signo)
1101+
{
1102+
/* If we have gotten a SIGPIPE outside send(), exit */
1103+
if (!PQinSend())
1104+
exit(128 + SIGPIPE); /* typical return value for SIG_DFL */
1105+
}
1106+
#endif
1107+
1108+
/*
1109+
* Indicates whether the current thread is in send()
1110+
* For use by SIGPIPE signal handlers; they should
1111+
* ignore SIGPIPE when libpq is in send(). This means
1112+
* that the backend has died unexpectedly.
1113+
*/
1114+
pqbool
1115+
PQinSend(void)
1116+
{
1117+
#ifdef ENABLE_THREAD_SAFETY
1118+
return (pthread_getspecific(thread_in_send) /* has it been set? */ &&
1119+
*(char *)pthread_getspecific(thread_in_send) == 't') ? true : false;
1120+
#else
1121+
return false; /* No threading, so we can't be in send() */
1122+
#endif
1123+
}

src/interfaces/libpq/libpq-fe.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.101 2003/11/29 22:41:28 pgsql Exp $
10+
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.102 2004/01/09 02:02:43 momjian Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -450,6 +450,14 @@ extern int PQmblen(const unsigned char *s, int encoding);
450450
/* Get encoding id from environment variable PGCLIENTENCODING */
451451
extern int PQenv2encoding(void);
452452

453+
/* === in fe-secure.c === */
454+
455+
/*
456+
* Indicates whether the libpq thread is in send().
457+
* Used to ignore SIGPIPE if thread is in send().
458+
*/
459+
pqbool PQinSend(void);
460+
453461
#ifdef __cplusplus
454462
}
455463
#endif

src/interfaces/libpq/libpq-int.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
15-
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.83 2003/11/29 22:41:28 pgsql Exp $
15+
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.84 2004/01/09 02:02:43 momjian Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -29,6 +29,9 @@
2929
#include <sys/time.h>
3030
#endif
3131

32+
#ifdef ENABLE_THREAD_SAFETY
33+
#include <pthread.h>
34+
#endif
3235

3336
#if defined(WIN32) && (!defined(ssize_t))
3437
typedef int ssize_t; /* ssize_t doesn't exist in VC (at least
@@ -442,6 +445,10 @@ extern PostgresPollingStatusType pqsecure_open_client(PGconn *);
442445
extern void pqsecure_close(PGconn *);
443446
extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len);
444447
extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len);
448+
#ifdef ENABLE_THREAD_SAFETY
449+
extern void check_sigpipe_handler(void);
450+
extern pthread_key_t thread_in_send;
451+
#endif
445452

446453
/*
447454
* this is so that we can check if a connection is non-blocking internally

src/interfaces/libpq/pqsignal.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/interfaces/libpq/pqsignal.c,v 1.18 2003/11/29 19:52:12 pgsql Exp $
12+
* $PostgreSQL: pgsql/src/interfaces/libpq/pqsignal.c,v 1.19 2004/01/09 02:02:43 momjian Exp $
1313
*
1414
* NOTES
1515
* This shouldn't be in libpq, but the monitor and some other
@@ -40,3 +40,25 @@ pqsignal(int signo, pqsigfunc func)
4040
return oact.sa_handler;
4141
#endif /* !HAVE_POSIX_SIGNALS */
4242
}
43+
44+
pqsigfunc
45+
pqsignalinquire(int signo)
46+
{
47+
#if !defined(HAVE_POSIX_SIGNALS)
48+
pqsigfunc old_sigfunc;
49+
int old_sigmask;
50+
51+
/* Prevent signal handler calls during test */
52+
old_sigmask = sigblock(sigmask(signo));
53+
old_sigfunc = signal(signo, SIG_DFL);
54+
signal(signo, old_sigfunc);
55+
sigblock(old_sigmask);
56+
return old_sigfunc;
57+
#else
58+
struct sigaction oact;
59+
60+
if (sigaction(signo, NULL, &oact) < 0)
61+
return SIG_ERR;
62+
return oact.sa_handler;
63+
#endif /* !HAVE_POSIX_SIGNALS */
64+
}

src/interfaces/libpq/pqsignal.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/interfaces/libpq/pqsignal.h,v 1.16 2003/11/29 22:41:28 pgsql Exp $
10+
* $PostgreSQL: pgsql/src/interfaces/libpq/pqsignal.h,v 1.17 2004/01/09 02:02:43 momjian Exp $
1111
*
1212
* NOTES
1313
* This shouldn't be in libpq, but the monitor and some other
@@ -24,4 +24,6 @@ typedef void (*pqsigfunc) (int);
2424

2525
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
2626

27+
extern pqsigfunc pqsignalinquire(int signo);
28+
2729
#endif /* PQSIGNAL_H */

0 commit comments

Comments
 (0)