~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/include/storage/s_lock.h

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * s_lock.h
 
4
 *         Hardware-dependent implementation of spinlocks.
 
5
 *
 
6
 *      NOTE: none of the macros in this file are intended to be called directly.
 
7
 *      Call them through the hardware-independent macros in spin.h.
 
8
 *
 
9
 *      The following hardware-dependent macros must be provided for each
 
10
 *      supported platform:
 
11
 *
 
12
 *      void S_INIT_LOCK(slock_t *lock)
 
13
 *              Initialize a spinlock (to the unlocked state).
 
14
 *
 
15
 *      void S_LOCK(slock_t *lock)
 
16
 *              Acquire a spinlock, waiting if necessary.
 
17
 *              Time out and abort() if unable to acquire the lock in a
 
18
 *              "reasonable" amount of time --- typically ~ 1 minute.
 
19
 *
 
20
 *      void S_UNLOCK(slock_t *lock)
 
21
 *              Unlock a previously acquired lock.
 
22
 *
 
23
 *      bool S_LOCK_FREE(slock_t *lock)
 
24
 *              Tests if the lock is free. Returns TRUE if free, FALSE if locked.
 
25
 *              This does *not* change the state of the lock.
 
26
 *
 
27
 *      void SPIN_DELAY(void)
 
28
 *              Delay operation to occur inside spinlock wait loop.
 
29
 *
 
30
 *      Note to implementors: there are default implementations for all these
 
31
 *      macros at the bottom of the file.  Check if your platform can use
 
32
 *      these or needs to override them.
 
33
 *
 
34
 *  Usually, S_LOCK() is implemented in terms of an even lower-level macro
 
35
 *      TAS():
 
36
 *
 
37
 *      int TAS(slock_t *lock)
 
38
 *              Atomic test-and-set instruction.  Attempt to acquire the lock,
 
39
 *              but do *not* wait.      Returns 0 if successful, nonzero if unable
 
40
 *              to acquire the lock.
 
41
 *
 
42
 *      TAS() is NOT part of the API, and should never be called directly.
 
43
 *
 
44
 *      CAUTION: on some platforms TAS() may sometimes report failure to acquire
 
45
 *      a lock even when the lock is not locked.  For example, on Alpha TAS()
 
46
 *      will "fail" if interrupted.  Therefore TAS() should always be invoked
 
47
 *      in a retry loop, even if you are certain the lock is free.
 
48
 *
 
49
 *      ANOTHER CAUTION: be sure that TAS() and S_UNLOCK() represent sequence
 
50
 *      points, ie, loads and stores of other values must not be moved across
 
51
 *      a lock or unlock.  In most cases it suffices to make the operation be
 
52
 *      done through a "volatile" pointer.
 
53
 *
 
54
 *      On most supported platforms, TAS() uses a tas() function written
 
55
 *      in assembly language to execute a hardware atomic-test-and-set
 
56
 *      instruction.  Equivalent OS-supplied mutex routines could be used too.
 
57
 *
 
58
 *      If no system-specific TAS() is available (ie, HAVE_SPINLOCKS is not
 
59
 *      defined), then we fall back on an emulation that uses SysV semaphores
 
60
 *      (see spin.c).  This emulation will be MUCH MUCH slower than a proper TAS()
 
61
 *      implementation, because of the cost of a kernel call per lock or unlock.
 
62
 *      An old report is that Postgres spends around 40% of its time in semop(2)
 
63
 *      when using the SysV semaphore code.
 
64
 *
 
65
 *
 
66
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
67
 * Portions Copyright (c) 1994, Regents of the University of California
 
68
 *
 
69
 *        $PostgreSQL: pgsql/src/include/storage/s_lock.h,v 1.133 2004-12-31 22:03:42 pgsql Exp $
 
70
 *
 
71
 *-------------------------------------------------------------------------
 
72
 */
 
73
#ifndef S_LOCK_H
 
74
#define S_LOCK_H
 
