sigpipe handling - Mailing list pgsql-patches

From Manfred Spraul
Subject sigpipe handling
Date
Msg-id 3FAD69CF.1070604@colorfullife.com
Whole thread Raw
Responses Re: sigpipe handling
List pgsql-patches
Attatched is the latest version of my patch that makes the
signal(SIG_PIPE, SIG_IGN) calls around the send() syscall conditional:
they are not sufficient to ensure that multithreaded libpq users are not
killed by SIGPIPE signals, and they cause a noticable slowdown.
I've switched to a global flag, and two functions to get/set the flag.
Any other ideas how to protect libpq against SIGPIPE?

--
    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: WIN32_DEV CVS branch
Next
From: "Marc G. Fournier"
Date:
Subject: Re: [pgsql-hackers-win32] WIN32_DEV CVS branch