From 1d36bdcfa6da8a0551362c423e50fc62a260495b Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" Date: Mon, 4 May 1998 15:45:03 +0000 Subject: [PATCH] Major screwed up s_lock patches...need to be fixed... --- src/backend/storage/buffer/Makefile | 10 +- src/backend/storage/buffer/s_lock.c | 355 ++++++++++++++++++++++++---- src/include/port/linux.h | 10 +- 3 files changed, 320 insertions(+), 55 deletions(-) diff --git a/src/backend/storage/buffer/Makefile b/src/backend/storage/buffer/Makefile index 20ac86ee2e..1f0f4ab8fe 100644 --- a/src/backend/storage/buffer/Makefile +++ b/src/backend/storage/buffer/Makefile @@ -4,7 +4,7 @@ # Makefile for storage/buffer # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/storage/buffer/Makefile,v 1.8 1998/04/29 12:37:51 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/backend/storage/buffer/Makefile,v 1.9 1998/05/04 15:44:39 scrappy Exp $ # #------------------------------------------------------------------------- @@ -24,11 +24,11 @@ depend dep: $(CC) -MM $(CFLAGS) *.c >depend clean: - rm -f SUBSYS.o $(OBJS) tas_test + rm -f SUBSYS.o $(OBJS) s_lock_test -tas_test: s_lock.c - $(CC) $(CFLAGS) -DTAS_TEST=1 -g s_lock.c -o tas_test - ./tas_test +s_lock_test: s_lock.c + $(CC) $(CFLAGS) -DS_LOCK_TEST=1 -g s_lock.c -o s_lock_test + ./s_lock_test ifeq (depend,$(wildcard depend)) include depend diff --git a/src/backend/storage/buffer/s_lock.c b/src/backend/storage/buffer/s_lock.c index a3f6373564..d5de97c142 100644 --- a/src/backend/storage/buffer/s_lock.c +++ b/src/backend/storage/buffer/s_lock.c @@ -7,61 +7,334 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.4 1998/04/27 14:43:15 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.5 1998/05/04 15:44:41 scrappy Exp $ * *------------------------------------------------------------------------- */ + +#include + +#include "config.h" +#include "c.h" +#include "storage/s_lock.h" + + /* - * S_LOCK() -- Implements the S_LOCK function for the Linux/Alpha platform. - * This function is usually an inlined macro for all other platforms, - * but must be a seperate function for the Linux/Alpha platform, due - * to the assembly code involved. + * Each time we busy spin we select the next element of this array as the + * number of microseconds to wait. This accomplishes pseudo random back-off. + * Values are not critical and are weighted to the low end of the range. They + * were chosen to work even with different select() timer resolutions on + * different platforms. + * note: total time to cycle through all 16 entries might be about .1 second. */ +int s_spincycle[S_NSPINCYCLE] = +{0, 0, 0, 1000, 5000, 0, 10000, 3000, + 0, 10000, 0, 15000, 9000, 21000, 6000, 30000 +}; -#include -#include -#include -#include -#include -#include +#if defined(S_LOCK_DEBUG) +/* + * s_lock(lock) - take a spinlock + * add intrumentation code to this and define S_LOCK_DEBUG + * instead of hacking up the macro in s_lock.h + */ +void +s_lock(slock_t *lock, char *file, int line) +{ + int spins = 0; -#include "postgres.h" + while (TAS(lock)) + { + struct timeval delay; -/* declarations split between these three files */ -#include "storage/buf.h" -#include "storage/buf_internals.h" -#include "storage/bufmgr.h" + delay.tv_sec = 0; + delay.tv_usec = s_spincycle[spins++ % S_NSPINCYCLE]; + (void) select(0, NULL, NULL, NULL, &delay); + if (spins > S_MAX_BUSY) + { + /* It's been well over a minute... */ + s_lock_stuck(lock, file, line); + } + } +} +#endif /* S_LOCK_DEBUG */ -#include "storage/fd.h" -#include "storage/ipc.h" -#include "storage/s_lock.h" -#if defined(__alpha) && defined(linux) +/* + * s_lock_stuck(lock) - deal with stuck spinlock + */ void -S_LOCK(slock_t *lock) +s_lock_stuck(slock_t *lock, char *file, int line) { - do + fprintf(stderr, + "\nFATAL: s_lock(%08x) at %s:%d, stuck spinlock. Aborting.\n", + (unsigned int) lock, file, line); + fprintf(stdout, + "\nFATAL: s_lock(%08x) at %s:%d, stuck spinlock. Aborting.\n", + (unsigned int) lock, file, line); + abort(); +} + + + +/* + * Various TAS implementations moved from s_lock.h to avoid redundant + * definitions of the same routine. + * RESOLVE: move this to tas.c. Alternatively get rid of tas.[cso] and fold + * all that into this file. + */ + + +#if defined(linux) +/************************************************************************* + * All the Linux flavors + */ + + +#if defined(__alpha__) +int +tas(slock_t *lock) +{ + slock_t _res; + + __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"); + + return (_res != 0); +} +#endif /* __alpha__ */ + + + +#if defined(i386) +int +tas(slock_t *lock) +{ + slock_t _res = 1; + + __asm__("lock; xchgb %0,%1": "=q"(_res), "=m"(*lock):"0"(0x1)); + return (_res != 0); +} +#endif /* i386 */ + + + +#if defined(sparc) + +int +tas(slock_t *lock) +{ + slock_t _res; + slock_t *tmplock = lock; + + __asm__("ldstub [%1], %0" \ + : "=&r"(_res), "=r"(tmplock) \ + : "1"(tmplock)); + return (_res != 0); +} + +#endif /* sparc */ + + + +#if 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\ + "); +} + +#endif /* PPC */ + + + +#else /* defined(linux) */ +/*************************************************************************** + * All Non-Linux + */ + + + +#if defined(sun3) +static void +tas_dummy() /* really means: extern int tas(slock_t *lock); */ +{ + 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 */ + + + +#if defined(NEED_SPARC_TAS_ASM) +/* + * bsd and bsdi sparc machines + */ + +/* if we're using -ansi w/ gcc, use __asm__ instead of asm */ +#if defined(__STRICT_ANSI__) +#define asm(x) __asm__(x) +#endif /* __STRICT_ANSI__ */ + +static void +tas_dummy() /* really means: extern int tas(slock_t *lock); */ +{ + asm(".seg \"data\""); + asm(".seg \"text\""); + asm("_tas:"); + + /* + * Sparc atomic test and set (sparc calls it "atomic load-store") + */ + asm("ldstub [%r8], %r8"); + + asm("retl"); + asm("nop"); +} + +#endif /* NEED_SPARC_TAS_ASM */ + + + + +#if defined(NEED_VAX_TAS_ASM) +/* + * VAXen -- even multiprocessor ones + * (thanks to Tom Ivar Helbekkmo) + */ +typedef unsigned char slock_t; + +int +tas(slock_t *lock) +{ + register ret; + + asm(" movl $1, r0 + bbssi $0, (%1), 1f + clrl r0 + 1: movl r0, %0 " + : "=r"(ret) /* return value, in register */ + : "r"(lock) /* argument, 'lock pointer', in register */ + : "r0"); /* inline code uses this register */ + + return ret; +} + +#endif /* NEED_VAX_TAS_ASM */ + + + +#if defined(NEED_I386_TAS_ASM) +/* + * i386 based things + */ + +#if defined(USE_UNIVEL_CC) +asm int +tas(slock_t *s_lock) +{ + %lab locked; +/* Upon entry, %eax will contain the pointer to the lock byte */ + pushl % ebx + xchgl % eax, %ebx + xor % eax, %eax + movb $255, %al + lock + xchgb % al, (%ebx) + popl % ebx +} + + +#else /* USE_UNIVEL_CC */ + +int +tas(slock_t *lock) +{ + slock_t _res = 1; + + __asm__("lock; xchgb %0,%1": "=q"(_res), "=m"(*lock):"0"(0x1)); + return (_res != 0); +} + +#endif /* USE_UNIVEL_CC */ + +#endif /* NEED_I386_TAS_ASM */ + + +#endif /* linux */ + + +#if defined(S_LOCK_TEST) + +slock_t test_lock; + +void +main() +{ + S_INIT_LOCK(&test_lock); + + if (!S_LOCK_FREE(&test_lock)) { - slock_t _res; + printf("S_LOCK_TEST: failed, lock not initialized.\n"); + exit(1); + } + + S_LOCK(&test_lock); + + if (S_LOCK_FREE(&test_lock)) + { + printf("S_LOCK_TEST: failed, lock not locked\n"); + exit(2); + } + + printf("S_LOCK_TEST: this will hang for a few minutes and then abort\n"); + printf(" with a 'stuck spinlock' message if S_LOCK()\n"); + printf(" and TAS() are working.\n"); + S_LOCK(&test_lock); + + printf("S_LOCK_TEST: failed, lock not locked~\n"); + exit(3); - 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); } -#endif +#endif /* S_LOCK_TEST */ diff --git a/src/include/port/linux.h b/src/include/port/linux.h index 437ee72312..e18e6fbaa8 100644 --- a/src/include/port/linux.h +++ b/src/include/port/linux.h @@ -12,7 +12,7 @@ #if defined(PPC) typedef unsigned int slock_t; -#elif defined(__alpha) +#elif defined(__alpha__) typedef long int slock_t; #else /* i386 probably */ @@ -33,14 +33,6 @@ typedef unsigned char slock_t; #endif #if defined(PPC) -#undef NEED_I386_TAS_ASM #undef HAVE_INT_TIMEZONE #endif -#if defined(sparc) -#undef NEED_I386_TAS_ASM -#endif - -#if defined(__alpha) -#undef NEED_I386_TAS_ASM -#endif -- 2.40.0