diff options
| author | Tom Lane | 2001-09-27 19:10:02 +0000 |
|---|---|---|
| committer | Tom Lane | 2001-09-27 19:10:02 +0000 |
| commit | 90aebf7f5242b11bc9576f5d9052d755336b1bcc (patch) | |
| tree | dbc549709f897a737f5e799986674c5cea4617b3 /src/backend/storage/ipc/spin.c | |
| parent | 3d59ad00e8cc6a1bd919280be839fca152149ec2 (diff) | |
Move s_lock.c and spin.c into lmgr subdirectory, which seems a much
more reasonable location for them.
Diffstat (limited to 'src/backend/storage/ipc/spin.c')
| -rw-r--r-- | src/backend/storage/ipc/spin.c | 397 |
1 files changed, 0 insertions, 397 deletions
diff --git a/src/backend/storage/ipc/spin.c b/src/backend/storage/ipc/spin.c deleted file mode 100644 index 05bf5acbbb3..00000000000 --- a/src/backend/storage/ipc/spin.c +++ /dev/null @@ -1,397 +0,0 @@ -/*------------------------------------------------------------------------- - * - * spin.c - * routines for managing spin locks - * - * POSTGRES has two kinds of locks: semaphores (which put the - * process to sleep) and spinlocks (which are supposed to be - * short term locks). Spinlocks are implemented via test-and-set (TAS) - * instructions if possible, else via semaphores. The semaphore method - * is too slow to be useful :-( - * - * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.33 2001/06/27 23:31:39 tgl Exp $ - * - *------------------------------------------------------------------------- - */ -#include "postgres.h" - -#include <errno.h> -#if !defined(HAS_TEST_AND_SET) && defined(HAVE_SYS_SEM_H) -#include <sys/sem.h> -#endif - -#include "miscadmin.h" -#include "storage/proc.h" -#include "storage/s_lock.h" - - -/* Probably should move these to an appropriate header file */ -extern SPINLOCK BufMgrLock; -extern SPINLOCK OidGenLockId; -extern SPINLOCK XidGenLockId; -extern SPINLOCK ControlFileLockId; -extern SPINLOCK ShmemLock; -extern SPINLOCK ShmemIndexLock; -extern SPINLOCK LockMgrLock; -extern SPINLOCK SInvalLock; -extern SPINLOCK ProcStructLock; -extern SPINLOCK FreeSpaceLock; -#ifdef STABLE_MEMORY_STORAGE -extern SPINLOCK MMCacheLock; -#endif - - -/* - * Initialize identifiers for permanent spinlocks during startup - * - * The same identifiers are used for both TAS and semaphore implementations, - * although in one case they are indexes into a shmem array and in the other - * they are semaphore numbers. - */ -static void -InitSpinLockIDs(void) -{ - BufMgrLock = (SPINLOCK) BUFMGRLOCKID; - OidGenLockId = (SPINLOCK) OIDGENLOCKID; - XidGenLockId = (SPINLOCK) XIDGENLOCKID; - ControlFileLockId = (SPINLOCK) CNTLFILELOCKID; - ShmemLock = (SPINLOCK) SHMEMLOCKID; - ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID; - LockMgrLock = (SPINLOCK) LOCKMGRLOCKID; - SInvalLock = (SPINLOCK) SINVALLOCKID; - ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID; - FreeSpaceLock = (SPINLOCK) FREESPACELOCKID; -#ifdef STABLE_MEMORY_STORAGE - MMCacheLock = (SPINLOCK) MMCACHELOCKID; -#endif -} - - -#ifdef HAS_TEST_AND_SET - -/* real spin lock implementation */ - -typedef struct slock -{ - slock_t shlock; -} SLock; - -#ifdef LOCK_DEBUG -bool Trace_spinlocks = false; - -inline static void -PRINT_SLDEBUG(const char *where, SPINLOCK lockid, const SLock *lock) -{ - if (Trace_spinlocks) - elog(DEBUG, "%s: id=%d", where, lockid); -} - -#else /* not LOCK_DEBUG */ -#define PRINT_SLDEBUG(a,b,c) -#endif /* not LOCK_DEBUG */ - - -static SLock *SLockArray = NULL; - -#define SLOCKMEMORYSIZE ((int) MAX_SPINS * sizeof(SLock)) - -/* - * SLockShmemSize --- return shared-memory space needed - */ -int -SLockShmemSize(void) -{ - return MAXALIGN(SLOCKMEMORYSIZE); -} - -/* - * CreateSpinlocks --- create and initialize spinlocks during startup - */ -void -CreateSpinlocks(PGShmemHeader *seghdr) -{ - int id; - - /* - * We must allocate the space "by hand" because shmem.c isn't up yet - */ - SLockArray = (SLock *) (((char *) seghdr) + seghdr->freeoffset); - seghdr->freeoffset += MAXALIGN(SLOCKMEMORYSIZE); - Assert(seghdr->freeoffset <= seghdr->totalsize); - - /* - * Initialize all spinlocks to "unlocked" state - */ - for (id = 0; id < (int) MAX_SPINS; id++) - { - SLock *slckP = &(SLockArray[id]); - - S_INIT_LOCK(&(slckP->shlock)); - } - - /* - * Assign indexes for fixed spinlocks - */ - InitSpinLockIDs(); -} - -void -SpinAcquire(SPINLOCK lockid) -{ - SLock *slckP = &(SLockArray[lockid]); - - PRINT_SLDEBUG("SpinAcquire", lockid, slckP); - - /* - * Acquire the lock, then record that we have done so (for recovery in - * case of elog(ERROR) while holding the lock). Note we assume here - * that S_LOCK will not accept cancel/die interrupts once it has - * acquired the lock. However, interrupts should be accepted while - * waiting, if InterruptHoldoffCount is zero. - */ - S_LOCK(&(slckP->shlock)); - PROC_INCR_SLOCK(lockid); - - /* - * Lock out cancel/die interrupts until we exit the code section - * protected by the spinlock. This ensures that interrupts will not - * interfere with manipulations of data structures in shared memory. - */ - HOLD_INTERRUPTS(); - - PRINT_SLDEBUG("SpinAcquire/done", lockid, slckP); -} - -void -SpinRelease(SPINLOCK lockid) -{ - SLock *slckP = &(SLockArray[lockid]); - - PRINT_SLDEBUG("SpinRelease", lockid, slckP); - - /* - * Check that we are actually holding the lock we are releasing. This - * can be done only after MyProc has been initialized. - */ - Assert(!MyProc || MyProc->sLocks[lockid] > 0); - - /* - * Record that we no longer hold the spinlock, and release it. - */ - PROC_DECR_SLOCK(lockid); - S_UNLOCK(&(slckP->shlock)); - - /* - * Exit the interrupt holdoff entered in SpinAcquire(). - */ - RESUME_INTERRUPTS(); - - PRINT_SLDEBUG("SpinRelease/done", lockid, slckP); -} - -#else /* !HAS_TEST_AND_SET */ - -/* - * No TAS, so spinlocks are implemented using SysV semaphores. - * - * We support two slightly different APIs here: SpinAcquire/SpinRelease - * work with SPINLOCK integer indexes for the permanent spinlocks, which - * are all assumed to live in the first spinlock semaphore set. There - * is also an emulation of the s_lock.h TAS-spinlock macros; for that case, - * typedef slock_t stores the semId and sem number of the sema to use. - * The semas needed are created by CreateSpinlocks and doled out by - * s_init_lock_sema. - * - * Since many systems have a rather small SEMMSL limit on semas per set, - * we allocate the semaphores required in sets of SPINLOCKS_PER_SET semas. - * This value is deliberately made equal to PROC_NSEMS_PER_SET so that all - * sema sets allocated by Postgres will be the same size; that eases the - * semaphore-recycling logic in IpcSemaphoreCreate(). - * - * Note that the SpinLockIds array is not in shared memory; it is filled - * by the postmaster and then inherited through fork() by backends. This - * is OK because its contents do not change after shmem initialization. - */ - -#define SPINLOCKS_PER_SET PROC_NSEMS_PER_SET - -static IpcSemaphoreId *SpinLockIds = NULL; - -static int numSpinSets = 0; /* number of sema sets used */ -static int numSpinLocks = 0; /* total number of semas allocated */ -static int nextSpinLock = 0; /* next free spinlock index */ - -static void SpinFreeAllSemaphores(void); - -/* - * SLockShmemSize --- return shared-memory space needed - */ -int -SLockShmemSize(void) -{ - return 0; -} - -/* - * CreateSpinlocks --- create and initialize spinlocks during startup - */ -void -CreateSpinlocks(PGShmemHeader *seghdr) -{ - int i; - - if (SpinLockIds == NULL) - { - - /* - * Compute number of spinlocks needed. If this logic gets any - * more complicated, it should be distributed into the affected - * modules, similar to the way shmem space estimation is handled. - * - * For now, though, we just need the fixed spinlocks (MAX_SPINS), two - * spinlocks per shared disk buffer, and four spinlocks for XLOG. - */ - numSpinLocks = (int) MAX_SPINS + 2 * NBuffers + 4; - - /* might as well round up to a multiple of SPINLOCKS_PER_SET */ - numSpinSets = (numSpinLocks - 1) / SPINLOCKS_PER_SET + 1; - numSpinLocks = numSpinSets * SPINLOCKS_PER_SET; - - SpinLockIds = (IpcSemaphoreId *) - malloc(numSpinSets * sizeof(IpcSemaphoreId)); - Assert(SpinLockIds != NULL); - } - - for (i = 0; i < numSpinSets; i++) - SpinLockIds[i] = -1; - - /* - * Arrange to delete semas on exit --- set this up now so that we will - * clean up if allocation fails. We use our own freeproc, rather than - * IpcSemaphoreCreate's removeOnExit option, because we don't want to - * fill up the on_shmem_exit list with a separate entry for each - * semaphore set. - */ - on_shmem_exit(SpinFreeAllSemaphores, 0); - - /* Create sema sets and set all semas to count 1 */ - for (i = 0; i < numSpinSets; i++) - { - SpinLockIds[i] = IpcSemaphoreCreate(SPINLOCKS_PER_SET, - IPCProtection, - 1, - false); - } - - /* - * Assign indexes for fixed spinlocks - */ - Assert(MAX_SPINS <= SPINLOCKS_PER_SET); - InitSpinLockIDs(); - - /* Init counter for allocating dynamic spinlocks */ - nextSpinLock = MAX_SPINS; -} - -/* - * SpinFreeAllSemaphores - - * called at shmem_exit time, ie when exiting the postmaster or - * destroying shared state for a failed set of backends. - * Free up all the semaphores allocated for spinlocks. - */ -static void -SpinFreeAllSemaphores(void) -{ - int i; - - for (i = 0; i < numSpinSets; i++) - { - if (SpinLockIds[i] >= 0) - IpcSemaphoreKill(SpinLockIds[i]); - } - free(SpinLockIds); - SpinLockIds = NULL; -} - -/* - * SpinAcquire -- grab a fixed spinlock - * - * FAILS if the semaphore is corrupted. - */ -void -SpinAcquire(SPINLOCK lock) -{ - - /* - * See the TAS() version of this routine for primary commentary. - * - * NOTE we must pass interruptOK = false to IpcSemaphoreLock, to ensure - * that a cancel/die interrupt cannot prevent us from recording - * ownership of a lock we have just acquired. - */ - IpcSemaphoreLock(SpinLockIds[0], lock, false); - PROC_INCR_SLOCK(lock); - HOLD_INTERRUPTS(); -} - -/* - * SpinRelease -- release a fixed spin lock - * - * FAILS if the semaphore is corrupted - */ -void -SpinRelease(SPINLOCK lock) -{ - /* See the TAS() version of this routine for commentary */ -#ifdef USE_ASSERT_CHECKING - /* Check it's locked */ - int semval; - - semval = IpcSemaphoreGetValue(SpinLockIds[0], lock); - Assert(semval < 1); -#endif - Assert(!MyProc || MyProc->sLocks[lockid] > 0); - PROC_DECR_SLOCK(lock); - IpcSemaphoreUnlock(SpinLockIds[0], lock); - RESUME_INTERRUPTS(); -} - -/* - * s_lock.h hardware-spinlock emulation - */ - -void -s_init_lock_sema(volatile slock_t *lock) -{ - if (nextSpinLock >= numSpinLocks) - elog(FATAL, "s_init_lock_sema: not enough semaphores"); - lock->semId = SpinLockIds[nextSpinLock / SPINLOCKS_PER_SET]; - lock->sem = nextSpinLock % SPINLOCKS_PER_SET; - nextSpinLock++; -} - -void -s_unlock_sema(volatile slock_t *lock) -{ - IpcSemaphoreUnlock(lock->semId, lock->sem); -} - -bool -s_lock_free_sema(volatile slock_t *lock) -{ - return IpcSemaphoreGetValue(lock->semId, lock->sem) > 0; -} - -int -tas_sema(volatile slock_t *lock) -{ - /* Note that TAS macros return 0 if *success* */ - return !IpcSemaphoreTryLock(lock->semId, lock->sem); -} - -#endif /* !HAS_TEST_AND_SET */ |
