Re: SIGPIPE handling - Mailing list pgsql-patches

From Manfred Spraul
Subject Re: SIGPIPE handling
Date
Msg-id 3FB7BFDE.3070303@colorfullife.com
Whole thread Raw
In response to Re: SIGPIPE handling  (Bruce Momjian <pgman@candle.pha.pa.us>)
Responses Re: SIGPIPE handling
Re: SIGPIPE handling
List pgsql-patches
Bruce Momjian wrote:

>I thought it should be global too, basically testing on the first
>connection request.
>
What if two PQconnect calls happen at the same time?
I would really prefer the manual approach with a new PQsetsighandler
function - the autodetection is fragile, it's trivial to find a special
case where it breaks.
Bruce, you wrote that a new function would be overdesign. Are you sure?
Your simpler proposals all fail with multithreaded apps.
I've attached the patch that implements the global flag with two special
function that access it.

--
    Manfred
Index: contrib/pgbench/README.pgbench
===================================================================
RCS file: /projects/cvsroot/pgsql-server/contrib/pgbench/README.pgbench,v
retrieving revision 1.9
diff -c -r1.9 README.pgbench
*** contrib/pgbench/README.pgbench    10 Jun 2003 09:07:15 -0000    1.9
--- contrib/pgbench/README.pgbench    8 Nov 2003 21:43:53 -0000
***************
*** 112,117 ****
--- 112,121 ----
          might be a security hole since ps command will
          show the password. Use this for TESTING PURPOSE ONLY.

+     -a
+         Disable SIGPIPE delivery globally instead of within each
+         libpq operation.
+
      -n
          No vacuuming and cleaning the history table prior to the
          test is performed.
Index: contrib/pgbench/pgbench.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/contrib/pgbench/pgbench.c,v
retrieving revision 1.27
diff -c -r1.27 pgbench.c
*** contrib/pgbench/pgbench.c    27 Sep 2003 19:15:34 -0000    1.27
--- contrib/pgbench/pgbench.c    8 Nov 2003 21:43:54 -0000
***************
*** 28,33 ****
--- 28,34 ----
  #else
  #include <sys/time.h>
  #include <unistd.h>
+ #include <signal.h>

  #ifdef HAVE_GETOPT_H
  #include <getopt.h>
***************
*** 105,112 ****
  static void
  usage()
  {
!     fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s
scaling_factor][-n][-C][-v][-S][-N][-l][-Ulogin][-P password][-d][dbname]\n"); 
!     fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P
password][-d][dbname]\n");
  }

  /* random number generator */
--- 106,113 ----
  static void
  usage()
  {
!     fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s
scaling_factor][-n][-C][-v][-S][-N][-l][-a][-Ulogin][-P password][-d][dbname]\n"); 
!     fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P
password][-d][dbname][-a]\n");
  }

  /* random number generator */
***************
*** 703,712 ****
      else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
          login = env;

