1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-25 01:02:05 +03:00

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:
Bruce Momjian
2004-01-09 02:02:43 +00:00
parent acc57543de
commit 0150dbdce5
9 changed files with 167 additions and 12 deletions

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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 */
}

View File

@ -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 */