Header And Logo

PostgreSQL
| The world's most advanced open source database.

pmsignal.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pmsignal.c
00004  *    routines for signaling the postmaster from its child processes
00005  *
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/storage/ipc/pmsignal.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include <signal.h>
00018 #include <unistd.h>
00019 
00020 #include "miscadmin.h"
00021 #include "postmaster/postmaster.h"
00022 #include "replication/walsender.h"
00023 #include "storage/pmsignal.h"
00024 #include "storage/shmem.h"
00025 
00026 
00027 /*
00028  * The postmaster is signaled by its children by sending SIGUSR1.  The
00029  * specific reason is communicated via flags in shared memory.  We keep
00030  * a boolean flag for each possible "reason", so that different reasons
00031  * can be signaled by different backends at the same time.  (However,
00032  * if the same reason is signaled more than once simultaneously, the
00033  * postmaster will observe it only once.)
00034  *
00035  * The flags are actually declared as "volatile sig_atomic_t" for maximum
00036  * portability.  This should ensure that loads and stores of the flag
00037  * values are atomic, allowing us to dispense with any explicit locking.
00038  *
00039  * In addition to the per-reason flags, we store a set of per-child-process
00040  * flags that are currently used only for detecting whether a backend has
00041  * exited without performing proper shutdown.  The per-child-process flags
00042  * have three possible states: UNUSED, ASSIGNED, ACTIVE.  An UNUSED slot is
00043  * available for assignment.  An ASSIGNED slot is associated with a postmaster
00044  * child process, but either the process has not touched shared memory yet,
00045  * or it has successfully cleaned up after itself.  A ACTIVE slot means the
00046  * process is actively using shared memory.  The slots are assigned to
00047  * child processes at random, and postmaster.c is responsible for tracking
00048  * which one goes with which PID.
00049  *
00050  * Actually there is a fourth state, WALSENDER.  This is just like ACTIVE,
00051  * but carries the extra information that the child is a WAL sender.
00052  * WAL senders too start in ACTIVE state, but switch to WALSENDER once they
00053  * start streaming the WAL (and they never go back to ACTIVE after that).
00054  */
00055 
00056 #define PM_CHILD_UNUSED     0   /* these values must fit in sig_atomic_t */
00057 #define PM_CHILD_ASSIGNED   1
00058 #define PM_CHILD_ACTIVE     2
00059 #define PM_CHILD_WALSENDER  3
00060 
00061 /* "typedef struct PMSignalData PMSignalData" appears in pmsignal.h */
00062 struct PMSignalData
00063 {
00064     /* per-reason flags */
00065     sig_atomic_t PMSignalFlags[NUM_PMSIGNALS];
00066     /* per-child-process flags */
00067     int         num_child_flags;    /* # of entries in PMChildFlags[] */
00068     int         next_child_flag;    /* next slot to try to assign */
00069     sig_atomic_t PMChildFlags[1];       /* VARIABLE LENGTH ARRAY */
00070 };
00071 
00072 NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL;
00073 
00074 
00075 /*
00076  * PMSignalShmemSize
00077  *      Compute space needed for pmsignal.c's shared memory
00078  */
00079 Size
00080 PMSignalShmemSize(void)
00081 {
00082     Size        size;
00083 
00084     size = offsetof(PMSignalData, PMChildFlags);
00085     size = add_size(size, mul_size(MaxLivePostmasterChildren(),
00086                                    sizeof(sig_atomic_t)));
00087 
00088     return size;
00089 }
00090 
00091 /*
00092  * PMSignalShmemInit - initialize during shared-memory creation
00093  */
00094 void
00095 PMSignalShmemInit(void)
00096 {
00097     bool        found;
00098 
00099     PMSignalState = (PMSignalData *)
00100         ShmemInitStruct("PMSignalState", PMSignalShmemSize(), &found);
00101 
00102     if (!found)
00103     {
00104         MemSet(PMSignalState, 0, PMSignalShmemSize());
00105         PMSignalState->num_child_flags = MaxLivePostmasterChildren();
00106     }
00107 }
00108 
00109 /*
00110  * SendPostmasterSignal - signal the postmaster from a child process
00111  */
00112 void
00113 SendPostmasterSignal(PMSignalReason reason)
00114 {
00115     /* If called in a standalone backend, do nothing */
00116     if (!IsUnderPostmaster)
00117         return;
00118     /* Atomically set the proper flag */
00119     PMSignalState->PMSignalFlags[reason] = true;
00120     /* Send signal to postmaster */
00121     kill(PostmasterPid, SIGUSR1);
00122 }
00123 
00124 /*
00125  * CheckPostmasterSignal - check to see if a particular reason has been
00126  * signaled, and clear the signal flag.  Should be called by postmaster
00127  * after receiving SIGUSR1.
00128  */
00129 bool
00130 CheckPostmasterSignal(PMSignalReason reason)
00131 {
00132     /* Careful here --- don't clear flag if we haven't seen it set */
00133     if (PMSignalState->PMSignalFlags[reason])
00134     {
00135         PMSignalState->PMSignalFlags[reason] = false;
00136         return true;
00137     }
00138     return false;
00139 }
00140 
00141 
00142 /*
00143  * AssignPostmasterChildSlot - select an unused slot for a new postmaster
00144  * child process, and set its state to ASSIGNED.  Returns a slot number
00145  * (one to N).
00146  *
00147  * Only the postmaster is allowed to execute this routine, so we need no
00148  * special locking.
00149  */
00150 int
00151 AssignPostmasterChildSlot(void)
00152 {
00153     int         slot = PMSignalState->next_child_flag;
00154     int         n;
00155 
00156     /*
00157      * Scan for a free slot.  We track the last slot assigned so as not to
00158      * waste time repeatedly rescanning low-numbered slots.
00159      */
00160     for (n = PMSignalState->num_child_flags; n > 0; n--)
00161     {
00162         if (--slot < 0)
00163             slot = PMSignalState->num_child_flags - 1;
00164         if (PMSignalState->PMChildFlags[slot] == PM_CHILD_UNUSED)
00165         {
00166             PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED;
00167             PMSignalState->next_child_flag = slot;
00168             return slot + 1;
00169         }
00170     }
00171 
00172     /* Out of slots ... should never happen, else postmaster.c messed up */
00173     elog(FATAL, "no free slots in PMChildFlags array");
00174     return 0;                   /* keep compiler quiet */
00175 }
00176 
00177 /*
00178  * ReleasePostmasterChildSlot - release a slot after death of a postmaster
00179  * child process.  This must be called in the postmaster process.
00180  *
00181  * Returns true if the slot had been in ASSIGNED state (the expected case),
00182  * false otherwise (implying that the child failed to clean itself up).
00183  */
00184 bool
00185 ReleasePostmasterChildSlot(int slot)
00186 {
00187     bool        result;
00188 
00189     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
00190     slot--;
00191 
00192     /*
00193      * Note: the slot state might already be unused, because the logic in
00194      * postmaster.c is such that this might get called twice when a child
00195      * crashes.  So we don't try to Assert anything about the state.
00196      */
00197     result = (PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED);
00198     PMSignalState->PMChildFlags[slot] = PM_CHILD_UNUSED;
00199     return result;
00200 }
00201 
00202 /*
00203  * IsPostmasterChildWalSender - check if given slot is in use by a
00204  * walsender process.
00205  */
00206 bool
00207 IsPostmasterChildWalSender(int slot)
00208 {
00209     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
00210     slot--;
00211 
00212     if (PMSignalState->PMChildFlags[slot] == PM_CHILD_WALSENDER)
00213         return true;
00214     else
00215         return false;
00216 }
00217 
00218 /*
00219  * MarkPostmasterChildActive - mark a postmaster child as about to begin
00220  * actively using shared memory.  This is called in the child process.
00221  */
00222 void
00223 MarkPostmasterChildActive(void)
00224 {
00225     int         slot = MyPMChildSlot;
00226 
00227     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
00228     slot--;
00229     Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED);
00230     PMSignalState->PMChildFlags[slot] = PM_CHILD_ACTIVE;
00231 }
00232 
00233 /*
00234  * MarkPostmasterChildWalSender - mark a postmaster child as a WAL sender
00235  * process.  This is called in the child process, sometime after marking the
00236  * child as active.
00237  */
00238 void
00239 MarkPostmasterChildWalSender(void)
00240 {
00241     int         slot = MyPMChildSlot;
00242 
00243     Assert(am_walsender);
00244 
00245     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
00246     slot--;
00247     Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ACTIVE);
00248     PMSignalState->PMChildFlags[slot] = PM_CHILD_WALSENDER;
00249 }
00250 
00251 /*
00252  * MarkPostmasterChildInactive - mark a postmaster child as done using
00253  * shared memory.  This is called in the child process.
00254  */
00255 void
00256 MarkPostmasterChildInactive(void)
00257 {
00258     int         slot = MyPMChildSlot;
00259 
00260     Assert(slot > 0 && slot <= PMSignalState->num_child_flags);
00261     slot--;
00262     Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ACTIVE ||
00263            PMSignalState->PMChildFlags[slot] == PM_CHILD_WALSENDER);
00264     PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED;
00265 }
00266 
00267 
00268 /*
00269  * PostmasterIsAlive - check whether postmaster process is still alive
00270  */
00271 bool
00272 PostmasterIsAlive(void)
00273 {
00274 #ifndef WIN32
00275     char        c;
00276     ssize_t     rc;
00277 
00278     rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1);
00279     if (rc < 0)
00280     {
00281         if (errno == EAGAIN || errno == EWOULDBLOCK)
00282             return true;
00283         else
00284             elog(FATAL, "read on postmaster death monitoring pipe failed: %m");
00285     }
00286     else if (rc > 0)
00287         elog(FATAL, "unexpected data in postmaster death monitoring pipe");
00288 
00289     return false;
00290 #else                           /* WIN32 */
00291     return (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT);
00292 #endif   /* WIN32 */
00293 }