LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - ipc.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 86.2 % 94 81
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 37.1 % 70 26

             Branch data     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                 :         810 : proc_exit(int code)
     106                 :             : {
     107                 :             :         /* not safe if forked by system(), etc. */
     108         [ +  - ]:         810 :         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                 :         810 :         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   [ -  +  +  + ]:         810 :         elog(DEBUG3, "exit(%d)", code);
     156                 :             : 
     157                 :         810 :         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                 :        1620 : 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                 :        1620 :         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                 :        1620 :         InterruptPending = false;
     180                 :        1620 :         ProcDiePending = false;
     181                 :        1620 :         QueryCancelPending = false;
     182                 :        1620 :         InterruptHoldoffCount = 1;
     183                 :        1620 :         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                 :        1620 :         error_context_stack = NULL;
     195                 :             :         /* For the same reason, reset debug_query_string before it's clobbered */
     196                 :        1620 :         debug_query_string = NULL;
     197                 :             : 
     198                 :             :         /* do our shared memory exits first */
     199                 :        1620 :         shmem_exit(code);
     200                 :             : 
     201   [ -  +  -  + ]:        1620 :         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         [ +  + ]:        2749 :         while (--on_proc_exit_index >= 0)
     214                 :        2258 :                 on_proc_exit_list[on_proc_exit_index].function(code,
     215                 :        1129 :                                                                                                            on_proc_exit_list[on_proc_exit_index].arg);
     216                 :             : 
     217                 :        1620 :         on_proc_exit_index = 0;
     218                 :        1620 : }
     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                 :        1620 : shmem_exit(int code)
     230                 :             : {
     231                 :        1620 :         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                 :        1620 :         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   [ -  +  -  + ]:        1620 :         elog(DEBUG3, "shmem_exit(%d): %d before_shmem_exit callbacks to make",
     248                 :             :                  code, before_shmem_exit_index);
     249         [ +  + ]:        6226 :         while (--before_shmem_exit_index >= 0)
     250                 :        9212 :                 before_shmem_exit_list[before_shmem_exit_index].function(code,
     251                 :        4606 :                                                                                                                                  before_shmem_exit_list[before_shmem_exit_index].arg);
     252                 :        1620 :         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                 :        1620 :         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   [ -  +  -  + ]:        1620 :         elog(DEBUG3, "shmem_exit(%d): %d on_shmem_exit callbacks to make",
     281                 :             :                  code, on_shmem_exit_index);
     282         [ +  + ]:        7290 :         while (--on_shmem_exit_index >= 0)
     283                 :       11340 :                 on_shmem_exit_list[on_shmem_exit_index].function(code,
     284                 :        5670 :                                                                                                                  on_shmem_exit_list[on_shmem_exit_index].arg);
     285                 :        1620 :         on_shmem_exit_index = 0;
     286                 :             : 
     287                 :        1620 :         shmem_exit_inprogress = false;
     288                 :        1620 : }
     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                 :         810 : 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                 :         810 :         proc_exit_prepare(-1);
     306                 :         810 : }
     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                 :        1129 : on_proc_exit(pg_on_exit_callback function, Datum arg)
     317                 :             : {
     318         [ +  - ]:        1129 :         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                 :        1129 :         on_proc_exit_list[on_proc_exit_index].function = function;
     324                 :        1129 :         on_proc_exit_list[on_proc_exit_index].arg = arg;
     325                 :             : 
     326                 :        1129 :         ++on_proc_exit_index;
     327                 :             : 
     328         [ +  + ]:        1129 :         if (!atexit_callback_setup)
     329                 :             :         {
     330                 :           6 :                 atexit(atexit_callback);
     331                 :           6 :                 atexit_callback_setup = true;
     332                 :           6 :         }
     333                 :        1129 : }
     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                 :        4782 : before_shmem_exit(pg_on_exit_callback function, Datum arg)
     345                 :             : {
     346         [ +  - ]:        4782 :         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                 :        4782 :         before_shmem_exit_list[before_shmem_exit_index].function = function;
     352                 :        4782 :         before_shmem_exit_list[before_shmem_exit_index].arg = arg;
     353                 :             : 
     354                 :        4782 :         ++before_shmem_exit_index;
     355                 :             : 
     356         [ +  - ]:        4782 :         if (!atexit_callback_setup)
     357                 :             :         {
     358                 :           0 :                 atexit(atexit_callback);
     359                 :           0 :                 atexit_callback_setup = true;
     360                 :           0 :         }
     361                 :        4782 : }
     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                 :        5670 : on_shmem_exit(pg_on_exit_callback function, Datum arg)
     373                 :             : {
     374         [ +  - ]:        5670 :         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                 :        5670 :         on_shmem_exit_list[on_shmem_exit_index].function = function;
     380                 :        5670 :         on_shmem_exit_list[on_shmem_exit_index].arg = arg;
     381                 :             : 
     382                 :        5670 :         ++on_shmem_exit_index;
     383                 :             : 
     384         [ +  - ]:        5670 :         if (!atexit_callback_setup)
     385                 :             :         {
     386                 :           0 :                 atexit(atexit_callback);
     387                 :           0 :                 atexit_callback_setup = true;
     388                 :           0 :         }
     389                 :        5670 : }
     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                 :         176 : cancel_before_shmem_exit(pg_on_exit_callback function, Datum arg)
     402                 :             : {
     403         [ +  - ]:         176 :         if (before_shmem_exit_index > 0 &&
     404                 :         176 :                 before_shmem_exit_list[before_shmem_exit_index - 1].function
     405                 :         176 :                 == function &&
     406                 :         176 :                 before_shmem_exit_list[before_shmem_exit_index - 1].arg == arg)
     407                 :         176 :                 --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                 :         176 : }
     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                 :         804 : on_exit_reset(void)
     424                 :             : {
     425                 :         804 :         before_shmem_exit_index = 0;
     426                 :         804 :         on_shmem_exit_index = 0;
     427                 :         804 :         on_proc_exit_index = 0;
     428                 :         804 :         reset_on_dsm_detach();
     429                 :         804 : }
     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                 :         315 : check_on_shmem_exit_lists_are_empty(void)
     440                 :             : {
     441         [ +  - ]:         315 :         if (before_shmem_exit_index)
     442   [ #  #  #  # ]:           0 :                 elog(FATAL, "before_shmem_exit has been called prematurely");
     443         [ +  - ]:         315 :         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                 :         315 : }
        

Generated by: LCOV version 2.3.2-1