75
 
 
76
#include "storage/pg_sema.h"
 
77
 
 
78
#ifdef HAVE_SPINLOCKS   /* skip spinlocks if requested */
 
79
 
 
80
 
 
81
#if defined(__GNUC__) || defined(__ICC)
 
82
/*************************************************************************
 
83
 * All the gcc inlines
 
84
 * Gcc consistently defines the CPU as __cpu__.
 
85
 * Other compilers use __cpu or __cpu__ so we test for both in those cases.
 
86
 */
 
87
 
 
88
/*----------
 
89
 * Standard gcc asm format (assuming "volatile slock_t *lock"):
 
90
 
 
91
        __asm__ __volatile__(
 
92
                "       instruction     \n"
 
93
                "       instruction     \n"
 
94
                "       instruction     \n"
 
95
:               "=r"(_res), "+m"(*lock)         // return register, in/out lock value
 
96
:               "r"(lock)                                       // lock pointer, in input register
 
97
:               "memory", "cc");                        // show clobbered registers here
 
98
 
 
99
 * The output-operands list (after first colon) should always include
 
100
 * "+m"(*lock), whether or not the asm code actually refers to this
 
101
 * operand directly.  This ensures that gcc believes the value in the
 
102
 * lock variable is used and set by the asm code.  Also, the clobbers
 
103
 * list (after third colon) should always include "memory"; this prevents
 
104
 * gcc from thinking it can cache the values of shared-memory fields
 
105
 * across the asm code.  Add "cc" if your asm code changes the condition
 
106
 * code register, and also list any temp registers the code uses.
 
107
 *----------
 
108
 */
 
109
 
 
110
 
 
111
#if defined(__i386__) || defined(__x86_64__) /* AMD Opteron */
 
112
#define HAS_TEST_AND_SET
 
113
 
 
114
typedef unsigned char slock_t;
 
115
 
 
116
#define TAS(lock) tas(lock)
 
117
 
 
118
static __inline__ int
 
119
tas(volatile slock_t *lock)
 
120
{
 
121
        register slock_t _res = 1;
 
122
 
 
123
        /* Use a non-locking test before asserting the bus lock */
 
124
        __asm__ __volatile__(
 
125
                "       cmpb    $0,%1   \n"
 
126
                "       jne             1f              \n"
 
127
                "       lock                    \n"
 
128
                "       xchgb   %0,%1   \n"
 
129
                "1: \n"
 
130
:               "+q"(_res), "+m"(*lock)
 
131
:
 
132
:               "memory", "cc");
 
133
        return (int) _res;
 
134
}
 
135
 
 
136
#define SPIN_DELAY() spin_delay()
 
137
 
 
138
static __inline__ void
 
139
spin_delay(void)
 
140
{
 
141
        /*
 
142
         * This sequence is equivalent to the PAUSE instruction ("rep" is
 
143
         * ignored by old IA32 processors if the following instruction is
 
144
         * not a string operation); the IA-32 Architecture Software
 
145
         * Developer's Manual, Vol. 3, Section 7.7.2 describes why using
 
146
         * PAUSE in the inner loop of a spin lock is necessary for good
 
147
         * performance:
 
148
         *
 
149
         *     The PAUSE instruction improves the performance of IA-32
 
150
         *     processors supporting Hyper-Threading Technology when
 
151
         *     executing spin-wait loops and other routines where one
 
152
         *     thread is accessing a shared lock or semaphore in a tight
 
153
         *     polling loop. When executing a spin-wait loop, the
 
154
         *     processor can suffer a severe performance penalty when
 
155
         *     exiting the loop because it detects a possible memory order
 
156
         *     violation and flushes the core processor's pipeline. The
 
157
         *     PAUSE instruction provides a hint to the processor that the
 
158
         *     code sequence is a spin-wait loop. The processor uses this
 
159
         *     hint to avoid the memory order violation and prevent the
 
160
         *     pipeline flush. In addition, the PAUSE instruction
 
161
         *     de-pipelines the spin-wait loop to prevent it from
 
162
         *     consuming execution resources excessively.
 
163
         */
 
164
        __asm__ __volatile__(
 
165
                " rep; nop                      \n");
 
166
}
 
