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 : #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. */
75 : StaticAssertDecl(SIGUSR2 < PG_NSIG, "SIGUSR2 >= PG_NSIG");
76 : StaticAssertDecl(SIGHUP < PG_NSIG, "SIGHUP >= PG_NSIG");
77 : StaticAssertDecl(SIGTERM < PG_NSIG, "SIGTERM >= PG_NSIG");
78 : StaticAssertDecl(SIGALRM < PG_NSIG, "SIGALRM >= PG_NSIG");
79 :
80 : static 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)
94 : static void
95 164901 : wrapper_handler(int postgres_signal_arg, siginfo_t * info, void *context)
96 : #else /* no USE_SIGINFO */
97 : static void
98 : wrapper_handler(int postgres_signal_arg)
99 : #endif
100 : {
101 164901 : 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 164742 : if (unlikely(MyProcPid != (int) getpid()))
117 : {
118 0 : pqsignal(postgres_signal_arg, PG_SIG_DFL);
119 0 : raise(postgres_signal_arg);
120 0 : 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 164901 : pg_info.pid = info->si_pid;
132 164901 : 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 164901 : (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg, &pg_info);
144 :
145 164900 : errno = save_errno;
146 159 : }
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 : */
155 : void
156 365438 : pqsignal(int signo, pqsigfunc func)
157 : {
158 : #ifdef USE_SIGACTION
159 : struct sigaction act;
160 : #else
161 : void (*wrapper_func_ptr) (int);
162 : #endif
163 365438 : bool is_ign = func == PG_SIG_IGN;
164 365438 : bool is_dfl = func == PG_SIG_DFL;
165 :
166 : Assert(signo > 0);
167 : Assert(signo < PG_NSIG);
168 :
169 : /* set up indirection handler */
170 365438 : if (!(is_ign || is_dfl))
171 : {
172 270904 : 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 365438 : sigemptyset(&act.sa_mask);
181 365438 : act.sa_flags = SA_RESTART;
182 :
183 365438 : if (is_ign)
184 60758 : act.sa_handler = SIG_IGN;
185 304680 : else if (is_dfl)
186 33776 : act.sa_handler = SIG_DFL;
187 : #ifdef USE_SIGINFO
188 : else
189 : {
190 270904 : act.sa_sigaction = wrapper_handler;
191 270904 : act.sa_flags |= SA_SIGINFO;
192 : }
193 : #else
194 : else
195 : act.sa_handler = wrapper_handler;
196 : #endif
197 :
198 : #ifdef SA_NOCLDSTOP
199 365438 : if (signo == SIGCHLD)
200 34670 : act.sa_flags |= SA_NOCLDSTOP;
201 : #endif
202 365438 : 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 365438 : }
|