Age Owner Branch data TLA 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
21 andrew@dunslane.net 95 :GNC 49737 : 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 : : {
811 nathan@postgresql.or 101 :CBC 49737 : int save_errno = errno;
102 : : pg_signal_info pg_info;
103 : :
424 104 [ - + ]: 49737 : Assert(postgres_signal_arg > 0);
105 [ - + ]: 49737 : 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 : : */
811 113 [ - + ]: 49579 : Assert(MyProcPid);
114 [ + + - + ]: 49579 : Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster);
115 : :
116 [ - + ]: 49579 : if (unlikely(MyProcPid != (int) getpid()))
117 : : {
21 andrew@dunslane.net 118 :UNC 0 : pqsignal(postgres_signal_arg, PG_SIG_DFL);
811 nathan@postgresql.or 119 :UBC 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 : : */
21 andrew@dunslane.net 131 :GNC 49737 : pg_info.pid = info->si_pid;
132 : 49737 : 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 : 49737 : (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg, &pg_info);
144 : :
811 nathan@postgresql.or 145 :CBC 49736 : errno = save_errno;
146 : 158 : }
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
4797 tgl@sss.pgh.pa.us 156 : 350188 : pqsignal(int signo, pqsigfunc func)
157 : : {
158 : : #ifdef USE_SIGACTION
159 : : struct sigaction act;
160 : : #else
161 : : void (*wrapper_func_ptr) (int);
162 : : #endif
21 andrew@dunslane.net 163 :GNC 350188 : bool is_ign = func == PG_SIG_IGN;
164 : 350188 : bool is_dfl = func == PG_SIG_DFL;
165 : :
424 nathan@postgresql.or 166 [ - + ]:CBC 350188 : Assert(signo > 0);
811 167 [ - + ]: 350188 : Assert(signo < PG_NSIG);
168 : :
169 : : /* set up indirection handler */
21 andrew@dunslane.net 170 [ + + + + ]:GNC 350188 : if (!(is_ign || is_dfl))
171 : : {
811 nathan@postgresql.or 172 :CBC 260022 : 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
4797 tgl@sss.pgh.pa.us 180 : 350188 : sigemptyset(&act.sa_mask);
4707 181 : 350188 : act.sa_flags = SA_RESTART;
182 : :
21 andrew@dunslane.net 183 [ + + ]:GNC 350188 : if (is_ign)
184 : 57731 : act.sa_handler = SIG_IGN;
185 [ + + ]: 292457 : else if (is_dfl)
186 : 32435 : act.sa_handler = SIG_DFL;
187 : : #ifdef USE_SIGINFO
188 : : else
189 : : {
29 190 : 260022 : act.sa_sigaction = wrapper_handler;
191 : 260022 : act.sa_flags |= SA_SIGINFO;
192 : : }
193 : : #else
194 : : else
195 : : act.sa_handler = wrapper_handler;
196 : : #endif
197 : :
198 : : #ifdef SA_NOCLDSTOP
4797 tgl@sss.pgh.pa.us 199 [ + + ]:CBC 350188 : if (signo == SIGCHLD)
200 : 33332 : act.sa_flags |= SA_NOCLDSTOP;
201 : : #endif
474 nathan@postgresql.or 202 [ - + ]: 350188 : if (sigaction(signo, &act, NULL) < 0)
474 nathan@postgresql.or 203 :UBC 0 : 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
4797 tgl@sss.pgh.pa.us 220 :CBC 350188 : }
|