
(14 Jun 1998)

Here is the long awaited optimized version of the S_LOCK patch. This
incorporates all the precedeing patches and emailed suggestions and the
results of the performance testing I posted last week. I would like
to get this tested on as many platforms as possible so I can verify it went
in correctly (as opposed to the horrorshow last time I sent in a patch).

Once this is confirmed, I will make a tarball of files that can be dropped
into a 6.3.2 source tree as a few people have asked for this in 6.3.2 as
well.


I have changed the portability model a bit from the last patch. Noticing
that the *BSD platforms and Linux all seem to use GCC, I have separated
the platforms in GCC platforms and non-GCC platforms. This was more or
less the case before because the GCC platforms were using the GCC specific
__asm__() syntax, so I have merely made it explicit. Having done so, I then
felt free to use the GCC __inline__ feature as well which made the code
prettier.

Possibly someone with access to the BSD platforms could get rid of the
NEED_I386_TAS_ASM and NEED_SPARC_TAS_ASM in the include/port/bsd.h and
include/port/bsdi.h as they are redundant now.

The patch is base on the pgsql CVS tree as of midday 14 Jun 1998.

To apply the patch, (assuming you unpacked the tar file in /tmp):

cd pgsql
patch < /tmp/s_lock.patch


I have tested this on i386 Linux, but as it involves platform specific code
it would be helpful if someone on each of the other platforms could test it.
To make it easy to test, I have included a simple test case:

 cd pgsql/src/backend/storage/buffer
 make s_lock_test

This will hang for a couple minutes and then abort with some alarming messages
about "Stuck Spinlock". This is what is supposed to happen. If it exits
quickly, your spinlocks are broken.

If it fails, please add -S to the compile flags in the s_lock_test target
in src/storage/buffer/Makefile and make s_lock_test again. This will
generate a s_lock.s file containing the assembler code. You can examine this
and see if something is wrong with the expansion. Or you can send it to me
(dg@illustra.com) and I will have a look. 


I ran regressions and everything that used to fail still failed ... ;-)
Btw, the failures I see on glibc linux are:
int2 .. failed
int4 .. failed
oidint2 .. failed
oidint4 .. failed
float8 .. failed
geometry .. failed
random .. failed
junkfilter .. failed

-dg


Index: src/backend/storage/buffer/Makefile
diff -c src/backend/storage/buffer/Makefile:1.1.1.2 src/backend/storage/buffer/Makefile:1.2
*** src/backend/storage/buffer/Makefile:1.1.1.2	Sun May 24 23:55:04 1998
--- src/backend/storage/buffer/Makefile	Sun Jun 14 19:37:44 1998
***************
*** 27,33 ****
  	rm -f SUBSYS.o $(OBJS) s_lock_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))
--- 27,33 ----
  	rm -f SUBSYS.o $(OBJS) s_lock_test
  
  s_lock_test: s_lock.c
! 	$(CC) $(CFLAGS) -DS_LOCK_TEST=1 s_lock.c -o s_lock_test
  	./s_lock_test
  
  ifeq (depend,$(wildcard depend))
Index: src/backend/storage/buffer/s_lock.c
diff -c src/backend/storage/buffer/s_lock.c:1.1.1.2 src/backend/storage/buffer/s_lock.c:1.2
*** src/backend/storage/buffer/s_lock.c:1.1.1.2	Sun May 24 23:55:05 1998
--- src/backend/storage/buffer/s_lock.c	Sun Jun 14 19:37:44 1998
***************
*** 11,18 ****
   *
   *-------------------------------------------------------------------------
   */
  
  #include <stdio.h>
  
  #include "config.h"
  #include "c.h"
--- 11,19 ----
   *
   *-------------------------------------------------------------------------
   */
  
  #include <stdio.h>
+ #include <sys/time.h>
  
  #include "config.h"
  #include "c.h"
***************
*** 22,46 ****
  /*
   * 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
  };
  
  
- #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;
  
--- 23,63 ----
  /*
   * 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 but 10 milliseconds is a common platform
!  * granularity.
!  * note: total time to cycle through all 16 entries might be about .07 sec.
!  */
! #define S_NSPINCYCLE    20
! #define S_MAX_BUSY      500 * S_NSPINCYCLE
! 
! int	s_spincycle[S_NSPINCYCLE] =
! {     0,     0,     0,     0, 10000,     0,     0,     0, 10000,     0,
!       0, 10000,     0,     0, 10000,     0, 10000,     0, 10000, 10000
  };
  
  
  /*
!  * s_lock_stuck(lock) - complain about a stuck spinlock
!  */
! static void
! s_lock_stuck(volatile slock_t *lock, const char *file, const int line)
! {
! 	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();
! }
! 
! 
! 
! /*
!  * s_lock(lock) - take a spinlock with backoff
   */
  void
