PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-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. */
76StaticAssertDecl(SIGHUP < PG_NSIG, "SIGHUP >= PG_NSIG");
77StaticAssertDecl(SIGTERM < PG_NSIG, "SIGTERM >= PG_NSIG");
78StaticAssertDecl(SIGALRM < PG_NSIG, "SIGALRM >= PG_NSIG");
79
80static 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)
94static void
95wrapper_handler(int postgres_signal_arg, siginfo_t * info, void *context)
96#else /* no USE_SIGINFO */
97static void
98wrapper_handler(int postgres_signal_arg)
99#endif
100{
101 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 if (unlikely(MyProcPid != (int) getpid()))
117 {
118 pqsignal(postgres_signal_arg, PG_SIG_DFL);
119 raise(postgres_signal_arg);
120 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 pg_info.pid = info->si_pid;
132 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 (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg, &pg_info);
144
145 errno = save_errno;
146}
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 */
155void
156pqsignal(int signo, pqsigfunc func)
157{
158#ifdef USE_SIGACTION
159 struct sigaction act;
160#else
161 void (*wrapper_func_ptr) (int);
162#endif
163 bool is_ign = func == PG_SIG_IGN;
164 bool is_dfl = func == PG_SIG_DFL;
165
166 Assert(signo > 0);
167 Assert(signo < PG_NSIG);
168
169 /* set up indirection handler */
170 if (!(is_ign || is_dfl))
171 {
172 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 sigemptyset(&act.sa_mask);
181 act.sa_flags = SA_RESTART;
182
183 if (is_ign)
184 act.sa_handler = SIG_IGN;
185 else if (is_dfl)
186 act.sa_handler = SIG_DFL;
187#ifdef USE_SIGINFO
188 else
189 {
190 act.sa_sigaction = wrapper_handler;
191 act.sa_flags |= SA_SIGINFO;
192 }
193#else
194 else
195 act.sa_handler = wrapper_handler;
196#endif
197
198#ifdef SA_NOCLDSTOP
199 if (signo == SIGCHLD)
200 act.sa_flags |= SA_NOCLDSTOP;
201#endif
202 if (sigaction(signo, &act, NULL) < 0)
203 Assert(false); /* probably indicates coding error */
204#else /* no USE_SIGACTION */
205
206 /*
207 * Forward to Windows native signal system, we need to send this though
208 * wrapper handler as it it needs to take single argument only.
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}
#define PG_NSIG
Definition pqsignal.c:63
StaticAssertDecl(SIGUSR2< PG_NSIG, "SIGUSR2 >= PG_NSIG")
static int fb(int x)
#define SIGHUP
Definition win32_port.h:158
#define SIGALRM
Definition win32_port.h:164