]> granicus.if.org Git - postgresql/blob - src/backend/storage/ipc/pmsignal.c
Work around unfortunate getppid() behavior on BSD-ish systems.
[postgresql] / src / backend / storage / ipc / pmsignal.c
1 /*-------------------------------------------------------------------------
2  *
3  * pmsignal.c
4  *        routines for signaling the postmaster from its child processes
5  *
6  *
7  * Portions Copyright (c) 1996-2010, 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 #include "miscadmin.h"
21 #include "postmaster/postmaster.h"
22 #include "replication/walsender.h"
23 #include "storage/pmsignal.h"
24 #include "storage/shmem.h"
25
26
27 /*
28  * The postmaster is signaled by its children by sending SIGUSR1.  The
29  * specific reason is communicated via flags in shared memory.  We keep
30  * a boolean flag for each possible "reason", so that different reasons
31  * can be signaled by different backends at the same time.      (However,
32  * if the same reason is signaled more than once simultaneously, the
33  * postmaster will observe it only once.)
34  *
35  * The flags are actually declared as "volatile sig_atomic_t" for maximum
36  * portability.  This should ensure that loads and stores of the flag
37  * values are atomic, allowing us to dispense with any explicit locking.
38  *
39  * In addition to the per-reason flags, we store a set of per-child-process
40  * flags that are currently used only for detecting whether a backend has
41  * exited without performing proper shutdown.  The per-child-process flags
42  * have three possible states: UNUSED, ASSIGNED, ACTIVE.  An UNUSED slot is
43  * available for assignment.  An ASSIGNED slot is associated with a postmaster
44  * child process, but either the process has not touched shared memory yet,
45  * or it has successfully cleaned up after itself.      A ACTIVE slot means the
46  * process is actively using shared memory.  The slots are assigned to
47  * child processes at random, and postmaster.c is responsible for tracking
48  * which one goes with which PID.
49  *
50  * Actually there is a fourth state, WALSENDER.  This is just like ACTIVE,
51  * but carries the extra information that the child is a WAL sender.
52  */
53
54 #define PM_CHILD_UNUSED         0       /* these values must fit in sig_atomic_t */
55 #define PM_CHILD_ASSIGNED       1
56 #define PM_CHILD_ACTIVE         2
57 #define PM_CHILD_WALSENDER      3
58
59 /* "typedef struct PMSignalData PMSignalData" appears in pmsignal.h */
60 struct PMSignalData
61 {
62         /* per-reason flags */
63         sig_atomic_t PMSignalFlags[NUM_PMSIGNALS];
64         /* per-child-process flags */
65         int                     num_child_flags;        /* # of entries in PMChildFlags[] */
66         int                     next_child_flag;        /* next slot to try to assign */
67         sig_atomic_t PMChildFlags[1];           /* VARIABLE LENGTH ARRAY */
68 };
69
70 NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL;
71
72
73 /*
74  * PMSignalShmemSize
75  *              Compute space needed for pmsignal.c's shared memory
76  */
77 Size
78 PMSignalShmemSize(void)
79 {
80         Size            size;
81
82         size = offsetof(PMSignalData, PMChildFlags);
83         size = add_size(size, mul_size(MaxLivePostmasterChildren(),
84                                                                    sizeof(sig_atomic_t)));
85
86         return size;
87 }
88
89 /*
90  * PMSignalShmemInit - initialize during shared-memory creation
91  */
92 void
93 PMSignalShmemInit(void)
94 {
95         bool            found;
96
97         PMSignalState = (PMSignalData *)
98                 ShmemInitStruct("PMSignalState", PMSignalShmemSize(), &found);
99
100         if (!found)
101         {
102                 MemSet(PMSignalState, 0, PMSignalShmemSize());
103                 PMSignalState->num_child_flags = MaxLivePostmasterChildren();
104         }
105 }
106
107 /*
108  * SendPostmasterSignal - signal the postmaster from a child process
109  */
110 void
111 SendPostmasterSignal(PMSignalReason reason)
112 {
113         /* If called in a standalone backend, do nothing */
114         if (!IsUnderPostmaster)
115                 return;
116         /* Atomically set the proper flag */
117         PMSignalState->PMSignalFlags[reason] = true;
118         /* Send signal to postmaster */
119         kill(PostmasterPid, SIGUSR1);
120 }
121
122 /*
123  * CheckPostmasterSignal - check to see if a particular reason has been
124  * signaled, and clear the signal flag.  Should be called by postmaster
125  * after receiving SIGUSR1.
126  */
127 bool
128 CheckPostmasterSignal(PMSignalReason reason)
129 {
130         /* Careful here --- don't clear flag if we haven't seen it set */
131         if (PMSignalState->PMSignalFlags[reason])
132         {
133                 PMSignalState->PMSignalFlags[reason] = false;
134                 return true;
135         }
136         return false;
137 }
138
139
140 /*
141  * AssignPostmasterChildSlot - select an unused slot for a new postmaster
142  * child process, and set its state to ASSIGNED.  Returns a slot number
143  * (one to N).
144  *
145  * Only the postmaster is allowed to execute this routine, so we need no
146  * special locking.
147  */
148 int
149 AssignPostmasterChildSlot(void)
150 {
151         int                     slot = PMSignalState->next_child_flag;
152         int                     n;
153
154         /*
155          * Scan for a free slot.  We track the last slot assigned so as not to
156          * waste time repeatedly rescanning low-numbered slots.
157          */
158         for (n = PMSignalState->num_child_flags; n > 0; n--)
159         {
160                 if (--slot < 0)
161                         slot = PMSignalState->num_child_flags - 1;
162                 if (PMSignalState->PMChildFlags[slot] == PM_CHILD_UNUSED)
163                 {
164                         PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED;
165                         PMSignalState->next_child_flag = slot;
166                         return slot + 1;
167                 }
168         }
169
170         /* Out of slots ... should never happen, else postmaster.c messed up */
171         elog(FATAL, "no free slots in PMChildFlags array");
172         return 0;                                       /* keep compiler quiet */
173 }
174
175 /*
176  * ReleasePostmasterChildSlot - release a slot after death of a postmaster
177  * child process.  This must be called in the postmaster process.
178  *
179  * Returns true if the slot had been in ASSIGNED state (the expected case),
180  * false otherwise (implying that the child failed to clean itself up).
181  */
182 bool
183 ReleasePostmasterChildSlot(int slot)
184 {
185         bool            result;
186
187         Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
188         slot--;
189
190         /*
191          * Note: the slot state might already be unused, because the logic in
192          * postmaster.c is such that this might get called twice when a child
193          * crashes.  So we don't try to Assert anything about the state.
194          */
195         result = (PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED);
196         PMSignalState->PMChildFlags[slot] = PM_CHILD_UNUSED;
197         return result;
198 }
199
200 /*
201  * IsPostmasterChildWalSender - check if given slot is in use by a
202  * walsender process.
203  */
204 bool
205 IsPostmasterChildWalSender(int slot)
206 {
207         Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
208         slot--;
209
210         if (PMSignalState->PMChildFlags[slot] == PM_CHILD_WALSENDER)
211                 return true;
212         else
213                 return false;
214 }
215
216 /*
217  * MarkPostmasterChildActive - mark a postmaster child as about to begin
218  * actively using shared memory.  This is called in the child process.
219  */
220 void
221 MarkPostmasterChildActive(void)
222 {
223         int                     slot = MyPMChildSlot;
224
225         Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
226         slot--;
227         Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED);
228         PMSignalState->PMChildFlags[slot] =
229                 (am_walsender ? PM_CHILD_WALSENDER : PM_CHILD_ACTIVE);
230 }
231
232 /*
233  * MarkPostmasterChildInactive - mark a postmaster child as done using
234  * shared memory.  This is called in the child process.
235  */
236 void
237 MarkPostmasterChildInactive(void)
238 {
239         int                     slot = MyPMChildSlot;
240
241         Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
242         slot--;
243         Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ACTIVE ||
244                    PMSignalState->PMChildFlags[slot] == PM_CHILD_WALSENDER);
245         PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED;
246 }
247
248
249 /*
250  * PostmasterIsAlive - check whether postmaster process is still alive
251  *
252  * amDirectChild should be passed as "true" by code that knows it is
253  * executing in a direct child process of the postmaster; pass "false"
254  * if an indirect child or not sure.  The "true" case uses a faster and
255  * more reliable test, so use it when possible.
256  */
257 bool
258 PostmasterIsAlive(bool amDirectChild)
259 {
260 #ifndef WIN32
261         if (amDirectChild)
262         {
263                 pid_t   ppid = getppid();
264
265                 /* If the postmaster is still our parent, it must be alive. */
266                 if (ppid == PostmasterPid)
267                         return true;
268
269                 /* If the init process is our parent, postmaster must be dead. */
270                 if (ppid == 1)
271                         return false;
272
273                 /*
274                  * If we get here, our parent process is neither the postmaster nor
275                  * init.  This can occur on BSD and MacOS systems if a debugger has
276                  * been attached.  We fall through to the less-reliable kill() method.
277                  */
278         }
279
280         /*
281          * Use kill() to see if the postmaster is still alive.  This can
282          * sometimes give a false positive result, since the postmaster's PID
283          * may get recycled, but it is good enough for existing uses by
284          * indirect children and in debugging environments.
285          */
286         return (kill(PostmasterPid, 0) == 0);
287 #else                                                   /* WIN32 */
288         return (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT);
289 #endif   /* WIN32 */
290 }