! s_lock(volatile slock_t *lock, const char *file, const int line)
  {
  	int			spins = 0;
  
***************
*** 49,162 ****
  		struct timeval delay;
  
  		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 */
  
  
- /*
-  * s_lock_stuck(lock) - deal with stuck spinlock
-  */
- void
- s_lock_stuck(slock_t *lock, char *file, int line)
- {
- 	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\
--- 66,104 ----
  		struct timeval delay;
  
  		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 over a minute...  */
  			s_lock_stuck(lock, file, line);
  		}
  	}
  }
  
  
  
  
  /*
!  * Various TAS implementations that cannot live in s_lock.h as no inline
!  * definition exists (yet).
!  * In the future, get rid of tas.[cso] and fold it into this file.
   */
  
  
! #if defined(__GNUC__)
  /*************************************************************************
!  * All the gcc flavors that are not inlined
   */
  
  
  
  #if defined(PPC)
! /* Note: need a nice gcc constrained asm version so it can be inlined */
! int
! tas(volatile slock_t *lock)
  {
! 	__asm__("lwarx	5,0,3	\n\
  			cmpwi	5,0		\n\
  			bne		fail	\n\
  			addi	5,5,1	\n\
***************
*** 169,189 ****
          	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");
--- 111,130 ----
          	blr				\n\
  	");
  }
  #endif /* PPC */
  
  
  
! #else /* defined(__GNUC__) */
  /***************************************************************************
!  * All non gcc
   */
  
  
  
  #if defined(sun3)
  static void
! tas_dummy()				/* really means: extern int tas(slock_t *lock); */
  {
  	asm("LLA0:");
  	asm("   .data");
***************
*** 208,233 ****
  
  #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");
  }
--- 149,166 ----
  
  #if defined(NEED_SPARC_TAS_ASM)
  /*
!  * sparc machines not using gcc
   */
  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");
  }
***************
*** 237,312 ****
  
  
  
- #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()
--- 170,194 ----
  
  
  
  #if defined(NEED_I386_TAS_ASM)
! /* non gcc i386 based things */
! #endif /* NEED_I386_TAS_ASM */
  
  
  
! #endif /* not __GNUC__ */
  
  
  
  
+ /*****************************************************************************/
  #if defined(S_LOCK_TEST)
  
! /*
!  * test program for verifying a port.
!  */
! 
! volatile slock_t	test_lock;
  
  void
  main()
***************
*** 330,336 ****
  	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);
--- 212,218 ----
  	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, __FILE__, __LINE__);
  
  	printf("S_LOCK_TEST: failed, lock not locked~\n");
  	exit(3);
***************
*** 338,340 ****
--- 220,223 ----
  }
  
  #endif /* S_LOCK_TEST */
+ 
Index: src/include/storage/s_lock.h
diff -c src/include/storage/s_lock.h:1.1.1.2 src/include/storage/s_lock.h:1.2
*** src/include/storage/s_lock.h:1.1.1.2	Sun May 24 23:57:20 1998
--- src/include/storage/s_lock.h	Sun Jun 14 19:37:47 1998
***************
*** 11,19 ****
   *
   *-------------------------------------------------------------------------
   */
  /*
   *	 DESCRIPTION
!  *		The public functions that must be provided are:
   *
   *		void S_INIT_LOCK(slock_t *lock)
   *
--- 11,20 ----
   *
   *-------------------------------------------------------------------------
   */
+ 
  /*
   *	 DESCRIPTION
!  *		The public macros that must be provided are:
   *
   *		void S_INIT_LOCK(slock_t *lock)
   *
***************
*** 45,55 ****
   *		#define TAS(lock) tas(lock)
   *		int tas(slock_t *lock)		// True if lock already set
   *
   *		If none of this can be 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
--- 46,60 ----
   *		#define TAS(lock) tas(lock)
   *		int tas(slock_t *lock)		// True if lock already set
   *
+  *		There are default implementations for all these macros at the bottom
+  *		of this file. Check if your platform can use these or needs to
+  *		override them.
+  *
+  *	NOTES
   *		If none of this can be 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)...).
   *
   *		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
***************
*** 57,66 ****
   *		regression test suite by about 25%.  I don't have an assembler
   *		manual for POWER in any case.
   *
-  *		There are default implementations for all these macros at the bottom
-  *		of this file. Check if your platform can use these or needs to
-  *		override them.
-  *
   */
  #if !defined(S_LOCK_H)
  #define S_LOCK_H
