LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - ipc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 76 87 87.4 %
Date: 2024-11-21 08:14:44 Functions: 10 10 100.0 %
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-2024, 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
     104       37672 : proc_exit(int code)
     105             : {
     106             :     /* not safe if forked by system(), etc. */
     107       37672 :     if (MyProcPid != (int) getpid())
     108           0 :         elog(PANIC, "proc_exit() called in child process");
     109             : 
     110             :     /* Clean up everything that must be cleaned up */
     111       37672 :     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       37672 :     elog(DEBUG3, "exit(%d)", code);
     155             : 
     156       37672 :     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
     165       75286 : 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       75286 :     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       75286 :     InterruptPending = false;
     179       75286 :     ProcDiePending = false;
     180       75286 :     QueryCancelPending = false;
     181       75286 :     InterruptHoldoffCount = 1;
     182       75286 :     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             :      */
     193       75286 :     error_context_stack = NULL;
     194             :     /* For the same reason, reset debug_query_string before it's clobbered */
     195       75286 :     debug_query_string = NULL;
     196             : 
     197             :     /* do our shared memory exits first */
     198       75286 :     shmem_exit(code);
     199             : 
     200       75286 :     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             :      */
     212      140102 :     while (--on_proc_exit_index >= 0)
     213       64816 :         on_proc_exit_list[on_proc_exit_index].function(code,
     214             :                                                        on_proc_exit_list[on_proc_exit_index].arg);
     215             : 
     216       75286 :     on_proc_exit_index = 0;
     217       75286 : }
     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
     228       75296 : shmem_exit(int code)
     229             : {
     230       75296 :     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             :      */
     240       75296 :     elog(DEBUG3, "shmem_exit(%d): %d before_shmem_exit callbacks to make",
     241             :          code, before_shmem_exit_index);
     242      224768 :     while (--before_shmem_exit_index >= 0)
     243      149472 :         before_shmem_exit_list[before_shmem_exit_index].function(code,
     244             :                                                                  before_shmem_exit_list[before_shmem_exit_index].arg);
     245       75296 :     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       75296 :     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       75296 :     elog(DEBUG3, "shmem_exit(%d): %d on_shmem_exit callbacks to make",
     274             :          code, on_shmem_exit_index);
     275      337224 :     while (--on_shmem_exit_index >= 0)
     276      261928 :         on_shmem_exit_list[on_shmem_exit_index].function(code,
     277             :                                                          on_shmem_exit_list[on_shmem_exit_index].arg);
     278       75296 :     on_shmem_exit_index = 0;
     279             : 
     280       75296 :     shmem_exit_inprogress = false;
     281       75296 : }
     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
     294       37614 : 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       37614 :     proc_exit_prepare(-1);
     299       37614 : }
     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
     309       64828 : on_proc_exit(pg_on_exit_callback function, Datum arg)
     310             : {
     311       64828 :     if (on_proc_exit_index >= MAX_ON_EXITS)
     312           0 :         ereport(FATAL,
     313             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     314             :                  errmsg_internal("out of on_proc_exit slots")));
     315             : 
     316       64828 :     on_proc_exit_list[on_proc_exit_index].function = function;
     317       64828 :     on_proc_exit_list[on_proc_exit_index].arg = arg;
     318             : 
     319       64828 :     ++on_proc_exit_index;
     320             : 
     321       64828 :     if (!atexit_callback_setup)
     322             :     {
     323        1908 :         atexit(atexit_callback);
     324        1908 :         atexit_callback_setup = true;
     325             :     }
     326       64828 : }
     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
     337      153206 : before_shmem_exit(pg_on_exit_callback function, Datum arg)
     338             : {
     339      153206 :     if (before_shmem_exit_index >= MAX_ON_EXITS)
     340           0 :         ereport(FATAL,
     341             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     342             :                  errmsg_internal("out of before_shmem_exit slots")));
     343             : 
     344      153206 :     before_shmem_exit_list[before_shmem_exit_index].function = function;
     345      153206 :     before_shmem_exit_list[before_shmem_exit_index].arg = arg;
     346             : 
     347      153206 :     ++before_shmem_exit_index;
     348             : 
     349      153206 :     if (!atexit_callback_setup)
     350             :     {
     351           0 :         atexit(atexit_callback);
     352           0 :         atexit_callback_setup = true;
     353             :     }
     354      153206 : }
     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
     365      261958 : on_shmem_exit(pg_on_exit_callback function, Datum arg)
     366             : {
     367      261958 :     if (on_shmem_exit_index >= MAX_ON_EXITS)
     368           0 :         ereport(FATAL,
     369             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     370             :                  errmsg_internal("out of on_shmem_exit slots")));
     371             : 
     372      261958 :     on_shmem_exit_list[on_shmem_exit_index].function = function;
     373      261958 :     on_shmem_exit_list[on_shmem_exit_index].arg = arg;
     374             : 
     375      261958 :     ++on_shmem_exit_index;
     376             : 
     377      261958 :     if (!atexit_callback_setup)
     378             :     {
     379           0 :         atexit(atexit_callback);
     380           0 :         atexit_callback_setup = true;
     381             :     }
     382      261958 : }
     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
     394        3734 : cancel_before_shmem_exit(pg_on_exit_callback function, Datum arg)
     395             : {
     396        3734 :     if (before_shmem_exit_index > 0 &&
     397        3734 :         before_shmem_exit_list[before_shmem_exit_index - 1].function
     398        3734 :         == function &&
     399        3734 :         before_shmem_exit_list[before_shmem_exit_index - 1].arg == arg)
     400        3734 :         --before_shmem_exit_index;
     401             :     else
     402           0 :         elog(ERROR, "before_shmem_exit callback (%p,0x%llx) is not the latest entry",
     403             :              function, (long long) arg);
     404        3734 : }
     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
     416       35712 : on_exit_reset(void)
     417             : {
     418       35712 :     before_shmem_exit_index = 0;
     419       35712 :     on_shmem_exit_index = 0;
     420       35712 :     on_proc_exit_index = 0;
     421       35712 :     reset_on_dsm_detach();
     422       35712 : }
     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
     432       25028 : check_on_shmem_exit_lists_are_empty(void)
     433             : {
     434       25028 :     if (before_shmem_exit_index)
     435           0 :         elog(FATAL, "before_shmem_exit has been called prematurely");
     436       25028 :     if (on_shmem_exit_index)
     437           0 :         elog(FATAL, "on_shmem_exit has been called prematurely");
     438             :     /* Checking DSM detach state seems unnecessary given the above */
     439       25028 : }

Generated by: LCOV version 1.14