LCOV - code coverage report
Current view: top level - src/port - pqsignal.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 19 24 79.2 %
Date: 2024-04-26 09:11:35 Functions: 2 2 100.0 %
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-2024, 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 the server knows about (i.e., any process
      78             :  * that has called InitProcessGlobals(), such as a client backend), and not a
      79             :  * child process forked by system(3), etc.  This check ensures that such child
      80             :  * processes do not modify shared memory, which is often detrimental.  If the
      81             :  * check succeeds, the function originally provided to pqsignal() is called.
      82             :  * Otherwise, the default signal handler is installed and then called.
      83             :  *
      84             :  * This wrapper also handles restoring the value of errno.
      85             :  */
      86             : static void
      87       62182 : wrapper_handler(SIGNAL_ARGS)
      88             : {
      89       62182 :     int         save_errno = errno;
      90             : 
      91             : #ifndef FRONTEND
      92             : 
      93             :     /*
      94             :      * We expect processes to set MyProcPid before calling pqsignal() or
      95             :      * before accepting signals.
      96             :      */
      97             :     Assert(MyProcPid);
      98             :     Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster);
      99             : 
     100       62182 :     if (unlikely(MyProcPid != (int) getpid()))
     101             :     {
     102           0 :         pqsignal(postgres_signal_arg, SIG_DFL);
     103           0 :         raise(postgres_signal_arg);
     104           0 :         return;
     105             :     }
     106             : #endif
     107             : 
     108       62182 :     (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg);
     109             : 
     110       62182 :     errno = save_errno;
     111           0 : }
     112             : 
     113             : /*
     114             :  * Set up a signal handler, with SA_RESTART, for signal "signo"
     115             :  *
     116             :  * Returns the previous handler.
     117             :  *
     118             :  * NB: If called within a signal handler, race conditions may lead to bogus
     119             :  * return values.  You should either avoid calling this within signal handlers
     120             :  * or ignore the return value.
     121             :  *
     122             :  * XXX: Since no in-tree callers use the return value, and there is little
     123             :  * reason to do so, it would be nice if we could convert this to a void
     124             :  * function instead of providing potentially-bogus return values.
     125             :  * Unfortunately, that requires modifying the pqsignal() in legacy-pqsignal.c,
     126             :  * which in turn requires an SONAME bump, which is probably not worth it.
     127             :  */
     128             : pqsigfunc
     129      411050 : pqsignal(int signo, pqsigfunc func)
     130             : {
     131      411050 :     pqsigfunc   orig_func = pqsignal_handlers[signo];   /* assumed atomic */
     132             : #if !(defined(WIN32) && defined(FRONTEND))
     133             :     struct sigaction act,
     134             :                 oact;
     135             : #else
     136             :     pqsigfunc   ret;
     137             : #endif
     138             : 
     139             :     Assert(signo < PG_NSIG);
     140             : 
     141      411050 :     if (func != SIG_IGN && func != SIG_DFL)
     142             :     {
     143      307778 :         pqsignal_handlers[signo] = func;    /* assumed atomic */
     144      307778 :         func = wrapper_handler;
     145             :     }
     146             : 
     147             : #if !(defined(WIN32) && defined(FRONTEND))
     148      411050 :     act.sa_handler = func;
     149      411050 :     sigemptyset(&act.sa_mask);
     150      411050 :     act.sa_flags = SA_RESTART;
     151             : #ifdef SA_NOCLDSTOP
     152      411050 :     if (signo == SIGCHLD)
     153       31444 :         act.sa_flags |= SA_NOCLDSTOP;
     154             : #endif
     155      411050 :     if (sigaction(signo, &act, &oact) < 0)
     156           0 :         return SIG_ERR;
     157      411050 :     else if (oact.sa_handler == wrapper_handler)
     158      275086 :         return orig_func;
     159             :     else
     160      135964 :         return oact.sa_handler;
     161             : #else
     162             :     /* Forward to Windows native signal system. */
     163             :     if ((ret = signal(signo, func)) == wrapper_handler)
     164             :         return orig_func;
     165             :     else
     166             :         return ret;
     167             : #endif
     168             : }

Generated by: LCOV version 1.14