]> granicus.if.org Git - postgresql/blob - src/include/storage/s_lock.h
Add comments that Solaris Sun compiler only supports sparc9 ASM,
[postgresql] / src / include / storage / s_lock.h
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-2006, 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.153 2006/05/17 23:57:03 momjian 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 #ifdef __i386__         /* 32-bit i386 */
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         /*
124          * Use a non-locking test before asserting the bus lock.  Note that the
125          * extra test appears to be a small loss on some x86 platforms and a small
126          * win on others; it's by no means clear that we should keep it.
127          */
128         __asm__ __volatile__(
129                 "       cmpb    $0,%1   \n"
130                 "       jne             1f              \n"
131                 "       lock                    \n"
132                 "       xchgb   %0,%1   \n"
133                 "1: \n"
134 :               "+q"(_res), "+m"(*lock)
135 :
136 :               "memory", "cc");
137         return (int) _res;
138 }
139
140 #define SPIN_DELAY() spin_delay()
141
142 static __inline__ void
143 spin_delay(void)
144 {
145         /*
146          * This sequence is equivalent to the PAUSE instruction ("rep" is
147          * ignored by old IA32 processors if the following instruction is
148          * not a string operation); the IA-32 Architecture Software
149          * Developer's Manual, Vol. 3, Section 7.7.2 describes why using
150          * PAUSE in the inner loop of a spin lock is necessary for good
151          * performance:
152          *
153          *     The PAUSE instruction improves the performance of IA-32
154          *     processors supporting Hyper-Threading Technology when
155          *     executing spin-wait loops and other routines where one
156          *     thread is accessing a shared lock or semaphore in a tight
157          *     polling loop. When executing a spin-wait loop, the
158          *     processor can suffer a severe performance penalty when
159          *     exiting the loop because it detects a possible memory order
160          *     violation and flushes the core processor's pipeline. The
161          *     PAUSE instruction provides a hint to the processor that the
162          *     code sequence is a spin-wait loop. The processor uses this
163          *     hint to avoid the memory order violation and prevent the
164          *     pipeline flush. In addition, the PAUSE instruction
165          *     de-pipelines the spin-wait loop to prevent it from
166          *     consuming execution resources excessively.
167          */
168         __asm__ __volatile__(
169                 " rep; nop                      \n");
170 }
171
172 #endif   /* __i386__ */
173
174
175 #ifdef __x86_64__               /* AMD Opteron, Intel EM64T */
176 #define HAS_TEST_AND_SET
177
178 typedef unsigned char slock_t;
179
180 #define TAS(lock) tas(lock)
181
182 static __inline__ int
183 tas(volatile slock_t *lock)
184 {
185         register slock_t _res = 1;
186
187         /*
188          * On Opteron, using a non-locking test before the locking instruction
189          * is a huge loss.  On EM64T, it appears to be a wash or small loss,
190          * so we needn't bother to try to distinguish the sub-architectures.
191          */
192         __asm__ __volatile__(
193                 "       lock                    \n"
194                 "       xchgb   %0,%1   \n"
195 :               "+q"(_res), "+m"(*lock)
196 :
197 :               "memory", "cc");
198         return (int) _res;
199 }
200
201 #define SPIN_DELAY() spin_delay()
202
203 static __inline__ void
204 spin_delay(void)
205 {
206         /*
207          * Adding a PAUSE in the spin delay loop is demonstrably a no-op on
208          * Opteron, but it may be of some use on EM64T, so we keep it.
209          */
210         __asm__ __volatile__(
211                 " rep; nop                      \n");
212 }
213
214 #endif   /* __x86_64__ */
215
216
217 #if defined(__ia64__) || defined(__ia64)        /* Intel Itanium */
218 #define HAS_TEST_AND_SET
219
220 typedef unsigned int slock_t;
221
222 #define TAS(lock) tas(lock)
223
224 #ifndef __INTEL_COMPILER
225
226 static __inline__ int
227 tas(volatile slock_t *lock)
228 {
229         long int        ret;
230
231         __asm__ __volatile__(
232                 "       xchg4   %0=%1,%2        \n"
233 :               "=r"(ret), "+m"(*lock)
234 :               "r"(1)
235 :               "memory");
236         return (int) ret;
237 }
238
239 #else /* __INTEL_COMPILER */
240
241 static __inline__ int
242 tas(volatile slock_t *lock)
243 {
244         int             ret;
245
246         ret = _InterlockedExchange(lock,1);     /* this is a xchg asm macro */
247
248         return ret;
249 }
250
251 #endif /* __INTEL_COMPILER */
252 #endif   /* __ia64__ || __ia64 */
253
254
255 #if defined(__arm__) || defined(__arm)
256 #define HAS_TEST_AND_SET
257
258 typedef unsigned char slock_t;
259
260 #define TAS(lock) tas(lock)
261
262 static __inline__ int
263 tas(volatile slock_t *lock)
264 {
265         register slock_t _res = 1;
266
267         __asm__ __volatile__(
268                 "       swpb    %0, %0, [%2]    \n"
269 :               "+r"(_res), "+m"(*lock)
270 :               "r"(lock)
271 :               "memory");
272         return (int) _res;
273 }
274
275 #endif   /* __arm__ */
276
277
278 /* S/390 and S/390x Linux (32- and 64-bit zSeries) */
279 #if defined(__s390__) || defined(__s390x__)
280 #define HAS_TEST_AND_SET
281
282 typedef unsigned int slock_t;
283
284 #define TAS(lock)          tas(lock)
285
286 static __inline__ int
287 tas(volatile slock_t *lock)
288 {
289         int                     _res = 0;
290
291         __asm__ __volatile__(
292                 "       cs      %0,%3,0(%2)             \n"
293 :               "+d"(_res), "+m"(*lock)
294 :               "a"(lock), "d"(1)
295 :               "memory", "cc");
296         return _res;
297 }
298
299 #endif   /* __s390__ || __s390x__ */
300
301
302 #if defined(__sparc__)          /* Sparc */
303 #define HAS_TEST_AND_SET
304
305 typedef unsigned char slock_t;
306
307 #define TAS(lock) tas(lock)
308
309 static __inline__ int
310 tas(volatile slock_t *lock)
311 {
312         register slock_t _res;
313
314         /*
315          *      See comment in /pg/backend/port/tas/solaris_sparc.s for why this
316          *      uses "ldstub", and that file uses "cas".
317          */
318         __asm__ __volatile__(
319                 "       ldstub  [%2], %0        \n"
320 :               "=r"(_res), "+m"(*lock)
321 :               "r"(lock)
322 :               "memory");
323         return (int) _res;
324 }
325
326 #endif   /* __sparc__ */
327
328
329 /* PowerPC */
330 #if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
331 #define HAS_TEST_AND_SET
332
333 #if defined(__ppc64__) || defined(__powerpc64__)
334 typedef unsigned long slock_t;
335 #else
336 typedef unsigned int slock_t;
337 #endif
338
339 #define TAS(lock) tas(lock)
340 /*
341  * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002,
342  * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop.
343  */
344 static __inline__ int
345 tas(volatile slock_t *lock)
346 {
347         slock_t _t;
348         int _res;
349
350         __asm__ __volatile__(
351 "       lwarx   %0,0,%3         \n"
352 "       cmpwi   %0,0            \n"
353 "       bne     1f                      \n"
354 "       addi    %0,%0,1         \n"
355 "       stwcx.  %0,0,%3         \n"
356 "       beq     2f              \n"
357 "1:     li      %1,1            \n"
358 "       b               3f                      \n"
359 "2:                                             \n"
360 "       isync                           \n"
361 "       li      %1,0            \n"
362 "3:                                             \n"
363
364 :       "=&r"(_t), "=r"(_res), "+m"(*lock)
365 :       "r"(lock)
366 :       "memory", "cc");
367         return _res;
368 }
369
370 /* PowerPC S_UNLOCK is almost standard but requires a "sync" instruction */
371 #define S_UNLOCK(lock)  \
372 do \
373 { \
374         __asm__ __volatile__ (" sync \n"); \
375         *((volatile slock_t *) (lock)) = 0; \
376 } while (0)
377
378 #endif /* powerpc */
379
380
381 /* Linux Motorola 68k */
382 #if (defined(__mc68000__) || defined(__m68k__)) && defined(__linux__)
383 #define HAS_TEST_AND_SET
384
385 typedef unsigned char slock_t;
386
387 #define TAS(lock) tas(lock)
388
389 static __inline__ int
390 tas(volatile slock_t *lock)
391 {
392         register int rv;
393
394         __asm__ __volatile__(
395                 "       clrl    %0              \n"
396                 "       tas             %1              \n"
397                 "       sne             %0              \n"
398 :               "=d"(rv), "+m"(*lock)
399 :
400 :               "memory", "cc");
401         return rv;
402 }
403
404 #endif   /* (__mc68000__ || __m68k__) && __linux__ */
405
406
407 /*
408  * VAXen -- even multiprocessor ones
409  * (thanks to Tom Ivar Helbekkmo)
410  */
411 #if defined(__vax__)
412 #define HAS_TEST_AND_SET
413
414 typedef unsigned char slock_t;
415
416 #define TAS(lock) tas(lock)
417
418 static __inline__ int
419 tas(volatile slock_t *lock)
420 {
421         register int    _res;
422
423         __asm__ __volatile__(
424                 "       movl    $1, %0                  \n"
425                 "       bbssi   $0, (%2), 1f    \n"
426                 "       clrl    %0                              \n"
427                 "1: \n"
428 :               "=&r"(_res), "+m"(*lock)
429 :               "r"(lock)
430 :               "memory");
431         return _res;
432 }
433
434 #endif   /* __vax__ */
435
436
437 #if defined(__ns32k__)          /* National Semiconductor 32K */
438 #define HAS_TEST_AND_SET
439
440 typedef unsigned char slock_t;
441
442 #define TAS(lock) tas(lock)
443
444 static __inline__ int
445 tas(volatile slock_t *lock)
446 {
447         register int    _res;
448
449         __asm__ __volatile__(
450                 "       sbitb   0, %1   \n"
451                 "       sfsd    %0              \n"
452 :               "=r"(_res), "+m"(*lock)
453 :
454 :               "memory");
455         return _res;
456 }
457
458 #endif   /* __ns32k__ */
459
460
461 #if defined(__alpha) || defined(__alpha__)      /* Alpha */
462 /*
463  * Correct multi-processor locking methods are explained in section 5.5.3
464  * of the Alpha AXP Architecture Handbook, which at this writing can be
465  * found at ftp://ftp.netbsd.org/pub/NetBSD/misc/dec-docs/index.html.
466  * For gcc we implement the handbook's code directly with inline assembler.
467  */
468 #define HAS_TEST_AND_SET
469
470 typedef unsigned long slock_t;
471
472 #define TAS(lock)  tas(lock)
473
474 static __inline__ int
475 tas(volatile slock_t *lock)
476 {
477         register slock_t _res;
478
479         __asm__ __volatile__(
480                 "       ldq             $0, %1  \n"
481                 "       bne             $0, 2f  \n"
482                 "       ldq_l   %0, %1  \n"
483                 "       bne             %0, 2f  \n"
484                 "       mov             1,  $0  \n"
485                 "       stq_c   $0, %1  \n"
486                 "       beq             $0, 2f  \n"
487                 "       mb                              \n"
488                 "       br              3f              \n"
489                 "2:     mov             1, %0   \n"
490                 "3:                                     \n"
491 :               "=&r"(_res), "+m"(*lock)
492 :
493 :               "memory", "0");
494         return (int) _res;
495 }
496
497 #define S_UNLOCK(lock)  \
498 do \
499 {\
500         __asm__ __volatile__ (" mb \n"); \
501         *((volatile slock_t *) (lock)) = 0; \
502 } while (0)
503
504 #endif /* __alpha || __alpha__ */
505
506
507 #if defined(__mips__) && !defined(__sgi)        /* non-SGI MIPS */
508 /* Note: on SGI we use the OS' mutex ABI, see below */
509 /* Note: R10000 processors require a separate SYNC */
510 #define HAS_TEST_AND_SET
511
512 typedef unsigned int slock_t;
513
514 #define TAS(lock) tas(lock)
515
516 static __inline__ int
517 tas(volatile slock_t *lock)
518 {
519         register volatile slock_t *_l = lock;
520         register int _res;
521         register int _tmp;
522
523         __asm__ __volatile__(
524                 "       .set push           \n"
525                 "       .set mips2          \n"
526                 "       .set noreorder      \n"
527                 "       .set nomacro        \n"
528                 "       ll      %0, %2      \n"
529                 "       or      %1, %0, 1   \n"
530                 "       sc      %1, %2      \n"
531                 "       xori    %1, 1       \n"
532                 "       or      %0, %0, %1  \n"
533                 "       sync                \n"
534                 "       .set pop              "
535 :               "=&r" (_res), "=&r" (_tmp), "+R" (*_l)
536 :
537 :               "memory");
538         return _res;
539 }
540
541 /* MIPS S_UNLOCK is almost standard but requires a "sync" instruction */
542 #define S_UNLOCK(lock)  \
543 do \
544 { \
545         __asm__ __volatile__( \
546                 "       .set push           \n" \
547                 "       .set mips2          \n" \
548                 "       .set noreorder      \n" \
549                 "       .set nomacro        \n" \
550                 "       sync                \n" \
551                 "       .set pop              "); \
552         *((volatile slock_t *) (lock)) = 0; \
553 } while (0)
554
555 #endif /* __mips__ && !__sgi */
556
557
558 /* These live in s_lock.c, but only for gcc */
559
560
561 #if defined(__m68k__) && !defined(__linux__)    /* non-Linux Motorola 68k */
562 #define HAS_TEST_AND_SET
563
564 typedef unsigned char slock_t;
565 #endif
566
567
568 #endif  /* __GNUC__ */
569
570
571
572 /*
573  * ---------------------------------------------------------------------
574  * Platforms that use non-gcc inline assembly:
575  * ---------------------------------------------------------------------
576  */
577
578 #if !defined(HAS_TEST_AND_SET)  /* We didn't trigger above, let's try here */
579
580
581 #if defined(USE_UNIVEL_CC)              /* Unixware compiler */
582 #define HAS_TEST_AND_SET
583
584 typedef unsigned char slock_t;
585
586 #define TAS(lock)       tas(lock)
587
588 asm int
589 tas(volatile slock_t *s_lock)
590 {
591 /* UNIVEL wants %mem in column 1, so we don't pg_indent this file */
592 %mem s_lock
593         pushl %ebx
594         movl s_lock, %ebx
595         movl $255, %eax
596         lock
597         xchgb %al, (%ebx)
598         popl %ebx
599 }
600
601 #endif   /* defined(USE_UNIVEL_CC) */
602
603
604 #if defined(__alpha) || defined(__alpha__)      /* Tru64 Unix Alpha compiler */
605 /*
606  * The Tru64 compiler doesn't support gcc-style inline asm, but it does
607  * have some builtin functions that accomplish much the same results.
608  * For simplicity, slock_t is defined as long (ie, quadword) on Alpha
609  * regardless of the compiler in use.  LOCK_LONG and UNLOCK_LONG only
610  * operate on an int (ie, longword), but that's OK as long as we define
611  * S_INIT_LOCK to zero out the whole quadword.
612  */
613 #define HAS_TEST_AND_SET
614
615 typedef unsigned long slock_t;
616
617 #include <alpha/builtins.h>
618 #define S_INIT_LOCK(lock)  (*(lock) = 0)
619 #define TAS(lock)                  (__LOCK_LONG_RETRY((lock), 1) == 0)
620 #define S_UNLOCK(lock)     __UNLOCK_LONG(lock)
621
622 #endif   /* __alpha || __alpha__ */
623
624
625 #if defined(__hppa) || defined(__hppa__)        /* HP PA-RISC, GCC and HP compilers */
626 /*
627  * HP's PA-RISC
628  *
629  * See src/backend/port/hpux/tas.c.template for details about LDCWX.  Because
630  * LDCWX requires a 16-byte-aligned address, we declare slock_t as a 16-byte
631  * struct.  The active word in the struct is whichever has the aligned address;
632  * the other three words just sit at -1.
633  *
634  * When using gcc, we can inline the required assembly code.
635  */
636 #define HAS_TEST_AND_SET
637
638 typedef struct
639 {
640         int                     sema[4];
641 } slock_t;
642
643 #define TAS_ACTIVE_WORD(lock)   ((volatile int *) (((long) (lock) + 15) & ~15))
644
645 #if defined(__GNUC__)
646
647 static __inline__ int
648 tas(volatile slock_t *lock)
649 {
650         volatile int *lockword = TAS_ACTIVE_WORD(lock);
651         register int lockval;
652
653         __asm__ __volatile__(
654                 "       ldcwx   0(0,%2),%0      \n"
655 :               "=r"(lockval), "+m"(*lockword)
656 :               "r"(lockword)
657 :               "memory");
658         return (lockval == 0);
659 }
660
661 #endif /* __GNUC__ */
662
663 #define S_UNLOCK(lock)  (*TAS_ACTIVE_WORD(lock) = -1)
664
665 #define S_INIT_LOCK(lock) \
666         do { \
667                 volatile slock_t *lock_ = (lock); \
668                 lock_->sema[0] = -1; \
669                 lock_->sema[1] = -1; \
670                 lock_->sema[2] = -1; \
671                 lock_->sema[3] = -1; \
672         } while (0)
673
674 #define S_LOCK_FREE(lock)       (*TAS_ACTIVE_WORD(lock) != 0)
675
676 #endif   /* __hppa || __hppa__ */
677
678
679 #if defined(__hpux) && defined(__ia64) && !defined(__GNUC__)
680
681 #define HAS_TEST_AND_SET
682
683 typedef unsigned int slock_t;
684
685 #include <ia64/sys/inline.h>
686 #define TAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE)
687
688 #endif  /* HPUX on IA64, non gcc */
689
690
691 #if defined(__sgi)      /* SGI compiler */
692 /*
693  * SGI IRIX 5
694  * slock_t is defined as a unsigned long. We use the standard SGI
695  * mutex API.
696  *
697  * The following comment is left for historical reasons, but is probably
698  * not a good idea since the mutex ABI is supported.
699  *
700  * This stuff may be supplemented in the future with Masato Kataoka's MIPS-II
701  * assembly from his NECEWS SVR4 port, but we probably ought to retain this
702  * for the R3000 chips out there.
703  */
704 #define HAS_TEST_AND_SET
705
706 typedef unsigned long slock_t;
707
708 #include "mutex.h"
709 #define TAS(lock)       (test_and_set(lock,1))
710 #define S_UNLOCK(lock)  (test_then_and(lock,0))
711 #define S_INIT_LOCK(lock)       (test_then_and(lock,0))
712 #define S_LOCK_FREE(lock)       (test_then_add(lock,0) == 0)
713 #endif   /* __sgi */
714
715
716 #if defined(sinix)              /* Sinix */
717 /*
718  * SINIX / Reliant UNIX
719  * slock_t is defined as a struct abilock_t, which has a single unsigned long
720  * member. (Basically same as SGI)
721  */
722 #define HAS_TEST_AND_SET
723
724 #include "abi_mutex.h"
725 typedef abilock_t slock_t;
726
727 #define TAS(lock)       (!acquire_lock(lock))
728 #define S_UNLOCK(lock)  release_lock(lock)
729 #define S_INIT_LOCK(lock)       init_lock(lock)
730 #define S_LOCK_FREE(lock)       (stat_lock(lock) == UNLOCKED)
731 #endif   /* sinix */
732
733
734 #if defined(_AIX)       /* AIX */
735 /*
736  * AIX (POWER)
737  */
738 #define HAS_TEST_AND_SET
739
740 typedef unsigned int slock_t;
741
742 #define TAS(lock)                       _check_lock(lock, 0, 1)
743 #define S_UNLOCK(lock)          _clear_lock(lock, 0)
744 #endif   /* _AIX */
745
746
747 #if defined (nextstep)          /* Nextstep */
748 #define HAS_TEST_AND_SET
749
750 typedef struct mutex slock_t;
751
752 #define S_LOCK(lock)    mutex_lock(lock)
753 #define S_UNLOCK(lock)  mutex_unlock(lock)
754 #define S_INIT_LOCK(lock)       mutex_init(lock)
755 /* For Mach, we have to delve inside the entrails of `struct mutex'.  Ick! */
756 #define S_LOCK_FREE(alock)      ((alock)->lock == 0)
757 #endif   /* nextstep */
758
759
760 /* These are in s_lock.c */
761
762
763 #if defined(sun3)               /* Sun3 */
764 #define HAS_TEST_AND_SET
765
766 typedef unsigned char slock_t;
767 #endif
768
769
770 #if defined(__sun) && (defined(__i386) || defined(__x86_64__) || defined(__sparc__) || defined(__sparc))
771 #define HAS_TEST_AND_SET
772 typedef unsigned int slock_t;
773
774 extern slock_t pg_atomic_cas(volatile slock_t *lock, slock_t with,
775                                                                           slock_t cmp);
776
777 #define TAS(a) (pg_atomic_cas((a), 1, 0) != 0)
778 #endif
779
780
781 #endif  /* !defined(HAS_TEST_AND_SET) */
782
783
784 /* Blow up if we didn't have any way to do spinlocks */
785 #ifndef HAS_TEST_AND_SET
786 #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.
787 #endif
788
789
790 #else   /* !HAVE_SPINLOCKS */
791
792
793 /*
794  * Fake spinlock implementation using semaphores --- slow and prone
795  * to fall foul of kernel limits on number of semaphores, so don't use this
796  * unless you must!  The subroutines appear in spin.c.
797  */
798 typedef PGSemaphoreData slock_t;
799
800 extern bool s_lock_free_sema(volatile slock_t *lock);
801 extern void s_unlock_sema(volatile slock_t *lock);
802 extern void s_init_lock_sema(volatile slock_t *lock);
803 extern int      tas_sema(volatile slock_t *lock);
804
805 #define S_LOCK_FREE(lock)       s_lock_free_sema(lock)
806 #define S_UNLOCK(lock)   s_unlock_sema(lock)
807 #define S_INIT_LOCK(lock)       s_init_lock_sema(lock)
808 #define TAS(lock)       tas_sema(lock)
809
810
811 #endif  /* HAVE_SPINLOCKS */
812
813
814 /*
815  * Default Definitions - override these above as needed.
816  */
817
818 #if !defined(S_LOCK)
819 #define S_LOCK(lock) \
820         do { \
821                 if (TAS(lock)) \
822                         s_lock((lock), __FILE__, __LINE__); \
823         } while (0)
824 #endif   /* S_LOCK */
825
826 #if !defined(S_LOCK_FREE)
827 #define S_LOCK_FREE(lock)       (*(lock) == 0)
828 #endif   /* S_LOCK_FREE */
829
830 #if !defined(S_UNLOCK)
831 #define S_UNLOCK(lock)          (*((volatile slock_t *) (lock)) = 0)
832 #endif   /* S_UNLOCK */
833
834 #if !defined(S_INIT_LOCK)
835 #define S_INIT_LOCK(lock)       S_UNLOCK(lock)
836 #endif   /* S_INIT_LOCK */
837
838 #if !defined(SPIN_DELAY)
839 #define SPIN_DELAY()    ((void) 0)
840 #endif   /* SPIN_DELAY */
841
842 #if !defined(TAS)
843 extern int      tas(volatile slock_t *lock);            /* in port/.../tas.s, or
844                                                                                                  * s_lock.c */
845
846 #define TAS(lock)               tas(lock)
847 #endif   /* TAS */
848
849
850 /*
851  * Platform-independent out-of-line support routines
852  */
853 extern void s_lock(volatile slock_t *lock, const char *file, int line);
854
855 /* Support for dynamic adjustment of spins_per_delay */
856 #define DEFAULT_SPINS_PER_DELAY  100
857
858 extern void set_spins_per_delay(int shared_spins_per_delay);
859 extern int      update_spins_per_delay(int shared_spins_per_delay);
860
861 #endif   /* S_LOCK_H */