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-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
60 nathan@postgresql.or 87 :GNC 127227 : wrapper_handler(SIGNAL_ARGS)
88 : : {
89 : 127227 : 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 [ - + ]: 127101 : Assert(MyProcPid);
98 [ + + - + ]: 127101 : Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster);
99 : :
100 [ - + ]: 127101 : if (unlikely(MyProcPid != (int) getpid()))
101 : : {
60 nathan@postgresql.or 102 :UNC 0 : pqsignal(postgres_signal_arg, SIG_DFL);
103 : 0 : raise(postgres_signal_arg);
104 : 0 : return;
105 : : }
106 : : #endif
107 : :
60 nathan@postgresql.or 108 :GNC 127227 : (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg);
109 : :
110 : 125697 : errno = save_errno;
111 : 126 : }
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
4046 tgl@sss.pgh.pa.us 129 :CBC 292914 : pqsignal(int signo, pqsigfunc func)
130 : : {
60 nathan@postgresql.or 131 :GNC 292914 : 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 [ - + ]: 292914 : Assert(signo < PG_NSIG);
140 : :
141 [ + + + + ]: 292914 : if (func != SIG_IGN && func != SIG_DFL)
142 : : {
143 : 218825 : pqsignal_handlers[signo] = func; /* assumed atomic */
144 : 218825 : func = wrapper_handler;
145 : : }
146 : :
147 : : #if !(defined(WIN32) && defined(FRONTEND))
4046 tgl@sss.pgh.pa.us 148 :CBC 292914 : act.sa_handler = func;
149 : 292914 : sigemptyset(&act.sa_mask);
3956 150 : 292914 : act.sa_flags = SA_RESTART;
151 : : #ifdef SA_NOCLDSTOP
4046 152 [ + + ]: 292914 : if (signo == SIGCHLD)
153 : 28537 : act.sa_flags |= SA_NOCLDSTOP;
154 : : #endif
155 [ - + ]: 292914 : if (sigaction(signo, &act, &oact) < 0)
4046 tgl@sss.pgh.pa.us 156 :UBC 0 : return SIG_ERR;
60 nathan@postgresql.or 157 [ + + ]:GNC 292914 : else if (oact.sa_handler == wrapper_handler)
158 : 173284 : return orig_func;
159 : : else
160 : 119630 : 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 : : }
|