LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - pmsignal.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 75 84 89.3 %
Date: 2021-12-04 22:09:09 Functions: 14 15 93.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14