aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/lmgr/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/lmgr/proc.c')
-rw-r--r--src/backend/storage/lmgr/proc.c219
1 files changed, 128 insertions, 91 deletions
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 34d80bfceea..605f8b5e68b 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.170 2005/12/11 21:02:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.171 2006/01/04 21:06:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -61,8 +61,8 @@ PGPROC *MyProc = NULL;
NON_EXEC_STATIC slock_t *ProcStructLock = NULL;
/* Pointers to shared-memory structures */
-static PROC_HDR *ProcGlobal = NULL;
-static PGPROC *DummyProcs = NULL;
+NON_EXEC_STATIC PROC_HDR *ProcGlobal = NULL;
+NON_EXEC_STATIC PGPROC *DummyProcs = NULL;
/* If we are waiting for a lock, this points to the associated LOCALLOCK */
static LOCALLOCK *lockAwaited = NULL;
@@ -76,6 +76,7 @@ volatile bool cancel_from_timeout = false;
static struct timeval statement_fin_time;
+static void RemoveProcFromArray(int code, Datum arg);
static void ProcKill(int code, Datum arg);
static void DummyProcKill(int code, Datum arg);
static bool CheckStatementTimeout(void);
@@ -113,7 +114,8 @@ ProcGlobalSemas(void)
/*
* InitProcGlobal -
- * Initialize the global process table during postmaster startup.
+ * Initialize the global process table during postmaster or standalone
+ * backend startup.
*
* We also create all the per-process semaphores we will need to support
* the requested number of backends. We used to allocate semaphores
@@ -129,69 +131,65 @@ ProcGlobalSemas(void)
* Another reason for creating semaphores here is that the semaphore
* implementation typically requires us to create semaphores in the
* postmaster, not in backends.
+ *
+ * Note: this is NOT called by individual backends under a postmaster,
+ * not even in the EXEC_BACKEND case. The ProcGlobal and DummyProcs
+ * pointers must be propagated specially for EXEC_BACKEND operation.
*/
void
InitProcGlobal(void)
{
- bool foundProcGlobal,
- foundDummy;
+ PGPROC *procs;
+ int i;
+ bool found;
- /* Create or attach to the ProcGlobal shared structure */
+ /* Create the ProcGlobal shared structure */
ProcGlobal = (PROC_HDR *)
- ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &foundProcGlobal);
+ ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
+ Assert(!found);
/*
- * Create or attach to the PGPROC structures for dummy (bgwriter)
- * processes, too. These do not get linked into the freeProcs list.
+ * Create the PGPROC structures for dummy (bgwriter) processes, too.
+ * These do not get linked into the freeProcs list.
*/
DummyProcs = (PGPROC *)
ShmemInitStruct("DummyProcs", NUM_DUMMY_PROCS * sizeof(PGPROC),
- &foundDummy);
-
- if (foundProcGlobal || foundDummy)
- {
- /* both should be present or neither */
- Assert(foundProcGlobal && foundDummy);
- }
- else
- {
- /*
- * We're the first - initialize.
- */
- PGPROC *procs;
- int i;
-
- ProcGlobal->freeProcs = INVALID_OFFSET;
+ &found);
+ Assert(!found);
- ProcGlobal->spins_per_delay = DEFAULT_SPINS_PER_DELAY;
+ /*
+ * Initialize the data structures.
+ */
+ ProcGlobal->freeProcs = INVALID_OFFSET;
- /*
- * Pre-create the PGPROC structures and create a semaphore for each.
- */
- procs = (PGPROC *) ShmemAlloc(MaxBackends * sizeof(PGPROC));
- if (!procs)
- ereport(FATAL,
- (errcode(ERRCODE_OUT_OF_MEMORY),
- errmsg("out of shared memory")));
- MemSet(procs, 0, MaxBackends * sizeof(PGPROC));
- for (i = 0; i < MaxBackends; i++)
- {
- PGSemaphoreCreate(&(procs[i].sem));
- procs[i].links.next = ProcGlobal->freeProcs;
- ProcGlobal->freeProcs = MAKE_OFFSET(&procs[i]);
- }
+ ProcGlobal->spins_per_delay = DEFAULT_SPINS_PER_DELAY;
- MemSet(DummyProcs, 0, NUM_DUMMY_PROCS * sizeof(PGPROC));
- for (i = 0; i < NUM_DUMMY_PROCS; i++)
- {
- DummyProcs[i].pid = 0; /* marks dummy proc as not in use */
- PGSemaphoreCreate(&(DummyProcs[i].sem));
- }
+ /*
+ * Pre-create the PGPROC structures and create a semaphore for each.
+ */
+ procs = (PGPROC *) ShmemAlloc(MaxBackends * sizeof(PGPROC));
+ if (!procs)
+ ereport(FATAL,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of shared memory")));
+ MemSet(procs, 0, MaxBackends * sizeof(PGPROC));
+ for (i = 0; i < MaxBackends; i++)
+ {
+ PGSemaphoreCreate(&(procs[i].sem));
+ procs[i].links.next = ProcGlobal->freeProcs;
+ ProcGlobal->freeProcs = MAKE_OFFSET(&procs[i]);
+ }
- /* Create ProcStructLock spinlock, too */
- ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
- SpinLockInit(ProcStructLock);
+ MemSet(DummyProcs, 0, NUM_DUMMY_PROCS * sizeof(PGPROC));
+ for (i = 0; i < NUM_DUMMY_PROCS; i++)
+ {
+ DummyProcs[i].pid = 0; /* marks dummy proc as not in use */
+ PGSemaphoreCreate(&(DummyProcs[i].sem));
}
+
+ /* Create ProcStructLock spinlock, too */
+ ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
+ SpinLockInit(ProcStructLock);
}
/*
@@ -206,8 +204,8 @@ InitProcess(void)
int i;
/*
- * ProcGlobal should be set by a previous call to InitProcGlobal (if we
- * are a backend, we inherit this by fork() from the postmaster).
+ * ProcGlobal should be set up already (if we are a backend, we inherit
+ * this by fork() or EXEC_BACKEND mechanism from the postmaster).
*/
if (procglobal == NULL)
elog(PANIC, "proc header uninitialized");
@@ -256,8 +254,8 @@ InitProcess(void)
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
MyProc->pid = MyProcPid;
- MyProc->databaseId = MyDatabaseId;
- /* Will be set properly after the session role id is determined */
+ /* databaseId and roleId will be filled in later */
+ MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid;
MyProc->lwWaiting = false;
MyProc->lwExclusive = false;
@@ -268,9 +266,10 @@ InitProcess(void)
SHMQueueInit(&(MyProc->myProcLocks[i]));
/*
- * Add our PGPROC to the PGPROC array in shared memory.
+ * We might be reusing a semaphore that belonged to a failed process. So
+ * be careful and reinitialize its value here.
*/
- ProcArrayAdd(MyProc);
+ PGSemaphoreReset(&MyProc->sem);
/*
* Arrange to clean up at backend exit.
@@ -278,12 +277,6 @@ InitProcess(void)
on_shmem_exit(ProcKill, 0);
/*
- * We might be reusing a semaphore that belonged to a failed process. So
- * be careful and reinitialize its value here.
- */
- PGSemaphoreReset(&MyProc->sem);
-
- /*
* Now that we have a PGPROC, we could try to acquire locks, so initialize
* the deadlock checker.
*/
@@ -291,25 +284,58 @@ InitProcess(void)
}
/*
+ * InitProcessPhase2 -- make MyProc visible in the shared ProcArray.
+ *
+ * This is separate from InitProcess because we can't acquire LWLocks until
+ * we've created a PGPROC, but in the EXEC_BACKEND case there is a good deal
+ * of stuff to be done before this step that will require LWLock access.
+ */
+void
+InitProcessPhase2(void)
+{
+ Assert(MyProc != NULL);
+
+ /*
+ * We should now know what database we're in, so advertise that. (We
+ * need not do any locking here, since no other backend can yet see
+ * our PGPROC.)
+ */
+ Assert(OidIsValid(MyDatabaseId));
+ MyProc->databaseId = MyDatabaseId;
+
+ /*
+ * Add our PGPROC to the PGPROC array in shared memory.
+ */
+ ProcArrayAdd(MyProc);
+
+ /*
+ * Arrange to clean that up at backend exit.
+ */
+ on_shmem_exit(RemoveProcFromArray, 0);
+}
+
+/*
* InitDummyProcess -- create a dummy per-process data structure
*
* This is called by bgwriter and similar processes so that they will have a
* MyProc value that's real enough to let them wait for LWLocks. The PGPROC
- * and sema that are assigned are the extra ones created during
+ * and sema that are assigned are one of the extra ones created during
* InitProcGlobal.
*
* Dummy processes are presently not expected to wait for real (lockmgr)
- * locks, nor to participate in sinval messaging.
+ * locks, so we need not set up the deadlock checker. They are never added
+ * to the ProcArray or the sinval messaging mechanism, either.
*/
void
-InitDummyProcess(int proctype)
+InitDummyProcess(void)
{
PGPROC *dummyproc;
+ int proctype;
int i;
/*
- * ProcGlobal should be set by a previous call to InitProcGlobal (we
- * inherit this by fork() from the postmaster).
+ * ProcGlobal should be set up already (if we are a backend, we inherit
+ * this by fork() or EXEC_BACKEND mechanism from the postmaster).
*/
if (ProcGlobal == NULL || DummyProcs == NULL)
elog(PANIC, "proc header uninitialized");
@@ -317,11 +343,9 @@ InitDummyProcess(int proctype)
if (MyProc != NULL)
elog(ERROR, "you already exist");
- Assert(proctype >= 0 && proctype < NUM_DUMMY_PROCS);
-
/*
- * Just for paranoia's sake, we use the ProcStructLock to protect
- * assignment and releasing of DummyProcs entries.
+ * We use the ProcStructLock to protect assignment and releasing of
+ * DummyProcs entries.
*
* While we are holding the ProcStructLock, also copy the current shared
* estimate of spins_per_delay to local storage.
@@ -330,32 +354,38 @@ InitDummyProcess(int proctype)
set_spins_per_delay(ProcGlobal->spins_per_delay);
- dummyproc = &DummyProcs[proctype];
-
/*
- * dummyproc should not presently be in use by anyone else
+ * Find a free dummyproc ... *big* trouble if there isn't one ...
*/
- if (dummyproc->pid != 0)
+ for (proctype = 0; proctype < NUM_DUMMY_PROCS; proctype++)
+ {
+ dummyproc = &DummyProcs[proctype];
+ if (dummyproc->pid == 0)
+ break;
+ }
+ if (proctype >= NUM_DUMMY_PROCS)
{
SpinLockRelease(ProcStructLock);
- elog(FATAL, "DummyProc[%d] is in use by PID %d",
- proctype, dummyproc->pid);
+ elog(FATAL, "all DummyProcs are in use");
}
- MyProc = dummyproc;
- MyProc->pid = MyProcPid; /* marks dummy proc as in use by me */
+ /* Mark dummy proc as in use by me */
+ /* use volatile pointer to prevent code rearrangement */
+ ((volatile PGPROC *) dummyproc)->pid = MyProcPid;
+
+ MyProc = dummyproc;
SpinLockRelease(ProcStructLock);
/*
- * Initialize all fields of MyProc, except MyProc->sem which was set up by
- * InitProcGlobal.
+ * Initialize all fields of MyProc, except for the semaphore which was
+ * prepared for us by InitProcGlobal.
*/
SHMQueueElemInit(&(MyProc->links));
MyProc->waitStatus = STATUS_OK;
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
- MyProc->databaseId = MyDatabaseId;
+ MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid;
MyProc->lwWaiting = false;
MyProc->lwExclusive = false;
@@ -366,15 +396,15 @@ InitDummyProcess(int proctype)
SHMQueueInit(&(MyProc->myProcLocks[i]));
/*
- * Arrange to clean up at process exit.
- */
- on_shmem_exit(DummyProcKill, Int32GetDatum(proctype));
-
- /*
* We might be reusing a semaphore that belonged to a failed process. So
* be careful and reinitialize its value here.
*/
PGSemaphoreReset(&MyProc->sem);
+
+ /*
+ * Arrange to clean up at process exit.
+ */
+ on_shmem_exit(DummyProcKill, Int32GetDatum(proctype));
}
/*
@@ -502,6 +532,16 @@ ProcReleaseLocks(bool isCommit)
/*
+ * RemoveProcFromArray() -- Remove this process from the shared ProcArray.
+ */
+static void
+RemoveProcFromArray(int code, Datum arg)
+{
+ Assert(MyProc != NULL);
+ ProcArrayRemove(MyProc);
+}
+
+/*
* ProcKill() -- Destroy the per-proc data structure for
* this process. Release any of its held LW locks.
*/
@@ -520,9 +560,6 @@ ProcKill(int code, Datum arg)
*/
LWLockReleaseAll();
- /* Remove our PGPROC from the PGPROC array in shared memory */
- ProcArrayRemove(MyProc);
-
SpinLockAcquire(ProcStructLock);
/* Return PGPROC structure (and semaphore) to freelist */