LCOV - code coverage report
Current view: top level - src/port - pqsignal.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 85.0 % 20 17
Test Date: 2026-03-03 10:15:07 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              : /* Check a couple of common signals to make sure PG_NSIG is accurate. */
      67              : StaticAssertDecl(SIGUSR2 < PG_NSIG, "SIGUSR2 >= PG_NSIG");
      68              : StaticAssertDecl(SIGHUP < PG_NSIG, "SIGHUP >= PG_NSIG");
      69              : StaticAssertDecl(SIGTERM < PG_NSIG, "SIGTERM >= PG_NSIG");
      70              : StaticAssertDecl(SIGALRM < PG_NSIG, "SIGALRM >= PG_NSIG");
      71              : 
      72              : static volatile pqsigfunc pqsignal_handlers[PG_NSIG];
      73              : 
      74              : /*
      75              :  * Except when called with SIG_IGN or SIG_DFL, pqsignal() sets up this function
      76              :  * as the handler for all signals.  This wrapper handler function checks that
      77              :  * it is called within a process that knew to maintain MyProcPid, and not a
      78              :  * child process forked by system(3), etc.  This check ensures that such child
      79              :  * processes do not modify shared memory, which is often detrimental.  If the
      80              :  * check succeeds, the function originally provided to pqsignal() is called.
      81              :  * Otherwise, the default signal handler is installed and then called.
      82              :  *
      83              :  * This wrapper also handles restoring the value of errno.
      84              :  */
      85              : static void
      86       170135 : wrapper_handler(SIGNAL_ARGS)
      87              : {
      88       170135 :     int         save_errno = errno;
      89              : 
      90              :     Assert(postgres_signal_arg > 0);
      91              :     Assert(postgres_signal_arg < PG_NSIG);
      92              : 
      93              : #ifndef FRONTEND
      94              : 
      95              :     /*
      96              :      * We expect processes to set MyProcPid before calling pqsignal() or
      97              :      * before accepting signals.
      98              :      */
      99              :     Assert(MyProcPid);
     100              :     Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster);
     101              : 
     102       169983 :     if (unlikely(MyProcPid != (int) getpid()))
     103              :     {
     104            0 :         pqsignal(postgres_signal_arg, SIG_DFL);
     105            0 :         raise(postgres_signal_arg);
     106            0 :         return;
     107              :     }
     108              : #endif
     109              : 
     110       170135 :     (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg);
     111              : 
     112       170135 :     errno = save_errno;
     113          152 : }
     114              : 
     115              : /*
     116              :  * Set up a signal handler, with SA_RESTART, for signal "signo"
     117              :  *
     118              :  * Note: the actual name of this function is either pqsignal_fe when
     119              :  * compiled with -DFRONTEND, or pqsignal_be when compiled without that.
     120              :  * This is to avoid a name collision with libpq's legacy-pqsignal.c.
     121              :  */
     122              : void
     123       341280 : pqsignal(int signo, pqsigfunc func)
     124              : {
     125              : #if !(defined(WIN32) && defined(FRONTEND))
     126              :     struct sigaction act;
     127              : #endif
     128              : 
     129              :     Assert(signo > 0);
     130              :     Assert(signo < PG_NSIG);
     131              : 
     132       341280 :     if (func != SIG_IGN && func != SIG_DFL)
     133              :     {
     134       253211 :         pqsignal_handlers[signo] = func;    /* assumed atomic */
     135       253211 :         func = wrapper_handler;
     136              :     }
     137              : 
     138              : #if !(defined(WIN32) && defined(FRONTEND))
     139       341280 :     act.sa_handler = func;
     140       341280 :     sigemptyset(&act.sa_mask);
     141       341280 :     act.sa_flags = SA_RESTART;
     142              : #ifdef SA_NOCLDSTOP
     143       341280 :     if (signo == SIGCHLD)
     144        31901 :         act.sa_flags |= SA_NOCLDSTOP;
     145              : #endif
     146       341280 :     if (sigaction(signo, &act, NULL) < 0)
     147              :         Assert(false);          /* probably indicates coding error */
     148              : #else
     149              :     /* Forward to Windows native signal system. */
     150              :     if (signal(signo, func) == SIG_ERR)
     151              :         Assert(false);          /* probably indicates coding error */
     152              : #endif
     153       341280 : }
        

Generated by: LCOV version 2.0-1