s_lock.c 4.37 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*-------------------------------------------------------------------------
 *
 * s_lock.c--
 *	  buffer manager interface routines
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
Bruce Momjian's avatar
Bruce Momjian committed
10
 *	  $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.12 1998/09/18 17:18:39 momjian Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
14 15

#include <stdio.h>
16
#include <sys/time.h>
17 18 19 20 21 22

#include "config.h"
#include "c.h"
#include "storage/s_lock.h"


23
/*
24 25
 * 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.
26 27 28
 * 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.
29
 */
30 31
#define S_NSPINCYCLE	20
#define S_MAX_BUSY		500 * S_NSPINCYCLE
32

33 34 35
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
36
};
37 38


39
/*
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
 * 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
58 59
 */
void
60
s_lock(volatile slock_t *lock, const char *file, const int line)
61 62
{
	int			spins = 0;
63

64 65 66
	while (TAS(lock))
	{
		struct timeval delay;
67

68
		delay.tv_sec = 0;
69
		delay.tv_usec = s_spincycle[spins % S_NSPINCYCLE];
70
		(void) select(0, NULL, NULL, NULL, &delay);
71
		if (++spins > S_MAX_BUSY)
72
		{
73
			/* It's been over a minute...  */
74 75 76 77
			s_lock_stuck(lock, file, line);
		}
	}
}
78

79 80 81 82



/*
83 84 85
 * 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.
86 87 88
 */


89
#if defined(__GNUC__)
90
/*************************************************************************
91
 * All the gcc flavors that are not inlined
92 93 94 95 96
 */



#if defined(PPC)
97
/* Note: need a nice gcc constrained asm version so it can be inlined */
98 99
static void
tas_dummy()
100
{
101 102 103 104 105 106 107
	__asm__("		\n\
.global		tas		\n\
tas:				\n\
		lwarx	5,0,3	\n\
		cmpwi	5,0	\n\
		bne	fail	\n\
		addi	5,5,1	\n\
108
        	stwcx.  5,0,3	\n\
109 110 111 112 113 114
     		beq	success	\n\
fail:		li	3,1	\n\
		blr		\n\
success:			\n\
		li 3,0		\n\
        	blr		\n\
115 116 117
	");
}

118
#endif	 /* PPC */
119 120


121 122

#else							/* defined(__GNUC__) */
123
/***************************************************************************
124
 * All non gcc
125 126 127 128 129 130
 */



#if defined(sun3)
static void
131 132
tas_dummy()						/* really means: extern int tas(slock_t
								 * *lock); */
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
{
	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");
}
151 152

#endif	 /* sun3 */
153 154 155 156 157



#if defined(NEED_SPARC_TAS_ASM)
/*
158
 * sparc machines not using gcc
159 160
 */
static void
161 162
tas_dummy()						/* really means: extern int tas(slock_t
								 * *lock); */
163 164 165 166
{
	asm(".seg \"data\"");
	asm(".seg \"text\"");
	asm("_tas:");
167

168 169 170 171 172 173 174 175
	/*
	 * Sparc atomic test and set (sparc calls it "atomic load-store")
	 */
	asm("ldstub [%r8], %r8");
	asm("retl");
	asm("nop");
}

176
#endif	 /* NEED_SPARC_TAS_ASM */
177 178 179 180 181




#if defined(NEED_I386_TAS_ASM)
182
/* non gcc i386 based things */
183
#endif	 /* NEED_I386_TAS_ASM */
184 185 186



187
#endif	 /* not __GNUC__ */
188 189 190 191




192
/*****************************************************************************/
193 194
#if defined(S_LOCK_TEST)

195 196 197 198
/*
 * test program for verifying a port.
 */

199
volatile slock_t test_lock;
200 201 202 203 204 205 206

void
main()
{
	S_INIT_LOCK(&test_lock);

	if (!S_LOCK_FREE(&test_lock))
207
	{
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
		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");
223
	s_lock(&test_lock, __FILE__, __LINE__);
224 225 226

	printf("S_LOCK_TEST: failed, lock not locked~\n");
	exit(3);
227

228
}
229

230
#endif	 /* S_LOCK_TEST */