LCOV - code coverage report
Current view: top level - src/port - pqsignal.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 89.3 % 28 25
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 3 3
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 91.7 % 12 11

             Branch data     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                 :      160005 : 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                 :      160005 :     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         [ -  + ]:      159843 :     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                 :      160006 :     pg_info.pid = info->si_pid;
     132                 :      160006 :     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                 :      160006 :     (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg, &pg_info);
     144                 :             : 
     145                 :      160006 :     errno = save_errno;
     146                 :         162 : }
     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                 :      372913 : 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                 :      372913 :     bool        is_ign = func == PG_SIG_IGN;
     164                 :      372913 :     bool        is_dfl = func == PG_SIG_DFL;
     165                 :             : 
     166                 :             :     Assert(signo > 0);
     167                 :             :     Assert(signo < PG_NSIG);
     168                 :             : 
     169                 :             :     /* set up indirection handler */
     170   [ +  +  +  + ]:      372913 :     if (!(is_ign || is_dfl))
     171                 :             :     {
     172                 :      276765 :         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                 :      372913 :     sigemptyset(&act.sa_mask);
     181                 :      372913 :     act.sa_flags = SA_RESTART;
     182                 :             : 
     183         [ +  + ]:      372913 :     if (is_ign)
     184                 :       61544 :         act.sa_handler = SIG_IGN;
     185         [ +  + ]:      311369 :     else if (is_dfl)
     186                 :       34604 :         act.sa_handler = SIG_DFL;
     187                 :             : #ifdef USE_SIGINFO
     188                 :             :     else
     189                 :             :     {
     190                 :      276765 :         act.sa_sigaction = wrapper_handler;
     191                 :      276765 :         act.sa_flags |= SA_SIGINFO;
     192                 :             :     }
     193                 :             : #else
     194                 :             :     else
     195                 :             :         act.sa_handler = wrapper_handler;
     196                 :             : #endif
     197                 :             : 
     198                 :             : #ifdef SA_NOCLDSTOP
     199         [ +  + ]:      372913 :     if (signo == SIGCHLD)
     200                 :       35502 :         act.sa_flags |= SA_NOCLDSTOP;
     201                 :             : #endif
     202                 :      372913 :     if (sigaction(signo, &act, NULL) < 0)
     203                 :             :         Assert(false);          /* probably indicates coding error */
     204                 :             : #else                           /* no USE_SIGACTION */
     205                 :             : 
     206                 :             :     /*
     207                 :             :      * Forward to the native Windows signal handler through a wrapper, since
     208                 :             :      * it accepts only one argument.
     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                 :      372913 : }
        

Generated by: LCOV version 2.0-1