167
 
 
168
#endif   /* __i386__ || __x86_64__ */
 
169
 
 
170
 
 
171
#if defined(__ia64__) || defined(__ia64)  /* __ia64 used by ICC compiler? */
 
172
/* Intel Itanium */
 
173
#define HAS_TEST_AND_SET
 
174
 
 
175
typedef unsigned int slock_t;
 
176
 
 
177
#define TAS(lock) tas(lock)
 
178
 
 
179
static __inline__ int
 
180
tas(volatile slock_t *lock)
 
181
{
 
182
        long int        ret;
 
183
 
 
184
        __asm__ __volatile__(
 
185
                "       xchg4   %0=%1,%2        \n"
 
186
:               "=r"(ret), "+m"(*lock)
 
187
:               "r"(1)
 
188
:               "memory");
 
189
        return (int) ret;
 
190
}
 
191
 
 
192
#endif   /* __ia64__ || __ia64 */
 
193
 
 
194
 
 
195
#if defined(__arm__) || defined(__arm)
 
196
#define HAS_TEST_AND_SET
 
197
 
 
198
typedef unsigned char slock_t;
 
199
 
 
200
#define TAS(lock) tas(lock)
 
201
 
 
202
static __inline__ int
 
203
tas(volatile slock_t *lock)
 
204
{
 
205
        register slock_t _res = 1;
 
206
 
 
207
        __asm__ __volatile__(
 
208
                "       swpb    %0, %0, [%2]    \n"
 
209
:               "+r"(_res), "+m"(*lock)
 
210
:               "r"(lock)
 
211
:               "memory");
 
212
        return (int) _res;
 
213
}
 
214
 
 
215
#endif   /* __arm__ */
 
216
 
 
217
 
 
218
#if defined(__s390__) || defined(__s390x__)
 
219
/* S/390 and S/390x Linux (32- and 64-bit zSeries) */
 
220
#define HAS_TEST_AND_SET
 
221
 
 
222
typedef unsigned int slock_t;
 
223
 
 
224
#define TAS(lock)          tas(lock)
 
225
 
 
226
static __inline__ int
 
227
tas(volatile slock_t *lock)
 
228
{
 
229
        int                     _res = 0;
 
230
 
 
231
        __asm__ __volatile__(
 
232
                "       cs      %0,%3,0(%2)             \n"
 
233
:               "+d"(_res), "+m"(*lock)
 
234
:               "a"(lock), "d"(1)
 
235
:               "memory", "cc");
 
236
        return _res;
 
237
}
 
238
 
 
239
#endif   /* __s390__ || __s390x__ */
 
240
 
 
241
 
 
242
#if defined(__sparc__)
 
243
#define HAS_TEST_AND_SET
 
244
 
 
245
typedef unsigned char slock_t;
 
246
 
 
247
#define TAS(lock) tas(lock)
 
248
 
 
249
static __inline__ int
 
250
tas(volatile slock_t *lock)
 
251
{
 
252
        register slock_t _res;
 
253
 
 
254
        __asm__ __volatile__(
 
255
                "       ldstub  [%2], %0        \n"
 
256
:               "=r"(_res), "+m"(*lock)
 
257
:               "r"(lock)
 
258
:               "memory");
 
259
        return (int) _res;
 
260
}
 
261
 
 
262
#endif   /* __sparc__ */
 
263
 
 
264
 
 
265
#if defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__)
 
266
#define HAS_TEST_AND_SET
 
267
 
 
268
#if defined(__powerpc64__)
 
269
typedef unsigned long slock_t;
 
270
#else
 
271
typedef unsigned int slock_t;
 
272
#endif
 
