LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - procsignal.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 57 74 77.0 %
Date: 2017-09-29 13:40:31 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * procsignal.c
       4             :  *    Routines for interprocess signalling
       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/procsignal.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include <signal.h>
      18             : #include <unistd.h>
      19             : 
      20             : #include "access/parallel.h"
      21             : #include "commands/async.h"
      22             : #include "miscadmin.h"
      23             : #include "replication/walsender.h"
      24             : #include "storage/latch.h"
      25             : #include "storage/ipc.h"
      26             : #include "storage/proc.h"
      27             : #include "storage/shmem.h"
      28             : #include "storage/sinval.h"
      29             : #include "tcop/tcopprot.h"
      30             : 
      31             : 
      32             : /*
      33             :  * The SIGUSR1 signal is multiplexed to support signalling multiple event
      34             :  * types. The specific reason is communicated via flags in shared memory.
      35             :  * We keep a boolean flag for each possible "reason", so that different
      36             :  * reasons can be signaled to a process concurrently.  (However, if the same
      37             :  * reason is signaled more than once nearly simultaneously, the process may
      38             :  * observe it only once.)
      39             :  *
      40             :  * Each process that wants to receive signals registers its process ID
      41             :  * in the ProcSignalSlots array. The array is indexed by backend ID to make
      42             :  * slot allocation simple, and to avoid having to search the array when you
      43             :  * know the backend ID of the process you're signalling.  (We do support
      44             :  * signalling without backend ID, but it's a bit less efficient.)
      45             :  *
      46             :  * The flags are actually declared as "volatile sig_atomic_t" for maximum
      47             :  * portability.  This should ensure that loads and stores of the flag
      48             :  * values are atomic, allowing us to dispense with any explicit locking.
      49             :  */
      50             : typedef struct
      51             : {
      52             :     pid_t       pss_pid;
      53             :     sig_atomic_t pss_signalFlags[NUM_PROCSIGNALS];
      54             : } ProcSignalSlot;
      55             : 
      56             : /*
      57             :  * We reserve a slot for each possible BackendId, plus one for each
      58             :  * possible auxiliary process type.  (This scheme assumes there is not
      59             :  * more than one of any auxiliary process type at a time.)
      60             :  */
      61             : #define NumProcSignalSlots  (MaxBackends + NUM_AUXPROCTYPES)
      62             : 
      63             : static ProcSignalSlot *ProcSignalSlots = NULL;
      64             : static volatile ProcSignalSlot *MyProcSignalSlot = NULL;
      65             : 
      66             : static bool CheckProcSignal(ProcSignalReason reason);
      67             : static void CleanupProcSignalState(int status, Datum arg);
      68             : 
      69             : /*
      70             :  * ProcSignalShmemSize
      71             :  *      Compute space needed for procsignal's shared memory
      72             :  */
      73             : Size
      74          10 : ProcSignalShmemSize(void)
      75             : {
      76          10 :     return NumProcSignalSlots * sizeof(ProcSignalSlot);
      77             : }
      78             : 
      79             : /*
      80             :  * ProcSignalShmemInit
      81             :  *      Allocate and initialize procsignal's shared memory
      82             :  */
      83             : void
      84           5 : ProcSignalShmemInit(void)
      85             : {
      86           5 :     Size        size = ProcSignalShmemSize();
      87             :     bool        found;
      88             : 
      89           5 :     ProcSignalSlots = (ProcSignalSlot *)
      90           5 :         ShmemInitStruct("ProcSignalSlots", size, &found);
      91             : 
      92             :     /* If we're first, set everything to zeroes */
      93           5 :     if (!found)
      94           5 :         MemSet(ProcSignalSlots, 0, size);
      95           5 : }
      96             : 
      97             : /*
      98             :  * ProcSignalInit
      99             :  *      Register the current process in the procsignal array
     100             :  *
     101             :  * The passed index should be my BackendId if the process has one,
     102             :  * or MaxBackends + aux process type if not.
     103             :  */
     104             : void
     105         342 : ProcSignalInit(int pss_idx)
     106             : {
     107             :     volatile ProcSignalSlot *slot;
     108             : 
     109         342 :     Assert(pss_idx >= 1 && pss_idx <= NumProcSignalSlots);
     110             : 
     111         342 :     slot = &ProcSignalSlots[pss_idx - 1];
     112             : 
     113             :     /* sanity check */
     114         342 :     if (slot->pss_pid != 0)
     115           0 :         elog(LOG, "process %d taking over ProcSignal slot %d, but it's not empty",
     116             :              MyProcPid, pss_idx);
     117             : 
     118             :     /* Clear out any leftover signal reasons */
     119         342 :     MemSet(slot->pss_signalFlags, 0, NUM_PROCSIGNALS * sizeof(sig_atomic_t));
     120             : 
     121             :     /* Mark slot with my PID */
     122         342 :     slot->pss_pid = MyProcPid;
     123             : 
     124             :     /* Remember slot location for CheckProcSignal */
     125         342 :     MyProcSignalSlot = slot;
     126             : 
     127             :     /* Set up to release the slot on process exit */
     128         342 :     on_shmem_exit(CleanupProcSignalState, Int32GetDatum(pss_idx));
     129         342 : }
     130             : 
     131             : /*
     132             :  * CleanupProcSignalState
     133             :  *      Remove current process from ProcSignalSlots
     134             :  *
     135             :  * This function is called via on_shmem_exit() during backend shutdown.
     136             :  */
     137             : static void
     138         342 : CleanupProcSignalState(int status, Datum arg)
     139             : {
     140         342 :     int         pss_idx = DatumGetInt32(arg);
     141             :     volatile ProcSignalSlot *slot;
     142             : 
     143         342 :     slot = &ProcSignalSlots[pss_idx - 1];
     144         342 :     Assert(slot == MyProcSignalSlot);
     145             : 
     146             :     /*
     147             :      * Clear MyProcSignalSlot, so that a SIGUSR1 received after this point
     148             :      * won't try to access it after it's no longer ours (and perhaps even
     149             :      * after we've unmapped the shared memory segment).
     150             :      */
     151         342 :     MyProcSignalSlot = NULL;
     152             : 
     153             :     /* sanity check */
     154         342 :     if (slot->pss_pid != MyProcPid)
     155             :     {
     156             :         /*
     157             :          * don't ERROR here. We're exiting anyway, and don't want to get into
     158             :          * infinite loop trying to exit
     159             :          */
     160           0 :         elog(LOG, "process %d releasing ProcSignal slot %d, but it contains %d",
     161             :              MyProcPid, pss_idx, (int) slot->pss_pid);
     162         342 :         return;                 /* XXX better to zero the slot anyway? */
     163             :     }
     164             : 
     165         342 :     slot->pss_pid = 0;
     166             : }
     167             : 
     168             : /*
     169             :  * SendProcSignal
     170             :  *      Send a signal to a Postgres process
     171             :  *
     172             :  * Providing backendId is optional, but it will speed up the operation.
     173             :  *
     174             :  * On success (a signal was sent), zero is returned.
     175             :  * On error, -1 is returned, and errno is set (typically to ESRCH or EPERM).
     176             :  *
     177             :  * Not to be confused with ProcSendSignal
     178             :  */
     179             : int
     180         448 : SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
     181             : {
     182             :     volatile ProcSignalSlot *slot;
     183             : 
     184         448 :     if (backendId != InvalidBackendId)
     185             :     {
     186         448 :         slot = &ProcSignalSlots[backendId - 1];
     187             : 
     188             :         /*
     189             :          * Note: Since there's no locking, it's possible that the target
     190             :          * process detaches from shared memory and exits right after this
     191             :          * test, before we set the flag and send signal. And the signal slot
     192             :          * might even be recycled by a new process, so it's remotely possible
     193             :          * that we set a flag for a wrong process. That's OK, all the signals
     194             :          * are such that no harm is done if they're mistakenly fired.
     195             :          */
     196         448 :         if (slot->pss_pid == pid)
     197             :         {
     198             :             /* Atomically set the proper flag */
     199         448 :             slot->pss_signalFlags[reason] = true;
     200             :             /* Send signal */
     201         448 :             return kill(pid, SIGUSR1);
     202             :         }
     203             :     }
     204             :     else
     205             :     {
     206             :         /*
     207             :          * BackendId not provided, so search the array using pid.  We search
     208             :          * the array back to front so as to reduce search overhead.  Passing
     209             :          * InvalidBackendId means that the target is most likely an auxiliary
     210             :          * process, which will have a slot near the end of the array.
     211             :          */
     212             :         int         i;
     213             : 
     214           0 :         for (i = NumProcSignalSlots - 1; i >= 0; i--)
     215             :         {
     216           0 :             slot = &ProcSignalSlots[i];
     217             : 
     218           0 :             if (slot->pss_pid == pid)
     219             :             {
     220             :                 /* the above note about race conditions applies here too */
     221             : 
     222             :                 /* Atomically set the proper flag */
     223           0 :                 slot->pss_signalFlags[reason] = true;
     224             :                 /* Send signal */
     225           0 :                 return kill(pid, SIGUSR1);
     226             :             }
     227             :         }
     228             :     }
     229             : 
     230           0 :     errno = ESRCH;
     231           0 :     return -1;
     232             : }
     233             : 
     234             : /*
     235             :  * CheckProcSignal - check to see if a particular reason has been
     236             :  * signaled, and clear the signal flag.  Should be called after receiving
     237             :  * SIGUSR1.
     238             :  */
     239             : static bool
     240       12680 : CheckProcSignal(ProcSignalReason reason)
     241             : {
     242       12680 :     volatile ProcSignalSlot *slot = MyProcSignalSlot;
     243             : 
     244       12680 :     if (slot != NULL)
     245             :     {
     246             :         /* Careful here --- don't clear flag if we haven't seen it set */
     247       12680 :         if (slot->pss_signalFlags[reason])
     248             :         {
     249         448 :             slot->pss_signalFlags[reason] = false;
     250         448 :             return true;
     251             :         }
     252             :     }
     253             : 
     254       12232 :     return false;
     255             : }
     256             : 
     257             : /*
     258             :  * procsignal_sigusr1_handler - handle SIGUSR1 signal.
     259             :  */
     260             : void
     261        1268 : procsignal_sigusr1_handler(SIGNAL_ARGS)
     262             : {
     263        1268 :     int         save_errno = errno;
     264             : 
     265        1268 :     if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
     266         218 :         HandleCatchupInterrupt();
     267             : 
     268        1268 :     if (CheckProcSignal(PROCSIG_NOTIFY_INTERRUPT))
     269           0 :         HandleNotifyInterrupt();
     270             : 
     271        1268 :     if (CheckProcSignal(PROCSIG_PARALLEL_MESSAGE))
     272         230 :         HandleParallelMessageInterrupt();
     273             : 
     274        1268 :     if (CheckProcSignal(PROCSIG_WALSND_INIT_STOPPING))
     275           0 :         HandleWalSndInitStopping();
     276             : 
     277        1268 :     if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_DATABASE))
     278           0 :         RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_DATABASE);
     279             : 
     280        1268 :     if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_TABLESPACE))
     281           0 :         RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_TABLESPACE);
     282             : 
     283        1268 :     if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_LOCK))
     284           0 :         RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_LOCK);
     285             : 
     286        1268 :     if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_SNAPSHOT))
     287           0 :         RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_SNAPSHOT);
     288             : 
     289        1268 :     if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK))
     290           0 :         RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
     291             : 
     292        1268 :     if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN))
     293           0 :         RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
     294             : 
     295        1268 :     SetLatch(MyLatch);
     296             : 
     297        1268 :     latch_sigusr1_handler();
     298             : 
     299        1268 :     errno = save_errno;
     300        1268 : }

Generated by: LCOV version 1.11