PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
procsignal.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * procsignal.c
4  * Routines for interprocess signalling
5  *
6  *
7  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  * src/backend/storage/ipc/procsignal.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include <signal.h>
18 #include <unistd.h>
19 
20 #include "access/parallel.h"
21 #include "commands/async.h"
22 #include "miscadmin.h"
23 #include "replication/walsender.h"
24 #include "storage/latch.h"
25 #include "storage/ipc.h"
26 #include "storage/proc.h"
27 #include "storage/shmem.h"
28 #include "storage/sinval.h"
29 #include "tcop/tcopprot.h"
30 
31 
32 /*
33  * The SIGUSR1 signal is multiplexed to support signalling multiple event
34  * types. The specific reason is communicated via flags in shared memory.
35  * We keep a boolean flag for each possible "reason", so that different
36  * reasons can be signaled to a process concurrently. (However, if the same
37  * reason is signaled more than once nearly simultaneously, the process may
38  * observe it only once.)
39  *
40  * Each process that wants to receive signals registers its process ID
41  * in the ProcSignalSlots array. The array is indexed by backend ID to make
42  * slot allocation simple, and to avoid having to search the array when you
43  * know the backend ID of the process you're signalling. (We do support
44  * signalling without backend ID, but it's a bit less efficient.)
45  *
46  * The flags are actually declared as "volatile sig_atomic_t" for maximum
47  * portability. This should ensure that loads and stores of the flag
48  * values are atomic, allowing us to dispense with any explicit locking.
49  */
50 typedef struct
51 {
52  pid_t pss_pid;
53  sig_atomic_t pss_signalFlags[NUM_PROCSIGNALS];
55 
56 /*
57  * We reserve a slot for each possible BackendId, plus one for each
58  * possible auxiliary process type. (This scheme assumes there is not
59  * more than one of any auxiliary process type at a time.)
60  */
61 #define NumProcSignalSlots (MaxBackends + NUM_AUXPROCTYPES)
62 
65 
66 static bool CheckProcSignal(ProcSignalReason reason);
67 static void CleanupProcSignalState(int status, Datum arg);
68 
69 /*
70  * ProcSignalShmemSize
71  * Compute space needed for procsignal's shared memory
72  */
73 Size
75 {
76  return NumProcSignalSlots * sizeof(ProcSignalSlot);
77 }
78 
79 /*
80  * ProcSignalShmemInit
81  * Allocate and initialize procsignal's shared memory
82  */
83 void
85 {
86  Size size = ProcSignalShmemSize();
87  bool found;
88 
89  ProcSignalSlots = (ProcSignalSlot *)
90  ShmemInitStruct("ProcSignalSlots", size, &found);
91 
92  /* If we're first, set everything to zeroes */
93  if (!found)
94  MemSet(ProcSignalSlots, 0, size);
95 }
96 
97 /*
98  * ProcSignalInit
99  * Register the current process in the procsignal array
100  *
101  * The passed index should be my BackendId if the process has one,
102  * or MaxBackends + aux process type if not.
103  */
104 void
105 ProcSignalInit(int pss_idx)
106 {
107  volatile ProcSignalSlot *slot;
108 
109  Assert(pss_idx >= 1 && pss_idx <= NumProcSignalSlots);
110 
111  slot = &ProcSignalSlots[pss_idx - 1];
112 
113  /* sanity check */
114  if (slot->pss_pid != 0)
115  elog(LOG, "process %d taking over ProcSignal slot %d, but it's not empty",
116  MyProcPid, pss_idx);
117 
118  /* Clear out any leftover signal reasons */
119  MemSet(slot->pss_signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t));
120 
121  /* Mark slot with my PID */
122  slot->pss_pid = MyProcPid;
123 
124  /* Remember slot location for CheckProcSignal */
125  MyProcSignalSlot = slot;
126 
127  /* Set up to release the slot on process exit */
129 }
130 
131 /*
132  * CleanupProcSignalState
133  * Remove current process from ProcSignalSlots
134  *
135  * This function is called via on_shmem_exit() during backend shutdown.
136  */
137 static void
139 {
140  int pss_idx = DatumGetInt32(arg);
141  volatile ProcSignalSlot *slot;
142 
143  slot = &ProcSignalSlots[pss_idx - 1];
144  Assert(slot == MyProcSignalSlot);
145 
146  /*
147  * Clear MyProcSignalSlot, so that a SIGUSR1 received after this point
148  * won't try to access it after it's no longer ours (and perhaps even
149  * after we've unmapped the shared memory segment).
150  */
151  MyProcSignalSlot = NULL;
152 
153  /* sanity check */
154  if (slot->pss_pid != MyProcPid)
155  {
156  /*
157  * don't ERROR here. We're exiting anyway, and don't want to get into
158  * infinite loop trying to exit
159  */
160  elog(LOG, "process %d releasing ProcSignal slot %d, but it contains %d",
161  MyProcPid, pss_idx, (int) slot->pss_pid);
162  return; /* XXX better to zero the slot anyway? */
163  }
164 
165  slot->pss_pid = 0;
166 }
167 
168 /*
169  * SendProcSignal
170  * Send a signal to a Postgres process
171  *
172  * Providing backendId is optional, but it will speed up the operation.
173  *
174  * On success (a signal was sent), zero is returned.
175  * On error, -1 is returned, and errno is set (typically to ESRCH or EPERM).
176  *
177  * Not to be confused with ProcSendSignal
178  */
179 int
180 SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
181 {
182  volatile ProcSignalSlot *slot;
183 
184  if (backendId != InvalidBackendId)
185  {
186  slot = &ProcSignalSlots[backendId - 1];
187 
188  /*
189  * Note: Since there's no locking, it's possible that the target
190  * process detaches from shared memory and exits right after this
191  * test, before we set the flag and send signal. And the signal slot
192  * might even be recycled by a new process, so it's remotely possible
193  * that we set a flag for a wrong process. That's OK, all the signals
194  * are such that no harm is done if they're mistakenly fired.
195  */
196  if (slot->pss_pid == pid)
197  {
198  /* Atomically set the proper flag */
199  slot->pss_signalFlags[reason] = true;
200  /* Send signal */
201  return kill(pid, SIGUSR1);
202  }
203  }
204  else
205  {
206  /*
207  * BackendId not provided, so search the array using pid. We search
208  * the array back to front so as to reduce search overhead. Passing
209  * InvalidBackendId means that the target is most likely an auxiliary
210  * process, which will have a slot near the end of the array.
211  */
212  int i;
213 
214  for (i = NumProcSignalSlots - 1; i >= 0; i--)
215  {
216  slot = &ProcSignalSlots[i];
217 
218  if (slot->pss_pid == pid)
219  {
220  /* the above note about race conditions applies here too */
221 
222  /* Atomically set the proper flag */
223  slot->pss_signalFlags[reason] = true;
224  /* Send signal */
225  return kill(pid, SIGUSR1);
226  }
227  }
228  }
229 
230  errno = ESRCH;
231  return -1;
232 }
233 
234 /*
235  * CheckProcSignal - check to see if a particular reason has been
236  * signaled, and clear the signal flag. Should be called after receiving
237  * SIGUSR1.
238  */
239 static bool
241 {
242  volatile ProcSignalSlot *slot = MyProcSignalSlot;
243 
244  if (slot != NULL)
245  {
246  /* Careful here --- don't clear flag if we haven't seen it set */
247  if (slot->pss_signalFlags[reason])
248  {
249  slot->pss_signalFlags[reason] = false;
250  return true;
251  }
252  }
253 
254  return false;
255 }
256 
257 /*
258  * procsignal_sigusr1_handler - handle SIGUSR1 signal.
259  */
260 void
262 {
263  int save_errno = errno;
264 
267 
270 
273 
276 
279 
282 
285 
288 
291 
294 
295  SetLatch(MyLatch);
296 
298 
299  errno = save_errno;
300 }
#define SIGUSR1
Definition: win32.h:202
static ProcSignalSlot * ProcSignalSlots
Definition: procsignal.c:63
void RecoveryConflictInterrupt(ProcSignalReason reason)
Definition: postgres.c:2705
int MyProcPid
Definition: globals.c:39
#define DatumGetInt32(X)
Definition: postgres.h:478
#define MemSet(start, val, len)
Definition: c.h:858
#define LOG
Definition: elog.h:26
static void CleanupProcSignalState(int status, Datum arg)
Definition: procsignal.c:138
void HandleWalSndInitStopping(void)
Definition: walsender.c:2902
int SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
Definition: procsignal.c:180
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:348
Size ProcSignalShmemSize(void)
Definition: procsignal.c:74
#define InvalidBackendId
Definition: backendid.h:23
uintptr_t Datum
Definition: postgres.h:372
int BackendId
Definition: backendid.h:21
static bool CheckProcSignal(ProcSignalReason reason)
Definition: procsignal.c:240
void SetLatch(volatile Latch *latch)
Definition: latch.c:414
#define SIGNAL_ARGS
Definition: c.h:1080
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
size_t Size
Definition: c.h:356
void ProcSignalInit(int pss_idx)
Definition: procsignal.c:105
#define Int32GetDatum(X)
Definition: postgres.h:485
void HandleNotifyInterrupt(void)
Definition: async.c:1702
int i
ProcSignalReason
Definition: procsignal.h:30
sig_atomic_t pss_signalFlags[NUM_PROCSIGNALS]
Definition: procsignal.c:53
void * arg
void ProcSignalShmemInit(void)
Definition: procsignal.c:84
static volatile ProcSignalSlot * MyProcSignalSlot
Definition: procsignal.c:64
#define NumProcSignalSlots
Definition: procsignal.c:61
struct Latch * MyLatch
Definition: globals.c:52
void HandleParallelMessageInterrupt(void)
Definition: parallel.c:681
#define elog
Definition: elog.h:219
void latch_sigusr1_handler(void)
Definition: latch.c:1473
void procsignal_sigusr1_handler(SIGNAL_ARGS)
Definition: procsignal.c:261
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
void HandleCatchupInterrupt(void)
Definition: sinval.c:157