Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * ipc.c
4 : : * POSTGRES inter-process communication definitions.
5 : : *
6 : : * This file is misnamed, as it no longer has much of anything directly
7 : : * to do with IPC. The functionality here is concerned with managing
8 : : * exit-time cleanup for either a postmaster or a backend.
9 : : *
10 : : *
11 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
12 : : * Portions Copyright (c) 1994, Regents of the University of California
13 : : *
14 : : *
15 : : * IDENTIFICATION
16 : : * src/backend/storage/ipc/ipc.c
17 : : *
18 : : *-------------------------------------------------------------------------
19 : : */
20 : : #include "postgres.h"
21 : :
22 : : #include <signal.h>
23 : : #include <unistd.h>
24 : : #include <sys/stat.h>
25 : :
26 : : #include "miscadmin.h"
27 : : #ifdef PROFILE_PID_DIR
28 : : #include "postmaster/autovacuum.h"
29 : : #endif
30 : : #include "storage/dsm.h"
31 : : #include "storage/ipc.h"
32 : : #include "tcop/tcopprot.h"
33 : :
34 : :
35 : : /*
36 : : * This flag is set during proc_exit() to change ereport()'s behavior,
37 : : * so that an ereport() from an on_proc_exit routine cannot get us out
38 : : * of the exit procedure. We do NOT want to go back to the idle loop...
39 : : */
40 : : bool proc_exit_inprogress = false;
41 : :
42 : : /*
43 : : * Set when shmem_exit() is in progress.
44 : : */
45 : : bool shmem_exit_inprogress = false;
46 : :
47 : : /*
48 : : * This flag tracks whether we've called atexit() in the current process
49 : : * (or in the parent postmaster).
50 : : */
51 : : static bool atexit_callback_setup = false;
52 : :
53 : : /* local functions */
54 : : static void proc_exit_prepare(int code);
55 : :
56 : :
57 : : /* ----------------------------------------------------------------
58 : : * exit() handling stuff
59 : : *
60 : : * These functions are in generally the same spirit as atexit(),
61 : : * but provide some additional features we need --- in particular,
62 : : * we want to register callbacks to invoke when we are disconnecting
63 : : * from a broken shared-memory context but not exiting the postmaster.
64 : : *
65 : : * Callback functions can take zero, one, or two args: the first passed
66 : : * arg is the integer exitcode, the second is the Datum supplied when
67 : : * the callback was registered.
68 : : * ----------------------------------------------------------------
69 : : */
70 : :
71 : : #define MAX_ON_EXITS 20
72 : :
73 : : struct ONEXIT
74 : : {
75 : : pg_on_exit_callback function;
76 : : Datum arg;
77 : : };
78 : :
79 : : static struct ONEXIT on_proc_exit_list[MAX_ON_EXITS];
80 : : static struct ONEXIT on_shmem_exit_list[MAX_ON_EXITS];
81 : : static struct ONEXIT before_shmem_exit_list[MAX_ON_EXITS];
82 : :
83 : : static int on_proc_exit_index,
84 : : on_shmem_exit_index,
85 : : before_shmem_exit_index;
86 : :
87 : :
88 : : /* ----------------------------------------------------------------
89 : : * proc_exit
90 : : *
91 : : * this function calls all the callbacks registered
92 : : * for it (to free resources) and then calls exit.
93 : : *
94 : : * This should be the only function to call exit().
95 : : * -cim 2/6/90
96 : : *
97 : : * Unfortunately, we can't really guarantee that add-on code
98 : : * obeys the rule of not calling exit() directly. So, while
99 : : * this is the preferred way out of the system, we also register
100 : : * an atexit callback that will make sure cleanup happens.
101 : : * ----------------------------------------------------------------
102 : : */
103 : : void
9933 bruce@momjian.us 104 :CBC 20041 : proc_exit(int code)
105 : : {
106 : : /* not safe if forked by system(), etc. */
690 nathan@postgresql.or 107 [ - + ]: 20041 : if (MyProcPid != (int) getpid())
690 nathan@postgresql.or 108 [ # # ]:UBC 0 : elog(PANIC, "proc_exit() called in child process");
109 : :
110 : : /* Clean up everything that must be cleaned up */
5968 tgl@sss.pgh.pa.us 111 :CBC 20041 : proc_exit_prepare(code);
112 : :
113 : : #ifdef PROFILE_PID_DIR
114 : : {
115 : : /*
116 : : * If we are profiling ourself then gprof's mcleanup() is about to
117 : : * write out a profile to ./gmon.out. Since mcleanup() always uses a
118 : : * fixed file name, each backend will overwrite earlier profiles. To
119 : : * fix that, we create a separate subdirectory for each backend
120 : : * (./gprof/pid) and 'cd' to that subdirectory before we exit() - that
121 : : * forces mcleanup() to write each profile into its own directory. We
122 : : * end up with something like: $PGDATA/gprof/8829/gmon.out
123 : : * $PGDATA/gprof/8845/gmon.out ...
124 : : *
125 : : * To avoid undesirable disk space bloat, autovacuum workers are
126 : : * discriminated against: all their gmon.out files go into the same
127 : : * subdirectory. Without this, an installation that is "just sitting
128 : : * there" nonetheless eats megabytes of disk space every few seconds.
129 : : *
130 : : * Note that we do this here instead of in an on_proc_exit() callback
131 : : * because we want to ensure that this code executes last - we don't
132 : : * want to interfere with any other on_proc_exit() callback. For the
133 : : * same reason, we do not include it in proc_exit_prepare ... so if
134 : : * you are exiting in the "wrong way" you won't drop your profile in a
135 : : * nice place.
136 : : */
137 : : char gprofDirName[32];
138 : :
139 : : if (AmAutoVacuumWorkerProcess())
140 : : snprintf(gprofDirName, 32, "gprof/avworker");
141 : : else
142 : : snprintf(gprofDirName, 32, "gprof/%d", (int) getpid());
143 : :
144 : : /*
145 : : * Use mkdir() instead of MakePGDirectory() since we aren't making a
146 : : * PG directory here.
147 : : */
148 : : mkdir("gprof", S_IRWXU | S_IRWXG | S_IRWXO);
149 : : mkdir(gprofDirName, S_IRWXU | S_IRWXG | S_IRWXO);
150 : : chdir(gprofDirName);
151 : : }
152 : : #endif
153 : :
154 [ + + ]: 20041 : elog(DEBUG3, "exit(%d)", code);
155 : :
10226 bruce@momjian.us 156 : 20041 : exit(code);
157 : : }
158 : :
159 : : /*
160 : : * Code shared between proc_exit and the atexit handler. Note that in
161 : : * normal exit through proc_exit, this will actually be called twice ...
162 : : * but the second call will have nothing to do.
163 : : */
164 : : static void
5968 tgl@sss.pgh.pa.us 165 : 40048 : proc_exit_prepare(int code)
166 : : {
167 : : /*
168 : : * Once we set this flag, we are committed to exit. Any ereport() will
169 : : * NOT send control back to the main loop, but right back here.
170 : : */
171 : 40048 : proc_exit_inprogress = true;
172 : :
173 : : /*
174 : : * Forget any pending cancel or die requests; we're doing our best to
175 : : * close up shop already. Note that the signal handlers will not set
176 : : * these flags again, now that proc_exit_inprogress is set.
177 : : */
178 : 40048 : InterruptPending = false;
179 : 40048 : ProcDiePending = false;
180 : 40048 : QueryCancelPending = false;
181 : 40048 : InterruptHoldoffCount = 1;
182 : 40048 : CritSectionCount = 0;
183 : :
184 : : /*
185 : : * Also clear the error context stack, to prevent error callbacks from
186 : : * being invoked by any elog/ereport calls made during proc_exit. Whatever
187 : : * context they might want to offer is probably not relevant, and in any
188 : : * case they are likely to fail outright after we've done things like
189 : : * aborting any open transaction. (In normal exit scenarios the context
190 : : * stack should be empty anyway, but it might not be in the case of
191 : : * elog(FATAL) for example.)
192 : : */
5649 193 : 40048 : error_context_stack = NULL;
194 : : /* For the same reason, reset debug_query_string before it's clobbered */
195 : 40048 : debug_query_string = NULL;
196 : :
197 : : /* do our shared memory exits first */
5968 198 : 40048 : shmem_exit(code);
199 : :
5958 200 [ + + ]: 40048 : elog(DEBUG3, "proc_exit(%d): %d callbacks to make",
201 : : code, on_proc_exit_index);
202 : :
203 : : /*
204 : : * call all the registered callbacks.
205 : : *
206 : : * Note that since we decrement on_proc_exit_index each time, if a
207 : : * callback calls ereport(ERROR) or ereport(FATAL) then it won't be
208 : : * invoked again when control comes back here (nor will the
209 : : * previously-completed callbacks). So, an infinite loop should not be
210 : : * possible.
211 : : */
5968 212 [ + + ]: 73147 : while (--on_proc_exit_index >= 0)
2921 peter_e@gmx.net 213 : 33099 : on_proc_exit_list[on_proc_exit_index].function(code,
214 : : on_proc_exit_list[on_proc_exit_index].arg);
215 : :
5968 tgl@sss.pgh.pa.us 216 : 40048 : on_proc_exit_index = 0;
217 : 40048 : }
218 : :
219 : : /* ------------------
220 : : * Run all of the on_shmem_exit routines --- but don't actually exit.
221 : : * This is used by the postmaster to re-initialize shared memory and
222 : : * semaphores after a backend dies horribly. As with proc_exit(), we
223 : : * remove each callback from the list before calling it, to avoid
224 : : * infinite loop in case of error.
225 : : * ------------------
226 : : */
227 : : void
9933 bruce@momjian.us 228 : 40052 : shmem_exit(int code)
229 : : {
2774 peter_e@gmx.net 230 : 40052 : shmem_exit_inprogress = true;
231 : :
232 : : /*
233 : : * Call before_shmem_exit callbacks.
234 : : *
235 : : * These should be things that need most of the system to still be up and
236 : : * working, such as cleanup of temp relations, which requires catalog
237 : : * access; or things that need to be completed because later cleanup steps
238 : : * depend on them, such as releasing lwlocks.
239 : : */
4280 rhaas@postgresql.org 240 [ + + ]: 40052 : elog(DEBUG3, "shmem_exit(%d): %d before_shmem_exit callbacks to make",
241 : : code, before_shmem_exit_index);
242 [ + + ]: 136347 : while (--before_shmem_exit_index >= 0)
2921 peter_e@gmx.net 243 : 96295 : before_shmem_exit_list[before_shmem_exit_index].function(code,
244 : : before_shmem_exit_list[before_shmem_exit_index].arg);
4280 rhaas@postgresql.org 245 : 40052 : before_shmem_exit_index = 0;
246 : :
247 : : /*
248 : : * Call dynamic shared memory callbacks.
249 : : *
250 : : * These serve the same purpose as late callbacks, but for dynamic shared
251 : : * memory segments rather than the main shared memory segment.
252 : : * dsm_backend_shutdown() has the same kind of progressive logic we use
253 : : * for the main shared memory segment; namely, it unregisters each
254 : : * callback before invoking it, so that we don't get stuck in an infinite
255 : : * loop if one of those callbacks itself throws an ERROR or FATAL.
256 : : *
257 : : * Note that explicitly calling this function here is quite different from
258 : : * registering it as an on_shmem_exit callback for precisely this reason:
259 : : * if one dynamic shared memory callback errors out, the remaining
260 : : * callbacks will still be invoked. Thus, hard-coding this call puts it
261 : : * equal footing with callbacks for the main shared memory segment.
262 : : */
263 : 40052 : dsm_backend_shutdown();
264 : :
265 : : /*
266 : : * Call on_shmem_exit callbacks.
267 : : *
268 : : * These are generally releasing low-level shared memory resources. In
269 : : * some cases, this is a backstop against the possibility that the early
270 : : * callbacks might themselves fail, leading to re-entry to this routine;
271 : : * in other cases, it's cleanup that only happens at process exit.
272 : : */
273 [ + + ]: 40052 : elog(DEBUG3, "shmem_exit(%d): %d on_shmem_exit callbacks to make",
274 : : code, on_shmem_exit_index);
9420 tgl@sss.pgh.pa.us 275 [ + + ]: 177901 : while (--on_shmem_exit_index >= 0)
2921 peter_e@gmx.net 276 : 137849 : on_shmem_exit_list[on_shmem_exit_index].function(code,
277 : : on_shmem_exit_list[on_shmem_exit_index].arg);
9933 bruce@momjian.us 278 : 40052 : on_shmem_exit_index = 0;
279 : :
2613 peter_e@gmx.net 280 : 40052 : shmem_exit_inprogress = false;
9933 bruce@momjian.us 281 : 40052 : }
282 : :
283 : : /* ----------------------------------------------------------------
284 : : * atexit_callback
285 : : *
286 : : * Backstop to ensure that direct calls of exit() don't mess us up.
287 : : *
288 : : * Somebody who was being really uncooperative could call _exit(),
289 : : * but for that case we have a "dead man switch" that will make the
290 : : * postmaster treat it as a crash --- see pmsignal.c.
291 : : * ----------------------------------------------------------------
292 : : */
293 : : static void
5968 tgl@sss.pgh.pa.us 294 : 20007 : atexit_callback(void)
295 : : {
296 : : /* Clean up everything that must be cleaned up */
297 : : /* ... too bad we don't know the real exit code ... */
298 : 20007 : proc_exit_prepare(-1);
299 : 20007 : }
300 : :
301 : : /* ----------------------------------------------------------------
302 : : * on_proc_exit
303 : : *
304 : : * this function adds a callback function to the list of
305 : : * functions invoked by proc_exit(). -cim 2/6/90
306 : : * ----------------------------------------------------------------
307 : : */
308 : : void
6352 309 : 33099 : on_proc_exit(pg_on_exit_callback function, Datum arg)
310 : : {
9933 bruce@momjian.us 311 [ - + ]: 33099 : if (on_proc_exit_index >= MAX_ON_EXITS)
8080 tgl@sss.pgh.pa.us 312 [ # # ]:UBC 0 : ereport(FATAL,
313 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
314 : : errmsg_internal("out of on_proc_exit slots")));
315 : :
9933 bruce@momjian.us 316 :CBC 33099 : on_proc_exit_list[on_proc_exit_index].function = function;
317 : 33099 : on_proc_exit_list[on_proc_exit_index].arg = arg;
318 : :
319 : 33099 : ++on_proc_exit_index;
320 : :
5968 tgl@sss.pgh.pa.us 321 [ + + ]: 33099 : if (!atexit_callback_setup)
322 : : {
323 : 1033 : atexit(atexit_callback);
324 : 1033 : atexit_callback_setup = true;
325 : : }
10651 scrappy@hub.org 326 : 33099 : }
327 : :
328 : : /* ----------------------------------------------------------------
329 : : * before_shmem_exit
330 : : *
331 : : * Register early callback to perform user-level cleanup,
332 : : * e.g. transaction abort, before we begin shutting down
333 : : * low-level subsystems.
334 : : * ----------------------------------------------------------------
335 : : */
336 : : void
4280 rhaas@postgresql.org 337 : 98539 : before_shmem_exit(pg_on_exit_callback function, Datum arg)
338 : : {
339 [ - + ]: 98539 : if (before_shmem_exit_index >= MAX_ON_EXITS)
4280 rhaas@postgresql.org 340 [ # # ]:UBC 0 : ereport(FATAL,
341 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
342 : : errmsg_internal("out of before_shmem_exit slots")));
343 : :
4280 rhaas@postgresql.org 344 :CBC 98539 : before_shmem_exit_list[before_shmem_exit_index].function = function;
345 : 98539 : before_shmem_exit_list[before_shmem_exit_index].arg = arg;
346 : :
347 : 98539 : ++before_shmem_exit_index;
348 : :
349 [ - + ]: 98539 : if (!atexit_callback_setup)
350 : : {
4280 rhaas@postgresql.org 351 :UBC 0 : atexit(atexit_callback);
352 : 0 : atexit_callback_setup = true;
353 : : }
4280 rhaas@postgresql.org 354 :CBC 98539 : }
355 : :
356 : : /* ----------------------------------------------------------------
357 : : * on_shmem_exit
358 : : *
359 : : * Register ordinary callback to perform low-level shutdown
360 : : * (e.g. releasing our PGPROC); run after before_shmem_exit
361 : : * callbacks and before on_proc_exit callbacks.
362 : : * ----------------------------------------------------------------
363 : : */
364 : : void
6352 tgl@sss.pgh.pa.us 365 : 137849 : on_shmem_exit(pg_on_exit_callback function, Datum arg)
366 : : {
9933 bruce@momjian.us 367 [ - + ]: 137849 : if (on_shmem_exit_index >= MAX_ON_EXITS)
8080 tgl@sss.pgh.pa.us 368 [ # # ]:UBC 0 : ereport(FATAL,
369 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
370 : : errmsg_internal("out of on_shmem_exit slots")));
371 : :
9933 bruce@momjian.us 372 :CBC 137849 : on_shmem_exit_list[on_shmem_exit_index].function = function;
373 : 137849 : on_shmem_exit_list[on_shmem_exit_index].arg = arg;
374 : :
375 : 137849 : ++on_shmem_exit_index;
376 : :
5968 tgl@sss.pgh.pa.us 377 [ - + ]: 137849 : if (!atexit_callback_setup)
378 : : {
5968 tgl@sss.pgh.pa.us 379 :UBC 0 : atexit(atexit_callback);
380 : 0 : atexit_callback_setup = true;
381 : : }
10651 scrappy@hub.org 382 :CBC 137849 : }
383 : :
384 : : /* ----------------------------------------------------------------
385 : : * cancel_before_shmem_exit
386 : : *
387 : : * this function removes a previously-registered before_shmem_exit
388 : : * callback. We only look at the latest entry for removal, as we
389 : : * expect callers to add and remove temporary before_shmem_exit
390 : : * callbacks in strict LIFO order.
391 : : * ----------------------------------------------------------------
392 : : */
393 : : void
4280 rhaas@postgresql.org 394 : 2244 : cancel_before_shmem_exit(pg_on_exit_callback function, Datum arg)
395 : : {
396 [ + - ]: 2244 : if (before_shmem_exit_index > 0 &&
397 [ + - ]: 2244 : before_shmem_exit_list[before_shmem_exit_index - 1].function
4141 bruce@momjian.us 398 : 2244 : == function &&
4280 rhaas@postgresql.org 399 [ + - ]: 2244 : before_shmem_exit_list[before_shmem_exit_index - 1].arg == arg)
400 : 2244 : --before_shmem_exit_index;
401 : : else
24 tgl@sss.pgh.pa.us 402 [ # # ]:UNC 0 : elog(ERROR, "before_shmem_exit callback (%p,0x%" PRIx64 ") is not the latest entry",
403 : : function, arg);
6352 tgl@sss.pgh.pa.us 404 :CBC 2244 : }
405 : :
406 : : /* ----------------------------------------------------------------
407 : : * on_exit_reset
408 : : *
409 : : * this function clears all on_proc_exit() and on_shmem_exit()
410 : : * registered functions. This is used just after forking a backend,
411 : : * so that the backend doesn't believe it should call the postmaster's
412 : : * on-exit routines when it exits...
413 : : * ----------------------------------------------------------------
414 : : */
415 : : void
9933 bruce@momjian.us 416 : 18974 : on_exit_reset(void)
417 : : {
4280 rhaas@postgresql.org 418 : 18974 : before_shmem_exit_index = 0;
9933 bruce@momjian.us 419 : 18974 : on_shmem_exit_index = 0;
420 : 18974 : on_proc_exit_index = 0;
4198 rhaas@postgresql.org 421 : 18974 : reset_on_dsm_detach();
9962 bruce@momjian.us 422 : 18974 : }
423 : :
424 : : /* ----------------------------------------------------------------
425 : : * check_on_shmem_exit_lists_are_empty
426 : : *
427 : : * Debugging check that no shmem cleanup handlers have been registered
428 : : * prematurely in the current process.
429 : : * ----------------------------------------------------------------
430 : : */
431 : : void
1821 tgl@sss.pgh.pa.us 432 : 12094 : check_on_shmem_exit_lists_are_empty(void)
433 : : {
434 [ - + ]: 12094 : if (before_shmem_exit_index)
1821 tgl@sss.pgh.pa.us 435 [ # # ]:UBC 0 : elog(FATAL, "before_shmem_exit has been called prematurely");
1821 tgl@sss.pgh.pa.us 436 [ - + ]:CBC 12094 : if (on_shmem_exit_index)
1821 tgl@sss.pgh.pa.us 437 [ # # ]:UBC 0 : elog(FATAL, "on_shmem_exit has been called prematurely");
438 : : /* Checking DSM detach state seems unnecessary given the above */
1821 tgl@sss.pgh.pa.us 439 :CBC 12094 : }
|