* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.31 2005/10/07 20:11:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.32 2005/10/07 21:42:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "storage/spin.h"
+/* We use the ShmemLock spinlock to protect LWLockAssign */
+extern slock_t *ShmemLock;
+
+
typedef struct LWLock
{
slock_t mutex; /* Protects LWLock and queue of PGPROCs */
*/
NON_EXEC_STATIC LWLockPadded *LWLockArray = NULL;
-/* shared counter for dynamic allocation of LWLockIds */
-static int *LWLockCounter;
-
/*
* We use this structure to keep track of locked LWLocks for release
/* Space for the LWLock array. */
size = mul_size(numLocks, sizeof(LWLockPadded));
- /* Space for shared allocation counter, plus room for alignment. */
+ /* Space for dynamic allocation counter, plus room for alignment. */
size = add_size(size, 2 * sizeof(int) + LWLOCK_PADDED_SIZE);
return size;
int numLocks = NumLWLocks();
Size spaceLocks = LWLockShmemSize();
LWLockPadded *lock;
+ int *LWLockCounter;
char *ptr;
int id;
/* Allocate space */
ptr = (char *) ShmemAlloc(spaceLocks);
+ /* Leave room for dynamic allocation counter */
+ ptr += 2 * sizeof(int);
+
/* Ensure desired alignment of LWLock array */
ptr += LWLOCK_PADDED_SIZE - ((unsigned long) ptr) % LWLOCK_PADDED_SIZE;
}
/*
- * Initialize the dynamic-allocation counter at the end of the array
+ * Initialize the dynamic-allocation counter, which is stored just before
+ * the first LWLock.
*/
- LWLockCounter = (int *) lock;
+ LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
LWLockCounter[0] = (int) NumFixedLWLocks;
LWLockCounter[1] = numLocks;
}
/*
* LWLockAssign - assign a dynamically-allocated LWLock number
*
- * NB: we do not currently try to interlock this. Could perhaps use
- * ShmemLock spinlock if there were any need to assign LWLockIds after
- * shmem setup.
+ * We interlock this using the same spinlock that is used to protect
+ * ShmemAlloc(). Interlocking is not really necessary during postmaster
+ * startup, but it is needed if any user-defined code tries to allocate
+ * LWLocks after startup.
*/
LWLockId
LWLockAssign(void)
{
+ LWLockId result;
+ int *LWLockCounter;
+
+ LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
+ SpinLockAcquire(ShmemLock);
if (LWLockCounter[0] >= LWLockCounter[1])
- elog(FATAL, "no more LWLockIds available");
- return (LWLockId) (LWLockCounter[0]++);
+ {
+ SpinLockRelease(ShmemLock);
+ elog(ERROR, "no more LWLockIds available");
+ }
+ result = (LWLockId) (LWLockCounter[0]++);
+ SpinLockRelease(ShmemLock);
+ return result;
}