diff options
Diffstat (limited to 'src/backend/storage')
| -rw-r--r-- | src/backend/storage/ipc/ipci.c | 5 | ||||
| -rw-r--r-- | src/backend/storage/ipc/pmsignal.c | 158 | ||||
| -rw-r--r-- | src/backend/storage/lmgr/proc.c | 18 |
3 files changed, 166 insertions, 15 deletions
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index f85f0a66df..281215d218 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.99 2009/01/03 17:08:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.100 2009/05/05 19:59:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -111,6 +111,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) size = add_size(size, ProcArrayShmemSize()); size = add_size(size, BackendStatusShmemSize()); size = add_size(size, SInvalShmemSize()); + size = add_size(size, PMSignalShmemSize()); size = add_size(size, BgWriterShmemSize()); size = add_size(size, AutoVacuumShmemSize()); size = add_size(size, BTreeShmemSize()); @@ -206,7 +207,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) /* * Set up interprocess signaling mechanisms */ - PMSignalInit(); + PMSignalShmemInit(); BgWriterShmemInit(); AutoVacuumShmemInit(); diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c index 02356de91b..c77831dd25 100644 --- a/src/backend/storage/ipc/pmsignal.c +++ b/src/backend/storage/ipc/pmsignal.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/pmsignal.c,v 1.26 2009/01/01 17:23:47 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/pmsignal.c,v 1.27 2009/05/05 19:59:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,26 +34,69 @@ * The flags are actually declared as "volatile sig_atomic_t" for maximum * portability. This should ensure that loads and stores of the flag * values are atomic, allowing us to dispense with any explicit locking. + * + * In addition to the per-reason flags, we store a set of per-child-process + * flags that are currently used only for detecting whether a backend has + * exited without performing proper shutdown. The per-child-process flags + * have three possible states: UNUSED, ASSIGNED, ACTIVE. An UNUSED slot is + * available for assignment. An ASSIGNED slot is associated with a postmaster + * child process, but either the process has not touched shared memory yet, + * or it has successfully cleaned up after itself. A ACTIVE slot means the + * process is actively using shared memory. The slots are assigned to + * child processes at random, and postmaster.c is responsible for tracking + * which one goes with which PID. + */ + +#define PM_CHILD_UNUSED 0 /* these values must fit in sig_atomic_t */ +#define PM_CHILD_ASSIGNED 1 +#define PM_CHILD_ACTIVE 2 + +/* "typedef struct PMSignalData PMSignalData" appears in pmsignal.h */ +struct PMSignalData +{ + /* per-reason flags */ + sig_atomic_t PMSignalFlags[NUM_PMSIGNALS]; + /* per-child-process flags */ + int num_child_flags; /* # of entries in PMChildFlags[] */ + int next_child_flag; /* next slot to try to assign */ + sig_atomic_t PMChildFlags[1]; /* VARIABLE LENGTH ARRAY */ +}; + +NON_EXEC_STATIC volatile PMSignalData *PMSignalState = NULL; + + +/* + * PMSignalShmemSize + * Compute space needed for pmsignal.c's shared memory */ +Size +PMSignalShmemSize(void) +{ + Size size; -static volatile sig_atomic_t *PMSignalFlags; + size = offsetof(PMSignalData, PMChildFlags); + size = add_size(size, mul_size(MaxLivePostmasterChildren(), + sizeof(sig_atomic_t))); + return size; +} /* - * PMSignalInit - initialize during shared-memory creation + * PMSignalShmemInit - initialize during shared-memory creation */ void -PMSignalInit(void) +PMSignalShmemInit(void) { bool found; - PMSignalFlags = (sig_atomic_t *) - ShmemInitStruct("PMSignalFlags", - NUM_PMSIGNALS * sizeof(sig_atomic_t), - &found); + PMSignalState = (PMSignalData *) + ShmemInitStruct("PMSignalState", PMSignalShmemSize(), &found); if (!found) - MemSet(PMSignalFlags, 0, NUM_PMSIGNALS * sizeof(sig_atomic_t)); + { + MemSet(PMSignalState, 0, PMSignalShmemSize()); + PMSignalState->num_child_flags = MaxLivePostmasterChildren(); + } } /* @@ -66,7 +109,7 @@ SendPostmasterSignal(PMSignalReason reason) if (!IsUnderPostmaster) return; /* Atomically set the proper flag */ - PMSignalFlags[reason] = true; + PMSignalState->PMSignalFlags[reason] = true; /* Send signal to postmaster */ kill(PostmasterPid, SIGUSR1); } @@ -80,14 +123,105 @@ bool CheckPostmasterSignal(PMSignalReason reason) { /* Careful here --- don't clear flag if we haven't seen it set */ - if (PMSignalFlags[reason]) + if (PMSignalState->PMSignalFlags[reason]) { - PMSignalFlags[reason] = false; + PMSignalState->PMSignalFlags[reason] = false; return true; } return false; } + +/* + * AssignPostmasterChildSlot - select an unused slot for a new postmaster + * child process, and set its state to ASSIGNED. Returns a slot number + * (one to N). + * + * Only the postmaster is allowed to execute this routine, so we need no + * special locking. + */ +int +AssignPostmasterChildSlot(void) +{ + int slot = PMSignalState->next_child_flag; + int n; + + /* + * Scan for a free slot. We track the last slot assigned so as not to + * waste time repeatedly rescanning low-numbered slots. + */ + for (n = PMSignalState->num_child_flags; n > 0; n--) + { + if (--slot < 0) + slot = PMSignalState->num_child_flags - 1; + if (PMSignalState->PMChildFlags[slot] == PM_CHILD_UNUSED) + { + PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED; + PMSignalState->next_child_flag = slot; + return slot + 1; + } + } + + /* Out of slots ... should never happen, else postmaster.c messed up */ + elog(FATAL, "no free slots in PMChildFlags array"); + return 0; /* keep compiler quiet */ +} + +/* + * ReleasePostmasterChildSlot - release a slot after death of a postmaster + * child process. This must be called in the postmaster process. + * + * Returns true if the slot had been in ASSIGNED state (the expected case), + * false otherwise (implying that the child failed to clean itself up). + */ +bool +ReleasePostmasterChildSlot(int slot) +{ + bool result; + + Assert(slot > 0 && slot <= PMSignalState->num_child_flags); + slot--; + /* + * Note: the slot state might already be unused, because the logic in + * postmaster.c is such that this might get called twice when a child + * crashes. So we don't try to Assert anything about the state. + */ + result = (PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED); + PMSignalState->PMChildFlags[slot] = PM_CHILD_UNUSED; + return result; +} + +/* + * MarkPostmasterChildActive - mark a postmaster child as about to begin + * actively using shared memory. This is called in the child process. + */ +void +MarkPostmasterChildActive(void) +{ + int slot = MyPMChildSlot; + + Assert(slot > 0 && slot <= PMSignalState->num_child_flags); + slot--; + Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ASSIGNED); + PMSignalState->PMChildFlags[slot] = PM_CHILD_ACTIVE; +} + +/* + * MarkPostmasterChildInactive - mark a postmaster child as done using + * shared memory. This is called in the child process. + */ +void +MarkPostmasterChildInactive(void) +{ + int slot = MyPMChildSlot; + + Assert(slot > 0 && slot <= PMSignalState->num_child_flags); + slot--; + Assert(PMSignalState->PMChildFlags[slot] == PM_CHILD_ACTIVE); + PMSignalState->PMChildFlags[slot] = PM_CHILD_ASSIGNED; +} + + /* * PostmasterIsAlive - check whether postmaster process is still alive * diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index e108179e0b..8f5b4e3304 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.205 2009/01/01 17:23:48 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.206 2009/05/05 19:59:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -41,6 +41,7 @@ #include "postmaster/autovacuum.h" #include "storage/ipc.h" #include "storage/lmgr.h" +#include "storage/pmsignal.h" #include "storage/proc.h" #include "storage/procarray.h" #include "storage/spin.h" @@ -275,6 +276,14 @@ InitProcess(void) } /* + * Now that we have a PGPROC, mark ourselves as an active postmaster + * child; this is so that the postmaster can detect it if we exit + * without cleaning up. + */ + if (IsUnderPostmaster) + MarkPostmasterChildActive(); + + /* * Initialize all fields of MyProc, except for the semaphore which was * prepared for us by InitProcGlobal. */ @@ -614,6 +623,13 @@ ProcKill(int code, Datum arg) SpinLockRelease(ProcStructLock); + /* + * This process is no longer present in shared memory in any meaningful + * way, so tell the postmaster we've cleaned up acceptably well. + */ + if (IsUnderPostmaster) + MarkPostmasterChildInactive(); + /* wake autovac launcher if needed -- see comments in FreeWorkerInfo */ if (AutovacuumLauncherPid != 0) kill(AutovacuumLauncherPid, SIGUSR1); |