273
 
 
274
#define TAS(lock) tas(lock)
 
275
/*
 
276
 * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002,
 
277
 * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop.
 
278
 */
 
279
static __inline__ int
 
280
tas(volatile slock_t *lock)
 
281
{
 
282
        slock_t _t;
 
283
        int _res;
 
284
 
 
285
        __asm__ __volatile__(
 
286
"       lwarx   %0,0,%3         \n"
 
287
"       cmpwi   %0,0            \n"
 
288
"       bne     1f                      \n"
 
289
"       addi    %0,%0,1         \n"
 
290
"       stwcx.  %0,0,%3         \n"
 
291
"       beq     2f              \n"
 
292
"1:     li      %1,1            \n"
 
293
"       b               3f                      \n"
 
294
"2:                                             \n"
 
295
"       isync                           \n"
 
296
"       li      %1,0            \n"
 
297
"3:                                             \n"
 
298
 
 
299
:       "=&r"(_t), "=r"(_res), "+m"(*lock)
 
300
:       "r"(lock)
 
301
:       "memory", "cc");
 
302
        return _res;
 
303
}
 
304
 
 
305
/* PowerPC S_UNLOCK is almost standard but requires a "sync" instruction */
 
306
#define S_UNLOCK(lock)  \
 
307
do \
 
308
{\
 
309
        __asm__ __volatile__ (" sync \n"); \
 
310
        *((volatile slock_t *) (lock)) = 0; \
 
311
} while (0)
 
312
 
 
313
#endif /* powerpc */
 
314
 
 
315
 
 
316
#if defined(__mc68000__) && defined(__linux__)
 
317
#define HAS_TEST_AND_SET
 
318
 
 
319
typedef unsigned char slock_t;
 
320
 
 
321
#define TAS(lock) tas(lock)
 
322
 
 
323
static __inline__ int
 
324
tas(volatile slock_t *lock)
 
325
{
 
326
        register int rv;
 
327
 
 
328
        __asm__ __volatile__(
 
329
                "       clrl    %0              \n"
 
330
                "       tas             %1              \n"
 
331
                "       sne             %0              \n"
 
332
:               "=d"(rv), "+m"(*lock)
 
333
:
 
334
:               "memory", "cc");
 
335
        return rv;
 
336
}
 
337
 
 
338
#endif   /* defined(__mc68000__) && defined(__linux__) */
 
339
 
 
340
 
 
341
#if defined(__vax__)
 
342
/*
 
343
 * VAXen -- even multiprocessor ones
 
344
 * (thanks to Tom Ivar Helbekkmo)
 
345
 */
 
346
#define HAS_TEST_AND_SET
 
347
 
 
348
typedef unsigned char slock_t;
 
349
 
 
350
#define TAS(lock) tas(lock)
 
351
 
 
352
static __inline__ int
 
353
tas(volatile slock_t *lock)
 
354
{
 
355
        register int    _res;
 
356
 
 
357
        __asm__ __volatile__(
 
358
                "       movl    $1, %0                  \n"
 
359
                "       bbssi   $0, (%2), 1f    \n"
 
360
                "       clrl    %0                              \n"
 
361
                "1: \n"
 
362
:               "=&r"(_res), "+m"(*lock)
 
363
:               "r"(lock)
 
364
:               "memory");
 
365
        return _res;
 
366
}
 
367
 
 
368
#endif   /* __vax__ */
 
369
 
 
370
 
 
371
#if defined(__ns32k__)
 
372
#define HAS_TEST_AND_SET
 
373
 
 
374
typedef unsigned char slock_t;
 
375
 
 
376
#define TAS(lock) tas(lock)
 
377
 
 
378
static __inline__ int
 
379
tas(volatile slock_t *lock)
 
380
{
 
381
        register int    _res;
 
382
 
 
383
        __asm__ __volatile__(
 
384
                "       sbitb   0, %1   \n"
 
385
                "       sfsd    %0              \n"
 
386
:               "=r"(_res), "+m"(*lock)
 
387
:
 
388
:               "memory");
 
389
        return _res;
 
390
}
 
