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.
This commit is contained in:
parent
acc57543de
commit
0150dbdce5
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.144 2003/12/13 23:59:06 neilc Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.145 2004/01/09 02:02:43 momjian Exp $
|
||||
-->
|
||||
|
||||
<chapter id="libpq">
|
||||
@ -3587,7 +3587,7 @@ thread-enabled applications.
|
||||
One restriction is that no two threads attempt to manipulate the same
|
||||
<structname>PGconn</> object at the same time. In particular, you cannot
|
||||
issue concurrent commands from different threads through the same
|
||||
connection object. (If you need to run concurrent commands, start up
|
||||
connection object. (If you need to run concurrent commands, use
|
||||
multiple connections.)
|
||||
</para>
|
||||
|
||||
@ -3612,6 +3612,25 @@ not thread-safe.<indexterm><primary>crypt</><secondary>thread
|
||||
safety</></> It is better to use the <literal>md5</literal> method,
|
||||
which is thread-safe on all platforms.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<application>libpq</application> must ignore <literal>SIGPIPE</> signals
|
||||
generated internally by <function>send()</> calls to backend processes.
|
||||
When <productname>PostgreSQL</> is configured without
|
||||
<literal>--enable-thread-safety</>, <application>libpq</> sets
|
||||
<literal>SIGPIPE</> to <literal>SIG_IGN</> before each
|
||||
<function>send()</> call and restores the original signal handler after
|
||||
completion. When <literal>--enable-thread-safety</> is used,
|
||||
<application>libpq</> installs its own <literal>SIGPIPE</> handler
|
||||
before the first database connection if no custom <literal>SIGPIPE</>
|
||||
handler has been installed previously. This handler uses thread-local
|
||||
storage to determine if a <literal>SIGPIPE</> signal has been generated
|
||||
by an internal <function>send()</>. If an application wants to install
|
||||
its own <literal>SIGPIPE</> signal handler, it should call
|
||||
<function>PQinSend()</> to determine if it should ignore the
|
||||
<literal>SIGPIPE</> signal. This function is available in both
|
||||
thread-safe and non-thread-safe versions of <application>libpq</>.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/read.c,v 1.37 2004/01/07 21:12:56 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/read.c,v 1.38 2004/01/09 02:02:43 momjian Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -22,6 +22,7 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "nodes/value.h"
|
||||
#include "nodes/pg_list.h"
|
||||
#include "nodes/readfuncs.h"
|
||||
#include "nodes/value.h"
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.266 2004/01/07 18:56:29 neilc Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.267 2004/01/09 02:02:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -43,6 +43,10 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "libpq/ip.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
|
||||
@ -66,7 +70,6 @@ long ioctlsocket_ret=1;
|
||||
#define DefaultSSLMode "disable"
|
||||
#endif
|
||||
|
||||
|
||||
/* ----------
|
||||
* Definition of the conninfo parameters and their fallback resources.
|
||||
*
|
||||
@ -198,6 +201,7 @@ static char *pwdfMatchesString(char *buf, char *token);
|
||||
static char *PasswordFromFile(char *hostname, char *port, char *dbname,
|
||||
char *username);
|
||||
|
||||
|
||||
/*
|
||||
* Connecting to a Database
|
||||
*
|
||||
@ -881,6 +885,12 @@ connectDBStart(PGconn *conn)
|
||||
struct addrinfo hint;
|
||||
const char *node = NULL;
|
||||
int ret;
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
static pthread_once_t check_sigpipe_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
/* Check only on first connection request */
|
||||
pthread_once(&check_sigpipe_once, check_sigpipe_handler);
|
||||
#endif
|
||||
|
||||
if (!conn)
|
||||
return 0;
|
||||
@ -3158,3 +3168,4 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
|
||||
|
||||
#undef LINELEN
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
* didn't really belong there.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.49 2003/11/29 19:52:12 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.50 2004/01/09 02:02:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -90,8 +90,10 @@ PQprint(FILE *fout,
|
||||
int fs_len = strlen(po->fieldSep);
|
||||
int total_line_length = 0;
|
||||
int usePipe = 0;
|
||||
pqsigfunc oldsigpipehandler = NULL;
|
||||
char *pagerenv;
|
||||
#if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
|
||||
pqsigfunc oldsigpipehandler = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGWINSZ
|
||||
struct winsize screen_size;
|
||||
@ -189,8 +191,12 @@ PQprint(FILE *fout,
|
||||
if (fout)
|
||||
{
|
||||
usePipe = 1;
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
pthread_setspecific(thread_in_send, "t");
|
||||
#else
|
||||
#ifndef WIN32
|
||||
oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -306,7 +312,13 @@ PQprint(FILE *fout,
|
||||
_pclose(fout);
|
||||
#else
|
||||
pclose(fout);
|
||||
#endif
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
pthread_setspecific(thread_in_send, "f");
|
||||
#else
|
||||
#ifndef WIN32
|
||||
pqsignal(SIGPIPE, oldsigpipehandler);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
if (po->html3 && !po->expanded)
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.34 2003/12/18 22:49:26 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.35 2004/01/09 02:02:43 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The client *requires* a valid server certificate. Since
|
||||
@ -106,6 +106,10 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
#include "strdup.h"
|
||||
#endif
|
||||
@ -142,6 +146,11 @@ static const char *SSLerrmessage(void);
|
||||
static SSL_CTX *SSL_context = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
static void sigpipe_handler_ignore_send(int signo);
|
||||
pthread_key_t thread_in_send;
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* Hardcoded values */
|
||||
/* ------------------------------------------------------------ */
|
||||
@ -347,9 +356,13 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
pthread_setspecific(thread_in_send, "t");
|
||||
#else
|
||||
#ifndef WIN32
|
||||
pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_SSL
|
||||
if (conn->ssl)
|
||||
@ -407,8 +420,12 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
|
||||
#endif
|
||||
n = send(conn->sock, ptr, len, 0);
|
||||
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
pthread_setspecific(thread_in_send, "f");
|
||||
#else
|
||||
#ifndef WIN32
|
||||
pqsignal(SIGPIPE, oldsighandler);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return n;
|
||||
@ -1048,3 +1065,59 @@ PQgetssl(PGconn *conn)
|
||||
}
|
||||
|
||||
#endif /* USE_SSL */
|
||||
|
||||
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
/*
|
||||
* Check SIGPIPE handler and perhaps install our own.
|
||||
*/
|
||||
void
|
||||
check_sigpipe_handler(void)
|
||||
{
|
||||
pqsigfunc pipehandler;
|
||||
|
||||
/*
|
||||
* If the app hasn't set a SIGPIPE handler, define our own
|
||||
* that ignores SIGPIPE on libpq send() and does SIG_DFL
|
||||
* for other SIGPIPE cases.
|
||||
*/
|
||||
pipehandler = pqsignalinquire(SIGPIPE);
|
||||
if (pipehandler == SIG_DFL) /* not set by application */
|
||||
{
|
||||
/*
|
||||
* Create key first because the signal handler might be called
|
||||
* right after being installed.
|
||||
*/
|
||||
pthread_key_create(&thread_in_send, NULL);
|
||||
pqsignal(SIGPIPE, sigpipe_handler_ignore_send);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Threaded SIGPIPE signal handler
|
||||
*/
|
||||
void
|
||||
sigpipe_handler_ignore_send(int signo)
|
||||
{
|
||||
/* If we have gotten a SIGPIPE outside send(), exit */
|
||||
if (!PQinSend())
|
||||
exit(128 + SIGPIPE); /* typical return value for SIG_DFL */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Indicates whether the current thread is in send()
|
||||
* For use by SIGPIPE signal handlers; they should
|
||||
* ignore SIGPIPE when libpq is in send(). This means
|
||||
* that the backend has died unexpectedly.
|
||||
*/
|
||||
pqbool
|
||||
PQinSend(void)
|
||||
{
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
return (pthread_getspecific(thread_in_send) /* has it been set? */ &&
|
||||
*(char *)pthread_getspecific(thread_in_send) == 't') ? true : false;
|
||||
#else
|
||||
return false; /* No threading, so we can't be in send() */
|
||||
#endif
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.101 2003/11/29 22:41:28 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.102 2004/01/09 02:02:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -450,6 +450,14 @@ extern int PQmblen(const unsigned char *s, int encoding);
|
||||
/* Get encoding id from environment variable PGCLIENTENCODING */
|
||||
extern int PQenv2encoding(void);
|
||||
|
||||
/* === in fe-secure.c === */
|
||||
|
||||
/*
|
||||
* Indicates whether the libpq thread is in send().
|
||||
* Used to ignore SIGPIPE if thread is in send().
|
||||
*/
|
||||
pqbool PQinSend(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -12,7 +12,7 @@
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.83 2003/11/29 22:41:28 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.84 2004/01/09 02:02:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -29,6 +29,9 @@
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && (!defined(ssize_t))
|
||||
typedef int ssize_t; /* ssize_t doesn't exist in VC (at least
|
||||
@ -442,6 +445,10 @@ extern PostgresPollingStatusType pqsecure_open_client(PGconn *);
|
||||
extern void pqsecure_close(PGconn *);
|
||||
extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len);
|
||||
extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len);
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
extern void check_sigpipe_handler(void);
|
||||
extern pthread_key_t thread_in_send;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* this is so that we can check if a connection is non-blocking internally
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/pqsignal.c,v 1.18 2003/11/29 19:52:12 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/pqsignal.c,v 1.19 2004/01/09 02:02:43 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This shouldn't be in libpq, but the monitor and some other
|
||||
@ -40,3 +40,25 @@ pqsignal(int signo, pqsigfunc func)
|
||||
return oact.sa_handler;
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
}
|
||||
|
||||
pqsigfunc
|
||||
pqsignalinquire(int signo)
|
||||
{
|
||||
#if !defined(HAVE_POSIX_SIGNALS)
|
||||
pqsigfunc old_sigfunc;
|
||||
int old_sigmask;
|
||||
|
||||
/* Prevent signal handler calls during test */
|
||||
old_sigmask = sigblock(sigmask(signo));
|
||||
old_sigfunc = signal(signo, SIG_DFL);
|
||||
signal(signo, old_sigfunc);
|
||||
sigblock(old_sigmask);
|
||||
return old_sigfunc;
|
||||
#else
|
||||
struct sigaction oact;
|
||||
|
||||
if (sigaction(signo, NULL, &oact) < 0)
|
||||
return SIG_ERR;
|
||||
return oact.sa_handler;
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/pqsignal.h,v 1.16 2003/11/29 22:41:28 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/pqsignal.h,v 1.17 2004/01/09 02:02:43 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This shouldn't be in libpq, but the monitor and some other
|
||||
@ -24,4 +24,6 @@ typedef void (*pqsigfunc) (int);
|
||||
|
||||
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
|
||||
|
||||
extern pqsigfunc pqsignalinquire(int signo);
|
||||
|
||||
#endif /* PQSIGNAL_H */
|
||||
|
Loading…
Reference in New Issue
Block a user