1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-02 04:21:28 +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

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