LCOV - code coverage report
Current view: top level - src/port - pqsignal.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 89.3 % 28 25
Test Date: 2026-05-04 19:16:35 Functions: 100.0 % 3 3
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * pqsignal.c
       4              :  *    reliable BSD-style signal(2) routine stolen from RWW who stole it
       5              :  *    from Stevens...
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  *
      11              :  * IDENTIFICATION
      12              :  *    src/port/pqsignal.c
      13              :  *
      14              :  *  This is the signal() implementation from "Advanced Programming in the UNIX
      15              :  *  Environment", with minor changes.  It was originally a replacement needed
      16              :  *  for old SVR4 systems whose signal() behaved as if sa_flags = SA_RESETHAND |
      17              :  *  SA_NODEFER, also known as "unreliable" signals due to races when the
      18              :  *  handler was reset.
      19              :  *
      20              :  *  By now, all known modern Unix systems have a "reliable" signal() call.
      21              :  *  We still don't want to use it though, because it remains
      22              :  *  implementation-defined by both C99 and POSIX whether the handler is reset
      23              :  *  or signals are blocked when the handler runs, and default restart behavior
      24              :  *  is also unspecified.  Therefore we take POSIX's advice and call sigaction()
      25              :  *  so we can provide explicit sa_flags, but wrap it in this more convenient
      26              :  *  traditional interface style.  It also provides a place to set any extra
      27              :  *  flags we want everywhere, such as SA_NOCLDSTOP.
      28              :  *
      29              :  *  Windows, of course, is resolutely in a class by itself.  In the backend,
      30              :  *  this relies on pqsigaction() in src/backend/port/win32/signal.c, which
      31              :  *  provides limited emulation of reliable signals.
      32              :  *
      33              :  *  Frontend programs can use this version of pqsignal() to forward to the
      34              :  *  native Windows signal() call if they wish, but beware that Windows signals
      35              :  *  behave quite differently.  Only the 6 signals required by C are supported.
      36              :  *  SIGINT handlers run in another thread instead of interrupting an existing
      37              :  *  thread, and the others don't interrupt system calls either, so SA_RESTART
      38              :  *  is moot.  All except SIGFPE have SA_RESETHAND semantics, meaning the
      39              :  *  handler is reset to SIG_DFL each time it runs.  The set of things you are
      40              :  *  allowed to do in a handler is also much more restricted than on Unix,
      41              :  *  according to the documentation.
      42              :  *
      43              :  * ------------------------------------------------------------------------
      44              :  */
      45              : 
      46              : #include "c.h"
      47              : 
      48              : #include <signal.h>
      49              : #ifndef FRONTEND
      50              : #include <unistd.h>
      51              : #endif
      52              : 
      53              : #ifndef FRONTEND
      54              : #include "libpq/pqsignal.h"
      55              : #include "miscadmin.h"
      56              : #endif
      57              : 
      58              : #ifdef PG_SIGNAL_COUNT          /* Windows */
      59              : #define PG_NSIG (PG_SIGNAL_COUNT)
      60              : #elif defined(NSIG)
      61              : #define PG_NSIG (NSIG)
      62              : #else
      63              : #define PG_NSIG (64)            /* XXX: wild guess */
      64              : #endif
      65              : 
      66              : #if !(defined(WIN32) && defined(FRONTEND))
      67              : #define USE_SIGACTION
      68              : #endif
      69              : 
      70              : #if defined(USE_SIGACTION) && defined(HAVE_SA_SIGINFO)
      71              : #define USE_SIGINFO
      72              : #endif
      73              : 
      74              : /* Check a couple of common signals to make sure PG_NSIG is accurate. */
      75              : StaticAssertDecl(SIGUSR2 < PG_NSIG, "SIGUSR2 >= PG_NSIG");
      76              : StaticAssertDecl(SIGHUP < PG_NSIG, "SIGHUP >= PG_NSIG");
      77              : StaticAssertDecl(SIGTERM < PG_NSIG, "SIGTERM >= PG_NSIG");
      78              : StaticAssertDecl(SIGALRM < PG_NSIG, "SIGALRM >= PG_NSIG");
      79              : 
      80              : static volatile pqsigfunc pqsignal_handlers[PG_NSIG];
      81              : 
      82              : /*
      83              :  * Except when called with SIG_IGN or SIG_DFL, pqsignal() sets up this function
      84              :  * as the handler for all signals.  This wrapper handler function checks that
      85              :  * it is called within a process that knew to maintain MyProcPid, and not a
      86              :  * child process forked by system(3), etc.  This check ensures that such child
      87              :  * processes do not modify shared memory, which is often detrimental.  If the
      88              :  * check succeeds, the function originally provided to pqsignal() is called.
      89              :  * Otherwise, the default signal handler is installed and then called.
      90              :  *
      91              :  * This wrapper also handles restoring the value of errno.
      92              :  */
      93              : #if defined(USE_SIGACTION) && defined(USE_SIGINFO)
      94              : static void
      95       164901 : wrapper_handler(int postgres_signal_arg, siginfo_t * info, void *context)
      96              : #else                           /* no USE_SIGINFO */
      97              : static void
      98              : wrapper_handler(int postgres_signal_arg)
      99              : #endif
     100              : {
     101       164901 :     int         save_errno = errno;
     102              :     pg_signal_info pg_info;
     103              : 
     104              :     Assert(postgres_signal_arg > 0);
     105              :     Assert(postgres_signal_arg < PG_NSIG);
     106              : 
     107              : #ifndef FRONTEND
     108              : 
     109              :     /*
     110              :      * We expect processes to set MyProcPid before calling pqsignal() or
     111              :      * before accepting signals.
     112              :      */
     113              :     Assert(MyProcPid);
     114              :     Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster);
     115              : 
     116       164742 :     if (unlikely(MyProcPid != (int) getpid()))
     117              :     {
     118            0 :         pqsignal(postgres_signal_arg, PG_SIG_DFL);
     119            0 :         raise(postgres_signal_arg);
     120            0 :         return;
     121              :     }
     122              : #endif
     123              : 
     124              : #ifdef HAVE_SA_SIGINFO
     125              : 
     126              :     /*
     127              :      * If supported by the system, forward interesting information from the
     128              :      * system's extended signal information to our platform independent
     129              :      * format.
     130              :      */
     131       164901 :     pg_info.pid = info->si_pid;
     132       164901 :     pg_info.uid = info->si_uid;
     133              : #else
     134              : 
     135              :     /*
     136              :      * Otherwise forward values indicating that we do not have the
     137              :      * information.
     138              :      */
     139              :     pg_info.pid = 0;
     140              :     pg_info.uid = 0;
     141              : #endif
     142              : 
     143       164901 :     (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg, &pg_info);
     144              : 
     145       164900 :     errno = save_errno;
     146          159 : }
     147              : 
     148              : /*
     149              :  * Set up a signal handler, with SA_RESTART, for signal "signo"
     150              :  *
     151              :  * Note: the actual name of this function is either pqsignal_fe when
     152              :  * compiled with -DFRONTEND, or pqsignal_be when compiled without that.
     153              :  * This is to avoid a name collision with libpq's legacy-pqsignal.c.
     154              :  */
     155              : void
     156       365438 : pqsignal(int signo, pqsigfunc func)
     157              : {
     158              : #ifdef USE_SIGACTION
     159              :     struct sigaction act;
     160              : #else
     161              :     void        (*wrapper_func_ptr) (int);
     162              : #endif
     163       365438 :     bool        is_ign = func == PG_SIG_IGN;
     164       365438 :     bool        is_dfl = func == PG_SIG_DFL;
     165              : 
     166              :     Assert(signo > 0);
     167              :     Assert(signo < PG_NSIG);
     168              : 
     169              :     /* set up indirection handler */
     170       365438 :     if (!(is_ign || is_dfl))
     171              :     {
     172       270904 :         pqsignal_handlers[signo] = func;    /* assumed atomic */
     173              :     }
     174              : 
     175              :     /*
     176              :      * Configure system to either ignore/reset the signal handler, or to
     177              :      * forward it to wrapper_handler.
     178              :      */
     179              : #ifdef USE_SIGACTION
     180       365438 :     sigemptyset(&act.sa_mask);
     181       365438 :     act.sa_flags = SA_RESTART;
     182              : 
     183       365438 :     if (is_ign)
     184        60758 :         act.sa_handler = SIG_IGN;
     185       304680 :     else if (is_dfl)
     186        33776 :         act.sa_handler = SIG_DFL;
     187              : #ifdef USE_SIGINFO
     188              :     else
     189              :     {
     190       270904 :         act.sa_sigaction = wrapper_handler;
     191       270904 :         act.sa_flags |= SA_SIGINFO;
     192              :     }
     193              : #else
     194              :     else
     195              :         act.sa_handler = wrapper_handler;
     196              : #endif
     197              : 
     198              : #ifdef SA_NOCLDSTOP
     199       365438 :     if (signo == SIGCHLD)
     200        34670 :         act.sa_flags |= SA_NOCLDSTOP;
     201              : #endif
     202       365438 :     if (sigaction(signo, &act, NULL) < 0)
     203              :         Assert(false);          /* probably indicates coding error */
     204              : #else                           /* no USE_SIGACTION */
     205              : 
     206              :     /*
     207              :      * Forward to Windows native signal system, we need to send this though
     208              :      * wrapper handler as it it needs to take single argument only.
     209              :      */
     210              :     if (is_ign)
     211              :         wrapper_func_ptr = SIG_IGN;
     212              :     else if (is_dfl)
     213              :         wrapper_func_ptr = SIG_DFL;
     214              :     else
     215              :         wrapper_func_ptr = wrapper_handler;
     216              : 
     217              :     if (signal(signo, wrapper_func_ptr) == SIG_ERR)
     218              :         Assert(false);          /* probably indicates coding error */
     219              : #endif
     220       365438 : }
        

Generated by: LCOV version 2.0-1