Coverage Report

Created: 2025-06-13 06:06

/src/postgres/src/port/pqsignal.c
Line
Count
Source (jump to first uncovered line)
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-2025, 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
wrapper_handler(SIGNAL_ARGS)
87
0
{
88
0
  int     save_errno = errno;
89
90
0
  Assert(postgres_signal_arg > 0);
91
0
  Assert(postgres_signal_arg < PG_NSIG);
92
93
0
#ifndef FRONTEND
94
95
  /*
96
   * We expect processes to set MyProcPid before calling pqsignal() or
97
   * before accepting signals.
98
   */
99
0
  Assert(MyProcPid);
100
0
  Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster);
101
102
0
  if (unlikely(MyProcPid != (int) getpid()))
103
0
  {
104
0
    pqsignal(postgres_signal_arg, SIG_DFL);
105
0
    raise(postgres_signal_arg);
106
0
    return;
107
0
  }
108
0
#endif
109
110
0
  (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg);
111
112
0
  errno = save_errno;
113
0
}
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
pqsignal(int signo, pqsigfunc func)
124
0
{
125
0
#if !(defined(WIN32) && defined(FRONTEND))
126
0
  struct sigaction act;
127
0
#endif
128
129
0
  Assert(signo > 0);
130
0
  Assert(signo < PG_NSIG);
131
132
0
  if (func != SIG_IGN && func != SIG_DFL)
133
0
  {
134
0
    pqsignal_handlers[signo] = func;  /* assumed atomic */
135
0
    func = wrapper_handler;
136
0
  }
137
138
0
#if !(defined(WIN32) && defined(FRONTEND))
139
0
  act.sa_handler = func;
140
0
  sigemptyset(&act.sa_mask);
141
0
  act.sa_flags = SA_RESTART;
142
0
#ifdef SA_NOCLDSTOP
143
0
  if (signo == SIGCHLD)
144
0
    act.sa_flags |= SA_NOCLDSTOP;
145
0
#endif
146
0
  if (sigaction(signo, &act, NULL) < 0)
147
0
    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
0
}