Coverage Report

Created: 2026-11-09 07:20

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