/src/postgres/src/port/pqsignal.c
Line | Count | Source (jump to first uncovered line) |
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-2025, 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 knew to maintain MyProcPid, and not a |
78 | | * child process forked by system(3), etc. This check ensures that such child |
79 | | * processes do not modify shared memory, which is often detrimental. If the |
80 | | * check succeeds, the function originally provided to pqsignal() is called. |
81 | | * Otherwise, the default signal handler is installed and then called. |
82 | | * |
83 | | * This wrapper also handles restoring the value of errno. |
84 | | */ |
85 | | static void |
86 | | wrapper_handler(SIGNAL_ARGS) |
87 | 0 | { |
88 | 0 | int save_errno = errno; |
89 | |
|
90 | 0 | Assert(postgres_signal_arg > 0); |
91 | 0 | Assert(postgres_signal_arg < PG_NSIG); |
92 | |
|
93 | 0 | #ifndef FRONTEND |
94 | | |
95 | | /* |
96 | | * We expect processes to set MyProcPid before calling pqsignal() or |
97 | | * before accepting signals. |
98 | | */ |
99 | 0 | Assert(MyProcPid); |
100 | 0 | Assert(MyProcPid != PostmasterPid || !IsUnderPostmaster); |
101 | |
|
102 | 0 | if (unlikely(MyProcPid != (int) getpid())) |
103 | 0 | { |
104 | 0 | pqsignal(postgres_signal_arg, SIG_DFL); |
105 | 0 | raise(postgres_signal_arg); |
106 | 0 | return; |
107 | 0 | } |
108 | 0 | #endif |
109 | | |
110 | 0 | (*pqsignal_handlers[postgres_signal_arg]) (postgres_signal_arg); |
111 | |
|
112 | 0 | errno = save_errno; |
113 | 0 | } |
114 | | |
115 | | /* |
116 | | * Set up a signal handler, with SA_RESTART, for signal "signo" |
117 | | * |
118 | | * Note: the actual name of this function is either pqsignal_fe when |
119 | | * compiled with -DFRONTEND, or pqsignal_be when compiled without that. |
120 | | * This is to avoid a name collision with libpq's legacy-pqsignal.c. |
121 | | */ |
122 | | void |
123 | | pqsignal(int signo, pqsigfunc func) |
124 | 0 | { |
125 | 0 | #if !(defined(WIN32) && defined(FRONTEND)) |
126 | 0 | struct sigaction act; |
127 | 0 | #endif |
128 | |
|
129 | 0 | Assert(signo > 0); |
130 | 0 | Assert(signo < PG_NSIG); |
131 | |
|
132 | 0 | if (func != SIG_IGN && func != SIG_DFL) |
133 | 0 | { |
134 | 0 | pqsignal_handlers[signo] = func; /* assumed atomic */ |
135 | 0 | func = wrapper_handler; |
136 | 0 | } |
137 | |
|
138 | 0 | #if !(defined(WIN32) && defined(FRONTEND)) |
139 | 0 | act.sa_handler = func; |
140 | 0 | sigemptyset(&act.sa_mask); |
141 | 0 | act.sa_flags = SA_RESTART; |
142 | 0 | #ifdef SA_NOCLDSTOP |
143 | 0 | if (signo == SIGCHLD) |
144 | 0 | act.sa_flags |= SA_NOCLDSTOP; |
145 | 0 | #endif |
146 | 0 | if (sigaction(signo, &act, NULL) < 0) |
147 | 0 | Assert(false); /* probably indicates coding error */ |
148 | | #else |
149 | | /* Forward to Windows native signal system. */ |
150 | | if (signal(signo, func) == SIG_ERR) |
151 | | Assert(false); /* probably indicates coding error */ |
152 | | #endif |
153 | 0 | } |