391
 
 
392
#endif   /* __ns32k__ */
 
393
 
 
394
 
 
395
#if defined(__alpha) || defined(__alpha__)
 
396
/*
 
397
 * Correct multi-processor locking methods are explained in section 5.5.3
 
398
 * of the Alpha AXP Architecture Handbook, which at this writing can be
 
399
 * found at ftp://ftp.netbsd.org/pub/NetBSD/misc/dec-docs/index.html.
 
400
 * For gcc we implement the handbook's code directly with inline assembler.
 
401
 */
 
402
#define HAS_TEST_AND_SET
 
403
 
 
404
typedef unsigned long slock_t;
 
405
 
 
406
#define TAS(lock)  tas(lock)
 
407
 
 
408
static __inline__ int
 
409
tas(volatile slock_t *lock)
 
410
{
 
411
        register slock_t _res;
 
412
 
 
413
        __asm__ __volatile__(
 
414
                "       ldq             $0, %1  \n"
 
415
                "       bne             $0, 2f  \n"
 
416
                "       ldq_l   %0, %1  \n"
 
417
                "       bne             %0, 2f  \n"
 
418
                "       mov             1,  $0  \n"
 
419
                "       stq_c   $0, %1  \n"
 
420
                "       beq             $0, 2f  \n"
 
421
                "       mb                              \n"
 
422
                "       br              3f              \n"
 
423
                "2:     mov             1, %0   \n"
 
424
                "3:                                     \n"
 
425
:               "=&r"(_res), "+m"(*lock)
 
426
:
 
427
:               "memory", "0");
 
428
        return (int) _res;
 
429
}
 
430
 
 
431
#define S_UNLOCK(lock)  \
 
432
do \
 
433
{\
 
434
        __asm__ __volatile__ (" mb \n"); \
 
435
        *((volatile slock_t *) (lock)) = 0; \
 
436
} while (0)
 
437
 
 
438
#endif /* __alpha || __alpha__ */
 
439
 
 
440
 
 
441
/* These live in s_lock.c, but only for gcc */
 
442
 
 
443
 
 
444
#if defined(__m68k__)
 
445
#define HAS_TEST_AND_SET
 
446
 
 
447
typedef unsigned char slock_t;
 
448
#endif
 
449
 
 
450
 
 
451
#if defined(__mips__) && !defined(__sgi)
 
452
#define HAS_TEST_AND_SET
 
453
 
 
454
typedef unsigned int slock_t;
 
455
#endif
 
456
 
 
457
 
 
458
#endif  /* __GNUC__ */
 
459
 
 
460
 
 
461
 
 
462
/***************************************************************************
 
463
 * Platforms that use non-gcc inline assembly:
 
464
 */
 
465
 
 
466
#if !defined(HAS_TEST_AND_SET)  /* We didn't trigger above, let's try here */
 
467
 
 
468
 
 
469
#if defined(USE_UNIVEL_CC)
 
470
#define HAS_TEST_AND_SET
 
471
 
 
472
typedef unsigned char slock_t;
 
473
 
 
474
#define TAS(lock)       tas(lock)
 
475
 
 
476
asm int
 
477
tas(volatile slock_t *s_lock)
 
478
{
 
479
/* UNIVEL wants %mem in column 1, so we don't pg_indent this file */
 
480
%mem s_lock
 
481
        pushl %ebx
 
482
        movl s_lock, %ebx
 
483
        movl $255, %eax
 
484
        lock
 
485
        xchgb %al, (%ebx)
 
486
        popl %ebx
 
487
}
 
488
 
 
489
#endif   /* defined(USE_UNIVEL_CC) */
 
490
 
 
491
 
 
492
#if defined(__alpha) || defined(__alpha__)
 