--- 62,67 ----
***************
*** 69,91 ****
  
  #if defined(HAS_TEST_AND_SET)
  
! #if defined(linux)
! /***************************************************************************
!  * All Linux
   */
  
  #if defined(__alpha)
! 
  #define S_UNLOCK(lock) { __asm__("mb"); *(lock) = 0; }
  
  #endif /* __alpha */
  
  
  
  
! #else /* linux */
  /***************************************************************************
!  * All non Linux
   */
  
  #if defined (nextstep)
--- 70,173 ----
  
  #if defined(HAS_TEST_AND_SET)
  
! 
! #if defined(__GNUC__)
! /*************************************************************************
!  * All the gcc inlines
   */
  
  #if defined(__alpha)
! #define TAS(lock) tas(lock)
  #define S_UNLOCK(lock) { __asm__("mb"); *(lock) = 0; }
  
+ static __inline__ int
+ tas(volatile slock_t *lock)
+ {
+ 	register 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 (int) _res;
+ }
  #endif /* __alpha */
  
  
  
+ #if defined(i386)
+ #define TAS(lock) tas(lock)
+ 
+ static __inline__ int
+ tas(volatile slock_t *lock)
+ {
+ 	register slock_t	_res = 1;
+ 
+     __asm__("lock; xchgb %0,%1" : "=q"(_res), "=m"(*lock) : "0"(_res) );
+ 	return (int) _res;
+ }
+ #endif /* i386 */
+ 
+ 
+ 
+ #if defined(sparc)
+ #define TAS(lock) tas(lock)
+ 
+ static __inline__ int
+ tas(volatile slock_t *lock)
+ {
+ 	register slock_t	_res = 1;
+ 
+     __asm__("ldstub [%1], %0" \
+             : "=r"(_res), "=m"(*lock) \
+             : "1"(lock));
+ 	return (int) _res;
+ }
+ #endif /* sparc */
+ 
+ 
+ 
+ #if defined(NEED_VAX_TAS_ASM)
+ /*
+  * VAXen -- even multiprocessor ones
+  * (thanks to Tom Ivar Helbekkmo)
+  */
+ #define TAS(lock) tas(lock)
+ 
+ typedef unsigned char slock_t;
+ 
+ static __inline__ int
+ tas(volatile slock_t *lock)
+ {
+ 	register	_res;
+ 
+ 	__asm__("	movl $1, r0
+ 		bbssi $0, (%1), 1f
+ 		clrl r0
+   1:	movl r0, %0 "
+   :		"=r"(_res)				/* return value, in register */
+   :		"r"(lock)				/* argument, 'lock pointer', in register */
+   :		"r0");					/* inline code uses this register */
+ 	return (int) _res;
+ }
+ #endif /* NEED_VAX_TAS_ASM */
+ 
+ 
  
! 
! #else /* __GNUC__ */
  /***************************************************************************
!  * All non gcc
   */
  
  #if defined (nextstep)
***************
*** 95,108 ****
   */
  
  #define S_LOCK(lock)	mutex_lock(lock)
- 
  #define S_UNLOCK(lock)	mutex_unlock(lock)
- 
  #define S_INIT_LOCK(lock)	mutex_init(lock)
- 
  /* For Mach, we have to delve inside the entrails of `struct mutex'.  Ick! */
  #define S_LOCK_FREE(alock)	((alock)->lock == 0)
- 
  #endif /* nextstep */
  
  
--- 177,186 ----
***************
*** 118,130 ****
   * for the R3000 chips out there.
   */
  #define TAS(lock)	(!acquire_lock(lock))
- 
  #define S_UNLOCK(lock)	release_lock(lock)
- 
  #define S_INIT_LOCK(lock)	init_lock(lock)
- 
  #define S_LOCK_FREE(lock)	(stat_lock(lock) == UNLOCKED)
- 
  #endif /* __sgi */
  
  
