PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pmsignal.c
Go to the documentation of this file.
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"
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#define PM_CHILD_UNUSED 0 /* these values must fit in sig_atomic_t */
68#define PM_CHILD_ASSIGNED 1
69#define PM_CHILD_ACTIVE 2
70#define PM_CHILD_WALSENDER 3
71
72/* "typedef struct PMSignalData PMSignalData" appears in pmsignal.h */
74{
75 /* per-reason flags for signaling the postmaster */
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[] */
82};
83
84/* PMSignalState pointer is valid in both postmaster and child processes */
86
87static void PMSignalShmemRequest(void *);
88static void PMSignalShmemInit(void *);
89
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 */
101
102/*
103 * Signal handler to be notified if postmaster dies.
104 */
105#ifdef USE_POSTMASTER_DEATH_SIGNAL
107
108static void
110{
112}
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#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
132static void MarkPostmasterChildInactive(int code, Datum arg);
133
134/*
135 * PMSignalShmemRequest - Register pmsignal.c's shared memory needs
136 */
137static void
139{
140 size_t size;
141
143
144 size = add_size(offsetof(PMSignalData, PMChildFlags),
146 ShmemRequestStruct(.name = "PMSignalState",
147 .size = size,
148 .ptr = (void **) &PMSignalState,
149 );
150}
151
152static void
159
160/*
161 * SendPostmasterSignal - signal the postmaster from a child process
162 */
163void
165{
166 /* If called in a standalone backend, do nothing */
168 return;
169 /* Atomically set the proper flag */
170 PMSignalState->PMSignalFlags[reason] = true;
171 /* Send signal to postmaster */
173}
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 */
180bool
182{
183 /* Careful here --- don't clear flag if we haven't seen it set */
184 if (PMSignalState->PMSignalFlags[reason])
185 {
186 PMSignalState->PMSignalFlags[reason] = false;
187 return true;
188 }
189 return false;
190}
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 */
200void
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 */
213{
214 /* This is called in signal handlers, so be extra paranoid. */
216 return PMQUIT_NOT_SENT;
218}
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 */
228void
230{
231 Assert(slot > 0 && slot <= num_child_flags);
232 slot--;
233
235 elog(FATAL, "postmaster child slot is already in use");
236
238}
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 */
247bool
249{
250 bool result;
251
252 Assert(slot > 0 && slot <= num_child_flags);
253 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 */
262 return result;
263}
264
265/*
266 * IsPostmasterChildWalSender - check if given slot is in use by a
267 * walsender process. This is called only by the postmaster.
268 */
269bool
271{
272 Assert(slot > 0 && slot <= num_child_flags);
273 slot--;
274
276 return true;
277 else
278 return false;
279}
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 */
288void
290{
291 int slot = MyPMChildSlot;
292
294 slot--;
297
298 /* Arrange to clean up at exit. */
300}
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 */
307void
319
320/*
321 * MarkPostmasterChildInactive - mark a postmaster child as done using
322 * shared memory. This is called in the child process.
323 */
324static void
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 */
344bool
346{
347#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 */
354#endif
355
356#ifndef WIN32
357 {
358 char c;
359 ssize_t rc;
360
362
363 /*
364 * In the usual case, the postmaster is still alive, and there is no
365 * data in the pipe.
366 */
367 if (rc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
368 return true;
369 else
370 {
371 /*
372 * Postmaster is dead, or something went wrong with the read()
373 * call.
374 */
375
376#ifdef USE_POSTMASTER_DEATH_SIGNAL
378#endif
379
380 if (rc < 0)
381 elog(FATAL, "read on postmaster death monitoring pipe failed: %m");
382 else if (rc > 0)
383 elog(FATAL, "unexpected data in postmaster death monitoring pipe");
384
385 return false;
386 }
387 }
388
389#else /* WIN32 */
391 return true;
392 else
393 {
394#ifdef USE_POSTMASTER_DEATH_SIGNAL
396#endif
397 return false;
398 }
399#endif /* WIN32 */
400}
401
402/*
403 * PostmasterDeathSignalInit - request signal on postmaster death if possible
404 */
405void
407{
408#ifdef USE_POSTMASTER_DEATH_SIGNAL
410
411 /* Register our signal handler. */
413
414 /* Request a signal on parent exit. */
415#if defined(PR_SET_PDEATHSIG)
416 if (prctl(PR_SET_PDEATHSIG, signum) < 0)
417 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 */
430#endif /* USE_POSTMASTER_DEATH_SIGNAL */
431}
#define SIGNAL_ARGS
Definition c.h:1450
#define Assert(condition)
Definition c.h:943
#define FLEXIBLE_ARRAY_MEMBER
Definition c.h:558
uint32 result
Datum arg
Definition elog.c:1322
#define FATAL
Definition elog.h:42
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
int MyPMChildSlot
Definition globals.c:56
pid_t PostmasterPid
Definition globals.c:108
bool IsUnderPostmaster
Definition globals.c:122
#define read(a, b, c)
Definition win32.h:13
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:372
int MaxLivePostmasterChildren(void)
Definition pmchild.c:81
#define PM_CHILD_WALSENDER
Definition pmsignal.c:70
bool CheckPostmasterSignal(PMSignalReason reason)
Definition pmsignal.c:181
static void MarkPostmasterChildInactive(int code, Datum arg)
Definition pmsignal.c:325
bool PostmasterIsAliveInternal(void)
Definition pmsignal.c:345
QuitSignalReason GetQuitSignalReason(void)
Definition pmsignal.c:212
#define PM_CHILD_ACTIVE
Definition pmsignal.c:69
#define PM_CHILD_UNUSED
Definition pmsignal.c:67
static void PMSignalShmemRequest(void *)
Definition pmsignal.c:138
void MarkPostmasterChildSlotAssigned(int slot)
Definition pmsignal.c:229
void SendPostmasterSignal(PMSignalReason reason)
Definition pmsignal.c:164
void SetQuitSignalReason(QuitSignalReason reason)
Definition pmsignal.c:201
static void PMSignalShmemInit(void *)
Definition pmsignal.c:153
NON_EXEC_STATIC volatile PMSignalData * PMSignalState
Definition pmsignal.c:85
const ShmemCallbacks PMSignalShmemCallbacks
Definition pmsignal.c:90
bool MarkPostmasterChildSlotUnassigned(int slot)
Definition pmsignal.c:248
void MarkPostmasterChildWalSender(void)
Definition pmsignal.c:308
static int num_child_flags
Definition pmsignal.c:100
bool IsPostmasterChildWalSender(int slot)
Definition pmsignal.c:270
void RegisterPostmasterChildActive(void)
Definition pmsignal.c:289
void PostmasterDeathSignalInit(void)
Definition pmsignal.c:406
#define PM_CHILD_ASSIGNED
Definition pmsignal.c:68
#define NUM_PMSIGNALS
Definition pmsignal.h:48
QuitSignalReason
Definition pmsignal.h:54
@ PMQUIT_NOT_SENT
Definition pmsignal.h:55
PMSignalReason
Definition pmsignal.h:34
#define pqsignal
Definition port.h:547
uint64_t Datum
Definition postgres.h:70
#define NON_EXEC_STATIC
Definition postgres.h:560
int postmaster_alive_fds[2]
Definition postmaster.c:486
#define POSTMASTER_FD_WATCH
Definition postmaster.h:83
char * c
static int fb(int x)
Size add_size(Size s1, Size s2)
Definition shmem.c:1048
Size mul_size(Size s1, Size s2)
Definition shmem.c:1063
#define ShmemRequestStruct(...)
Definition shmem.h:176
sig_atomic_t PMSignalFlags[NUM_PMSIGNALS]
Definition pmsignal.c:76
sig_atomic_t PMChildFlags[FLEXIBLE_ARRAY_MEMBER]
Definition pmsignal.c:81
int num_child_flags
Definition pmsignal.c:80
QuitSignalReason sigquit_reason
Definition pmsignal.c:78
ShmemRequestCallback request_fn
Definition shmem.h:133
const char * name
bool am_walsender
Definition walsender.c:135
#define EWOULDBLOCK
Definition win32_port.h:367
#define kill(pid, sig)
Definition win32_port.h:490
#define SIGUSR1
Definition win32_port.h:170
#define EAGAIN
Definition win32_port.h:359