493
/*
 
494
 * The Tru64 compiler doesn't support gcc-style inline asm, but it does
 
495
 * have some builtin functions that accomplish much the same results.
 
496
 * For simplicity, slock_t is defined as long (ie, quadword) on Alpha
 
497
 * regardless of the compiler in use.  LOCK_LONG and UNLOCK_LONG only
 
498
 * operate on an int (ie, longword), but that's OK as long as we define
 
499
 * S_INIT_LOCK to zero out the whole quadword.
 
500
 */
 
501
#define HAS_TEST_AND_SET
 
502
 
 
503
typedef unsigned long slock_t;
 
504
 
 
505
#include <alpha/builtins.h>
 
506
#define S_INIT_LOCK(lock)  (*(lock) = 0)
 
507
#define TAS(lock)                  (__LOCK_LONG_RETRY((lock), 1) == 0)
 
508
#define S_UNLOCK(lock)     __UNLOCK_LONG(lock)
 
509
 
 
510
#endif   /* __alpha || __alpha__ */
 
511
 
 
512
 
 
513
#if defined(__hppa) || defined(__hppa__)
 
514
/*
 
515
 * HP's PA-RISC
 
516
 *
 
517
 * See src/backend/port/hpux/tas.c.template for details about LDCWX.  Because
 
518
 * LDCWX requires a 16-byte-aligned address, we declare slock_t as a 16-byte
 
519
 * struct.  The active word in the struct is whichever has the aligned address;
 
520
 * the other three words just sit at -1.
 
521
 *
 
522
 * When using gcc, we can inline the required assembly code.
 
523
 */
 
524
#define HAS_TEST_AND_SET
 
525
 
 
526
typedef struct
 
527
{
 
528
        int                     sema[4];
 
529
} slock_t;
 
530
 
 
531
#define TAS_ACTIVE_WORD(lock)   ((volatile int *) (((long) (lock) + 15) & ~15))
 
532
 
 
533
#if defined(__GNUC__)
 
534
 
 
535
static __inline__ int
 
536
tas(volatile slock_t *lock)
 
537
{
 
538
        volatile int *lockword = TAS_ACTIVE_WORD(lock);
 
539
        register int lockval;
 
540
 
 
541
        __asm__ __volatile__(
 
542
                "       ldcwx   0(0,%2),%0      \n"
 
543
:               "=r"(lockval), "+m"(*lockword)
 
544
:               "r"(lockword)
 
545
:               "memory");
 
546
        return (lockval == 0);
 
547
}
 
548
 
 
549
#endif /* __GNUC__ */
 
550
 
 
551
#define S_UNLOCK(lock)  (*TAS_ACTIVE_WORD(lock) = -1)
 
552
 
 
553
#define S_INIT_LOCK(lock) \
 
554
        do { \
 
555
                volatile slock_t *lock_ = (lock); \
 
556
                lock_->sema[0] = -1; \
 
557
                lock_->sema[1] = -1; \
 
558
                lock_->sema[2] = -1; \
 
559
                lock_->sema[3] = -1; \
 
560
        } while (0)
 
561
 
 
562
#define S_LOCK_FREE(lock)       (*TAS_ACTIVE_WORD(lock) != 0)
 
563
 
 
564
#endif   /* __hppa || __hppa__ */
 
565
 
 
566
 
 
567
#if defined(__hpux) && defined(__ia64) && !defined(__GNUC__)
 
568
 
 
569
#define HAS_TEST_AND_SET
 
570
 
 
571
typedef unsigned int slock_t;
 
572
 
 
573
#include <ia64/sys/inline.h>
 
574
#define TAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE)
 
575
 
 
576
#endif  /* HPUX on IA64, non gcc */
 
577
 
 
578
 
 
579
#if defined(__QNX__) && defined(__WATCOMC__)
 
580
/*
 
581
 * QNX 4 using WATCOM C
 
582
 */
 
583
#define HAS_TEST_AND_SET
 
584
 
 
585
typedef unsigned char slock_t;
 
