PostgreSQL Source Code  git master
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-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,
51  * or it has successfully cleaned up after itself. A ACTIVE slot means the
52  * process is actively using shared memory. The slots are assigned to
53  * child processes at random, and postmaster.c is responsible for tracking
54  * which 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 */
73 {
74  /* per-reason flags for signaling the postmaster */
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[] */
81 };
82 
83 /* PMSignalState pointer is valid in both postmaster and child processes */
85 
86 /*
87  * These static variables are valid only in the postmaster. We keep a
88  * duplicative private array so that we can trust its state even if some
89  * failing child has clobbered the PMSignalData struct in shared memory.
90  */
91 static int num_child_inuse; /* # of entries in PMChildInUse[] */
92 static int next_child_inuse; /* next slot to try to assign */
93 static bool *PMChildInUse; /* true if i'th flag slot is assigned */
94 
95 /*
96  * Signal handler to be notified if postmaster dies.
97  */
98 #ifdef USE_POSTMASTER_DEATH_SIGNAL
99 volatile sig_atomic_t postmaster_possibly_dead = false;
100 
101 static void
102 postmaster_death_handler(SIGNAL_ARGS)
103 {
104  postmaster_possibly_dead = true;
105 }
106 
107 /*
108  * The available signals depend on the OS. SIGUSR1 and SIGUSR2 are already
109  * used for other things, so choose another one.
110  *
111  * Currently, we assume that we can always find a signal to use. That
112  * seems like a reasonable assumption for all platforms that are modern
113  * enough to have a parent-death signaling mechanism.
114  */
115 #if defined(SIGINFO)
116 #define POSTMASTER_DEATH_SIGNAL SIGINFO
117 #elif defined(SIGPWR)
118 #define POSTMASTER_DEATH_SIGNAL SIGPWR
119 #else
120 #error "cannot find a signal to use for postmaster death"
121 #endif
122 
123 #endif /* USE_POSTMASTER_DEATH_SIGNAL */
124 
125 static void MarkPostmasterChildInactive(int code, Datum arg);
126 
127 /*
128  * PMSignalShmemSize
129  * Compute space needed for pmsignal.c's shared memory
130  */
131 Size
133 {
134  Size size;
135 
136  size = offsetof(PMSignalData, PMChildFlags);
138  sizeof(sig_atomic_t)));
139 
140  return size;
141 }
142 
143 /*
144  * PMSignalShmemInit - initialize during shared-memory creation
145  */
146 void
148 {
149  bool found;
150 
152  ShmemInitStruct("PMSignalState", PMSignalShmemSize(), &found);
153 
154  if (!found)
155  {
156  /* initialize all flags to zeroes */
160 
161  /*
162  * Also allocate postmaster's private PMChildInUse[] array. We
163  * might've already done that in a previous shared-memory creation
164  * cycle, in which case free the old array to avoid a leak. (Do it
165  * like this to support the possibility that MaxLivePostmasterChildren
166  * changed.) In a standalone backend, we do not need this.
167  */
168  if (PostmasterContext != NULL)
169  {
170  if (PMChildInUse)
172  PMChildInUse = (bool *)
174  num_child_inuse * sizeof(bool));
175  }
176  next_child_inuse = 0;
177  }
178 }
179 
180 /*
181  * SendPostmasterSignal - signal the postmaster from a child process
182  */
183 void
185 {
186  /* If called in a standalone backend, do nothing */
187  if (!IsUnderPostmaster)
188  return;
189  /* Atomically set the proper flag */
190  PMSignalState->PMSignalFlags[reason] = true;
191  /* Send signal to postmaster */
193 }
194 
195 /*
196  * CheckPostmasterSignal - check to see if a particular reason has been
197  * signaled, and clear the signal flag. Should be called by postmaster
198  * after receiving SIGUSR1.
199  */
200 bool
202 {
203  /* Careful here --- don't clear flag if we haven't seen it set */
204  if (PMSignalState->PMSignalFlags[reason])
205  {
206  PMSignalState->PMSignalFlags[reason] = false;
207  return true;
208  }
209  return false;
210 }
211 
212 /*
213  * SetQuitSignalReason - broadcast the reason for a system shutdown.
214  * Should be called by postmaster before sending SIGQUIT to children.
215  *
216  * Note: in a crash-and-restart scenario, the "reason" field gets cleared
217  * as a part of rebuilding shared memory; the postmaster need not do it
218  * explicitly.
219  */
220 void
222 {
223  PMSignalState->sigquit_reason = reason;
224 }
225 
226 /*
227  * GetQuitSignalReason - obtain the reason for a system shutdown.
228  * Called by child processes when they receive SIGQUIT.
229  * If the postmaster hasn't actually sent SIGQUIT, will return PMQUIT_NOT_SENT.
230  */
233 {
234  /* This is called in signal handlers, so be extra paranoid. */
235  if (!IsUnderPostmaster || PMSignalState == NULL)
236  return PMQUIT_NOT_SENT;
238 }
239 
240 
241 /*
242  * AssignPostmasterChildSlot - select an unused slot for a new postmaster
243  * child process, and set its state to ASSIGNED. Returns a slot number
244  * (one to N).
245  *
246  * Only the postmaster is allowed to execute this routine, so we need no
247  * special locking.
248  */
249 int
251 {
252  int slot = next_child_inuse;
253  int n;
254 
255  /*
256  * Scan for a free slot. Notice that we trust nothing about the contents
257  * of PMSignalState, but use only postmaster-local data for this decision.
258  * We track the last slot assigned so as not to waste time repeatedly
259  * rescanning low-numbered slots.
260  */
261  for (n = num_child_inuse; n > 0; n--)
262  {
263  if (--slot < 0)
264  slot = num_child_inuse - 1;
265  if (!PMChildInUse[slot])
266  {
267  PMChildInUse[slot] = true;
269  next_child_inuse = slot;
270  return slot + 1;
271  }
272  }
273 
274  /* Out of slots ... should never happen, else postmaster.c messed up */
275  elog(FATAL, "no free slots in PMChildFlags array");
276  return 0; /* keep compiler quiet */
277 }
278 
279 /*
280  * ReleasePostmasterChildSlot - release a slot after death of a postmaster
281  * child process. This must be called in the postmaster process.
282  *
283  * Returns true if the slot had been in ASSIGNED state (the expected case),
284  * false otherwise (implying that the child failed to clean itself up).
285  */
286 bool
288 {
289  bool result;
290 
291  Assert(slot > 0 && slot <= num_child_inuse);
292  slot--;
293 
294  /*
295  * Note: the slot state might already be unused, because the logic in
296  * postmaster.c is such that this might get called twice when a child
297  * crashes. So we don't try to Assert anything about the state.
298  */
299  result = (PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED);
301  PMChildInUse[slot] = false;
302  return result;
303 }
304 
305 /*
306  * IsPostmasterChildWalSender - check if given slot is in use by a
307  * walsender process. This is called only by the postmaster.
308  */
309 bool
311 {
312  Assert(slot > 0 && slot <= num_child_inuse);
313  slot--;
314 
316  return true;
317  else
318  return false;
319 }
320 
321 /*
322  * RegisterPostmasterChildActive - mark a postmaster child as about to begin
323  * actively using shared memory. This is called in the child process.
324  *
325  * This register an shmem exit hook to mark us as inactive again when the
326  * process exits normally.
327  */
328 void
330 {
331  int slot = MyPMChildSlot;
332 
333  Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
334  slot--;
337 
338  /* Arrange to clean up at exit. */
340 }
341 
342 /*
343  * MarkPostmasterChildWalSender - mark a postmaster child as a WAL sender
344  * process. This is called in the child process, sometime after marking the
345  * child as active.
346  */
347 void
349 {
350  int slot = MyPMChildSlot;
351 
353 
354  Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
355  slot--;
358 }
359 
360 /*
361  * MarkPostmasterChildInactive - mark a postmaster child as done using
362  * shared memory. This is called in the child process.
363  */
364 static void
366 {
367  int slot = MyPMChildSlot;
368 
369  Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
370  slot--;
374 }
375 
376 
377 /*
378  * PostmasterIsAliveInternal - check whether postmaster process is still alive
379  *
380  * This is the slow path of PostmasterIsAlive(), where the caller has already
381  * checked 'postmaster_possibly_dead'. (On platforms that don't support
382  * a signal for parent death, PostmasterIsAlive() is just an alias for this.)
383  */
384 bool
386 {
387 #ifdef USE_POSTMASTER_DEATH_SIGNAL
388  /*
389  * Reset the flag before checking, so that we don't miss a signal if
390  * postmaster dies right after the check. If postmaster was indeed dead,
391  * we'll re-arm it before returning to caller.
392  */
393  postmaster_possibly_dead = false;
394 #endif
395 
396 #ifndef WIN32
397  {
398  char c;
399  ssize_t rc;
400 
402 
403  /*
404  * In the usual case, the postmaster is still alive, and there is no
405  * data in the pipe.
406  */
407  if (rc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
408  return true;
409  else
410  {
411  /*
412  * Postmaster is dead, or something went wrong with the read()
413  * call.
414  */
415 
416 #ifdef USE_POSTMASTER_DEATH_SIGNAL
417  postmaster_possibly_dead = true;
418 #endif
419 
420  if (rc < 0)
421  elog(FATAL, "read on postmaster death monitoring pipe failed: %m");
422  else if (rc > 0)
423  elog(FATAL, "unexpected data in postmaster death monitoring pipe");
424 
425  return false;
426  }
427  }
428 
429 #else /* WIN32 */
430  if (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT)
431  return true;
432  else
433  {
434 #ifdef USE_POSTMASTER_DEATH_SIGNAL
435  postmaster_possibly_dead = true;
436 #endif
437  return false;
438  }
439 #endif /* WIN32 */
440 }
441 
442 /*
443  * PostmasterDeathSignalInit - request signal on postmaster death if possible
444  */
445 void
447 {
448 #ifdef USE_POSTMASTER_DEATH_SIGNAL
449  int signum = POSTMASTER_DEATH_SIGNAL;
450 
451  /* Register our signal handler. */
452  pqsignal(signum, postmaster_death_handler);
453 
454  /* Request a signal on parent exit. */
455 #if defined(PR_SET_PDEATHSIG)
456  if (prctl(PR_SET_PDEATHSIG, signum) < 0)
457  elog(ERROR, "could not request parent death signal: %m");
458 #elif defined(PROC_PDEATHSIG_CTL)
459  if (procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum) < 0)
460  elog(ERROR, "could not request parent death signal: %m");
461 #else
462 #error "USE_POSTMASTER_DEATH_SIGNAL set, but there is no mechanism to request the signal"
463 #endif
464 
465  /*
466  * Just in case the parent was gone already and we missed it, we'd better
467  * check the slow way on the first call.
468  */
469  postmaster_possibly_dead = true;
470 #endif /* USE_POSTMASTER_DEATH_SIGNAL */
471 }
#define unvolatize(underlying_type, expr)
Definition: c.h:1238
#define SIGNAL_ARGS
Definition: c.h:1336
#define Assert(condition)
Definition: c.h:849
#define FLEXIBLE_ARRAY_MEMBER
Definition: c.h:401
#define MemSet(start, val, len)
Definition: c.h:1011
size_t Size
Definition: c.h:596
#define FATAL
Definition: elog.h:41
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
int MyPMChildSlot
Definition: globals.c:53
pid_t PostmasterPid
Definition: globals.c:105
bool IsUnderPostmaster
Definition: globals.c:119
#define read(a, b, c)
Definition: win32.h:13
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
void pfree(void *pointer)
Definition: mcxt.c:1521
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1215
MemoryContext PostmasterContext
Definition: mcxt.c:151
void * arg
static bool * PMChildInUse
Definition: pmsignal.c:93
#define PM_CHILD_WALSENDER
Definition: pmsignal.c:69
static int num_child_inuse
Definition: pmsignal.c:91
static int next_child_inuse
Definition: pmsignal.c:92
Size PMSignalShmemSize(void)
Definition: pmsignal.c:132
bool ReleasePostmasterChildSlot(int slot)
Definition: pmsignal.c:287
bool CheckPostmasterSignal(PMSignalReason reason)
Definition: pmsignal.c:201
static void MarkPostmasterChildInactive(int code, Datum arg)
Definition: pmsignal.c:365
bool PostmasterIsAliveInternal(void)
Definition: pmsignal.c:385
QuitSignalReason GetQuitSignalReason(void)
Definition: pmsignal.c:232
#define PM_CHILD_ACTIVE
Definition: pmsignal.c:68
#define PM_CHILD_UNUSED
Definition: pmsignal.c:66
void SendPostmasterSignal(PMSignalReason reason)
Definition: pmsignal.c:184
void SetQuitSignalReason(QuitSignalReason reason)
Definition: pmsignal.c:221
NON_EXEC_STATIC volatile PMSignalData * PMSignalState
Definition: pmsignal.c:84
void MarkPostmasterChildWalSender(void)
Definition: pmsignal.c:348
bool IsPostmasterChildWalSender(int slot)
Definition: pmsignal.c:310
void RegisterPostmasterChildActive(void)
Definition: pmsignal.c:329
void PostmasterDeathSignalInit(void)
Definition: pmsignal.c:446
int AssignPostmasterChildSlot(void)
Definition: pmsignal.c:250
void PMSignalShmemInit(void)
Definition: pmsignal.c:147
#define PM_CHILD_ASSIGNED
Definition: pmsignal.c:67
#define NUM_PMSIGNALS
Definition: pmsignal.h:45
QuitSignalReason
Definition: pmsignal.h:51
@ PMQUIT_NOT_SENT
Definition: pmsignal.h:52
PMSignalReason
Definition: pmsignal.h:34
pqsigfunc pqsignal(int signo, pqsigfunc func)
uintptr_t Datum
Definition: postgres.h:64
#define NON_EXEC_STATIC
Definition: postgres.h:576
int postmaster_alive_fds[2]
Definition: postmaster.c:453
int MaxLivePostmasterChildren(void)
Definition: postmaster.c:3876
#define POSTMASTER_FD_WATCH
Definition: postmaster.h:48
char * c
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510
static pg_noinline void Size size
Definition: slab.c:607
sig_atomic_t PMSignalFlags[NUM_PMSIGNALS]
Definition: pmsignal.c:75
sig_atomic_t PMChildFlags[FLEXIBLE_ARRAY_MEMBER]
Definition: pmsignal.c:80
int num_child_flags
Definition: pmsignal.c:79
QuitSignalReason sigquit_reason
Definition: pmsignal.c:77
bool am_walsender
Definition: walsender.c:115
#define EWOULDBLOCK
Definition: win32_port.h:380
#define kill(pid, sig)
Definition: win32_port.h:503
#define SIGUSR1
Definition: win32_port.h:180
#define EAGAIN
Definition: win32_port.h:372