LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - pmsignal.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 55 74 74.3 %
Date: 2017-09-29 15:12:54 Functions: 9 11 81.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pmsignal.c
       4             :  *    routines for signaling the postmaster from its child processes
       5             :  *
       6             :  *
       7             :  * Portions Copyright (c) 1996-2017, 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             : #include "miscadmin.h"
      21             : #include "postmaster/postmaster.h"
      22             : #include "replication/walsender.h"
      23             : #include "storage/pmsignal.h"
      24             : #include "storage/shmem.h"
      25             : 
      26             : 
      27             : /*
      28             :  * The postmaster is signaled by its children by sending SIGUSR1.  The
      29             :  * specific reason is communicated via flags in shared memory.  We keep
      30             :  * a boolean flag for each possible "reason", so that different reasons
      31             :  * can be signaled by different backends at the same time.  (However,
      32             :  * if the same reason is signaled more than once simultaneously, the
      33             :  * postmaster will observe it only once.)
      34             :  *
      35             :  * The flags are actually declared as "volatile sig_atomic_t" for maximum
      36             :  * portability.  This should ensure that loads and stores of the flag
      37             :  * values are atomic, allowing us to dispense with any explicit locking.
      38             :  *
      39             :  * In addition to the per-reason flags, we store a set of per-child-process
      40             :  * flags that are currently used only for detecting whether a backend has
      41             :  * exited without performing proper shutdown.  The per-child-process flags
      42             :  * have three possible states: UNUSED, ASSIGNED, ACTIVE.  An UNUSED slot is
      43             :  * available for assignment.  An ASSIGNED slot is associated with a postmaster
      44             :  * child process, but either the process has not touched shared memory yet,
      45             :  * or it has successfully cleaned up after itself.  A ACTIVE slot means the
      46             :  * process is actively using shared memory.  The slots are assigned to
      47             :  * child processes at random, and postmaster.c is responsible for tracking
      48             :  * which one goes with which PID.
      49             :  *
      50             :  * Actually there is a fourth state, WALSENDER.  This is just like ACTIVE,
      51             :  * but carries the extra information that the child is a WAL sender.
      52             :  * WAL senders too start in ACTIVE state, but switch to WALSENDER once they
      53             :  * start streaming the WAL (and they never go back to ACTIVE after that).
      54             :  */
      55             : 
      56             : #define PM_CHILD_UNUSED     0   /* these values must fit in sig_atomic_t */
      57             : #define PM_CHILD_ASSIGNED   1
      58             : #define PM_CHILD_ACTIVE     2
      59             : #define PM_CHILD_WALSENDER  3
      60             : 
      61             : /* "typedef struct PMSignalData PMSignalData" appears in pmsignal.h */
      62             : struct PMSignalData
      63             : {
      64             :     /* per-reason flags */
      65             :     sig_atomic_t PMSignalFlags[NUM_PMSIGNALS];
      66             :     /* per-child-process flags */
      67             :     int         num_child_flags;    /* # of entries in PMChildFlags[] */
      68             :     int         next_child_flag;    /* next slot to try to assign */
      69             :     sig_atomic_t PMChildFlags[FLEXIBLE_ARRAY_MEMBER];
      70             : };
      71             : 
      72             : NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL;
      73             : 
      74             : 
      75             : /*
      76             :  * PMSignalShmemSize
      77             :  *      Compute space needed for pmsignal.c's shared memory
      78             :  */
      79             : Size
      80          15 : PMSignalShmemSize(void)
      81             : {
      82             :     Size        size;
      83             : 
      84          15 :     size = offsetof(PMSignalData, PMChildFlags);
      85          15 :     size = add_size(size, mul_size(MaxLivePostmasterChildren(),
      86             :                                    sizeof(sig_atomic_t)));
      87             : 
      88          15 :     return size;
      89             : }
      90             : 
      91             : /*
      92             :  * PMSignalShmemInit - initialize during shared-memory creation
      93             :  */
      94             : void
      95           5 : PMSignalShmemInit(void)
      96             : {
      97             :     bool        found;
      98             : 
      99           5 :     PMSignalState = (PMSignalData *)
     100           5 :         ShmemInitStruct("PMSignalState", PMSignalShmemSize(), &found);
     101             : 
     102           5 :     if (!found)
     103             :     {
     104           5 :         MemSet(PMSignalState, 0, PMSignalShmemSize());
     105           5 :         PMSignalState->num_child_flags = MaxLivePostmasterChildren();
     106             :     }
     107           5 : }
     108             : 
     109             : /*
     110             :  * SendPostmasterSignal - signal the postmaster from a child process
     111             :  */
     112             : void
     113         119 : SendPostmasterSignal(PMSignalReason reason)
     114             : {
     115             :     /* If called in a standalone backend, do nothing */
     116         119 :     if (!IsUnderPostmaster)
     117         119 :         return;
     118             :     /* Atomically set the proper flag */
     119         119 :     PMSignalState->PMSignalFlags[reason] = true;
     120             :     /* Send signal to postmaster */
     121         119 :     kill(PostmasterPid, SIGUSR1);
     122             : }
     123             : 
     124             : /*
     125             :  * CheckPostmasterSignal - check to see if a particular reason has been
     126             :  * signaled, and clear the signal flag.  Should be called by postmaster
     127             :  * after receiving SIGUSR1.
     128             :  */
     129             : bool
     130         405 : CheckPostmasterSignal(PMSignalReason reason)
     131             : {
     132             :     /* Careful here --- don't clear flag if we haven't seen it set */
     133         405 :     if (PMSignalState->PMSignalFlags[reason])
     134             :     {
     135          36 :         PMSignalState->PMSignalFlags[reason] = false;
     136          36 :         return true;
     137             :     }
     138         369 :     return false;
     139             : }
     140             : 
     141             : 
     142             : /*
     143             :  * AssignPostmasterChildSlot - select an unused slot for a new postmaster
     144             :  * child process, and set its state to ASSIGNED.  Returns a slot number
     145             :  * (one to N).
     146             :  *
     147             :  * Only the postmaster is allowed to execute this routine, so we need no
     148             :  * special locking.
     149             :  */
     150             : int
     151         335 : AssignPostmasterChildSlot(void)
     152             : {
     153         335 :     int         slot = PMSignalState->next_child_flag;
     154             :     int         n;
     155             : 
     156             :     /*
     157             :      * Scan for a free slot.  We track the last slot assigned so as not to
     158             :      * waste time repeatedly rescanning low-numbered slots.
     159             :      */
     160         336 :     for (n = PMSignalState->num_child_flags; n > 0; n--)
     161             :     {
     162         336 :         if (--slot < 0)
     163           2 :             slot = PMSignalState->num_child_flags - 1;
     164         336 :         if (PMSignalState->PMChildFlags[slot] == PM_CHILD_UNUSED)
     165             :         {
     166         335 :             PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED;
     167         335 :             PMSignalState->next_child_flag = slot;
     168         335 :             return slot + 1;
     169             :         }
     170             :     }
     171             : 
     172             :     /* Out of slots ... should never happen, else postmaster.c messed up */
     173           0 :     elog(FATAL, "no free slots in PMChildFlags array");
     174             :     return 0;                   /* keep compiler quiet */
     175             : }
     176             : 
     177             : /*
     178             :  * ReleasePostmasterChildSlot - release a slot after death of a postmaster
     179             :  * child process.  This must be called in the postmaster process.
     180             :  *
     181             :  * Returns true if the slot had been in ASSIGNED state (the expected case),
     182             :  * false otherwise (implying that the child failed to clean itself up).
     183             :  */
     184             : bool
     185         335 : ReleasePostmasterChildSlot(int slot)
     186             : {
     187             :     bool        result;
     188             : 
     189         335 :     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
     190         335 :     slot--;
     191             : 
     192             :     /*
     193             :      * Note: the slot state might already be unused, because the logic in
     194             :      * postmaster.c is such that this might get called twice when a child
     195             :      * crashes.  So we don't try to Assert anything about the state.
     196             :      */
     197         335 :     result = (PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED);
     198         335 :     PMSignalState->PMChildFlags[slot] = PM_CHILD_UNUSED;
     199         335 :     return result;
     200             : }
     201             : 
     202             : /*
     203             :  * IsPostmasterChildWalSender - check if given slot is in use by a
     204             :  * walsender process.
     205             :  */
     206             : bool
     207          11 : IsPostmasterChildWalSender(int slot)
     208             : {
     209          11 :     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
     210          11 :     slot--;
     211             : 
     212          11 :     if (PMSignalState->PMChildFlags[slot] == PM_CHILD_WALSENDER)
     213           0 :         return true;
     214             :     else
     215          11 :         return false;
     216             : }
     217             : 
     218             : /*
     219             :  * MarkPostmasterChildActive - mark a postmaster child as about to begin
     220             :  * actively using shared memory.  This is called in the child process.
     221             :  */
     222             : void
     223         335 : MarkPostmasterChildActive(void)
     224             : {
     225         335 :     int         slot = MyPMChildSlot;
     226             : 
     227         335 :     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
     228         335 :     slot--;
     229         335 :     Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED);
     230         335 :     PMSignalState->PMChildFlags[slot] = PM_CHILD_ACTIVE;
     231         335 : }
     232             : 
     233             : /*
     234             :  * MarkPostmasterChildWalSender - mark a postmaster child as a WAL sender
     235             :  * process.  This is called in the child process, sometime after marking the
     236             :  * child as active.
     237             :  */
     238             : void
     239           0 : MarkPostmasterChildWalSender(void)
     240             : {
     241           0 :     int         slot = MyPMChildSlot;
     242             : 
     243           0 :     Assert(am_walsender);
     244             : 
     245           0 :     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
     246           0 :     slot--;
     247           0 :     Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ACTIVE);
     248           0 :     PMSignalState->PMChildFlags[slot] = PM_CHILD_WALSENDER;
     249           0 : }
     250             : 
     251             : /*
     252             :  * MarkPostmasterChildInactive - mark a postmaster child as done using
     253             :  * shared memory.  This is called in the child process.
     254             :  */
     255             : void
     256         335 : MarkPostmasterChildInactive(void)
     257             : {
     258         335 :     int         slot = MyPMChildSlot;
     259             : 
     260         335 :     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
     261         335 :     slot--;
     262         335 :     Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ACTIVE ||
     263             :            PMSignalState->PMChildFlags[slot] == PM_CHILD_WALSENDER);
     264         335 :     PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED;
     265         335 : }
     266             : 
     267             : 
     268             : /*
     269             :  * PostmasterIsAlive - check whether postmaster process is still alive
     270             :  */
     271             : bool
     272           0 : PostmasterIsAlive(void)
     273             : {
     274             : #ifndef WIN32
     275             :     char        c;
     276             :     ssize_t     rc;
     277             : 
     278           0 :     rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1);
     279           0 :     if (rc < 0)
     280             :     {
     281           0 :         if (errno == EAGAIN || errno == EWOULDBLOCK)
     282           0 :             return true;
     283             :         else
     284           0 :             elog(FATAL, "read on postmaster death monitoring pipe failed: %m");
     285             :     }
     286           0 :     else if (rc > 0)
     287           0 :         elog(FATAL, "unexpected data in postmaster death monitoring pipe");
     288             : 
     289           0 :     return false;
     290             : #else                           /* WIN32 */
     291             :     return (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT);
     292             : #endif                          /* WIN32 */
     293             : }

Generated by: LCOV version 1.11