586
 
 
587
#define TAS(lock) wc_tas(lock)
 
588
extern slock_t wc_tas(volatile slock_t *lock);
 
589
#pragma aux wc_tas =\
 
590
                "       mov   al,1    " \
 
591
                " lock  xchg    al,[esi]" \
 
592
                parm [esi]        \
 
593
                value [al];
 
594
 
 
595
#endif   /* __QNX__ and __WATCOMC__*/
 
596
 
 
597
 
 
598
#if defined(__sgi)
 
599
/*
 
600
 * SGI IRIX 5
 
601
 * slock_t is defined as a unsigned long. We use the standard SGI
 
602
 * mutex API.
 
603
 *
 
604
 * The following comment is left for historical reasons, but is probably
 
605
 * not a good idea since the mutex ABI is supported.
 
606
 *
 
607
 * This stuff may be supplemented in the future with Masato Kataoka's MIPS-II
 
608
 * assembly from his NECEWS SVR4 port, but we probably ought to retain this
 
609
 * for the R3000 chips out there.
 
610
 */
 
611
#define HAS_TEST_AND_SET
 
612
 
 
613
typedef unsigned long slock_t;
 
614
 
 
615
#include "mutex.h"
 
616
#define TAS(lock)       (test_and_set(lock,1))
 
617
#define S_UNLOCK(lock)  (test_then_and(lock,0))
 
618
#define S_INIT_LOCK(lock)       (test_then_and(lock,0))
 
619
#define S_LOCK_FREE(lock)       (test_then_add(lock,0) == 0)
 
620
#endif   /* __sgi */
 
621
 
 
622
 
 
623
#if defined(sinix)
 
624
/*
 
625
 * SINIX / Reliant UNIX
 
626
 * slock_t is defined as a struct abilock_t, which has a single unsigned long
 
627
 * member. (Basically same as SGI)
 
628
 */
 
629
#define HAS_TEST_AND_SET
 
630
 
 
631
#include "abi_mutex.h"
 
632
typedef abilock_t slock_t;
 
633
 
 
634
#define TAS(lock)       (!acquire_lock(lock))
 
635
#define S_UNLOCK(lock)  release_lock(lock)
 
636
#define S_INIT_LOCK(lock)       init_lock(lock)
 
637
#define S_LOCK_FREE(lock)       (stat_lock(lock) == UNLOCKED)
 
638
#endif   /* sinix */
 
639
 
 
640
 
 
641
#if defined(_AIX)
 
642
/*
 
643
 * AIX (POWER)
 
644
 */
 
645
#define HAS_TEST_AND_SET
 
646
 
 
647
typedef unsigned int slock_t;
 
648
 
 
649
#define TAS(lock)                       _check_lock(lock, 0, 1)
 
650
#define S_UNLOCK(lock)          _clear_lock(lock, 0)
 
651
#endif   /* _AIX */
 
652
 
 
653
 
 
654
#if defined (nextstep)
 
655
#define HAS_TEST_AND_SET
 
656
 
 
657
typedef struct mutex slock_t;
 
658
 
 
659
#define S_LOCK(lock)    mutex_lock(lock)
 
660
#define S_UNLOCK(lock)  mutex_unlock(lock)
 
661
#define S_INIT_LOCK(lock)       mutex_init(lock)
 
662
/* For Mach, we have to delve inside the entrails of `struct mutex'.  Ick! */
 
663
#define S_LOCK_FREE(alock)      ((alock)->lock == 0)
 
664
#endif   /* nextstep */
 
665
 
 
666
 
 
667
/* These are in s_lock.c */
 
668
 
 
669
 
 
670
#if defined(sun3)
 
671
#define HAS_TEST_AND_SET
 
672
 
 
673
typedef unsigned char slock_t;
 
674
#endif
 
675
 
 
676
 
 
677
#if defined(__sparc__) || defined(__sparc)
 
678
#define HAS_TEST_AND_SET
 
