s_lock.h 5.77 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*-------------------------------------------------------------------------
 *
 * s_lock.h--
 *	   This file contains the implementation (if any) for spinlocks.
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.32 1998/05/04 16:58:59 scrappy Exp $
11 12 13 14 15
 *
 *-------------------------------------------------------------------------
 */
/*
 *	 DESCRIPTION
16
 *		The public functions that must be provided are:
17
 *
18
 *		void S_INIT_LOCK(slock_t *lock)
19 20 21
 *
 *		void S_LOCK(slock_t *lock)
 *
22
 *		void S_UNLOCK(slock_t *lock)
23
 *
24 25
 *		void S_LOCK_FREE(slock_t *lock)
 *			Tests if the lock is free. Returns non-zero if free, 0 if locked.
26
 *
27 28
 *		The S_LOCK() macro	implements a primitive but still useful random
 *		backoff to avoid hordes of busywaiting lockers chewing CPU.
29
 *
30
 *		Effectively:
31
 *		void
32
 *		S_LOCK(slock_t *lock)
33
 *		{
34 35
 *			while (TAS(lock))
 *			{
36
 *			// back off the cpu for a semi-random short time
37
 *			}
38 39
 *		}
 *
40 41 42
 *		This implementation takes advantage of a tas function written
 *		(in assembly language) on machines that have a native test-and-set
 *		instruction. Alternative mutex implementations may also be used.
43
 *		This function is hidden under the TAS macro to allow substitutions.
44
 *
45 46 47 48 49 50 51 52
 *		#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
53 54 55 56 57 58 59
 *		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.
 *
60 61 62 63
 *		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.
 *
64
 */
65
#if !defined(S_LOCK_H)
66 67 68 69 70 71
#define S_LOCK_H

#include "storage/ipc.h"

#if defined(HAS_TEST_AND_SET)

72 73 74 75 76 77 78 79 80
#if defined(linux)
/***************************************************************************
 * All Linux
 */

#if defined(__alpha__)

#define S_UNLOCK(lock) { __asm__("mb"); *(lock) = 0; }

81
#endif /* __alpha__ */
82 83 84 85




86
#else /* linux */
87 88 89 90
/***************************************************************************
 * All non Linux
 */

91 92 93 94 95
#if defined (nextstep)
/*
 * NEXTSTEP (mach)
 * slock_t is defined as a struct mutex.
 */
96

97
#define S_LOCK(lock)	mutex_lock(lock)
98

99
#define S_UNLOCK(lock)	mutex_unlock(lock)
100

101
#define S_INIT_LOCK(lock)	mutex_init(lock)
102 103

/* For Mach, we have to delve inside the entrails of `struct mutex'.  Ick! */
104
#define S_LOCK_FREE(alock)	((alock)->lock == 0)
105

106
#endif /* nextstep */
107 108 109



110
#if defined(__sgi)
111 112 113 114 115 116 117 118 119
/*
 * 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.
 */
120
#define TAS(lock)	(!acquire_lock(lock))
121 122 123

#define S_UNLOCK(lock)	release_lock(lock)

124
#define S_INIT_LOCK(lock)	init_lock(lock)
125

126
#define S_LOCK_FREE(lock)	(stat_lock(lock) == UNLOCKED)
127

128 129
#endif /* __sgi */

130 131


132
#if (defined(__alpha__)
133 134 135 136 137 138
/*
 * OSF/1 (Alpha AXP)
 *
 * Note that slock_t on the Alpha AXP is msemaphore instead of char
 * (see storage/ipc.h).
 */
139
#define TAS(lock)	(msem_lock((lock), MSEM_IF_NOWAIT) < 0)
140

141
#define S_UNLOCK(lock)	msem_unlock((lock), 0)
142

143
#define S_INIT_LOCK(lock)	msem_init((lock), MSEM_UNLOCKED)
144

145
#define S_LOCK_FREE(lock)	(!(lock)->msem_state)
146

147
#endif /* __alpha__ */
148 149 150



151
#if defined(_AIX)
152 153 154 155 156 157
/*
 * AIX (POWER)
 *
 * Note that slock_t on POWER/POWER2/PowerPC is int instead of char
 * (see storage/ipc.h).
 */
158
#define TAS(lock)	cs((int *) (lock), 0, 1)
159

160
#endif /* _AIX */
161 162 163



164
#if defined(__hpux)
165 166 167 168 169
/*
 * HP-UX (PA-RISC)
 *
 * Note that slock_t on PA-RISC is a structure instead of char
 * (see storage/ipc.h).
170 171 172
 *
 * a "set" slock_t has a single word cleared.  a "clear" slock_t has
 * all words set to non-zero. tas() in tas.s
173
 */
174 175
static slock_t clear_lock =
{-1, -1, -1, -1};
176

177
#define S_UNLOCK(lock)	(*(lock) = clear_lock)	/* struct assignment */
178

179
#define S_LOCK_FREE(lock)	( *(int *) (((long) (lock) + 15) & ~15) != 0)
180

181
#endif /* __hpux */
182 183 184



185
#endif /* else defined(linux) */
186 187 188 189




190 191
/****************************************************************************
 * Default Definitions - override these above as needed.
192 193
 */

194
#if !defined(S_LOCK)
195

196
#include <sys/time.h>
197

198 199
#define S_NSPINCYCLE	16
#define S_MAX_BUSY		1000 * S_NSPINCYCLE
200

201 202
extern int	s_spincycle[];
extern void s_lock_stuck(slock_t *lock, char *file, int line);
203

204
#if defined(S_LOCK_DEBUG)
205

206
extern void s_lock(slock_t *lock);
207

208
#define S_LOCK(lock) s_lock(lock, __FILE__, __LINE__)
209

210
#else /* S_LOCK_DEBUG */
211

212 213 214 215 216 217 218 219 220 221 222 223 224
#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
225

226 227
#endif /* S_LOCK_DEBUG */
#endif /* S_LOCK */
228 229 230



231 232 233
#if !defined(S_LOCK_FREE)
#define S_LOCK_FREE(lock)	((*lock) == 0)
#endif /* S_LOCK_FREE */
234

235 236 237
#if !defined(S_UNLOCK)
#define S_UNLOCK(lock)		(*(lock) = 0)
#endif /* S_UNLOCK */
238

239
#if !defined(S_INIT_LOCK)
240
#define S_INIT_LOCK(lock)	S_UNLOCK(lock)
241
#endif /* S_INIT_LOCK */
242

243 244
#if !defined(TAS)
int			tas(slock_t *lock); /* port/.../tas.s, or s_lock.c */
245

246 247
#define TAS(lock)		tas(lock)
#endif /* TAS */
Bruce Momjian's avatar
Bruce Momjian committed
248

Bruce Momjian's avatar
Bruce Momjian committed
249

250
#endif /* HAS_TEST_AND_SET */
251

252
#endif /* S_LOCK_H */