/src/postgres/src/backend/storage/ipc/pmsignal.c
Line | Count | Source |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * pmsignal.c |
4 | | * routines for signaling between the postmaster and its child processes |
5 | | * |
6 | | * |
7 | | * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group |
8 | | * Portions Copyright (c) 1994, Regents of the University of California |
9 | | * |
10 | | * IDENTIFICATION |
11 | | * src/backend/storage/ipc/pmsignal.c |
12 | | * |
13 | | *------------------------------------------------------------------------- |
14 | | */ |
15 | | #include "postgres.h" |
16 | | |
17 | | #include <signal.h> |
18 | | #include <unistd.h> |
19 | | |
20 | | #ifdef HAVE_SYS_PRCTL_H |
21 | | #include <sys/prctl.h> |
22 | | #endif |
23 | | |
24 | | #include "miscadmin.h" |
25 | | #include "postmaster/postmaster.h" |
26 | | #include "replication/walsender.h" |
27 | | #include "storage/ipc.h" |
28 | | #include "storage/pmsignal.h" |
29 | | #include "storage/shmem.h" |
30 | | #include "storage/subsystems.h" |
31 | | #include "utils/memutils.h" |
32 | | |
33 | | |
34 | | /* |
35 | | * The postmaster is signaled by its children by sending SIGUSR1. The |
36 | | * specific reason is communicated via flags in shared memory. We keep |
37 | | * a boolean flag for each possible "reason", so that different reasons |
38 | | * can be signaled by different backends at the same time. (However, |
39 | | * if the same reason is signaled more than once simultaneously, the |
40 | | * postmaster will observe it only once.) |
41 | | * |
42 | | * The flags are actually declared as "volatile sig_atomic_t" for maximum |
43 | | * portability. This should ensure that loads and stores of the flag |
44 | | * values are atomic, allowing us to dispense with any explicit locking. |
45 | | * |
46 | | * In addition to the per-reason flags, we store a set of per-child-process |
47 | | * flags that are currently used only for detecting whether a backend has |
48 | | * exited without performing proper shutdown. The per-child-process flags |
49 | | * have three possible states: UNUSED, ASSIGNED, ACTIVE. An UNUSED slot is |
50 | | * available for assignment. An ASSIGNED slot is associated with a postmaster |
51 | | * child process, but either the process has not touched shared memory yet, or |
52 | | * it has successfully cleaned up after itself. An ACTIVE slot means the |
53 | | * process is actively using shared memory. The slots are assigned to child |
54 | | * processes by postmaster, and pmchild.c is responsible for tracking which |
55 | | * one goes with which PID. |
56 | | * |
57 | | * Actually there is a fourth state, WALSENDER. This is just like ACTIVE, |
58 | | * but carries the extra information that the child is a WAL sender. |
59 | | * WAL senders too start in ACTIVE state, but switch to WALSENDER once they |
60 | | * start streaming the WAL (and they never go back to ACTIVE after that). |
61 | | * |
62 | | * We also have a shared-memory field that is used for communication in |
63 | | * the opposite direction, from postmaster to children: it tells why the |
64 | | * postmaster has broadcasted SIGQUIT signals, if indeed it has done so. |
65 | | */ |
66 | | |
67 | 0 | #define PM_CHILD_UNUSED 0 /* these values must fit in sig_atomic_t */ |
68 | 0 | #define PM_CHILD_ASSIGNED 1 |
69 | 0 | #define PM_CHILD_ACTIVE 2 |
70 | 0 | #define PM_CHILD_WALSENDER 3 |
71 | | |
72 | | /* "typedef struct PMSignalData PMSignalData" appears in pmsignal.h */ |
73 | | struct PMSignalData |
74 | | { |
75 | | /* per-reason flags for signaling the postmaster */ |
76 | | sig_atomic_t PMSignalFlags[NUM_PMSIGNALS]; |
77 | | /* global flags for signals from postmaster to children */ |
78 | | QuitSignalReason sigquit_reason; /* why SIGQUIT was sent */ |
79 | | /* per-child-process flags */ |
80 | | int num_child_flags; /* # of entries in PMChildFlags[] */ |
81 | | sig_atomic_t PMChildFlags[FLEXIBLE_ARRAY_MEMBER]; |
82 | | }; |
83 | | |
84 | | /* PMSignalState pointer is valid in both postmaster and child processes */ |
85 | | NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL; |
86 | | |
87 | | static void PMSignalShmemRequest(void *); |
88 | | static void PMSignalShmemInit(void *); |
89 | | |
90 | | const ShmemCallbacks PMSignalShmemCallbacks = { |
91 | | .request_fn = PMSignalShmemRequest, |
92 | | .init_fn = PMSignalShmemInit, |
93 | | }; |
94 | | |
95 | | /* |
96 | | * Local copy of PMSignalState->num_child_flags, only valid in the |
97 | | * postmaster. Postmaster keeps a local copy so that it doesn't need to |
98 | | * trust the value in shared memory. |
99 | | */ |
100 | | static int num_child_flags; |
101 | | |
102 | | /* |
103 | | * Signal handler to be notified if postmaster dies. |
104 | | */ |
105 | | #ifdef USE_POSTMASTER_DEATH_SIGNAL |
106 | | volatile sig_atomic_t postmaster_possibly_dead = false; |
107 | | |
108 | | static void |
109 | | postmaster_death_handler(SIGNAL_ARGS) |
110 | 0 | { |
111 | 0 | postmaster_possibly_dead = true; |
112 | 0 | } |
113 | | |
114 | | /* |
115 | | * The available signals depend on the OS. SIGUSR1 and SIGUSR2 are already |
116 | | * used for other things, so choose another one. |
117 | | * |
118 | | * Currently, we assume that we can always find a signal to use. That |
119 | | * seems like a reasonable assumption for all platforms that are modern |
120 | | * enough to have a parent-death signaling mechanism. |
121 | | */ |
122 | | #if defined(SIGINFO) |
123 | | #define POSTMASTER_DEATH_SIGNAL SIGINFO |
124 | | #elif defined(SIGPWR) |
125 | 0 | #define POSTMASTER_DEATH_SIGNAL SIGPWR |
126 | | #else |
127 | | #error "cannot find a signal to use for postmaster death" |
128 | | #endif |
129 | | |
130 | | #endif /* USE_POSTMASTER_DEATH_SIGNAL */ |
131 | | |
132 | | static void MarkPostmasterChildInactive(int code, Datum arg); |
133 | | |
134 | | /* |
135 | | * PMSignalShmemRequest - Register pmsignal.c's shared memory needs |
136 | | */ |
137 | | static void |
138 | | PMSignalShmemRequest(void *arg) |
139 | 0 | { |
140 | 0 | size_t size; |
141 | |
|
142 | 0 | num_child_flags = MaxLivePostmasterChildren(); |
143 | |
|
144 | 0 | size = add_size(offsetof(PMSignalData, PMChildFlags), |
145 | 0 | mul_size(num_child_flags, sizeof(sig_atomic_t))); |
146 | 0 | ShmemRequestStruct(.name = "PMSignalState", |
147 | 0 | .size = size, |
148 | 0 | .ptr = (void **) &PMSignalState, |
149 | 0 | ); |
150 | 0 | } |
151 | | |
152 | | static void |
153 | | PMSignalShmemInit(void *arg) |
154 | 0 | { |
155 | 0 | Assert(PMSignalState); |
156 | 0 | Assert(num_child_flags > 0); |
157 | 0 | PMSignalState->num_child_flags = num_child_flags; |
158 | 0 | } |
159 | | |
160 | | /* |
161 | | * SendPostmasterSignal - signal the postmaster from a child process |
162 | | */ |
163 | | void |
164 | | SendPostmasterSignal(PMSignalReason reason) |
165 | 0 | { |
166 | | /* If called in a standalone backend, do nothing */ |
167 | 0 | if (!IsUnderPostmaster) |
168 | 0 | return; |
169 | | /* Atomically set the proper flag */ |
170 | 0 | PMSignalState->PMSignalFlags[reason] = true; |
171 | | /* Send signal to postmaster */ |
172 | 0 | kill(PostmasterPid, SIGUSR1); |
173 | 0 | } |
174 | | |
175 | | /* |
176 | | * CheckPostmasterSignal - check to see if a particular reason has been |
177 | | * signaled, and clear the signal flag. Should be called by postmaster |
178 | | * after receiving SIGUSR1. |
179 | | */ |
180 | | bool |
181 | | CheckPostmasterSignal(PMSignalReason reason) |
182 | 0 | { |
183 | | /* Careful here --- don't clear flag if we haven't seen it set */ |
184 | 0 | if (PMSignalState->PMSignalFlags[reason]) |
185 | 0 | { |
186 | 0 | PMSignalState->PMSignalFlags[reason] = false; |
187 | 0 | return true; |
188 | 0 | } |
189 | 0 | return false; |
190 | 0 | } |
191 | | |
192 | | /* |
193 | | * SetQuitSignalReason - broadcast the reason for a system shutdown. |
194 | | * Should be called by postmaster before sending SIGQUIT to children. |
195 | | * |
196 | | * Note: in a crash-and-restart scenario, the "reason" field gets cleared |
197 | | * as a part of rebuilding shared memory; the postmaster need not do it |
198 | | * explicitly. |
199 | | */ |
200 | | void |
201 | | SetQuitSignalReason(QuitSignalReason reason) |
202 | 0 | { |
203 | 0 | PMSignalState->sigquit_reason = reason; |
204 | 0 | } |
205 | | |
206 | | /* |
207 | | * GetQuitSignalReason - obtain the reason for a system shutdown. |
208 | | * Called by child processes when they receive SIGQUIT. |
209 | | * If the postmaster hasn't actually sent SIGQUIT, will return PMQUIT_NOT_SENT. |
210 | | */ |
211 | | QuitSignalReason |
212 | | GetQuitSignalReason(void) |
213 | 0 | { |
214 | | /* This is called in signal handlers, so be extra paranoid. */ |
215 | 0 | if (!IsUnderPostmaster || PMSignalState == NULL) |
216 | 0 | return PMQUIT_NOT_SENT; |
217 | 0 | return PMSignalState->sigquit_reason; |
218 | 0 | } |
219 | | |
220 | | |
221 | | /* |
222 | | * MarkPostmasterChildSlotAssigned - mark the given slot as ASSIGNED for a |
223 | | * new postmaster child process. |
224 | | * |
225 | | * Only the postmaster is allowed to execute this routine, so we need no |
226 | | * special locking. |
227 | | */ |
228 | | void |
229 | | MarkPostmasterChildSlotAssigned(int slot) |
230 | 0 | { |
231 | 0 | Assert(slot > 0 && slot <= num_child_flags); |
232 | 0 | slot--; |
233 | |
|
234 | 0 | if (PMSignalState->PMChildFlags[slot] != PM_CHILD_UNUSED) |
235 | 0 | elog(FATAL, "postmaster child slot is already in use"); |
236 | | |
237 | 0 | PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED; |
238 | 0 | } |
239 | | |
240 | | /* |
241 | | * MarkPostmasterChildSlotUnassigned - release a slot after death of a |
242 | | * postmaster child process. This must be called in the postmaster process. |
243 | | * |
244 | | * Returns true if the slot had been in ASSIGNED state (the expected case), |
245 | | * false otherwise (implying that the child failed to clean itself up). |
246 | | */ |
247 | | bool |
248 | | MarkPostmasterChildSlotUnassigned(int slot) |
249 | 0 | { |
250 | 0 | bool result; |
251 | |
|
252 | 0 | Assert(slot > 0 && slot <= num_child_flags); |
253 | 0 | slot--; |
254 | | |
255 | | /* |
256 | | * Note: the slot state might already be unused, because the logic in |
257 | | * postmaster.c is such that this might get called twice when a child |
258 | | * crashes. So we don't try to Assert anything about the state. |
259 | | */ |
260 | 0 | result = (PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED); |
261 | 0 | PMSignalState->PMChildFlags[slot] = PM_CHILD_UNUSED; |
262 | 0 | return result; |
263 | 0 | } |
264 | | |
265 | | /* |
266 | | * IsPostmasterChildWalSender - check if given slot is in use by a |
267 | | * walsender process. This is called only by the postmaster. |
268 | | */ |
269 | | bool |
270 | | IsPostmasterChildWalSender(int slot) |
271 | 0 | { |
272 | 0 | Assert(slot > 0 && slot <= num_child_flags); |
273 | 0 | slot--; |
274 | |
|
275 | 0 | if (PMSignalState->PMChildFlags[slot] == PM_CHILD_WALSENDER) |
276 | 0 | return true; |
277 | 0 | else |
278 | 0 | return false; |
279 | 0 | } |
280 | | |
281 | | /* |
282 | | * RegisterPostmasterChildActive - mark a postmaster child as about to begin |
283 | | * actively using shared memory. This is called in the child process. |
284 | | * |
285 | | * This register an shmem exit hook to mark us as inactive again when the |
286 | | * process exits normally. |
287 | | */ |
288 | | void |
289 | | RegisterPostmasterChildActive(void) |
290 | 0 | { |
291 | 0 | int slot = MyPMChildSlot; |
292 | |
|
293 | 0 | Assert(slot > 0 && slot <= PMSignalState->num_child_flags); |
294 | 0 | slot--; |
295 | 0 | Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED); |
296 | 0 | PMSignalState->PMChildFlags[slot] = PM_CHILD_ACTIVE; |
297 | | |
298 | | /* Arrange to clean up at exit. */ |
299 | 0 | on_shmem_exit(MarkPostmasterChildInactive, 0); |
300 | 0 | } |
301 | | |
302 | | /* |
303 | | * MarkPostmasterChildWalSender - mark a postmaster child as a WAL sender |
304 | | * process. This is called in the child process, sometime after marking the |
305 | | * child as active. |
306 | | */ |
307 | | void |
308 | | MarkPostmasterChildWalSender(void) |
309 | 0 | { |
310 | 0 | int slot = MyPMChildSlot; |
311 | |
|
312 | 0 | Assert(am_walsender); |
313 | |
|
314 | 0 | Assert(slot > 0 && slot <= PMSignalState->num_child_flags); |
315 | 0 | slot--; |
316 | 0 | Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ACTIVE); |
317 | 0 | PMSignalState->PMChildFlags[slot] = PM_CHILD_WALSENDER; |
318 | 0 | } |
319 | | |
320 | | /* |
321 | | * MarkPostmasterChildInactive - mark a postmaster child as done using |
322 | | * shared memory. This is called in the child process. |
323 | | */ |
324 | | static void |
325 | | MarkPostmasterChildInactive(int code, Datum arg) |
326 | 0 | { |
327 | 0 | int slot = MyPMChildSlot; |
328 | |
|
329 | 0 | Assert(slot > 0 && slot <= PMSignalState->num_child_flags); |
330 | 0 | slot--; |
331 | 0 | Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ACTIVE || |
332 | 0 | PMSignalState->PMChildFlags[slot] == PM_CHILD_WALSENDER); |
333 | 0 | PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED; |
334 | 0 | } |
335 | | |
336 | | |
337 | | /* |
338 | | * PostmasterIsAliveInternal - check whether postmaster process is still alive |
339 | | * |
340 | | * This is the slow path of PostmasterIsAlive(), where the caller has already |
341 | | * checked 'postmaster_possibly_dead'. (On platforms that don't support |
342 | | * a signal for parent death, PostmasterIsAlive() is just an alias for this.) |
343 | | */ |
344 | | bool |
345 | | PostmasterIsAliveInternal(void) |
346 | 0 | { |
347 | 0 | #ifdef USE_POSTMASTER_DEATH_SIGNAL |
348 | | /* |
349 | | * Reset the flag before checking, so that we don't miss a signal if |
350 | | * postmaster dies right after the check. If postmaster was indeed dead, |
351 | | * we'll re-arm it before returning to caller. |
352 | | */ |
353 | 0 | postmaster_possibly_dead = false; |
354 | 0 | #endif |
355 | |
|
356 | 0 | #ifndef WIN32 |
357 | 0 | { |
358 | 0 | char c; |
359 | 0 | ssize_t rc; |
360 | |
|
361 | 0 | rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1); |
362 | | |
363 | | /* |
364 | | * In the usual case, the postmaster is still alive, and there is no |
365 | | * data in the pipe. |
366 | | */ |
367 | 0 | if (rc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) |
368 | 0 | return true; |
369 | 0 | else |
370 | 0 | { |
371 | | /* |
372 | | * Postmaster is dead, or something went wrong with the read() |
373 | | * call. |
374 | | */ |
375 | |
|
376 | 0 | #ifdef USE_POSTMASTER_DEATH_SIGNAL |
377 | 0 | postmaster_possibly_dead = true; |
378 | 0 | #endif |
379 | |
|
380 | 0 | if (rc < 0) |
381 | 0 | elog(FATAL, "read on postmaster death monitoring pipe failed: %m"); |
382 | 0 | else if (rc > 0) |
383 | 0 | elog(FATAL, "unexpected data in postmaster death monitoring pipe"); |
384 | | |
385 | 0 | return false; |
386 | 0 | } |
387 | 0 | } |
388 | |
|
389 | | #else /* WIN32 */ |
390 | | if (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT) |
391 | | return true; |
392 | | else |
393 | | { |
394 | | #ifdef USE_POSTMASTER_DEATH_SIGNAL |
395 | | postmaster_possibly_dead = true; |
396 | | #endif |
397 | | return false; |
398 | | } |
399 | | #endif /* WIN32 */ |
400 | 0 | } |
401 | | |
402 | | /* |
403 | | * PostmasterDeathSignalInit - request signal on postmaster death if possible |
404 | | */ |
405 | | void |
406 | | PostmasterDeathSignalInit(void) |
407 | 0 | { |
408 | 0 | #ifdef USE_POSTMASTER_DEATH_SIGNAL |
409 | 0 | int signum = POSTMASTER_DEATH_SIGNAL; |
410 | | |
411 | | /* Register our signal handler. */ |
412 | 0 | pqsignal(signum, postmaster_death_handler); |
413 | | |
414 | | /* Request a signal on parent exit. */ |
415 | 0 | #if defined(PR_SET_PDEATHSIG) |
416 | 0 | if (prctl(PR_SET_PDEATHSIG, signum) < 0) |
417 | 0 | elog(ERROR, "could not request parent death signal: %m"); |
418 | | #elif defined(PROC_PDEATHSIG_CTL) |
419 | | if (procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum) < 0) |
420 | | elog(ERROR, "could not request parent death signal: %m"); |
421 | | #else |
422 | | #error "USE_POSTMASTER_DEATH_SIGNAL set, but there is no mechanism to request the signal" |
423 | | #endif |
424 | | |
425 | | /* |
426 | | * Just in case the parent was gone already and we missed it, we'd better |
427 | | * check the slow way on the first call. |
428 | | */ |
429 | 0 | postmaster_possibly_dead = true; |
430 | 0 | #endif /* USE_POSTMASTER_DEATH_SIGNAL */ |
431 | 0 | } |