--- 196,204 ----
***************
*** 137,149 ****
   * (see storage/ipc.h).
   */
  #define TAS(lock)	(msem_lock((lock), MSEM_IF_NOWAIT) < 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 */
  
  
--- 211,219 ----
***************
*** 156,162 ****
   * (see storage/ipc.h).
   */
  #define TAS(lock)	cs((int *) (lock), 0, 1)
- 
  #endif /* _AIX */
  
  
--- 226,231 ----
***************
*** 175,235 ****
  {-1, -1, -1, -1};
  
  #define S_UNLOCK(lock)	(*(lock) = clear_lock)	/* struct assignment */
- 
  #define S_LOCK_FREE(lock)	( *(int *) (((long) (lock) + 15) & ~15) != 0)
- 
  #endif /* __hpux */
  
  
  
! #endif /* else defined(linux) */
  
  
  
  
- /****************************************************************************
-  * Default Definitions - override these above as needed.
-  */
- 
- #if !defined(S_LOCK)
- 
- #include <sys/time.h>
  
! #define S_NSPINCYCLE	16
! #define S_MAX_BUSY		1000 * S_NSPINCYCLE
  
- extern int	s_spincycle[];
- extern void s_lock_stuck(slock_t *lock, char *file, int line);
  
! #if defined(S_LOCK_DEBUG)
  
- extern void s_lock(slock_t *lock);
  
- #define S_LOCK(lock) s_lock(lock, __FILE__, __LINE__)
  
- #else /* S_LOCK_DEBUG */
  
! #define S_LOCK(lock) if (1) { \
! 	int spins = 0; \
! 	while (TAS(lock)) { \
! 		struct timeval	delay; \
! 		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__); \
! 		} \
! 	} \
! } else
  
! #endif /* S_LOCK_DEBUG */
  #endif /* S_LOCK */
  
- 
- 
  #if !defined(S_LOCK_FREE)
! #define S_LOCK_FREE(lock)	((*lock) == 0)
  #endif /* S_LOCK_FREE */
  
  #if !defined(S_UNLOCK)
--- 244,299 ----
  {-1, -1, -1, -1};
  
  #define S_UNLOCK(lock)	(*(lock) = clear_lock)	/* struct assignment */
  #define S_LOCK_FREE(lock)	( *(int *) (((long) (lock) + 15) & ~15) != 0)
  #endif /* __hpux */
  
  
  
! #if defined(NEED_I386_TAS_ASM)
! /* non gcc i386 based things */
  
  
+ #if defined(USE_UNIVEL_CC)
+ #define TAS(lock)	tas(lock)
  
+ 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
+ }
+ #endif /* USE_UNIVEL_CC */
  
  
! #endif /* NEED_I386_TAS_ASM */
  
  
! #endif /* else defined(__GNUC__) */
  
  
  
  
! /****************************************************************************
!  * Default Definitions - override these above as needed.
!  */
  
! #if !defined(S_LOCK)
! extern void s_lock(volatile slock_t *lock, const char *file, const int line);
! #define S_LOCK(lock) \
!     if (TAS((volatile slock_t *) lock)) {\
!         s_lock((volatile slock_t *) lock, __FILE__, __LINE__); \
!     } else
  #endif /* S_LOCK */
  
  #if !defined(S_LOCK_FREE)
! #define S_LOCK_FREE(lock)	(*(lock) == 0)
  #endif /* S_LOCK_FREE */
  
  #if !defined(S_UNLOCK)
***************
*** 241,252 ****
  #endif /* S_INIT_LOCK */
  
  #if !defined(TAS)
! int			tas(slock_t *lock); /* port/.../tas.s, or s_lock.c */
! 
! #define TAS(lock)		tas(lock)
  #endif /* TAS */
  
  
  #endif /* HAS_TEST_AND_SET */
- 
  #endif /* S_LOCK_H */
--- 305,315 ----
  #endif /* S_INIT_LOCK */
  
  #if !defined(TAS)
! int	tas(volatile slock_t *lock); /* port/.../tas.s, or s_lock.c */
! #define TAS(lock)		tas((volatile slock_t *) lock)
  #endif /* TAS */
  
  
  #endif /* HAS_TEST_AND_SET */
  #endif /* S_LOCK_H */
+ 

Mon, 15 Jun 1998 13:26:14 -0700 (PDT)
dg@illustra.com (David Gould)
Revised Optimized S_LOCK patch