Index: configure =================================================================== RCS file: /cvsroot/pgsql/configure,v retrieving revision 1.409 diff -c -c -r1.409 configure *** configure 30 Nov 2004 06:13:03 -0000 1.409 --- configure 1 Dec 2004 22:53:58 -0000 *************** *** 17431,17436 **** --- 17431,17448 ---- fi HAVE_POSIX_SIGNALS=$pgac_cv_func_posix_signals + if test "$pgac_cv_func_posix_signals" != yes -a "$enable_thread_safety" = yes; then + { { echo "$as_me:$LINENO: error: + *** Thread-safety requires POSIX signals, which are not supported by your + *** operating system. + " >&5 + echo "$as_me: error: + *** Thread-safety requires POSIX signals, which are not supported by your + *** operating system. + " >&2;} + { (exit 1); exit 1; }; } + fi + if test $ac_cv_func_fseeko = yes; then # Check whether --enable-largefile or --disable-largefile was given. if test "${enable_largefile+set}" = set; then Index: configure.in =================================================================== RCS file: /cvsroot/pgsql/configure.in,v retrieving revision 1.387 diff -c -c -r1.387 configure.in *** configure.in 30 Nov 2004 06:13:04 -0000 1.387 --- configure.in 1 Dec 2004 22:54:11 -0000 *************** *** 1174,1179 **** --- 1174,1186 ---- PGAC_FUNC_POSIX_SIGNALS + if test "$pgac_cv_func_posix_signals" != yes -a "$enable_thread_safety" = yes; then + AC_MSG_ERROR([ + *** Thread-safety requires POSIX signals, which are not supported by your + *** operating system. + ]) + fi + if test $ac_cv_func_fseeko = yes; then AC_SYS_LARGEFILE fi Index: doc/src/sgml/libpq.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v retrieving revision 1.169 diff -c -c -r1.169 libpq.sgml *** doc/src/sgml/libpq.sgml 27 Nov 2004 21:56:04 -0000 1.169 --- doc/src/sgml/libpq.sgml 1 Dec 2004 22:54:45 -0000 *************** *** 3955,3975 **** ! libpq must ignore SIGPIPE signals ! generated internally by send() calls to backend processes. ! When PostgreSQL is configured without ! --enable-thread-safety, libpq sets ! SIGPIPE to SIG_IGN before each ! send() call and restores the original signal handler after ! completion. When --enable-thread-safety is used, ! libpq installs its own SIGPIPE handler ! before the first database connection. This handler uses thread-local ! storage to determine if a SIGPIPE signal has been generated ! by a libpq send(). If an application wants to install ! its own SIGPIPE signal handler, it should call ! PQinSend() to determine if it should ignore the ! SIGPIPE signal. This function is available in both ! thread-safe and non-thread-safe versions of libpq. --- 3955,3964 ---- ! libpq blocks and discards SIGPIPE ! signals generated internally by send() calls to the backend ! process. Therefore, applications should not expect blocked SIGPIPE ! signals to remain across libpq function calls. Index: doc/src/sgml/ref/copy.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/ref/copy.sgml,v retrieving revision 1.60 diff -c -c -r1.60 copy.sgml *** doc/src/sgml/ref/copy.sgml 27 Nov 2004 21:56:05 -0000 1.60 --- doc/src/sgml/ref/copy.sgml 1 Dec 2004 22:54:57 -0000 *************** *** 3,8 **** --- 3,9 ---- PostgreSQL documentation --> + COPY Index: src/interfaces/libpq/fe-connect.c =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v retrieving revision 1.289 diff -c -c -r1.289 fe-connect.c *** src/interfaces/libpq/fe-connect.c 30 Oct 2004 23:11:26 -0000 1.289 --- src/interfaces/libpq/fe-connect.c 1 Dec 2004 22:55:18 -0000 *************** *** 865,879 **** const char *node = NULL; int ret; - #ifdef ENABLE_THREAD_SAFETY - #ifndef WIN32 - static pthread_once_t check_sigpipe_once = PTHREAD_ONCE_INIT; - - /* Check only on first connection request */ - pthread_once(&check_sigpipe_once, pq_check_sigpipe_handler); - #endif - #endif - if (!conn) return 0; --- 865,870 ---- Index: src/interfaces/libpq/fe-print.c =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/fe-print.c,v retrieving revision 1.55 diff -c -c -r1.55 fe-print.c *** src/interfaces/libpq/fe-print.c 9 Nov 2004 15:57:57 -0000 1.55 --- src/interfaces/libpq/fe-print.c 1 Dec 2004 22:55:25 -0000 *************** *** 91,97 **** int total_line_length = 0; int usePipe = 0; char *pagerenv; ! #if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) pqsigfunc oldsigpipehandler = NULL; #endif --- 91,100 ---- int total_line_length = 0; int usePipe = 0; char *pagerenv; ! #ifdef ENABLE_THREAD_SAFETY ! sigset_t osigset; ! bool sigpipe_masked = false; ! #endif #if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) pqsigfunc oldsigpipehandler = NULL; #endif *************** *** 189,195 **** { usePipe = 1; #ifdef ENABLE_THREAD_SAFETY ! pthread_setspecific(pq_thread_in_send, "t"); #else #ifndef WIN32 oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN); --- 192,199 ---- { usePipe = 1; #ifdef ENABLE_THREAD_SAFETY ! pq_block_sigpipe(&osigset); ! sigpipe_masked = true; #else #ifndef WIN32 oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN); *************** *** 311,317 **** pclose(fout); #endif #ifdef ENABLE_THREAD_SAFETY ! pthread_setspecific(pq_thread_in_send, "f"); #else #ifndef WIN32 pqsignal(SIGPIPE, oldsigpipehandler); --- 315,322 ---- pclose(fout); #endif #ifdef ENABLE_THREAD_SAFETY ! if (sigpipe_masked) ! pq_reset_sigpipe(&osigset); #else #ifndef WIN32 pqsignal(SIGPIPE, oldsigpipehandler); Index: src/interfaces/libpq/fe-secure.c =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/fe-secure.c,v retrieving revision 1.57 diff -c -c -r1.57 fe-secure.c *** src/interfaces/libpq/fe-secure.c 20 Nov 2004 00:35:13 -0000 1.57 --- src/interfaces/libpq/fe-secure.c 1 Dec 2004 22:55:31 -0000 *************** *** 152,163 **** static SSL_CTX *SSL_context = NULL; #endif - #ifdef ENABLE_THREAD_SAFETY - static void sigpipe_handler_ignore_send(int signo); - pthread_key_t pq_thread_in_send = 0; /* initializer needed on Darwin */ - static pqsigfunc pq_pipe_handler; - #endif - /* ------------------------------------------------------------ */ /* Hardcoded values */ /* ------------------------------------------------------------ */ --- 152,157 ---- *************** *** 379,387 **** pqsecure_write(PGconn *conn, const void *ptr, size_t len) { ssize_t n; ! #ifdef ENABLE_THREAD_SAFETY ! pthread_setspecific(pq_thread_in_send, "t"); #else #ifndef WIN32 pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN); --- 373,383 ---- pqsecure_write(PGconn *conn, const void *ptr, size_t len) { ssize_t n; ! #ifdef ENABLE_THREAD_SAFETY ! sigset_t osigmask; ! ! pq_block_sigpipe(&osigmask); #else #ifndef WIN32 pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN); *************** *** 454,460 **** n = send(conn->sock, ptr, len, 0); #ifdef ENABLE_THREAD_SAFETY ! pthread_setspecific(pq_thread_in_send, "f"); #else #ifndef WIN32 pqsignal(SIGPIPE, oldsighandler); --- 450,456 ---- n = send(conn->sock, ptr, len, 0); #ifdef ENABLE_THREAD_SAFETY ! pq_reset_sigpipe(&osigmask); #else #ifndef WIN32 pqsignal(SIGPIPE, oldsighandler); *************** *** 1216,1280 **** } #endif /* USE_SSL */ - #ifdef ENABLE_THREAD_SAFETY - #ifndef WIN32 /* ! * Check SIGPIPE handler and perhaps install our own. */ ! void ! pq_check_sigpipe_handler(void) { ! pthread_key_create(&pq_thread_in_send, NULL); ! ! /* ! * Find current pipe handler and chain on to it. ! */ ! pq_pipe_handler = pqsignalinquire(SIGPIPE); ! 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(), chain or exit if we are ! * at the end of the chain. Synchronous signals are delivered to the ! * thread that caused the signal. ! */ ! if (!PQinSend()) { ! if (pq_pipe_handler == SIG_DFL) /* not set by application */ ! exit(128 + SIGPIPE); /* typical return value for SIG_DFL */ ! else ! (*pq_pipe_handler) (signo); /* call original handler */ } - } - #endif - #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(pq_thread_in_send) /* has it been set? */ && - *(char *) pthread_getspecific(pq_thread_in_send) == 't') ? true : false; - #else ! /* ! * No threading: our code ignores SIGPIPE around send(). Therefore, we ! * can't be in send() if we are checking from a SIGPIPE signal ! * handler. ! */ ! return false; ! #endif } --- 1212,1264 ---- } #endif /* USE_SSL */ #ifdef ENABLE_THREAD_SAFETY /* ! * Block SIGPIPE for this thread. This prevents send()/write() from exiting ! * the application. */ ! int ! pq_block_sigpipe(sigset_t *osigset) { ! sigset_t sigpipe_sigset; ! ! sigemptyset(&sigpipe_sigset); ! sigaddset(&sigpipe_sigset, SIGPIPE); ! ! /* Block SIGPIPE and save previous mask for later reset */ ! return pthread_sigmask(SIG_BLOCK, &sigpipe_sigset, osigset); ! } ! ! /* ! * Discard any pending SIGPIPE and reset the signal mask. ! * We might be discarding a blocked SIGPIPE that we didn't generate, ! * but we document that you can't keep blocked SIGPIPE calls across ! * libpq function calls. */ ! int ! pq_reset_sigpipe(sigset_t *osigset) { ! int signo; ! sigset_t sigset; ! ! /* Is SIGPIPE pending? */ ! if (sigpending(&sigset) != 0) ! return -1; ! ! if (sigismember(&sigset, SIGPIPE)) { ! sigset_t sigpipe_sigset; ! ! sigemptyset(&sigpipe_sigset); ! sigaddset(&sigpipe_sigset, SIGPIPE); ! ! /* Discard pending and blocked SIGPIPE */ ! sigwait(&sigpipe_sigset, &signo); ! if (signo != SIGPIPE) ! return -1; } ! /* Restore saved block mask */ ! return pthread_sigmask(SIG_SETMASK, osigset, NULL); } + #endif Index: src/interfaces/libpq/libpq-fe.h =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/libpq-fe.h,v retrieving revision 1.113 diff -c -c -r1.113 libpq-fe.h *** src/interfaces/libpq/libpq-fe.h 30 Oct 2004 23:11:27 -0000 1.113 --- src/interfaces/libpq/libpq-fe.h 1 Dec 2004 22:55:33 -0000 *************** *** 497,508 **** /* === in fe-secure.c === */ - /* - * Indicates whether the libpq thread is in send(). - * Used to ignore SIGPIPE if thread is in send(). - */ - extern pqbool PQinSend(void); - #ifdef __cplusplus } #endif --- 497,502 ---- Index: src/interfaces/libpq/libpq-int.h =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/libpq-int.h,v retrieving revision 1.96 diff -c -c -r1.96 libpq-int.h *** src/interfaces/libpq/libpq-int.h 30 Oct 2004 23:11:27 -0000 1.96 --- src/interfaces/libpq/libpq-int.h 1 Dec 2004 22:55:35 -0000 *************** *** 31,36 **** --- 31,37 ---- #ifdef ENABLE_THREAD_SAFETY #include + #include #endif #ifdef WIN32_CLIENT_ONLY *************** *** 475,489 **** 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 pq_check_sigpipe_handler(void); - extern pthread_key_t pq_thread_in_send; - #endif - #ifdef USE_SSL extern bool pq_initssllib; #endif /* * this is so that we can check if a connection is non-blocking internally * without the overhead of a function call --- 476,490 ---- extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len); extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len); #ifdef USE_SSL extern bool pq_initssllib; #endif + #ifdef ENABLE_THREAD_SAFETY + int pq_block_sigpipe(sigset_t *osigset); + int pq_reset_sigpipe(sigset_t *osigset); + #endif + /* * this is so that we can check if a connection is non-blocking internally * without the overhead of a function call