!     while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNSl")) != -1)
      {
          switch (c)
          {
              case 'i':
                  is_init_mode++;
                  break;
--- 704,719 ----
      else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
          login = env;

!     while ((c = getopt(argc, argv, "aih:nvp:dc:t:s:U:P:CNSl")) != -1)
      {
          switch (c)
          {
+             case 'a':
+ #ifndef WIN32
+                 signal(SIGPIPE, SIG_IGN);
+ #endif
+                 PQsetsighandling(0);
+                 break;
              case 'i':
                  is_init_mode++;
                  break;
Index: doc/src/sgml/libpq.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/libpq.sgml,v
retrieving revision 1.141
diff -c -r1.141 libpq.sgml
*** doc/src/sgml/libpq.sgml    1 Nov 2003 01:56:29 -0000    1.141
--- doc/src/sgml/libpq.sgml    8 Nov 2003 21:43:56 -0000
***************
*** 645,650 ****
--- 645,693 ----
    </listitem>
   </varlistentry>

+  <varlistentry>
+   <term><function>PQsetsighandling</function><indexterm><primary>PQsetsighandling</></></term>
+   <term><function>PQgetsighandling</function><indexterm><primary>PQgetsighandling</></></term>
+   <listitem>
+    <para>
+    Set/query SIGPIPE signal handling.
+ <synopsis>
+ void PQsetsighandling(int internal_sigign);
+ </synopsis>
+ <synopsis>
+ int PQgetsighandling(void);
+ </synopsis>
+ </para>
+
+ <para>
+     These functions allow to query and set the SIGPIPE signal handling
+     of libpq: by default, Unix systems generate a (fatal) SIGPIPE signal
+     on write attempts to a disconnected socket. Most callers expect a
+     normal error return instead of the signal. A normal error return can
+     be achieved by blocking or ignoring the SIGPIPE signal. This can be
+     done either globally in the application or inside libpq.
+    </para>
+    <para>
+     If internal signal handling is enabled (this is the default), then
+     libpq sets the SIGPIPE handler to SIG_IGN before every socket send
+     operation and restores it afterwards. This prevents libpq from
+     killing the application, at the cost of a slight performance
+     decrease. This approach is not reliable for multithreaded applications.
+    </para>
+    <para>
+     If internal signal handling is disabled, then the caller is
+     responsible for blocking or handling SIGPIPE signals. This is
+     recommended for multithreaded applications.
+    </para>
+    <para>
+     The signal handler setting is a global flag, it affects all
+     connections. The setting has no effect for Win32 clients - Win32
+     doesn't generate SIGPIPE events.
+    </para>
+   </listitem>
+  </varlistentry>
+
+
   </variablelist>
  </para>
  </sect1>
Index: src/interfaces/libpq/blibpqdll.def
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/blibpqdll.def,v
retrieving revision 1.9
diff -c -r1.9 blibpqdll.def
*** src/interfaces/libpq/blibpqdll.def    13 Aug 2003 16:29:03 -0000    1.9
--- src/interfaces/libpq/blibpqdll.def    8 Nov 2003 21:43:57 -0000
***************
*** 113,118 ****
--- 113,120 ----
      _PQfformat               @ 109
      _PQexecPrepared          @ 110
      _PQsendQueryPrepared     @ 111
+     _PQsetsighandling        @ 112
+     _PQgetsighandling        @ 113

  ; Aliases for MS compatible names
      PQconnectdb             = _PQconnectdb
***************
*** 226,228 ****
--- 228,232 ----
      PQfformat               = _PQfformat
      PQexecPrepared          = _PQexecPrepared
      PQsendQueryPrepared     = _PQsendQueryPrepared
+     PQsetsighandling        = _PQsetsighandling
+     PQgetsighandling        = _PQgetsighandling
Index: src/interfaces/libpq/fe-secure.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/fe-secure.c,v
retrieving revision 1.32
diff -c -r1.32 fe-secure.c
*** src/interfaces/libpq/fe-secure.c    29 Sep 2003 16:38:04 -0000    1.32
--- src/interfaces/libpq/fe-secure.c    8 Nov 2003 21:43:58 -0000
***************
*** 198,203 ****
--- 198,204 ----
  -----END DH PARAMETERS-----\n";
  #endif

+ static int do_sigaction = 1;
  /* ------------------------------------------------------------ */
  /*             Procedures common to all secure sessions            */
  /* ------------------------------------------------------------ */
***************
*** 348,354 ****
      ssize_t        n;

  #ifndef WIN32
!     pqsigfunc    oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
  #endif

  #ifdef USE_SSL
--- 349,358 ----
      ssize_t        n;

  #ifndef WIN32
!     pqsigfunc    oldsighandler = NULL;
!
!     if (do_sigaction)
!         oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
  #endif

  #ifdef USE_SSL
***************
*** 408,417 ****
          n = send(conn->sock, ptr, len, 0);

  #ifndef WIN32
!     pqsignal(SIGPIPE, oldsighandler);
  #endif

      return n;
  }

  /* ------------------------------------------------------------ */
--- 412,432 ----
          n = send(conn->sock, ptr, len, 0);

  #ifndef WIN32
!     if (do_sigaction)
!         pqsignal(SIGPIPE, oldsighandler);
  #endif

      return n;
+ }
+
+ void PQsetsighandling(int internal_sigign)
+ {
+     do_sigaction = internal_sigign;
+ }
+
+ int PQgetsighandling(void)
+ {
+     return do_sigaction;
  }

  /* ------------------------------------------------------------ */
Index: src/interfaces/libpq/libpq-fe.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/libpq-fe.h,v
retrieving revision 1.100
diff -c -r1.100 libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h    27 Aug 2003 00:33:34 -0000    1.100
--- src/interfaces/libpq/libpq-fe.h    8 Nov 2003 21:43:58 -0000
***************
*** 221,226 ****
--- 221,232 ----
  /* free the data structure returned by PQconndefaults() */
  extern void PQconninfoFree(PQconninfoOption *connOptions);

+ /* ===    in fe-secure.c === */
+
+ /* get/set SIGPIPE handling */
+ extern void PQsetsighandling(int internal_sigign);
+ extern int PQgetsighandling(void);
+
  /*
   * close the current connection and restablish a new one with the same
   * parameters

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: SRA Win32 sync() code
Next
From: Tom Lane
Date:
Subject: Re: SRA Win32 sync() code