679
 
 
680
typedef unsigned char slock_t;
 
681
#endif
 
682
 
 
683
 
 
684
/* out-of-line assembler from src/backend/port/tas/foo.s */
 
685
 
 
686
#if defined(__sun) && defined(__i386)
 
687
/*
 
688
 * Solaris/386 (we only get here for non-gcc case)
 
689
 */
 
690
#define HAS_TEST_AND_SET
 
691
 
 
692
typedef unsigned char slock_t;
 
693
#endif
 
694
 
 
695
 
 
696
#endif  /* !defined(HAS_TEST_AND_SET) */
 
697
 
 
698
 
 
699
/* Blow up if we didn't have any way to do spinlocks */
 
700
#ifndef HAS_TEST_AND_SET
 
701
#error PostgreSQL does not have native spinlock support on this platform.  To continue the compilation, rerun configure using --disable-spinlocks.  However, performance will be poor.  Please report this to pgsql-bugs@postgresql.org.
 
702
#endif
 
703
 
 
704
 
 
705
#else   /* !HAVE_SPINLOCKS */
 
706
 
 
707
 
 
708
/*
 
709
 * Fake spinlock implementation using semaphores --- slow and prone
 
710
 * to fall foul of kernel limits on number of semaphores, so don't use this
 
711
 * unless you must!  The subroutines appear in spin.c.
 
712
 */
 
713
typedef PGSemaphoreData slock_t;
 
714
 
 
715
extern bool s_lock_free_sema(volatile slock_t *lock);
 
716
extern void s_unlock_sema(volatile slock_t *lock);
 
717
extern void s_init_lock_sema(volatile slock_t *lock);
 
718
extern int      tas_sema(volatile slock_t *lock);
 
719
 
 
720
#define S_LOCK_FREE(lock)       s_lock_free_sema(lock)
 
721
#define S_UNLOCK(lock)   s_unlock_sema(lock)
 
722
#define S_INIT_LOCK(lock)       s_init_lock_sema(lock)
 
723
#define TAS(lock)       tas_sema(lock)
 
724
 
 
725
 
 
726
#endif  /* HAVE_SPINLOCKS */
 
727
 
 
728
 
 
729
/*
 
730
 * Default Definitions - override these above as needed.
 
731
 */
 
732
 
 
733
#if !defined(S_LOCK)
 
734
#define S_LOCK(lock) \
 
735
        do { \
 
736
                if (TAS(lock)) \
 
737
                        s_lock((lock), __FILE__, __LINE__); \
 
738
        } while (0)
 
739
#endif   /* S_LOCK */
 
740
 
 
741
#if !defined(S_LOCK_FREE)
 
742
#define S_LOCK_FREE(lock)       (*(lock) == 0)
 
743
#endif   /* S_LOCK_FREE */
 
744
 
 
745
#if !defined(S_UNLOCK)
 
746
#define S_UNLOCK(lock)          (*((volatile slock_t *) (lock)) = 0)
 
747
#endif   /* S_UNLOCK */
 
748
 
 
749
#if !defined(S_INIT_LOCK)
 
750
#define S_INIT_LOCK(lock)       S_UNLOCK(lock)
 
751
#endif   /* S_INIT_LOCK */
 
752
 
 
753
#if !defined(SPIN_DELAY)
 
754
#define SPIN_DELAY()    ((void) 0)
 
755
#endif   /* SPIN_DELAY */
 
756
 
 
757
#if !defined(TAS)
 
758
extern int      tas(volatile slock_t *lock);            /* in port/.../tas.s, or
 
759
                                                                                                 * s_lock.c */
 
760
 
 
761
#define TAS(lock)               tas(lock)
 
762
#endif   /* TAS */
 
763
 
 
764
 
 
765
/*
 
766
 * Platform-independent out-of-line support routines
 
767
 */
 
768
extern void s_lock(volatile slock_t *lock, const char *file, int line);
 
769
 
 
770
#endif   /* S_LOCK_H */