PostgreSQL Source Code  git master
pqsignal.c
Go to the documentation of this file.
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 wrapper_handler(SIGNAL_ARGS)
88 {
89  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  if (unlikely(MyProcPid != (int) getpid()))
101  {
102  pqsignal(postgres_signal_arg, SIG_DFL);
103  raise(postgres_signal_arg);
104  return;
105  }
106 #endif
107 
108  (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg);
109 
110  errno = save_errno;
111 }
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 pqsignal(int signo, pqsigfunc func)
130 {
131  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  if (func != SIG_IGN && func != SIG_DFL)
142  {
143  pqsignal_handlers[signo] = func; /* assumed atomic */
144  func = wrapper_handler;
145  }
146 
147 #if !(defined(WIN32) && defined(FRONTEND))
148  act.sa_handler = func;
149  sigemptyset(&act.sa_mask);
150  act.sa_flags = SA_RESTART;
151 #ifdef SA_NOCLDSTOP
152  if (signo == SIGCHLD)
153  act.sa_flags |= SA_NOCLDSTOP;
154 #endif
155  if (sigaction(signo, &act, &oact) < 0)
156  return SIG_ERR;
157  else if (oact.sa_handler == wrapper_handler)
158  return orig_func;
159  else
160  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 }
#define PG_NSIG
Definition: pqsignal.c:63
StaticAssertDecl(SIGUSR2< PG_NSIG, "SIGUSR2 >= PG_NSIG")
#define SIGHUP
Definition: win32_port.h:168
#define SIGALRM
Definition: win32_port.h:174