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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy