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