summaryrefslogtreecommitdiff
path: root/src/backend/storage
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage')
-rw-r--r--src/backend/storage/ipc/ipci.c5
-rw-r--r--src/backend/storage/ipc/pmsignal.c158
-rw-r--r--src/backend/storage/lmgr/proc.c18
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);