1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* spin.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* routines for managing spin locks
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2000-04-12 19:17:23 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.24 2000/04/12 17:15:37 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* POSTGRES has two kinds of locks: semaphores (which put the
|
|
|
|
* process to sleep) and spinlocks (which are supposed to be
|
|
|
|
* short term locks). Currently both are implemented as SysV
|
|
|
|
* semaphores, but presumably this can change if we move to
|
|
|
|
* a machine with a test-and-set (TAS) instruction. Its probably
|
|
|
|
* a good idea to think about (and allocate) short term and long
|
|
|
|
* term semaphores separately anyway.
|
|
|
|
*
|
|
|
|
* NOTE: These routines are not supposed to be widely used in Postgres.
|
1997-09-07 07:04:48 +02:00
|
|
|
* They are preserved solely for the purpose of porting Mark Sullivan's
|
|
|
|
* buffer manager to Postgres.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
#include <errno.h>
|
|
|
|
#include "postgres.h"
|
|
|
|
|
1997-01-14 02:53:11 +01:00
|
|
|
#ifndef HAS_TEST_AND_SET
|
|
|
|
#include <sys/sem.h>
|
|
|
|
#endif
|
|
|
|
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "storage/proc.h"
|
|
|
|
#include "storage/s_lock.h"
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* globals used in this file */
|
1997-09-08 04:41:22 +02:00
|
|
|
IpcSemaphoreId SpinLockId;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
#ifdef HAS_TEST_AND_SET
|
|
|
|
/* real spin lock implementations */
|
|
|
|
|
1999-10-06 23:58:18 +02:00
|
|
|
void
|
1996-07-09 08:22:35 +02:00
|
|
|
CreateSpinlocks(IPCKey key)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
/* the spin lock shared memory must have been created by now */
|
1999-10-06 23:58:18 +02:00
|
|
|
return;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1999-10-06 23:58:18 +02:00
|
|
|
void
|
|
|
|
InitSpinLocks(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
extern SPINLOCK ShmemLock;
|
1998-06-27 17:47:48 +02:00
|
|
|
extern SPINLOCK ShmemIndexLock;
|
1997-09-07 07:04:48 +02:00
|
|
|
extern SPINLOCK BufMgrLock;
|
|
|
|
extern SPINLOCK LockMgrLock;
|
|
|
|
extern SPINLOCK ProcStructLock;
|
|
|
|
extern SPINLOCK SInvalLock;
|
|
|
|
extern SPINLOCK OidGenLockId;
|
1999-10-06 23:58:18 +02:00
|
|
|
extern SPINLOCK XidGenLockId;
|
2000-04-12 19:17:23 +02:00
|
|
|
extern SPINLOCK ControlFileLockId;
|
|
|
|
|
1998-06-23 17:35:48 +02:00
|
|
|
#ifdef STABLE_MEMORY_STORAGE
|
1997-09-07 07:04:48 +02:00
|
|
|
extern SPINLOCK MMCacheLock;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1998-06-23 17:35:48 +02:00
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* These six spinlocks have fixed location is shmem */
|
|
|
|
ShmemLock = (SPINLOCK) SHMEMLOCKID;
|
1998-06-27 17:47:48 +02:00
|
|
|
ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID;
|
1997-09-07 07:04:48 +02:00
|
|
|
BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
|
|
|
|
LockMgrLock = (SPINLOCK) LOCKMGRLOCKID;
|
|
|
|
ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
|
|
|
|
SInvalLock = (SPINLOCK) SINVALLOCKID;
|
|
|
|
OidGenLockId = (SPINLOCK) OIDGENLOCKID;
|
1999-10-06 23:58:18 +02:00
|
|
|
XidGenLockId = (SPINLOCK) XIDGENLOCKID;
|
|
|
|
ControlFileLockId = (SPINLOCK) CNTLFILELOCKID;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-06-23 17:35:48 +02:00
|
|
|
#ifdef STABLE_MEMORY_STORAGE
|
1997-09-07 07:04:48 +02:00
|
|
|
MMCacheLock = (SPINLOCK) MMCACHELOCKID;
|
1998-06-23 17:35:48 +02:00
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-10-06 23:58:18 +02:00
|
|
|
return;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-18 16:21:02 +02:00
|
|
|
#ifdef LOCKDEBUG
|
1998-08-25 23:34:10 +02:00
|
|
|
#define PRINT_LOCK(LOCK) \
|
1998-09-01 06:40:42 +02:00
|
|
|
TPRINTF(TRACE_SPINLOCKS, \
|
1998-08-25 23:34:10 +02:00
|
|
|
"(locklock = %d, flag = %d, nshlocks = %d, shlock = %d, " \
|
|
|
|
"exlock =%d)\n", LOCK->locklock, \
|
|
|
|
LOCK->flag, LOCK->nshlocks, LOCK->shlock, \
|
|
|
|
LOCK->exlock)
|
1997-09-18 16:21:02 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* from ipc.c */
|
|
|
|
extern SLock *SLockArray;
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
void
|
1997-09-18 16:21:02 +02:00
|
|
|
SpinAcquire(SPINLOCK lockid)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-18 16:21:02 +02:00
|
|
|
SLock *slckP;
|
|
|
|
|
|
|
|
/* This used to be in ipc.c, but move here to reduce function calls */
|
|
|
|
slckP = &(SLockArray[lockid]);
|
|
|
|
#ifdef LOCKDEBUG
|
1998-08-25 23:34:10 +02:00
|
|
|
TPRINTF(TRACE_SPINLOCKS, "SpinAcquire: %d", lockid);
|
1997-09-18 16:21:02 +02:00
|
|
|
PRINT_LOCK(slckP);
|
|
|
|
#endif
|
|
|
|
ex_try_again:
|
|
|
|
S_LOCK(&(slckP->locklock));
|
|
|
|
switch (slckP->flag)
|
|
|
|
{
|
|
|
|
case NOLOCK:
|
|
|
|
slckP->flag = EXCLUSIVELOCK;
|
|
|
|
S_LOCK(&(slckP->exlock));
|
|
|
|
S_LOCK(&(slckP->shlock));
|
|
|
|
S_UNLOCK(&(slckP->locklock));
|
|
|
|
#ifdef LOCKDEBUG
|
1998-08-25 23:34:10 +02:00
|
|
|
TPRINTF(TRACE_SPINLOCKS, "OUT: ");
|
1997-09-18 16:21:02 +02:00
|
|
|
PRINT_LOCK(slckP);
|
|
|
|
#endif
|
1997-09-22 06:20:53 +02:00
|
|
|
break;
|
1997-09-18 16:21:02 +02:00
|
|
|
case SHAREDLOCK:
|
|
|
|
case EXCLUSIVELOCK:
|
|
|
|
S_UNLOCK(&(slckP->locklock));
|
|
|
|
S_LOCK(&(slckP->exlock));
|
|
|
|
S_UNLOCK(&(slckP->exlock));
|
|
|
|
goto ex_try_again;
|
|
|
|
}
|
|
|
|
PROC_INCR_SLOCK(lockid);
|
1998-08-25 23:34:10 +02:00
|
|
|
#ifdef LOCKDEBUG
|
|
|
|
TPRINTF(TRACE_SPINLOCKS, "SpinAcquire: got %d", lockid);
|
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1997-09-18 16:21:02 +02:00
|
|
|
SpinRelease(SPINLOCK lockid)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-18 16:21:02 +02:00
|
|
|
SLock *slckP;
|
|
|
|
|
|
|
|
/* This used to be in ipc.c, but move here to reduce function calls */
|
|
|
|
slckP = &(SLockArray[lockid]);
|
1998-08-25 23:34:10 +02:00
|
|
|
|
|
|
|
#ifdef USE_ASSERT_CHECKING
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1998-08-25 23:34:10 +02:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Check that we are actually holding the lock we are releasing. This
|
|
|
|
* can be done only after MyProc has been initialized.
|
1998-08-25 23:34:10 +02:00
|
|
|
*/
|
|
|
|
if (MyProc)
|
|
|
|
Assert(MyProc->sLocks[lockid] > 0);
|
|
|
|
Assert(slckP->flag != NOLOCK);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
PROC_DECR_SLOCK(lockid);
|
|
|
|
|
1997-09-18 16:21:02 +02:00
|
|
|
#ifdef LOCKDEBUG
|
1998-08-25 23:34:10 +02:00
|
|
|
TPRINTF("SpinRelease: %d\n", lockid);
|
1997-09-18 16:21:02 +02:00
|
|
|
PRINT_LOCK(slckP);
|
|
|
|
#endif
|
|
|
|
S_LOCK(&(slckP->locklock));
|
|
|
|
/* -------------
|
|
|
|
* give favor to read processes
|
|
|
|
* -------------
|
|
|
|
*/
|
|
|
|
slckP->flag = NOLOCK;
|
|
|
|
if (slckP->nshlocks > 0)
|
|
|
|
{
|
|
|
|
while (slckP->nshlocks > 0)
|
|
|
|
{
|
|
|
|
S_UNLOCK(&(slckP->shlock));
|
|
|
|
S_LOCK(&(slckP->comlock));
|
|
|
|
}
|
|
|
|
S_UNLOCK(&(slckP->shlock));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
S_UNLOCK(&(slckP->shlock));
|
|
|
|
S_UNLOCK(&(slckP->exlock));
|
|
|
|
S_UNLOCK(&(slckP->locklock));
|
|
|
|
#ifdef LOCKDEBUG
|
1998-08-25 23:34:10 +02:00
|
|
|
TPRINTF(TRACE_SPINLOCKS, "SpinRelease: released %d", lockid);
|
1997-09-18 16:21:02 +02:00
|
|
|
PRINT_LOCK(slckP);
|
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
#else /* HAS_TEST_AND_SET */
|
1997-08-19 23:40:56 +02:00
|
|
|
/* Spinlocks are implemented using SysV semaphores */
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool AttachSpinLocks(IPCKey key);
|
|
|
|
static bool SpinIsLocked(SPINLOCK lock);
|
1997-08-19 23:40:56 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* SpinAcquire -- try to grab a spinlock
|
|
|
|
*
|
|
|
|
* FAILS if the semaphore is corrupted.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SpinAcquire(SPINLOCK lock)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
IpcSemaphoreLock(SpinLockId, lock, IpcExclusiveLock);
|
|
|
|
PROC_INCR_SLOCK(lock);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SpinRelease -- release a spin lock
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
* FAILS if the semaphore is corrupted
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SpinRelease(SPINLOCK lock)
|
|
|
|
{
|
2000-04-12 06:58:09 +02:00
|
|
|
Assert(SpinIsLocked(lock));
|
1996-07-09 08:22:35 +02:00
|
|
|
PROC_DECR_SLOCK(lock);
|
1997-09-07 07:04:48 +02:00
|
|
|
IpcSemaphoreUnlock(SpinLockId, lock, IpcExclusiveLock);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool
|
1996-07-09 08:22:35 +02:00
|
|
|
SpinIsLocked(SPINLOCK lock)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int semval;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
semval = IpcSemaphoreGetValue(SpinLockId, lock);
|
1998-09-01 05:29:17 +02:00
|
|
|
return semval < IpcSemaphoreDefaultStartValue;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CreateSpinlocks -- Create a sysV semaphore array for
|
1997-09-07 07:04:48 +02:00
|
|
|
* the spinlocks
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
1999-10-06 23:58:18 +02:00
|
|
|
void
|
1996-07-09 08:22:35 +02:00
|
|
|
CreateSpinlocks(IPCKey key)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-10-06 23:58:18 +02:00
|
|
|
SpinLockId = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
|
2000-04-12 19:17:23 +02:00
|
|
|
IpcSemaphoreDefaultStartValue, 1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-10-06 23:58:18 +02:00
|
|
|
if (SpinLockId <= 0)
|
|
|
|
elog(STOP, "CreateSpinlocks: cannot create spin locks");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-10-06 23:58:18 +02:00
|
|
|
return;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* InitSpinLocks -- Spinlock bootstrapping
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
* We need several spinlocks for bootstrapping:
|
1998-06-27 17:47:48 +02:00
|
|
|
* ShmemIndexLock (for the shmem index table) and
|
1996-07-09 08:22:35 +02:00
|
|
|
* ShmemLock (for the shmem allocator), BufMgrLock (for buffer
|
|
|
|
* pool exclusive access), LockMgrLock (for the lock table), and
|
|
|
|
* ProcStructLock (a spin lock for the shared process structure).
|
|
|
|
* If there's a Sony WORM drive attached, we also have a spinlock
|
|
|
|
* (SJCacheLock) for it. Same story for the main memory storage mgr.
|
|
|
|
*
|
|
|
|
*/
|
1999-10-06 23:58:18 +02:00
|
|
|
void
|
|
|
|
InitSpinLocks(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
extern SPINLOCK ShmemLock;
|
1998-06-27 17:47:48 +02:00
|
|
|
extern SPINLOCK ShmemIndexLock;
|
1997-09-07 07:04:48 +02:00
|
|
|
extern SPINLOCK BufMgrLock;
|
|
|
|
extern SPINLOCK LockMgrLock;
|
|
|
|
extern SPINLOCK ProcStructLock;
|
|
|
|
extern SPINLOCK SInvalLock;
|
|
|
|
extern SPINLOCK OidGenLockId;
|
1999-10-06 23:58:18 +02:00
|
|
|
extern SPINLOCK XidGenLockId;
|
2000-04-12 19:17:23 +02:00
|
|
|
extern SPINLOCK ControlFileLockId;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-06-23 17:35:48 +02:00
|
|
|
#ifdef STABLE_MEMORY_STORAGE
|
1997-09-07 07:04:48 +02:00
|
|
|
extern SPINLOCK MMCacheLock;
|
|
|
|
|
1998-06-23 17:35:48 +02:00
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* These five (or six) spinlocks have fixed location is shmem */
|
|
|
|
ShmemLock = (SPINLOCK) SHMEMLOCKID;
|
1998-06-27 17:47:48 +02:00
|
|
|
ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID;
|
1997-09-07 07:04:48 +02:00
|
|
|
BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
|
|
|
|
LockMgrLock = (SPINLOCK) LOCKMGRLOCKID;
|
|
|
|
ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
|
|
|
|
SInvalLock = (SPINLOCK) SINVALLOCKID;
|
|
|
|
OidGenLockId = (SPINLOCK) OIDGENLOCKID;
|
1999-10-06 23:58:18 +02:00
|
|
|
XidGenLockId = (SPINLOCK) XIDGENLOCKID;
|
|
|
|
ControlFileLockId = (SPINLOCK) CNTLFILELOCKID;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-06-23 17:35:48 +02:00
|
|
|
#ifdef STABLE_MEMORY_STORAGE
|
1997-09-07 07:04:48 +02:00
|
|
|
MMCacheLock = (SPINLOCK) MMCACHELOCKID;
|
1998-06-23 17:35:48 +02:00
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-10-06 23:58:18 +02:00
|
|
|
return;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
#endif /* HAS_TEST_AND_SET */
|