LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - ipc.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 87.5 % 88 77
Test Date: 2026-03-03 14:15:12 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit

            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-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              : #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        24303 : proc_exit(int code)
     106              : {
     107              :     /* not safe if forked by system(), etc. */
     108        24303 :     if (MyProcPid != (int) getpid())
     109            0 :         elog(PANIC, "proc_exit() called in child process");
     110              : 
     111              :     /* Clean up everything that must be cleaned up */
     112        24303 :     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        24303 :     elog(DEBUG3, "exit(%d)", code);
     156              : 
     157        24303 :     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        48572 : proc_exit_prepare(int code)
     167              : {
     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        48572 :     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        48572 :     InterruptPending = false;
     180        48572 :     ProcDiePending = false;
     181        48572 :     QueryCancelPending = false;
     182        48572 :     InterruptHoldoffCount = 1;
     183        48572 :     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        48572 :     error_context_stack = NULL;
     195              :     /* For the same reason, reset debug_query_string before it's clobbered */
     196        48572 :     debug_query_string = NULL;
     197              : 
     198              :     /* do our shared memory exits first */
     199        48572 :     shmem_exit(code);
     200              : 
     201        48572 :     elog(DEBUG3, "proc_exit(%d): %d callbacks to make",
     202              :          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        87771 :     while (--on_proc_exit_index >= 0)
     214        39199 :         on_proc_exit_list[on_proc_exit_index].function(code,
     215              :                                                        on_proc_exit_list[on_proc_exit_index].arg);
     216              : 
     217        48572 :     on_proc_exit_index = 0;
     218        48572 : }
     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        48577 : shmem_exit(int code)
     230              : {
     231        48577 :     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        48577 :     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        48577 :     elog(DEBUG3, "shmem_exit(%d): %d before_shmem_exit callbacks to make",
     248              :          code, before_shmem_exit_index);
     249       166066 :     while (--before_shmem_exit_index >= 0)
     250       117489 :         before_shmem_exit_list[before_shmem_exit_index].function(code,
     251              :                                                                  before_shmem_exit_list[before_shmem_exit_index].arg);
     252        48577 :     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        48577 :     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        48577 :     elog(DEBUG3, "shmem_exit(%d): %d on_shmem_exit callbacks to make",
     281              :          code, on_shmem_exit_index);
     282       217964 :     while (--on_shmem_exit_index >= 0)
     283       169387 :         on_shmem_exit_list[on_shmem_exit_index].function(code,
     284              :                                                          on_shmem_exit_list[on_shmem_exit_index].arg);
     285        48577 :     on_shmem_exit_index = 0;
     286              : 
     287        48577 :     shmem_exit_inprogress = false;
     288        48577 : }
     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        24269 : atexit_callback(void)
     302              : {
     303              :     /* Clean up everything that must be cleaned up */
     304              :     /* ... too bad we don't know the real exit code ... */
     305        24269 :     proc_exit_prepare(-1);
     306        24269 : }
     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        39199 : on_proc_exit(pg_on_exit_callback function, Datum arg)
     317              : {
     318        39199 :     if (on_proc_exit_index >= MAX_ON_EXITS)
     319            0 :         ereport(FATAL,
     320              :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     321              :                  errmsg_internal("out of on_proc_exit slots")));
     322              : 
     323        39199 :     on_proc_exit_list[on_proc_exit_index].function = function;
     324        39199 :     on_proc_exit_list[on_proc_exit_index].arg = arg;
     325              : 
     326        39199 :     ++on_proc_exit_index;
     327              : 
     328        39199 :     if (!atexit_callback_setup)
     329              :     {
     330         1154 :         atexit(atexit_callback);
     331         1154 :         atexit_callback_setup = true;
     332              :     }
     333        39199 : }
     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       119730 : before_shmem_exit(pg_on_exit_callback function, Datum arg)
     345              : {
     346       119730 :     if (before_shmem_exit_index >= MAX_ON_EXITS)
     347            0 :         ereport(FATAL,
     348              :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     349              :                  errmsg_internal("out of before_shmem_exit slots")));
     350              : 
     351       119730 :     before_shmem_exit_list[before_shmem_exit_index].function = function;
     352       119730 :     before_shmem_exit_list[before_shmem_exit_index].arg = arg;
     353              : 
     354       119730 :     ++before_shmem_exit_index;
     355              : 
     356       119730 :     if (!atexit_callback_setup)
     357              :     {
     358            0 :         atexit(atexit_callback);
     359            0 :         atexit_callback_setup = true;
     360              :     }
     361       119730 : }
     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       169387 : on_shmem_exit(pg_on_exit_callback function, Datum arg)
     373              : {
     374       169387 :     if (on_shmem_exit_index >= MAX_ON_EXITS)
     375            0 :         ereport(FATAL,
     376              :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     377              :                  errmsg_internal("out of on_shmem_exit slots")));
     378              : 
     379       169387 :     on_shmem_exit_list[on_shmem_exit_index].function = function;
     380       169387 :     on_shmem_exit_list[on_shmem_exit_index].arg = arg;
     381              : 
     382       169387 :     ++on_shmem_exit_index;
     383              : 
     384       169387 :     if (!atexit_callback_setup)
     385              :     {
     386            0 :         atexit(atexit_callback);
     387            0 :         atexit_callback_setup = true;
     388              :     }
     389       169387 : }
     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         2241 : cancel_before_shmem_exit(pg_on_exit_callback function, Datum arg)
     402              : {
     403         2241 :     if (before_shmem_exit_index > 0 &&
     404         2241 :         before_shmem_exit_list[before_shmem_exit_index - 1].function
     405         2241 :         == function &&
     406         2241 :         before_shmem_exit_list[before_shmem_exit_index - 1].arg == arg)
     407         2241 :         --before_shmem_exit_index;
     408              :     else
     409            0 :         elog(ERROR, "before_shmem_exit callback (%p,0x%" PRIx64 ") is not the latest entry",
     410              :              function, arg);
     411         2241 : }
     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        23115 : on_exit_reset(void)
     424              : {
     425        23115 :     before_shmem_exit_index = 0;
     426        23115 :     on_shmem_exit_index = 0;
     427        23115 :     on_proc_exit_index = 0;
     428        23115 :     reset_on_dsm_detach();
     429        23115 : }
     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        13788 : check_on_shmem_exit_lists_are_empty(void)
     440              : {
     441        13788 :     if (before_shmem_exit_index)
     442            0 :         elog(FATAL, "before_shmem_exit has been called prematurely");
     443        13788 :     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        13788 : }
        

Generated by: LCOV version 2.0-1