LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - pmsignal.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 88.5 % 78 69
Test Date: 2026-07-22 20:15:44 Functions: 93.3 % 15 14
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 37.5 % 32 12

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * pmsignal.c
       4                 :             :  *    routines for signaling between the postmaster and its child processes
       5                 :             :  *
       6                 :             :  *
       7                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *    src/backend/storage/ipc/pmsignal.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include <signal.h>
      18                 :             : #include <unistd.h>
      19                 :             : 
      20                 :             : #ifdef HAVE_SYS_PRCTL_H
      21                 :             : #include <sys/prctl.h>
      22                 :             : #endif
      23                 :             : 
      24                 :             : #include "miscadmin.h"
      25                 :             : #include "postmaster/postmaster.h"
      26                 :             : #include "replication/walsender.h"
      27                 :             : #include "storage/ipc.h"
      28                 :             : #include "storage/pmsignal.h"
      29                 :             : #include "storage/shmem.h"
      30                 :             : #include "storage/subsystems.h"
      31                 :             : #include "utils/memutils.h"
      32                 :             : 
      33                 :             : 
      34                 :             : /*
      35                 :             :  * The postmaster is signaled by its children by sending SIGUSR1.  The
      36                 :             :  * specific reason is communicated via flags in shared memory.  We keep
      37                 :             :  * a boolean flag for each possible "reason", so that different reasons
      38                 :             :  * can be signaled by different backends at the same time.  (However,
      39                 :             :  * if the same reason is signaled more than once simultaneously, the
      40                 :             :  * postmaster will observe it only once.)
      41                 :             :  *
      42                 :             :  * The flags are actually declared as "volatile sig_atomic_t" for maximum
      43                 :             :  * portability.  This should ensure that loads and stores of the flag
      44                 :             :  * values are atomic, allowing us to dispense with any explicit locking.
      45                 :             :  *
      46                 :             :  * In addition to the per-reason flags, we store a set of per-child-process
      47                 :             :  * flags that are currently used only for detecting whether a backend has
      48                 :             :  * exited without performing proper shutdown.  The per-child-process flags
      49                 :             :  * have three possible states: UNUSED, ASSIGNED, ACTIVE.  An UNUSED slot is
      50                 :             :  * available for assignment.  An ASSIGNED slot is associated with a postmaster
      51                 :             :  * child process, but either the process has not touched shared memory yet, or
      52                 :             :  * it has successfully cleaned up after itself.  An ACTIVE slot means the
      53                 :             :  * process is actively using shared memory.  The slots are assigned to child
      54                 :             :  * processes by postmaster, and pmchild.c is responsible for tracking which
      55                 :             :  * one goes with which PID.
      56                 :             :  *
      57                 :             :  * Actually there is a fourth state, WALSENDER.  This is just like ACTIVE,
      58                 :             :  * but carries the extra information that the child is a WAL sender.
      59                 :             :  * WAL senders too start in ACTIVE state, but switch to WALSENDER once they
      60                 :             :  * start streaming the WAL (and they never go back to ACTIVE after that).
      61                 :             :  *
      62                 :             :  * We also have a shared-memory field that is used for communication in
      63                 :             :  * the opposite direction, from postmaster to children: it tells why the
      64                 :             :  * postmaster has broadcasted SIGQUIT signals, if indeed it has done so.
      65                 :             :  */
      66                 :             : 
      67                 :             : #define PM_CHILD_UNUSED     0   /* these values must fit in sig_atomic_t */
      68                 :             : #define PM_CHILD_ASSIGNED   1
      69                 :             : #define PM_CHILD_ACTIVE     2
      70                 :             : #define PM_CHILD_WALSENDER  3
      71                 :             : 
      72                 :             : /* "typedef struct PMSignalData PMSignalData" appears in pmsignal.h */
      73                 :             : struct PMSignalData
      74                 :             : {
      75                 :             :     /* per-reason flags for signaling the postmaster */
      76                 :             :     sig_atomic_t PMSignalFlags[NUM_PMSIGNALS];
      77                 :             :     /* global flags for signals from postmaster to children */
      78                 :             :     QuitSignalReason sigquit_reason;    /* why SIGQUIT was sent */
      79                 :             :     /* per-child-process flags */
      80                 :             :     int         num_child_flags;    /* # of entries in PMChildFlags[] */
      81                 :             :     sig_atomic_t PMChildFlags[FLEXIBLE_ARRAY_MEMBER];
      82                 :             : };
      83                 :             : 
      84                 :             : /* PMSignalState pointer is valid in both postmaster and child processes */
      85                 :             : NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL;
      86                 :             : 
      87                 :             : static void PMSignalShmemRequest(void *);
      88                 :             : static void PMSignalShmemInit(void *);
      89                 :             : 
      90                 :             : const ShmemCallbacks PMSignalShmemCallbacks = {
      91                 :             :     .request_fn = PMSignalShmemRequest,
      92                 :             :     .init_fn = PMSignalShmemInit,
      93                 :             : };
      94                 :             : 
      95                 :             : /*
      96                 :             :  * Local copy of PMSignalState->num_child_flags, only valid in the
      97                 :             :  * postmaster.  Postmaster keeps a local copy so that it doesn't need to
      98                 :             :  * trust the value in shared memory.
      99                 :             :  */
     100                 :             : static int  num_child_flags;
     101                 :             : 
     102                 :             : /*
     103                 :             :  * Signal handler to be notified if postmaster dies.
     104                 :             :  */
     105                 :             : #ifdef USE_POSTMASTER_DEATH_SIGNAL
     106                 :             : volatile sig_atomic_t postmaster_possibly_dead = false;
     107                 :             : 
     108                 :             : static void
     109                 :          22 : postmaster_death_handler(SIGNAL_ARGS)
     110                 :             : {
     111                 :          22 :     postmaster_possibly_dead = true;
     112                 :          22 : }
     113                 :             : 
     114                 :             : /*
     115                 :             :  * The available signals depend on the OS.  SIGUSR1 and SIGUSR2 are already
     116                 :             :  * used for other things, so choose another one.
     117                 :             :  *
     118                 :             :  * Currently, we assume that we can always find a signal to use.  That
     119                 :             :  * seems like a reasonable assumption for all platforms that are modern
     120                 :             :  * enough to have a parent-death signaling mechanism.
     121                 :             :  */
     122                 :             : #if defined(SIGINFO)
     123                 :             : #define POSTMASTER_DEATH_SIGNAL SIGINFO
     124                 :             : #elif defined(SIGPWR)
     125                 :             : #define POSTMASTER_DEATH_SIGNAL SIGPWR
     126                 :             : #else
     127                 :             : #error "cannot find a signal to use for postmaster death"
     128                 :             : #endif
     129                 :             : 
     130                 :             : #endif                          /* USE_POSTMASTER_DEATH_SIGNAL */
     131                 :             : 
     132                 :             : static void MarkPostmasterChildInactive(int code, Datum arg);
     133                 :             : 
     134                 :             : /*
     135                 :             :  * PMSignalShmemRequest - Register pmsignal.c's shared memory needs
     136                 :             :  */
     137                 :             : static void
     138                 :        1259 : PMSignalShmemRequest(void *arg)
     139                 :             : {
     140                 :             :     size_t      size;
     141                 :             : 
     142                 :        1259 :     num_child_flags = MaxLivePostmasterChildren();
     143                 :             : 
     144                 :        1259 :     size = add_size(offsetof(PMSignalData, PMChildFlags),
     145                 :             :                     mul_size(num_child_flags, sizeof(sig_atomic_t)));
     146                 :        1259 :     ShmemRequestStruct(.name = "PMSignalState",
     147                 :             :                        .size = size,
     148                 :             :                        .ptr = (void **) &PMSignalState,
     149                 :             :         );
     150                 :        1259 : }
     151                 :             : 
     152                 :             : static void
     153                 :        1256 : PMSignalShmemInit(void *arg)
     154                 :             : {
     155                 :             :     Assert(PMSignalState);
     156                 :             :     Assert(num_child_flags > 0);
     157                 :        1256 :     PMSignalState->num_child_flags = num_child_flags;
     158                 :        1256 : }
     159                 :             : 
     160                 :             : /*
     161                 :             :  * SendPostmasterSignal - signal the postmaster from a child process
     162                 :             :  */
     163                 :             : void
     164                 :      118516 : SendPostmasterSignal(PMSignalReason reason)
     165                 :             : {
     166                 :             :     /* If called in a standalone backend, do nothing */
     167         [ -  + ]:      118516 :     if (!IsUnderPostmaster)
     168                 :           0 :         return;
     169                 :             :     /* Atomically set the proper flag */
     170                 :      118516 :     PMSignalState->PMSignalFlags[reason] = true;
     171                 :             :     /* Send signal to postmaster */
     172                 :      118516 :     kill(PostmasterPid, SIGUSR1);
     173                 :             : }
     174                 :             : 
     175                 :             : /*
     176                 :             :  * CheckPostmasterSignal - check to see if a particular reason has been
     177                 :             :  * signaled, and clear the signal flag.  Should be called by postmaster
     178                 :             :  * after receiving SIGUSR1.
     179                 :             :  */
     180                 :             : bool
     181                 :     1160171 : CheckPostmasterSignal(PMSignalReason reason)
     182                 :             : {
     183                 :             :     /* Careful here --- don't clear flag if we haven't seen it set */
     184         [ +  + ]:     1160171 :     if (PMSignalState->PMSignalFlags[reason])
     185                 :             :     {
     186                 :      116666 :         PMSignalState->PMSignalFlags[reason] = false;
     187                 :      116666 :         return true;
     188                 :             :     }
     189                 :     1043505 :     return false;
     190                 :             : }
     191                 :             : 
     192                 :             : /*
     193                 :             :  * SetQuitSignalReason - broadcast the reason for a system shutdown.
     194                 :             :  * Should be called by postmaster before sending SIGQUIT to children.
     195                 :             :  *
     196                 :             :  * Note: in a crash-and-restart scenario, the "reason" field gets cleared
     197                 :             :  * as a part of rebuilding shared memory; the postmaster need not do it
     198                 :             :  * explicitly.
     199                 :             :  */
     200                 :             : void
     201                 :         370 : SetQuitSignalReason(QuitSignalReason reason)
     202                 :             : {
     203                 :         370 :     PMSignalState->sigquit_reason = reason;
     204                 :         370 : }
     205                 :             : 
     206                 :             : /*
     207                 :             :  * GetQuitSignalReason - obtain the reason for a system shutdown.
     208                 :             :  * Called by child processes when they receive SIGQUIT.
     209                 :             :  * If the postmaster hasn't actually sent SIGQUIT, will return PMQUIT_NOT_SENT.
     210                 :             :  */
     211                 :             : QuitSignalReason
     212                 :           0 : GetQuitSignalReason(void)
     213                 :             : {
     214                 :             :     /* This is called in signal handlers, so be extra paranoid. */
     215   [ #  #  #  # ]:           0 :     if (!IsUnderPostmaster || PMSignalState == NULL)
     216                 :           0 :         return PMQUIT_NOT_SENT;
     217                 :           0 :     return PMSignalState->sigquit_reason;
     218                 :             : }
     219                 :             : 
     220                 :             : 
     221                 :             : /*
     222                 :             :  * MarkPostmasterChildSlotAssigned - mark the given slot as ASSIGNED for a
     223                 :             :  * new postmaster child process.
     224                 :             :  *
     225                 :             :  * Only the postmaster is allowed to execute this routine, so we need no
     226                 :             :  * special locking.
     227                 :             :  */
     228                 :             : void
     229                 :       27419 : MarkPostmasterChildSlotAssigned(int slot)
     230                 :             : {
     231                 :             :     Assert(slot > 0 && slot <= num_child_flags);
     232                 :       27419 :     slot--;
     233                 :             : 
     234         [ -  + ]:       27419 :     if (PMSignalState->PMChildFlags[slot] != PM_CHILD_UNUSED)
     235         [ #  # ]:           0 :         elog(FATAL, "postmaster child slot is already in use");
     236                 :             : 
     237                 :       27419 :     PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED;
     238                 :       27419 : }
     239                 :             : 
     240                 :             : /*
     241                 :             :  * MarkPostmasterChildSlotUnassigned - release a slot after death of a
     242                 :             :  * postmaster child process.  This must be called in the postmaster process.
     243                 :             :  *
     244                 :             :  * Returns true if the slot had been in ASSIGNED state (the expected case),
     245                 :             :  * false otherwise (implying that the child failed to clean itself up).
     246                 :             :  */
     247                 :             : bool
     248                 :       27418 : MarkPostmasterChildSlotUnassigned(int slot)
     249                 :             : {
     250                 :             :     bool        result;
     251                 :             : 
     252                 :             :     Assert(slot > 0 && slot <= num_child_flags);
     253                 :       27418 :     slot--;
     254                 :             : 
     255                 :             :     /*
     256                 :             :      * Note: the slot state might already be unused, because the logic in
     257                 :             :      * postmaster.c is such that this might get called twice when a child
     258                 :             :      * crashes.  So we don't try to Assert anything about the state.
     259                 :             :      */
     260                 :       27418 :     result = (PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED);
     261                 :       27418 :     PMSignalState->PMChildFlags[slot] = PM_CHILD_UNUSED;
     262                 :       27418 :     return result;
     263                 :             : }
     264                 :             : 
     265                 :             : /*
     266                 :             :  * IsPostmasterChildWalSender - check if given slot is in use by a
     267                 :             :  * walsender process.  This is called only by the postmaster.
     268                 :             :  */
     269                 :             : bool
     270                 :        1528 : IsPostmasterChildWalSender(int slot)
     271                 :             : {
     272                 :             :     Assert(slot > 0 && slot <= num_child_flags);
     273                 :        1528 :     slot--;
     274                 :             : 
     275         [ +  + ]:        1528 :     if (PMSignalState->PMChildFlags[slot] == PM_CHILD_WALSENDER)
     276                 :          48 :         return true;
     277                 :             :     else
     278                 :        1480 :         return false;
     279                 :             : }
     280                 :             : 
     281                 :             : /*
     282                 :             :  * RegisterPostmasterChildActive - mark a postmaster child as about to begin
     283                 :             :  * actively using shared memory.  This is called in the child process.
     284                 :             :  *
     285                 :             :  * This register an shmem exit hook to mark us as inactive again when the
     286                 :             :  * process exits normally.
     287                 :             :  */
     288                 :             : void
     289                 :       24708 : RegisterPostmasterChildActive(void)
     290                 :             : {
     291                 :       24708 :     int         slot = MyPMChildSlot;
     292                 :             : 
     293                 :             :     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
     294                 :       24708 :     slot--;
     295                 :             :     Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED);
     296                 :       24708 :     PMSignalState->PMChildFlags[slot] = PM_CHILD_ACTIVE;
     297                 :             : 
     298                 :             :     /* Arrange to clean up at exit. */
     299                 :       24708 :     on_shmem_exit(MarkPostmasterChildInactive, 0);
     300                 :       24708 : }
     301                 :             : 
     302                 :             : /*
     303                 :             :  * MarkPostmasterChildWalSender - mark a postmaster child as a WAL sender
     304                 :             :  * process.  This is called in the child process, sometime after marking the
     305                 :             :  * child as active.
     306                 :             :  */
     307                 :             : void
     308                 :        1331 : MarkPostmasterChildWalSender(void)
     309                 :             : {
     310                 :        1331 :     int         slot = MyPMChildSlot;
     311                 :             : 
     312                 :             :     Assert(am_walsender);
     313                 :             : 
     314                 :             :     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
     315                 :        1331 :     slot--;
     316                 :             :     Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ACTIVE);
     317                 :        1331 :     PMSignalState->PMChildFlags[slot] = PM_CHILD_WALSENDER;
     318                 :        1331 : }
     319                 :             : 
     320                 :             : /*
     321                 :             :  * MarkPostmasterChildInactive - mark a postmaster child as done using
     322                 :             :  * shared memory.  This is called in the child process.
     323                 :             :  */
     324                 :             : static void
     325                 :       24708 : MarkPostmasterChildInactive(int code, Datum arg)
     326                 :             : {
     327                 :       24708 :     int         slot = MyPMChildSlot;
     328                 :             : 
     329                 :             :     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
     330                 :       24708 :     slot--;
     331                 :             :     Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ACTIVE ||
     332                 :             :            PMSignalState->PMChildFlags[slot] == PM_CHILD_WALSENDER);
     333                 :       24708 :     PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED;
     334                 :       24708 : }
     335                 :             : 
     336                 :             : 
     337                 :             : /*
     338                 :             :  * PostmasterIsAliveInternal - check whether postmaster process is still alive
     339                 :             :  *
     340                 :             :  * This is the slow path of PostmasterIsAlive(), where the caller has already
     341                 :             :  * checked 'postmaster_possibly_dead'.  (On platforms that don't support
     342                 :             :  * a signal for parent death, PostmasterIsAlive() is just an alias for this.)
     343                 :             :  */
     344                 :             : bool
     345                 :         715 : PostmasterIsAliveInternal(void)
     346                 :             : {
     347                 :             : #ifdef USE_POSTMASTER_DEATH_SIGNAL
     348                 :             :     /*
     349                 :             :      * Reset the flag before checking, so that we don't miss a signal if
     350                 :             :      * postmaster dies right after the check.  If postmaster was indeed dead,
     351                 :             :      * we'll re-arm it before returning to caller.
     352                 :             :      */
     353                 :         715 :     postmaster_possibly_dead = false;
     354                 :             : #endif
     355                 :             : 
     356                 :             : #ifndef WIN32
     357                 :             :     {
     358                 :             :         char        c;
     359                 :             :         ssize_t     rc;
     360                 :             : 
     361                 :         715 :         rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1);
     362                 :             : 
     363                 :             :         /*
     364                 :             :          * In the usual case, the postmaster is still alive, and there is no
     365                 :             :          * data in the pipe.
     366                 :             :          */
     367   [ +  +  -  +  :         715 :         if (rc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
                   -  - ]
     368                 :         694 :             return true;
     369                 :             :         else
     370                 :             :         {
     371                 :             :             /*
     372                 :             :              * Postmaster is dead, or something went wrong with the read()
     373                 :             :              * call.
     374                 :             :              */
     375                 :             : 
     376                 :             : #ifdef USE_POSTMASTER_DEATH_SIGNAL
     377                 :          21 :             postmaster_possibly_dead = true;
     378                 :             : #endif
     379                 :             : 
     380         [ -  + ]:          21 :             if (rc < 0)
     381         [ #  # ]:           0 :                 elog(FATAL, "read on postmaster death monitoring pipe failed: %m");
     382         [ -  + ]:          21 :             else if (rc > 0)
     383         [ #  # ]:           0 :                 elog(FATAL, "unexpected data in postmaster death monitoring pipe");
     384                 :             : 
     385                 :          21 :             return false;
     386                 :             :         }
     387                 :             :     }
     388                 :             : 
     389                 :             : #else                           /* WIN32 */
     390                 :             :     if (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT)
     391                 :             :         return true;
     392                 :             :     else
     393                 :             :     {
     394                 :             : #ifdef USE_POSTMASTER_DEATH_SIGNAL
     395                 :             :         postmaster_possibly_dead = true;
     396                 :             : #endif
     397                 :             :         return false;
     398                 :             :     }
     399                 :             : #endif                          /* WIN32 */
     400                 :             : }
     401                 :             : 
     402                 :             : /*
     403                 :             :  * PostmasterDeathSignalInit - request signal on postmaster death if possible
     404                 :             :  */
     405                 :             : void
     406                 :       25019 : PostmasterDeathSignalInit(void)
     407                 :             : {
     408                 :             : #ifdef USE_POSTMASTER_DEATH_SIGNAL
     409                 :       25019 :     int         signum = POSTMASTER_DEATH_SIGNAL;
     410                 :             : 
     411                 :             :     /* Register our signal handler. */
     412                 :       25019 :     pqsignal(signum, postmaster_death_handler);
     413                 :             : 
     414                 :             :     /* Request a signal on parent exit. */
     415                 :             : #if defined(PR_SET_PDEATHSIG)
     416         [ -  + ]:       25019 :     if (prctl(PR_SET_PDEATHSIG, signum) < 0)
     417         [ #  # ]:           0 :         elog(ERROR, "could not request parent death signal: %m");
     418                 :             : #elif defined(PROC_PDEATHSIG_CTL)
     419                 :             :     if (procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum) < 0)
     420                 :             :         elog(ERROR, "could not request parent death signal: %m");
     421                 :             : #else
     422                 :             : #error "USE_POSTMASTER_DEATH_SIGNAL set, but there is no mechanism to request the signal"
     423                 :             : #endif
     424                 :             : 
     425                 :             :     /*
     426                 :             :      * Just in case the parent was gone already and we missed it, we'd better
     427                 :             :      * check the slow way on the first call.
     428                 :             :      */
     429                 :       25019 :     postmaster_possibly_dead = true;
     430                 :             : #endif                          /* USE_POSTMASTER_DEATH_SIGNAL */
     431                 :       25019 : }
        

Generated by: LCOV version 2.0-1