Tom Lane wrote:
> Bruce Momjian <[EMAIL PROTECTED]> writes:
> > Yes, that is the logic in my patch, except that I don't check errno, I
> > just call sigpending().
> 
> No, that's wrong: if there is a pending SIGPIPE that belongs to the
> outer app, you'd clear it.

True, but I documented that in the patch.

> > There are a few writes and it seemed impossible
> > to check them all.
> 
> Hmm?  There is only one place this needs to be done, namely
> pqsecure_write.

Look also in fe-print.c.  Looks like a lot of popen writes in there.
I can do it but it will be harder.

> BTW, have you posted the patch yet or are you still working on it?
> The mail server seems a bit flaky today ...

OK, patch attached.  I already sent it but who knows what happened to
it.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  [EMAIL PROTECTED]               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
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 ****
  </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.  This handler uses thread-local
! storage to determine if a <literal>SIGPIPE</> signal has been generated
! by a libpq <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>
  
  <para>
--- 3955,3964 ----
  </para>
  
  <para>
! <application>libpq</application> blocks and discards <literal>SIGPIPE</>
! signals generated internally by <function>send()</> calls to the backend 
! process. Therefore, applications should not expect blocked <literal>SIGPIPE</>
! signals to remain across <application>libpq</application> function calls.
  </para>
  
  <para>
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
  -->
  
+ 
  <refentry id="SQL-COPY">
   <refmeta>
    <refentrytitle id="sql-copy-title">COPY</refentrytitle>
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 <pthread.h>
+ #include <signal.h>
  #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
---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faqs/FAQ.html

Reply via email to