diff --git a/src/backend/access/common/heapvalid.c b/src/backend/access/common/heapvalid.c index da2e93a30b..22d62afcd3 100644 --- a/src/backend/access/common/heapvalid.c +++ b/src/backend/access/common/heapvalid.c @@ -7,143 +7,15 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/common/Attic/heapvalid.c,v 1.19 1997/09/12 04:07:09 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/common/Attic/heapvalid.c,v 1.20 1997/09/18 14:19:27 momjian Exp $ * *------------------------------------------------------------------------- */ #include <postgres.h> -#include <fmgr.h> #include <access/heapam.h> -#include <access/valid.h> #include <access/xact.h> -#include <storage/bufpage.h> -#include <utils/rel.h> -#include <utils/tqual.h> -#include <storage/bufmgr.h> -#include <utils/builtins.h> - -/* ---------------- - * heap_keytest - * - * Test a heap tuple with respect to a scan key. - * ---------------- - */ -bool -heap_keytest(HeapTuple t, - TupleDesc tupdesc, - int nkeys, - ScanKey keys) -{ - bool isnull; - Datum atp; - int test; - - for (; nkeys--; keys++) - { - atp = heap_getattr(t, InvalidBuffer, - keys->sk_attno, - tupdesc, - &isnull); - - if (isnull) - /* XXX eventually should check if SK_ISNULL */ - return false; - - if (keys->sk_flags & SK_ISNULL) - { - return (false); - } - - if (keys->sk_func == (func_ptr) oideq) /* optimization */ - test = (keys->sk_argument == atp); - else if (keys->sk_flags & SK_COMMUTE) - test = (long) FMGR_PTR2(keys->sk_func, keys->sk_procedure, - keys->sk_argument, atp); - else - test = (long) FMGR_PTR2(keys->sk_func, keys->sk_procedure, - atp, keys->sk_argument); - - if (!test == !(keys->sk_flags & SK_NEGATE)) - return false; - } - - return true; -} - -/* ---------------- - * heap_tuple_satisfies - * - * Returns a valid HeapTuple if it satisfies the timequal and keytest. - * Returns NULL otherwise. Used to be heap_satisifies (sic) which - * returned a boolean. It now returns a tuple so that we can avoid doing two - * PageGetItem's per tuple. - * - * Complete check of validity including LP_CTUP and keytest. - * This should perhaps be combined with valid somehow in the - * future. (Also, additional rule tests/time range tests.) - * - * on 8/21/92 mao says: i rearranged the tests here to do keytest before - * SatisfiesTimeQual. profiling indicated that even for vacuumed relations, - * time qual checking was more expensive than key testing. time qual is - * least likely to fail, too. we should really add the time qual test to - * the restriction and optimize it in the normal way. this has interactions - * with joey's expensive function work. - * ---------------- - */ -HeapTuple -heap_tuple_satisfies(ItemId itemId, - Relation relation, - Buffer buffer, - PageHeader disk_page, - TimeQual qual, - int nKeys, - ScanKey key) -{ - HeapTuple tuple, - result; - bool res; - TransactionId old_tmin, - old_tmax; - - if (!ItemIdIsUsed(itemId)) - return NULL; - - tuple = (HeapTuple) PageGetItem((Page) disk_page, itemId); - - if (key != NULL) - res = heap_keytest(tuple, RelationGetTupleDescriptor(relation), - nKeys, key); - else - res = TRUE; - - result = (HeapTuple) NULL; - if (res) - { - if (relation->rd_rel->relkind == RELKIND_UNCATALOGED) - { - result = tuple; - } - else - { - old_tmin = tuple->t_tmin; - old_tmax = tuple->t_tmax; - res = HeapTupleSatisfiesTimeQual(tuple, qual); - if (tuple->t_tmin != old_tmin || - tuple->t_tmax != old_tmax) - { - SetBufferCommitInfoNeedsSave(buffer); - } - if (res) - { - result = tuple; - } - } - } - - return result; -} /* * TupleUpdatedByCurXactAndCmd() -- Returns true if this tuple has diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 19bdf5b34c..2537e7e777 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.19 1997/09/08 21:40:57 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.20 1997/09/18 14:19:30 momjian Exp $ * * * INTERFACE ROUTINES @@ -429,8 +429,9 @@ heapgettup(Relation relation, * if current tuple qualifies, return it. * ---------------- */ - if ((rtup = heap_tuple_satisfies(lpp, relation, *b, (PageHeader) dp, - timeQual, nkeys, key)) != NULL) + HeapTupleSatisfies(lpp, relation, *b, (PageHeader) dp, + timeQual, nkeys, key, rtup); + if (rtup != NULL) { ItemPointer iptr = &(rtup->t_ctid); @@ -1092,8 +1093,8 @@ heap_fetch(Relation relation, * ---------------- */ - tuple = heap_tuple_satisfies(lp, relation, buffer, dp, - timeQual, 0, (ScanKey) NULL); + HeapTupleSatisfies(lp, relation, buffer, dp, + timeQual, 0, (ScanKey) NULL, tuple); if (tuple == NULL) { @@ -1257,8 +1258,9 @@ heap_delete(Relation relation, ItemPointer tid) * check that we're deleteing a valid item * ---------------- */ - if (!(tp = heap_tuple_satisfies(lp, relation, b, dp, - NowTimeQual, 0, (ScanKey) NULL))) + HeapTupleSatisfies(lp, relation, b, dp, + NowTimeQual, 0, (ScanKey) NULL, tp); + if (!tp) { /* XXX call something else */ @@ -1317,7 +1319,8 @@ heap_replace(Relation relation, ItemPointer otid, HeapTuple tup) HeapTuple tp; Page dp; Buffer buffer; - + HeapTuple tuple; + /* ---------------- * increment access statistics * ---------------- @@ -1388,13 +1391,15 @@ heap_replace(Relation relation, ItemPointer otid, HeapTuple tup) * xact, we only want to flag the 'non-functional' NOTICE. -mer * ---------------- */ - if (!heap_tuple_satisfies(lp, - relation, - buffer, - (PageHeader) dp, - NowTimeQual, - 0, - (ScanKey) NULL)) + HeapTupleSatisfies(lp, + relation, + buffer, + (PageHeader) dp, + NowTimeQual, + 0, + (ScanKey) NULL, + tuple); + if (!tuple) { ReleaseBuffer(buffer); elog(WARN, "heap_replace: (am)invalid otid"); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 58d93a0799..5aa70f52cb 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -792,8 +792,9 @@ GetTupleForTrigger(Relation relation, ItemPointer tid, bool before) return (NULL); } - if (!(tuple = heap_tuple_satisfies(lp, relation, b, dp, - NowTimeQual, 0, (ScanKey) NULL))) + HeapTupleSatisfies(lp, relation, b, dp, + NowTimeQual, 0, (ScanKey) NULL, tuple); + if (!tuple) { ReleaseBuffer(b); elog(WARN, "GetTupleForTrigger: (am)invalid tid"); diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index a0f45eca09..9b2f7a237c 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.12 1997/09/08 02:28:27 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.13 1997/09/18 14:19:58 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -26,6 +26,7 @@ #include "storage/fd.h" #include "storage/ipc.h" +#include "storage/s_lock.h" #include "storage/shmem.h" #include "storage/spin.h" #include "storage/smgr.h" diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 7acc70342c..0fc48c2052 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.23 1997/09/08 21:46:50 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.24 1997/09/18 14:20:00 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -56,6 +56,7 @@ #include "storage/fd.h" #include "storage/ipc.h" +#include "storage/s_lock.h" #include "storage/shmem.h" #include "storage/spin.h" #include "storage/smgr.h" diff --git a/src/backend/storage/ipc/Makefile b/src/backend/storage/ipc/Makefile index 821bf688cf..e5517135d3 100644 --- a/src/backend/storage/ipc/Makefile +++ b/src/backend/storage/ipc/Makefile @@ -4,7 +4,7 @@ # Makefile for storage/ipc # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/storage/ipc/Makefile,v 1.3 1996/11/09 06:21:47 momjian Exp $ +# $Header: /cvsroot/pgsql/src/backend/storage/ipc/Makefile,v 1.4 1997/09/18 14:20:08 momjian Exp $ # #------------------------------------------------------------------------- @@ -17,7 +17,7 @@ INCLUDE_OPT = -I../.. \ CFLAGS+=$(INCLUDE_OPT) -OBJS = ipc.o ipci.o s_lock.o shmem.o shmqueue.o sinval.o \ +OBJS = ipc.o ipci.o shmem.o shmqueue.o sinval.o \ sinvaladt.o spin.o all: SUBSYS.o diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c index 856ca13508..2ef50c5c91 100644 --- a/src/backend/storage/ipc/ipc.c +++ b/src/backend/storage/ipc/ipc.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.14 1997/09/08 21:46:59 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.15 1997/09/18 14:20:14 momjian Exp $ * * NOTES * @@ -33,6 +33,7 @@ #include "postgres.h" #include "storage/ipc.h" +#include "storage/s_lock.h" /* In Ultrix, sem.h and shm.h must be included AFTER ipc.h */ #include <sys/sem.h> #include <sys/shm.h> @@ -615,7 +616,10 @@ IpcMemoryKill(IpcMemoryKey memKey) * supply of locks. * ------------------ */ -static SLock *SLockArray = NULL; + +/* used in spin.c */ +SLock *SLockArray = NULL; + static SLock **FreeSLockPP; static int *UnusedSLockIP; static slock_t *SLockMemoryLock; @@ -676,92 +680,13 @@ AttachSLockMemory(IPCKey key) return; } - -#ifdef LOCKDEBUG -#define PRINT_LOCK(LOCK) printf("(locklock = %d, flag = %d, nshlocks = %d, \ -shlock = %d, exlock =%d)\n", LOCK->locklock, \ - LOCK->flag, LOCK->nshlocks, LOCK->shlock, \ - LOCK->exlock) -#endif - -void -ExclusiveLock(int lockid) -{ - SLock *slckP; - - slckP = &(SLockArray[lockid]); -#ifdef LOCKDEBUG - printf("ExclusiveLock(%d)\n", lockid); - printf("IN: "); - 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 - printf("OUT: "); - PRINT_LOCK(slckP); -#endif - return; - case SHAREDLOCK: - case EXCLUSIVELOCK: - S_UNLOCK(&(slckP->locklock)); - S_LOCK(&(slckP->exlock)); - S_UNLOCK(&(slckP->exlock)); - goto ex_try_again; - } -} - -void -ExclusiveUnlock(int lockid) -{ - SLock *slckP; - - slckP = &(SLockArray[lockid]); -#ifdef LOCKDEBUG - printf("ExclusiveUnlock(%d)\n", lockid); - printf("IN: "); - 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 - printf("OUT: "); - PRINT_LOCK(slckP); -#endif - return; -} - +#ifdef NOT_USED bool LockIsFree(int lockid) { return (SLockArray[lockid].flag == NOLOCK); } +#endif #endif /* HAS_TEST_AND_SET */ diff --git a/src/backend/storage/ipc/s_lock.c b/src/backend/storage/ipc/s_lock.c deleted file mode 100644 index 82551f8b96..0000000000 --- a/src/backend/storage/ipc/s_lock.c +++ /dev/null @@ -1,525 +0,0 @@ -/*------------------------------------------------------------------------- - * - * s_lock.c-- - * This file contains the implementation (if any) for spinlocks. - * - * Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/s_lock.c,v 1.24 1997/09/08 21:47:04 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -/* - * DESCRIPTION - * The following code fragment should be written (in assembly - * language) on machines that have a native test-and-set instruction: - * - * void - * S_LOCK(char_address) - * char *char_address; - * { - * while (test_and_set(char_address)) - * ; - * } - * - * If this is not done, POSTGRES will default to using System V - * semaphores (and take a large performance hit -- around 40% of - * its time on a DS5000/240 is spent in semop(3)...). - * - * NOTES - * AIX has a test-and-set but the recommended interface is the cs(3) - * system call. This provides an 8-instruction (plus system call - * overhead) uninterruptible compare-and-set operation. True - * spinlocks might be faster but using cs(3) still speeds up the - * regression test suite by about 25%. I don't have an assembler - * manual for POWER in any case. - * - */ -#include "postgres.h" - -#include "storage/ipc.h" - - -#if defined(HAS_TEST_AND_SET) - -#if defined (nextstep) -/* - * NEXTSTEP (mach) - * slock_t is defined as a struct mutex. - */ -void -S_LOCK(slock_t *lock) -{ - mutex_lock(lock); -} -void -S_UNLOCK(slock_t *lock) -{ - mutex_unlock(lock); -} -void -S_INIT_LOCK(slock_t *lock) -{ - mutex_init(lock); -} - - /* S_LOCK_FREE should return 1 if lock is free; 0 if lock is locked */ -int -S_LOCK_FREE(slock_t *lock) -{ -/* For Mach, we have to delve inside the entrails of `struct mutex'. Ick! */ - return (lock->lock == 0); -} - -#endif /* next */ - - - -#if defined(irix5) -/* - * SGI IRIX 5 - * slock_t is defined as a struct abilock_t, which has a single unsigned long - * member. - * - * This stuff may be supplemented in the future with Masato Kataoka's MIPS-II - * assembly from his NECEWS SVR4 port, but we probably ought to retain this - * for the R3000 chips out there. - */ -void -S_LOCK(slock_t *lock) -{ - /* spin_lock(lock); */ - while (!acquire_lock(lock)) - ; -} - -void -S_UNLOCK(slock_t *lock) -{ - release_lock(lock); -} - -void -S_INIT_LOCK(slock_t *lock) -{ - init_lock(lock); -} - -/* S_LOCK_FREE should return 1 if lock is free; 0 if lock is locked */ -int -S_LOCK_FREE(slock_t *lock) -{ - return (stat_lock(lock) == UNLOCKED); -} - -#endif /* irix5 */ - - -/* - * OSF/1 (Alpha AXP) - * - * Note that slock_t on the Alpha AXP is msemaphore instead of char - * (see storage/ipc.h). - */ - -#if defined(__alpha__) || defined(__alpha) - -void -S_LOCK(slock_t *lock) -{ - while (msem_lock(lock, MSEM_IF_NOWAIT) < 0) - ; -} - -void -S_UNLOCK(slock_t *lock) -{ - msem_unlock(lock, 0); -} - -void -S_INIT_LOCK(slock_t *lock) -{ - msem_init(lock, MSEM_UNLOCKED); -} - -int -S_LOCK_FREE(slock_t *lock) -{ - return (lock->msem_state ? 0 : 1); -} - -#endif /* alpha */ - -/* - * Solaris 2 - */ - -#if defined(i386_solaris) || \ - defined(sparc_solaris) -/* for xxxxx_solaris, this is defined in port/.../tas.s */ - -static int tas(slock_t *lock); - -void -S_LOCK(slock_t *lock) -{ - while (tas(lock)) - ; -} - -void -S_UNLOCK(slock_t *lock) -{ - *lock = 0; -} - -void -S_INIT_LOCK(slock_t *lock) -{ - S_UNLOCK(lock); -} - -#endif /* i86pc_solaris || sparc_solaris */ - -/* - * AIX (POWER) - * - * Note that slock_t on POWER/POWER2/PowerPC is int instead of char - * (see storage/ipc.h). - */ - -#if defined(aix) - -void -S_LOCK(slock_t *lock) -{ - while (cs((int *) lock, 0, 1)) - ; -} - -void -S_UNLOCK(slock_t *lock) -{ - *lock = 0; -} - -void -S_INIT_LOCK(slock_t *lock) -{ - S_UNLOCK(lock); -} - -#endif /* aix */ - -/* - * HP-UX (PA-RISC) - * - * Note that slock_t on PA-RISC is a structure instead of char - * (see storage/ipc.h). - */ - -#if defined(hpux) - -/* -* a "set" slock_t has a single word cleared. a "clear" slock_t has -* all words set to non-zero. -*/ -static slock_t clear_lock = {-1, -1, -1, -1}; - -static int tas(slock_t *lock); - -void -S_LOCK(slock_t *lock) -{ - while (tas(lock)) - ; -} - -void -S_UNLOCK(slock_t *lock) -{ - *lock = clear_lock; /* struct assignment */ -} - -void -S_INIT_LOCK(slock_t *lock) -{ - S_UNLOCK(lock); -} - -int -S_LOCK_FREE(slock_t *lock) -{ - register int *lock_word = (int *) (((long) lock + 15) & ~15); - - return (*lock_word != 0); -} - -#endif /* hpux */ - -/* - * sun3 - */ - -#if defined(sun3) - -static int tas(slock_t *lock); - -void -S_LOCK(slock_t *lock) -{ - while (tas(lock)); -} - -void -S_UNLOCK(slock_t *lock) -{ - *lock = 0; -} - -void -S_INIT_LOCK(slock_t *lock) -{ - S_UNLOCK(lock); -} - -static int -tas_dummy() -{ - asm("LLA0:"); - asm(" .data"); - asm(" .text"); - asm("|#PROC# 04"); - asm(" .globl _tas"); - asm("_tas:"); - asm("|#PROLOGUE# 1"); - asm(" movel sp@(0x4),a0"); - asm(" tas a0@"); - asm(" beq LLA1"); - asm(" moveq #-128,d0"); - asm(" rts"); - asm("LLA1:"); - asm(" moveq #0,d0"); - asm(" rts"); - asm(" .data"); -} - -#endif /* sun3 */ - -/* - * sparc machines - */ - -#if defined(NEED_SPARC_TAS_ASM) - -/* if we're using -ansi w/ gcc, use __asm__ instead of asm */ -#if defined(__STRICT_ANSI__) -#define asm(x) __asm__(x) -#endif - -static int tas(slock_t *lock); - -static int -tas_dummy() -{ - asm(".seg \"data\""); - asm(".seg \"text\""); - asm(".global _tas"); - asm("_tas:"); - - /* - * Sparc atomic test and set (sparc calls it "atomic load-store") - */ - - asm("ldstub [%r8], %r8"); - - /* - * Did test and set actually do the set? - */ - - asm("tst %r8"); - - asm("be,a ReturnZero"); - - /* - * otherwise, just return. - */ - - asm("clr %r8"); - asm("mov 0x1, %r8"); - asm("ReturnZero:"); - asm("retl"); - asm("nop"); -} - -void -S_LOCK(unsigned char *addr) -{ - while (tas(addr)); -} - - -/* - * addr should be as in the above S_LOCK routine - */ -void -S_UNLOCK(unsigned char *addr) -{ - *addr = 0; -} - -void -S_INIT_LOCK(unsigned char *addr) -{ - *addr = 0; -} - -#endif /* NEED_SPARC_TAS_ASM */ - -/* - * i386 based things - */ - -#if defined(NEED_I386_TAS_ASM) - -void -S_LOCK(slock_t *lock) -{ - slock_t res; - - do - { -__asm__("xchgb %0,%1": "=q"(res), "=m"(*lock):"0"(0x1)); - } while (res != 0); -} - -void -S_UNLOCK(slock_t *lock) -{ - *lock = 0; -} - -void -S_INIT_LOCK(slock_t *lock) -{ - S_UNLOCK(lock); -} - -#endif /* NEED_I386_TAS_ASM */ - - -#if defined(__alpha__) && defined(linux) - -void -S_LOCK(slock_t *lock) -{ - slock_t res; - - do - { -__asm__(" ldq $0, %0 \n\ - bne $0, already_set \n\ - ldq_l $0, %0 \n\ - bne $0, already_set \n\ - or $31, 1, $0 \n\ - stq_c $0, %0 \n\ - beq $0, stqc_fail \n\ - success: bis $31, $31, %1 \n\ - mb \n\ - jmp $31, end \n\ - stqc_fail: or $31, 1, $0 \n\ - already_set: bis $0, $0, %1 \n\ - end: nop ": "=m"(*lock), "=r"(res): :"0"); - } while (res != 0); -} - -void -S_UNLOCK(slock_t *lock) -{ - __asm__("mb"); - *lock = 0; -} - -void -S_INIT_LOCK(slock_t *lock) -{ - S_UNLOCK(lock); -} - -#endif /* defined(__alpha__) && defined(linux) */ - -#if defined(linux) && defined(sparc) - -void -S_LOCK(slock_t *lock) -{ - slock_t res; - - do - { - __asm__("ldstub [%1], %0" -: "=&r"(res) -: "r"(lock)); - } while (!res != 0); -} - -void -S_UNLOCK(slock_t *lock) -{ - *lock = 0; -} - -void -S_INIT_LOCK(slock_t *lock) -{ - S_UNLOCK(lock); -} - -#endif /* defined(linux) && defined(sparc) */ - -#if defined(linux) && defined(PPC) - -static int -tas_dummy() -{ - __asm__(" \n\ -tas: \n\ - lwarx 5,0,3 \n\ - cmpwi 5,0 \n\ - bne fail \n\ - addi 5,5,1 \n\ - stwcx. 5,0,3 \n\ - beq success \n\ -fail: li 3,1 \n\ - blr \n\ -success: \n\ - li 3,0 \n\ - blr \n\ - "); -} - -void -S_LOCK(slock_t *lock) -{ - while (tas(lock)) - ; -} - -void -S_UNLOCK(slock_t *lock) -{ - *lock = 0; -} - -void -S_INIT_LOCK(slock_t *lock) -{ - S_UNLOCK(lock); -} - -#endif /* defined(linux) && defined(PPC) */ - -#endif /* HAS_TEST_AND_SET */ diff --git a/src/backend/storage/ipc/spin.c b/src/backend/storage/ipc/spin.c index 3443c2db95..5300e2ecd4 100644 --- a/src/backend/storage/ipc/spin.c +++ b/src/backend/storage/ipc/spin.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.8 1997/09/08 02:29:02 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.9 1997/09/18 14:20:18 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -27,6 +27,7 @@ #include <errno.h> #include "postgres.h" #include "storage/ipc.h" +#include "storage/s_lock.h" #include "storage/shmem.h" #include "storage/spin.h" #include "storage/proc.h" @@ -80,18 +81,91 @@ InitSpinLocks(int init, IPCKey key) return (TRUE); } +#ifdef LOCKDEBUG +#define PRINT_LOCK(LOCK) printf("(locklock = %d, flag = %d, nshlocks = %d, \ +shlock = %d, exlock =%d)\n", LOCK->locklock, \ + LOCK->flag, LOCK->nshlocks, LOCK->shlock, \ + LOCK->exlock) +#endif + +/* from ipc.c */ +extern SLock *SLockArray; + void -SpinAcquire(SPINLOCK lock) +SpinAcquire(SPINLOCK lockid) { - ExclusiveLock(lock); - PROC_INCR_SLOCK(lock); + SLock *slckP; + + /* This used to be in ipc.c, but move here to reduce function calls */ + slckP = &(SLockArray[lockid]); +#ifdef LOCKDEBUG + printf("SpinAcquire(%d)\n", lockid); + printf("IN: "); + 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 + printf("OUT: "); + PRINT_LOCK(slckP); +#endif + return; + case SHAREDLOCK: + case EXCLUSIVELOCK: + S_UNLOCK(&(slckP->locklock)); + S_LOCK(&(slckP->exlock)); + S_UNLOCK(&(slckP->exlock)); + goto ex_try_again; + } + PROC_INCR_SLOCK(lockid); } void -SpinRelease(SPINLOCK lock) +SpinRelease(SPINLOCK lockid) { - PROC_DECR_SLOCK(lock); - ExclusiveUnlock(lock); + SLock *slckP; + + PROC_DECR_SLOCK(lockid); + + /* This used to be in ipc.c, but move here to reduce function calls */ + slckP = &(SLockArray[lockid]); +#ifdef LOCKDEBUG + printf("SpinRelease(%d)\n", lockid); + printf("IN: "); + 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 + printf("OUT: "); + PRINT_LOCK(slckP); +#endif } #else /* HAS_TEST_AND_SET */ diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index dc6b7bd466..c8abb92e46 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.14 1997/09/08 21:47:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.15 1997/09/18 14:20:22 momjian Exp $ * * NOTES * Outside modules can create a lock table and acquire/release @@ -51,7 +51,7 @@ static int WaitOnLock(LOCKTAB *ltable, LockTableId tableId, LOCK *lock, LOCKT lockt); - + /*#define LOCK_MGR_DEBUG*/ #ifndef LOCK_MGR_DEBUG @@ -451,6 +451,7 @@ LockTabRename(LockTableId tableId) * DZ - 4 Oct 1996 #endif */ + bool LockAcquire(LockTableId tableId, LOCKTAG *lockName, LOCKT lockt) { @@ -540,7 +541,7 @@ LockAcquire(LockTableId tableId, LOCKTAG *lockName, LOCKT lockt) * word alignment and ensures hashing consistency). * ------------------ */ - memset(&item, 0, XID_TAGSIZE); + memset(&item, 0, XID_TAGSIZE); /* must clear padding, needed */ TransactionIdStore(myXid, &item.tag.xid); item.tag.lock = MAKE_OFFSET(lock); #if 0 diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index c74565ddfa..f0d41a7116 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.14 1997/09/12 04:08:28 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.15 1997/09/18 14:20:29 momjian Exp $ * * Notes: * XXX This needs to use exception.h to handle recovery when @@ -839,16 +839,20 @@ SearchSysCache(struct catcache * cache, elt; elt = DLGetSucc(elt)) { + bool res; + ct = (CatCTup *) DLE_VAL(elt); /* ---------------- * see if the cached tuple matches our key. * (should we be worried about time ranges? -cim 10/2/90) * ---------------- */ - if (heap_keytest(ct->ct_tup, + HeapKeyTest(ct->ct_tup, cache->cc_tupdesc, cache->cc_nkeys, - cache->cc_skey)) + cache->cc_skey, + res); + if (res) break; } diff --git a/src/include/access/valid.h b/src/include/access/valid.h index 7b047d66d6..a37258c62a 100644 --- a/src/include/access/valid.h +++ b/src/include/access/valid.h @@ -6,31 +6,156 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: valid.h,v 1.7 1997/09/08 21:51:05 momjian Exp $ + * $Id: valid.h,v 1.8 1997/09/18 14:20:45 momjian Exp $ * *------------------------------------------------------------------------- */ #ifndef VALID_H #define VALID_H +#include <fmgr.h> +#include <access/heapam.h> +#include <access/valid.h> #include <utils/tqual.h> +#include <storage/bufmgr.h> #include <storage/bufpage.h> #include <utils/rel.h> +#include <utils/builtins.h> /* ---------------- * extern decl's * ---------------- */ -extern bool -heap_keytest(HeapTuple t, TupleDesc tupdesc, - int nkeys, ScanKey keys); +/* ---------------- + * HeapKeyTest + * + * Test a heap tuple with respect to a scan key. + * ---------------- + */ -extern HeapTuple -heap_tuple_satisfies(ItemId itemId, Relation relation, - Buffer buffer, PageHeader disk_page, - TimeQual qual, int nKeys, - ScanKey key); +#define HeapKeyTest(tuple, \ + tupdesc, \ + nkeys, \ + keys, \ + result) \ +do \ +{ \ +/* We use underscores to protect the variable passed in as parameters */ \ +/* We use two underscore here because this macro is included in the \ + macro below */ \ + bool __isnull; \ + Datum __atp; \ + int __test; \ + int __cur_nkeys = (nkeys); \ + ScanKey __cur_keys = (keys); \ + \ + (result) = true; /* may change */ \ + for (; __cur_nkeys--; __cur_keys++) \ + { \ + __atp = heap_getattr((tuple), InvalidBuffer, \ + __cur_keys->sk_attno, \ + (tupdesc), \ + &__isnull); \ + \ + if (__isnull) \ + { \ + /* XXX eventually should check if SK_ISNULL */ \ + (result) = false; \ + break; \ + } \ + \ + if (__cur_keys->sk_flags & SK_ISNULL) \ + { \ + (result) = false; \ + break; \ + } \ + \ + if (__cur_keys->sk_func == (func_ptr) oideq) /* optimization */ \ + __test = (__cur_keys->sk_argument == __atp); \ + else if (__cur_keys->sk_flags & SK_COMMUTE) \ + __test = (long) FMGR_PTR2(__cur_keys->sk_func, __cur_keys->sk_procedure, \ + __cur_keys->sk_argument, __atp); \ + else \ + __test = (long) FMGR_PTR2(__cur_keys->sk_func, __cur_keys->sk_procedure, \ + __atp, __cur_keys->sk_argument); \ + \ + if (!__test == !(__cur_keys->sk_flags & SK_NEGATE)) \ + { \ + /* XXX eventually should check if SK_ISNULL */ \ + (result) = false; \ + break; \ + } \ + } \ +} while (0) + +/* ---------------- + * HeapTupleSatisfies + * + * Returns a valid HeapTuple if it satisfies the timequal and keytest. + * Returns NULL otherwise. Used to be heap_satisifies (sic) which + * returned a boolean. It now returns a tuple so that we can avoid doing two + * PageGetItem's per tuple. + * + * Complete check of validity including LP_CTUP and keytest. + * This should perhaps be combined with valid somehow in the + * future. (Also, additional rule tests/time range tests.) + * + * on 8/21/92 mao says: i rearranged the tests here to do keytest before + * SatisfiesTimeQual. profiling indicated that even for vacuumed relations, + * time qual checking was more expensive than key testing. time qual is + * least likely to fail, too. we should really add the time qual test to + * the restriction and optimize it in the normal way. this has interactions + * with joey's expensive function work. + * ---------------- + */ +#define HeapTupleSatisfies(itemId, \ + relation, \ + buffer, \ + disk_page, \ + qual, \ + nKeys, \ + key, \ + result) \ +do \ +{ \ +/* We use underscores to protect the variable passed in as parameters */ \ + HeapTuple _tuple; \ + bool _res; \ + TransactionId _old_tmin, \ + _old_tmax; \ + \ + if (!ItemIdIsUsed(itemId)) \ + (result) = (HeapTuple) NULL; \ + else \ + { \ + _tuple = (HeapTuple) PageGetItem((Page) (disk_page), (itemId)); \ + \ + if ((key) != NULL) \ + HeapKeyTest(_tuple, RelationGetTupleDescriptor(relation), \ + (nKeys), (key), _res); \ + else \ + _res = TRUE; \ + \ + (result) = (HeapTuple) NULL; \ + if (_res) \ + { \ + if ((relation)->rd_rel->relkind == RELKIND_UNCATALOGED) \ + (result) = _tuple; \ + else \ + { \ + _old_tmin = _tuple->t_tmin; \ + _old_tmax = _tuple->t_tmax; \ + _res = HeapTupleSatisfiesTimeQual(_tuple, (qual)); \ + if (_tuple->t_tmin != _old_tmin || \ + _tuple->t_tmax != _old_tmax) \ + SetBufferCommitInfoNeedsSave(buffer); \ + if (_res) \ + (result) = _tuple; \ + } \ + } \ + } \ +} while (0) extern bool TupleUpdatedByCurXactAndCmd(HeapTuple t); diff --git a/src/include/c.h b/src/include/c.h index 05c3cc5e92..b247b2e8fa 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -7,7 +7,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: c.h,v 1.19 1997/09/08 21:50:24 momjian Exp $ + * $Id: c.h,v 1.20 1997/09/18 14:20:40 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -692,6 +692,27 @@ typedef struct Exception /* we do this so if the macro is used in an if action, it will work */ #define strNcpy(dst,src,len) (strncpy((dst),(src),(len)),*((dst)+(len))='\0') +/* Get a bit mask of the bits set in non-int32 aligned addresses */ +#define INT_ALIGN_MASK (sizeof(int32) - 1) + +/* This function gets call too often, so we inline it if we can */ +#define MemSet(start, val, len) do \ + { /* are we aligned for int32? */ \ + if (((start) & INT_ALIGN_MASK) == 0 && \ + ((len) & INT_ALIGN_MASK) == 0 && \ + (val) == 0 && \ + (len) <= 256) \ + { \ + int32 *i = (int32 *)(start); \ + int32 *stop = (int32 *)((char *)(start) + (len)); \ + \ + while (i < stop) \ + *i++ = 0; \ + } \ + else \ + memset((start), (val), (len)); \ + } + /* ---------------------------------------------------------------- * Section 9: externs * ---------------------------------------------------------------- diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h index b62387b668..1e95f66927 100644 --- a/src/include/storage/ipc.h +++ b/src/include/storage/ipc.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: ipc.h,v 1.20 1997/09/08 21:54:21 momjian Exp $ + * $Id: ipc.h,v 1.21 1997/09/18 14:20:54 momjian Exp $ * * NOTES * This file is very architecture-specific. This stuff should actually @@ -28,10 +28,6 @@ #if defined(HAS_TEST_AND_SET) -extern void S_LOCK(slock_t *lock); -extern void S_UNLOCK(slock_t *lock); -extern void S_INIT_LOCK(slock_t *lock); - #if (defined(alpha) && !defined(linuxalpha)) || \ defined(hpux) || \ defined(irix5) || \ @@ -150,10 +146,6 @@ typedef struct slock struct slock *next; } SLock; -extern void ExclusiveLock(int lockid); -extern void ExclusiveUnlock(int lockid); -extern bool LockIsFree(int lockid); - #else /* HAS_TEST_AND_SET */ typedef enum _LockId_ diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h new file mode 100644 index 0000000000..3bc0af34e5 --- /dev/null +++ b/src/include/storage/s_lock.h @@ -0,0 +1,808 @@ +/*------------------------------------------------------------------------- + * + * s_lock.h-- + * This file contains the implementation (if any) for spinlocks. + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.1 1997/09/18 14:20:59 momjian Exp $ + * + *------------------------------------------------------------------------- + */ +/* + * DESCRIPTION + * The following code fragment should be written (in assembly + * language) on machines that have a native test-and-set instruction: + * + * void + * S_LOCK(char_address) + * char *char_address; + * { + * while (test_and_set(char_address)) + * ; + * } + * + * If this is not done, POSTGRES will default to using System V + * semaphores (and take a large performance hit -- around 40% of + * its time on a DS5000/240 is spent in semop(3)...). + * + * NOTES + * AIX has a test-and-set but the recommended interface is the cs(3) + * system call. This provides an 8-instruction (plus system call + * overhead) uninterruptible compare-and-set operation. True + * spinlocks might be faster but using cs(3) still speeds up the + * regression test suite by about 25%. I don't have an assembler + * manual for POWER in any case. + * + */ +#ifndef S_LOCK_H +#define S_LOCK_H + +#include "storage/ipc.h" + +#if defined(HAS_TEST_AND_SET) + +#if defined (nextstep) +/* + * NEXTSTEP (mach) + * slock_t is defined as a struct mutex. + */ +#define S_LOCK(lock) mutex_lock(lock) + +#define S_UNLOCK(lock) mutex_unlock(lock) + +#define S_INIT_LOCK(lock) mutex_init(lock) + + /* S_LOCK_FREE should return 1 if lock is free; 0 if lock is locked */ +/* For Mach, we have to delve inside the entrails of `struct mutex'. Ick! */ +#define S_LOCK_FREE(alock) ((alock)->lock == 0) + +#endif /* next */ + + + +#if defined(irix5) +/* + * SGI IRIX 5 + * slock_t is defined as a struct abilock_t, which has a single unsigned long + * member. + * + * This stuff may be supplemented in the future with Masato Kataoka's MIPS-II + * assembly from his NECEWS SVR4 port, but we probably ought to retain this + * for the R3000 chips out there. + */ +#define S_LOCK(lock) do \ + { \ + while (!acquire_lock(lock)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) release_lock(lock) + +#define S_INIT_LOCK(lock) init_lock(lock) + +/* S_LOCK_FREE should return 1 if lock is free; 0 if lock is locked */ + +#define S_LOCK_FREE(lock) (stat_lock(lock) == UNLOCKED) + +#endif /* irix5 */ + + +/* + * OSF/1 (Alpha AXP) + * + * Note that slock_t on the Alpha AXP is msemaphore instead of char + * (see storage/ipc.h). + */ + +#if defined(__alpha__) || defined(__alpha) + +#define S_LOCK(lock) do \ + { \ + while (msem_lock((lock), MSEM_IF_NOWAIT) < 0) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) msem_unlock((lock), 0) + +#define S_INIT_LOCK(lock) msem_init((lock), MSEM_UNLOCKED) + +#define S_LOCK_FREE(lock) (!(lock)->msem_state) + +#endif /* alpha */ + +/* + * Solaris 2 + */ + +#if defined(i386_solaris) || \ + defined(sparc_solaris) +/* for xxxxx_solaris, this is defined in port/.../tas.s */ + +static int tas(slock_t *lock); + +#define S_LOCK(lock) do \ + { \ + while (tas(lock)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* i86pc_solaris || sparc_solaris */ + +/* + * AIX (POWER) + * + * Note that slock_t on POWER/POWER2/PowerPC is int instead of char + * (see storage/ipc.h). + */ + +#if defined(aix) + +#define S_LOCK(lock) do \ + { \ + while (cs((int *) (lock), 0, 1)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* aix */ + +/* + * HP-UX (PA-RISC) + * + * Note that slock_t on PA-RISC is a structure instead of char + * (see storage/ipc.h). + */ + +#if defined(hpux) + +/* +* a "set" slock_t has a single word cleared. a "clear" slock_t has +* all words set to non-zero. +*/ +static slock_t clear_lock = {-1, -1, -1, -1}; + +static int tas(slock_t *lock); + +#define S_LOCK(lock) do \ + { \ + while (tas(lock)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = clear_lock) /* struct assignment */ + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#define S_LOCK_FREE(lock) ( *(int *) (((long) (lock) + 15) & ~15) != 0) + +#endif /* hpux */ + +/* + * sun3 + */ + +#if defined(sun3) + +static int tas(slock_t *lock); + +#define S_LOCK(lock) do \ + { \ + while (tas(lock)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#ifdef NOT_USED +static int +tas_dummy() +{ + asm("LLA0:"); + asm(" .data"); + asm(" .text"); + asm("|#PROC# 04"); + asm(" .globl _tas"); + asm("_tas:"); + asm("|#PROLOGUE# 1"); + asm(" movel sp@(0x4),a0"); + asm(" tas a0@"); + asm(" beq LLA1"); + asm(" moveq #-128,d0"); + asm(" rts"); + asm("LLA1:"); + asm(" moveq #0,d0"); + asm(" rts"); + asm(" .data"); +} +#endif + +#endif /* sun3 */ + +/* + * sparc machines + */ + +#if defined(NEED_SPARC_TAS_ASM) + +/* if we're using -ansi w/ gcc, use __asm__ instead of asm */ +#if defined(__STRICT_ANSI__) +#define asm(x) __asm__(x) +#endif + +static int tas(slock_t *lock); + +#ifdef NOT_USED +static int +tas_dummy() +{ + asm(".seg \"data\""); + asm(".seg \"text\""); + asm(".global _tas"); + asm("_tas:"); + + /* + * Sparc atomic test and set (sparc calls it "atomic load-store") + */ + + asm("ldstub [%r8], %r8"); + + /* + * Did test and set actually do the set? + */ + + asm("tst %r8"); + + asm("be,a ReturnZero"); + + /* + * otherwise, just return. + */ + + asm("clr %r8"); + asm("mov 0x1, %r8"); + asm("ReturnZero:"); + asm("retl"); + asm("nop"); +} +#endif + +#define S_LOCK(addr) do \ + { \ + while (tas(addr)) \ + ; \ + } while (0) + +/* + * addr should be as in the above S_LOCK routine + */ +#define S_UNLOCK(addr) (*(addr) = 0) + +#define S_INIT_LOCK(addr) (*(addr) = 0) + +#endif /* NEED_SPARC_TAS_ASM */ + +/* + * i386 based things + */ + +#if defined(NEED_I386_TAS_ASM) + +#define S_LOCK(lock) do \ + { \ + slock_t res; \ + do \ + { \ + __asm__("xchgb %0,%1": "=q"(res), "=m"(*lock):"0"(0x1)); \ + } while (res != 0); \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* NEED_I386_TAS_ASM */ + + +#if defined(__alpha__) && defined(linux) + +#define S_LOCK(lock) do \ + { \ + slock_t res; \ + do \ + { \ + __asm__(" ldq $0, %0 \n\ + bne $0, already_set \n\ + ldq_l $0, %0 \n\ + bne $0, already_set \n\ + or $31, 1, $0 \n\ + stq_c $0, %0 \n\ + beq $0, stqc_fail \n\ + success: bis $31, $31, %1 \n\ + mb \n\ + jmp $31, end \n\ + stqc_fail: or $31, 1, $0 \n\ + already_set: bis $0, $0, %1 \n\ + end: nop ": "=m"(*lock), "=r"(res): :"0"); \ + } while (res != 0); \ + } while (0) + + +#define S_UNLOCK(lock) (__asm__("mb"), *(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* defined(__alpha__) && defined(linux) */ + +#if defined(linux) && defined(sparc) + +#define S_LOCK(lock) do \ + { \ + slock_t res; \ + do \ + { \ + __asm__("ldstub [%1], %0" \ + : "=&r"(res) \ + : "r"(lock)); \ + } while (!res != 0); \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* defined(linux) && defined(sparc) */ + +#if defined(linux) && defined(PPC) + +#ifdef NOT_USED +static int +tas_dummy() +{ + __asm__(" \n\ +tas: \n\ + lwarx 5,0,3 \n\ + cmpwi 5,0 \n\ + bne fail \n\ + addi 5,5,1 \n\ + stwcx. 5,0,3 \n\ + beq success \n\ +fail: li 3,1 \n\ + blr \n\ +success: \n\ + li 3,0 \n\ + blr \n\ + "); +} +#endif + +#define S_LOCK(lock) do \ + { \ + while (tas(lock)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* defined(linux) && defined(PPC) */ + +#endif /* HAS_TEST_AND_SET */ + +#endif /* S_LOCK_H */ +/*------------------------------------------------------------------------- + * + * s_lock.h-- + * This file contains the implementation (if any) for spinlocks. + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.1 1997/09/18 14:20:59 momjian Exp $ + * + *------------------------------------------------------------------------- + */ +/* + * DESCRIPTION + * The following code fragment should be written (in assembly + * language) on machines that have a native test-and-set instruction: + * + * void + * S_LOCK(char_address) + * char *char_address; + * { + * while (test_and_set(char_address)) + * ; + * } + * + * If this is not done, POSTGRES will default to using System V + * semaphores (and take a large performance hit -- around 40% of + * its time on a DS5000/240 is spent in semop(3)...). + * + * NOTES + * AIX has a test-and-set but the recommended interface is the cs(3) + * system call. This provides an 8-instruction (plus system call + * overhead) uninterruptible compare-and-set operation. True + * spinlocks might be faster but using cs(3) still speeds up the + * regression test suite by about 25%. I don't have an assembler + * manual for POWER in any case. + * + */ +#ifndef S_LOCK_H +#define S_LOCK_H + +#include "storage/ipc.h" + +#if defined(HAS_TEST_AND_SET) + +#if defined (nextstep) +/* + * NEXTSTEP (mach) + * slock_t is defined as a struct mutex. + */ +#define S_LOCK(lock) mutex_lock(lock) + +#define S_UNLOCK(lock) mutex_unlock(lock) + +#define S_INIT_LOCK(lock) mutex_init(lock) + + /* S_LOCK_FREE should return 1 if lock is free; 0 if lock is locked */ +/* For Mach, we have to delve inside the entrails of `struct mutex'. Ick! */ +#define S_LOCK_FREE(alock) ((alock)->lock == 0) + +#endif /* next */ + + + +#if defined(irix5) +/* + * SGI IRIX 5 + * slock_t is defined as a struct abilock_t, which has a single unsigned long + * member. + * + * This stuff may be supplemented in the future with Masato Kataoka's MIPS-II + * assembly from his NECEWS SVR4 port, but we probably ought to retain this + * for the R3000 chips out there. + */ +#define S_LOCK(lock) do \ + { \ + while (!acquire_lock(lock)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) release_lock(lock) + +#define S_INIT_LOCK(lock) init_lock(lock) + +/* S_LOCK_FREE should return 1 if lock is free; 0 if lock is locked */ + +#define S_LOCK_FREE(lock) (stat_lock(lock) == UNLOCKED) + +#endif /* irix5 */ + + +/* + * OSF/1 (Alpha AXP) + * + * Note that slock_t on the Alpha AXP is msemaphore instead of char + * (see storage/ipc.h). + */ + +#if defined(__alpha__) || defined(__alpha) + +#define S_LOCK(lock) do \ + { \ + while (msem_lock((lock), MSEM_IF_NOWAIT) < 0) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) msem_unlock((lock), 0) + +#define S_INIT_LOCK(lock) msem_init((lock), MSEM_UNLOCKED) + +#define S_LOCK_FREE(lock) (!(lock)->msem_state) + +#endif /* alpha */ + +/* + * Solaris 2 + */ + +#if defined(i386_solaris) || \ + defined(sparc_solaris) +/* for xxxxx_solaris, this is defined in port/.../tas.s */ + +static int tas(slock_t *lock); + +#define S_LOCK(lock) do \ + { \ + while (tas(lock)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* i86pc_solaris || sparc_solaris */ + +/* + * AIX (POWER) + * + * Note that slock_t on POWER/POWER2/PowerPC is int instead of char + * (see storage/ipc.h). + */ + +#if defined(aix) + +#define S_LOCK(lock) do \ + { \ + while (cs((int *) (lock), 0, 1)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* aix */ + +/* + * HP-UX (PA-RISC) + * + * Note that slock_t on PA-RISC is a structure instead of char + * (see storage/ipc.h). + */ + +#if defined(hpux) + +/* +* a "set" slock_t has a single word cleared. a "clear" slock_t has +* all words set to non-zero. +*/ +static slock_t clear_lock = {-1, -1, -1, -1}; + +static int tas(slock_t *lock); + +#define S_LOCK(lock) do \ + { \ + while (tas(lock)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = clear_lock) /* struct assignment */ + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#define S_LOCK_FREE(lock) ( *(int *) (((long) (lock) + 15) & ~15) != 0) + +#endif /* hpux */ + +/* + * sun3 + */ + +#if defined(sun3) + +static int tas(slock_t *lock); + +#define S_LOCK(lock) do \ + { \ + while (tas(lock)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#ifdef NOT_USED +static int +tas_dummy() +{ + asm("LLA0:"); + asm(" .data"); + asm(" .text"); + asm("|#PROC# 04"); + asm(" .globl _tas"); + asm("_tas:"); + asm("|#PROLOGUE# 1"); + asm(" movel sp@(0x4),a0"); + asm(" tas a0@"); + asm(" beq LLA1"); + asm(" moveq #-128,d0"); + asm(" rts"); + asm("LLA1:"); + asm(" moveq #0,d0"); + asm(" rts"); + asm(" .data"); +} +#endif + +#endif /* sun3 */ + +/* + * sparc machines + */ + +#if defined(NEED_SPARC_TAS_ASM) + +/* if we're using -ansi w/ gcc, use __asm__ instead of asm */ +#if defined(__STRICT_ANSI__) +#define asm(x) __asm__(x) +#endif + +static int tas(slock_t *lock); + +#ifdef NOT_USED +static int +tas_dummy() +{ + asm(".seg \"data\""); + asm(".seg \"text\""); + asm(".global _tas"); + asm("_tas:"); + + /* + * Sparc atomic test and set (sparc calls it "atomic load-store") + */ + + asm("ldstub [%r8], %r8"); + + /* + * Did test and set actually do the set? + */ + + asm("tst %r8"); + + asm("be,a ReturnZero"); + + /* + * otherwise, just return. + */ + + asm("clr %r8"); + asm("mov 0x1, %r8"); + asm("ReturnZero:"); + asm("retl"); + asm("nop"); +} +#endif + +#define S_LOCK(addr) do \ + { \ + while (tas(addr)) \ + ; \ + } while (0) + +/* + * addr should be as in the above S_LOCK routine + */ +#define S_UNLOCK(addr) (*(addr) = 0) + +#define S_INIT_LOCK(addr) (*(addr) = 0) + +#endif /* NEED_SPARC_TAS_ASM */ + +/* + * i386 based things + */ + +#if defined(NEED_I386_TAS_ASM) + +#define S_LOCK(lock) do \ + { \ + slock_t res; \ + do \ + { \ + __asm__("xchgb %0,%1": "=q"(res), "=m"(*lock):"0"(0x1)); \ + } while (res != 0); \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* NEED_I386_TAS_ASM */ + + +#if defined(__alpha__) && defined(linux) + +#define S_LOCK(lock) do \ + { \ + slock_t res; \ + do \ + { \ + __asm__(" ldq $0, %0 \n\ + bne $0, already_set \n\ + ldq_l $0, %0 \n\ + bne $0, already_set \n\ + or $31, 1, $0 \n\ + stq_c $0, %0 \n\ + beq $0, stqc_fail \n\ + success: bis $31, $31, %1 \n\ + mb \n\ + jmp $31, end \n\ + stqc_fail: or $31, 1, $0 \n\ + already_set: bis $0, $0, %1 \n\ + end: nop ": "=m"(*lock), "=r"(res): :"0"); \ + } while (res != 0); \ + } while (0) + + +#define S_UNLOCK(lock) (__asm__("mb"), *(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* defined(__alpha__) && defined(linux) */ + +#if defined(linux) && defined(sparc) + +#define S_LOCK(lock) do \ + { \ + slock_t res; \ + do \ + { \ + __asm__("ldstub [%1], %0" \ + : "=&r"(res) \ + : "r"(lock)); \ + } while (!res != 0); \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* defined(linux) && defined(sparc) */ + +#if defined(linux) && defined(PPC) + +#ifdef NOT_USED +static int +tas_dummy() +{ + __asm__(" \n\ +tas: \n\ + lwarx 5,0,3 \n\ + cmpwi 5,0 \n\ + bne fail \n\ + addi 5,5,1 \n\ + stwcx. 5,0,3 \n\ + beq success \n\ +fail: li 3,1 \n\ + blr \n\ +success: \n\ + li 3,0 \n\ + blr \n\ + "); +} +#endif + +#define S_LOCK(lock) do \ + { \ + while (tas(lock)) \ + ; \ + } while (0) + +#define S_UNLOCK(lock) (*(lock) = 0) + +#define S_INIT_LOCK(lock) S_UNLOCK(lock) + +#endif /* defined(linux) && defined(PPC) */ + +#endif /* HAS_TEST_AND_SET */ + +#endif /* S_LOCK_H */ diff --git a/src/include/storage/spin.h b/src/include/storage/spin.h index d41768039e..c94a74255f 100644 --- a/src/include/storage/spin.h +++ b/src/include/storage/spin.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: spin.h,v 1.5 1997/09/08 02:39:14 momjian Exp $ + * $Id: spin.h,v 1.6 1997/09/18 14:21:02 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -29,7 +29,7 @@ typedef int SPINLOCK; extern bool CreateSpinlocks(IPCKey key); extern bool InitSpinLocks(int init, IPCKey key); -extern void SpinAcquire(SPINLOCK lock); -extern void SpinRelease(SPINLOCK lock); +extern void SpinAcquire(SPINLOCK lockid); +extern void SpinRelease(SPINLOCK lockid); #endif /* SPIN_H */