Thread: Re: [HACKERS] libpq problem

Re: [HACKERS] libpq problem

From
Andreas Pflug
Date:
Andreas Pflug wrote:
> Some recent change in libpq seems to interfere with gtk.
>
> After I tested a new pgadmin3 version on linuy yesterday, I found that
> the GUI is hanging after PQconnectdb was called. After the call, the db
> connection is fully functional, but the GUI mouse will show "waiting"
> and the program doesn't react to mouse clicks any more; screen updates
> are not performed either.
>
> When I replace the 8.0 libpq.so* version with an older saved version
> (7.4.3 from debian installation) it works ok.

OK, I found out. Seems I didn't run make distclean for a longer time, so
I didn't realize earlier.

The reason is the sigpipe handling code. If the app (in this case: some
gtk internals) already installed a SIGPIPE handler, the thread_in_send
key is not created. pthread_setspecific calls will thus use an invalid
key, which screws up gtk.

The attached patch will implement two features:
1) unconditionally create thread_in_send
2) Always register our own SIGPIPE handler, chain to a previously
registered handler when the signal is thrown while not sending.

Regards,
Andreas
Index: fe-secure.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/fe-secure.c,v
retrieving revision 1.45
diff -u -r1.45 fe-secure.c
--- fe-secure.c    12 Jul 2004 14:23:28 -0000    1.45
+++ fe-secure.c    11 Aug 2004 12:49:35 -0000
@@ -153,6 +153,7 @@
 #ifdef ENABLE_THREAD_SAFETY
 static void sigpipe_handler_ignore_send(int signo);
 pthread_key_t thread_in_send;
+static pqsigfunc pipehandler;
 #endif

 /* ------------------------------------------------------------ */
@@ -1190,23 +1191,14 @@
 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.
      */
+    pthread_key_create(&thread_in_send, NULL);
     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);
-    }
+    pqsignal(SIGPIPE, sigpipe_handler_ignore_send);
 }

 /*
@@ -1221,7 +1213,12 @@
      *    that caused the signal.
      */
     if (!PQinSend())
-        exit(128 + SIGPIPE);    /* typical return value for SIG_DFL */
+    {
+        if (pipehandler == SIG_DFL)    /* not set by application */
+            exit(128 + SIGPIPE);    /* typical return value for SIG_DFL */
+        else
+            (*pipehandler)(signo);      /* call original handler */
+    }
 }
 #endif
 #endif

Re: [HACKERS] libpq problem

From
Bruce Momjian
Date:
OK, I like your idea of chaining on to any existing SIGPIPE handler
rather than just do it if none is installed.  I also see your fix for
the uninitialized thread-specific variable.

I added some comments to the patch, renamed the pipeheader variable so
it was pg_* to avoid namespace conflicts, and updated the documentation.

Patch attached and applied.

---------------------------------------------------------------------------

Andreas Pflug wrote:
> Andreas Pflug wrote:
> > Some recent change in libpq seems to interfere with gtk.
> >
> > After I tested a new pgadmin3 version on linuy yesterday, I found that
> > the GUI is hanging after PQconnectdb was called. After the call, the db
> > connection is fully functional, but the GUI mouse will show "waiting"
> > and the program doesn't react to mouse clicks any more; screen updates
> > are not performed either.
> >
> > When I replace the 8.0 libpq.so* version with an older saved version
> > (7.4.3 from debian installation) it works ok.
>
> OK, I found out. Seems I didn't run make distclean for a longer time, so
> I didn't realize earlier.
>
> The reason is the sigpipe handling code. If the app (in this case: some
> gtk internals) already installed a SIGPIPE handler, the thread_in_send
> key is not created. pthread_setspecific calls will thus use an invalid
> key, which screws up gtk.
>
> The attached patch will implement two features:
> 1) unconditionally create thread_in_send
> 2) Always register our own SIGPIPE handler, chain to a previously
> registered handler when the signal is thrown while not sending.
>
> Regards,
> Andreas


>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: the planner will ignore your desire to choose an index scan if your
>       joining column's datatypes do not match

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: doc/src/sgml/libpq.sgml
===================================================================
RCS file: /cvsroot/pgsql-server/doc/src/sgml/libpq.sgml,v
retrieving revision 1.159
diff -c -c -r1.159 libpq.sgml
*** doc/src/sgml/libpq.sgml    16 Aug 2004 02:12:29 -0000    1.159
--- doc/src/sgml/libpq.sgml    17 Aug 2004 16:43:10 -0000
***************
*** 3738,3745 ****
  <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 a libpq <function>send()</>. If an application wants to install
  its own <literal>SIGPIPE</> signal handler, it should call
--- 3738,3744 ----
  <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
Index: src/interfaces/libpq/fe-secure.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/interfaces/libpq/fe-secure.c,v
retrieving revision 1.46
diff -c -c -r1.46 fe-secure.c
*** src/interfaces/libpq/fe-secure.c    17 Aug 2004 04:24:23 -0000    1.46
--- src/interfaces/libpq/fe-secure.c    17 Aug 2004 16:43:19 -0000
***************
*** 152,158 ****

  #ifdef ENABLE_THREAD_SAFETY
  static void sigpipe_handler_ignore_send(int signo);
! pthread_key_t pq_thread_in_send = 0;
  #endif

  /* ------------------------------------------------------------ */
--- 152,159 ----

  #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

  /* ------------------------------------------------------------ */
***************
*** 1190,1212 ****
  void
  pq_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(&pq_thread_in_send, NULL);
!         pqsignal(SIGPIPE, sigpipe_handler_ignore_send);
!     }
  }

  /*
--- 1191,1202 ----
  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);
  }

  /*
***************
*** 1216,1227 ****
  sigpipe_handler_ignore_send(int signo)
  {
      /*
!      *    If we have gotten a SIGPIPE outside send(), exit.
!      *    Synchronous signals are delivered to the thread
!      *    that caused the signal.
       */
      if (!PQinSend())
!         exit(128 + SIGPIPE);    /* typical return value for SIG_DFL */
  }
  #endif
  #endif
--- 1206,1223 ----
  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

Re: [HACKERS] libpq problem

From
Oliver Jowett
Date:
Bruce Momjian wrote:
> OK, I like your idea of chaining on to any existing SIGPIPE handler
> rather than just do it if none is installed.  I also see your fix for
> the uninitialized thread-specific variable.
>
> I added some comments to the patch, renamed the pipeheader variable so
> it was pg_* to avoid namespace conflicts, and updated the documentation.
>
> Patch attached and applied.

At a glance, this looks like it will break applications that pass
SA_SIGINFO in sa_flags for their SIGPIPE handlers. This changes the
expected signal handler signature to a three-arg form; the extra two
args provide context about where the signal occurred. The libpq handler,
however, doesn't pass those args when chaining to the next handler.

The Sun JVM under linux is one example of an app that does1 this. I've
seen a similar problem to this before with a version of libnss_ldap that
did not correctly restore the entire sigaction state when restoring the
SIGPIPE handler before returning from libnss_ldap .. the next SIGPIPE
that arrives would crash the JVM. See
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4630104 for more
details (requires registration)

-O