<!--
-$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">
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>
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>
*
*
* 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
#include <ctype.h>
#include <errno.h>
+#include "nodes/value.h"
#include "nodes/pg_list.h"
#include "nodes/readfuncs.h"
#include "nodes/value.h"
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include <arpa/inet.h>
#endif
+#ifdef ENABLE_THREAD_SAFETY
+#include <pthread.h>
+#endif
+
#include "libpq/ip.h"
#include "mb/pg_wchar.h"
#define DefaultSSLMode "disable"
#endif
-
/* ----------
* Definition of the conninfo parameters and their fallback resources.
*
static char *PasswordFromFile(char *hostname, char *port, char *dbname,
char *username);
+
/*
* Connecting to a Database
*
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;
#undef LINELEN
}
+
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
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
_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)
*
*
* 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
#include <arpa/inet.h>
#endif
+#ifdef ENABLE_THREAD_SAFETY
+#include <pthread.h>
+#endif
+
#ifndef HAVE_STRDUP
#include "strdup.h"
#endif
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 */
/* ------------------------------------------------------------ */
{
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)
#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;
}
#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
+}
* 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 $
*
*-------------------------------------------------------------------------
*/
/* 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
* 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 $
*
*-------------------------------------------------------------------------
*/
#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
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
*
*
* 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
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 */
+}
* 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
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
+extern pqsigfunc pqsignalinquire(int signo);
+
#endif /* PQSIGNAL_H */