]> granicus.if.org Git - postgresql/blob - src/include/storage/s_lock.h
Remove Alpha and Tru64 support.
[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  *      int 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  *              Should return number of "delays"; see s_lock.c
20  *
21  *      void S_UNLOCK(slock_t *lock)
22  *              Unlock a previously acquired lock.
23  *
24  *      bool S_LOCK_FREE(slock_t *lock)
25  *              Tests if the lock is free. Returns TRUE if free, FALSE if locked.
26  *              This does *not* change the state of the lock.
27  *
28  *      void SPIN_DELAY(void)
29  *              Delay operation to occur inside spinlock wait loop.
30  *
31  *      Note to implementors: there are default implementations for all these
32  *      macros at the bottom of the file.  Check if your platform can use
33  *      these or needs to override them.
34  *
35  *  Usually, S_LOCK() is implemented in terms of even lower-level macros
36  *      TAS() and TAS_SPIN():
37  *
38  *      int TAS(slock_t *lock)
39  *              Atomic test-and-set instruction.  Attempt to acquire the lock,
40  *              but do *not* wait.      Returns 0 if successful, nonzero if unable
41  *              to acquire the lock.
42  *
43  *      int TAS_SPIN(slock_t *lock)
44  *              Like TAS(), but this version is used when waiting for a lock
45  *              previously found to be contended.  By default, this is the
46  *              same as TAS(), but on some architectures it's better to poll a
47  *              contended lock using an unlocked instruction and retry the
48  *              atomic test-and-set only when it appears free.
49  *
50  *      TAS() and TAS_SPIN() are NOT part of the API, and should never be called
51  *      directly.
52  *
53  *      CAUTION: on some platforms TAS() and/or TAS_SPIN() may sometimes report
54  *      failure to acquire a lock even when the lock is not locked.  For example,
55  *      on Alpha TAS() will "fail" if interrupted.  Therefore a retry loop must
56  *      always be used, even if you are certain the lock is free.
57  *
58  *      Another caution for users of these macros is that it is the caller's
59  *      responsibility to ensure that the compiler doesn't re-order accesses
60  *      to shared memory to precede the actual lock acquisition, or follow the
61  *      lock release.  Typically we handle this by using volatile-qualified
62  *      pointers to refer to both the spinlock itself and the shared data
63  *      structure being accessed within the spinlocked critical section.
64  *      That fixes it because compilers are not allowed to re-order accesses
65  *      to volatile objects relative to other such accesses.
66  *
67  *      On platforms with weak memory ordering, the TAS(), TAS_SPIN(), and
68  *      S_UNLOCK() macros must further include hardware-level memory fence
69  *      instructions to prevent similar re-ordering at the hardware level.
70  *      TAS() and TAS_SPIN() must guarantee that loads and stores issued after
71  *      the macro are not executed until the lock has been obtained.  Conversely,
72  *      S_UNLOCK() must guarantee that loads and stores issued before the macro
73  *      have been executed before the lock is released.
74  *
75  *      On most supported platforms, TAS() uses a tas() function written
76  *      in assembly language to execute a hardware atomic-test-and-set
77  *      instruction.  Equivalent OS-supplied mutex routines could be used too.
78  *
79  *      If no system-specific TAS() is available (ie, HAVE_SPINLOCKS is not
80  *      defined), then we fall back on an emulation that uses SysV semaphores
81  *      (see spin.c).  This emulation will be MUCH MUCH slower than a proper TAS()
82  *      implementation, because of the cost of a kernel call per lock or unlock.
83  *      An old report is that Postgres spends around 40% of its time in semop(2)
84  *      when using the SysV semaphore code.
85  *
86  *
87  * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
88  * Portions Copyright (c) 1994, Regents of the University of California
89  *
90  *        src/include/storage/s_lock.h
91  *
92  *-------------------------------------------------------------------------
93  */
94 #ifndef S_LOCK_H
95 #define S_LOCK_H
96
97 #ifdef HAVE_SPINLOCKS   /* skip spinlocks if requested */
98
99 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
100 /*************************************************************************
101  * All the gcc inlines
102  * Gcc consistently defines the CPU as __cpu__.
103  * Other compilers use __cpu or __cpu__ so we test for both in those cases.
104  */
105
106 /*----------
107  * Standard gcc asm format (assuming "volatile slock_t *lock"):
108
109         __asm__ __volatile__(
110                 "       instruction     \n"
111                 "       instruction     \n"
112                 "       instruction     \n"
113 :               "=r"(_res), "+m"(*lock)         // return register, in/out lock value
114 :               "r"(lock)                                       // lock pointer, in input register
115 :               "memory", "cc");                        // show clobbered registers here
116
117  * The output-operands list (after first colon) should always include
118  * "+m"(*lock), whether or not the asm code actually refers to this
119  * operand directly.  This ensures that gcc believes the value in the
120  * lock variable is used and set by the asm code.  Also, the clobbers
121  * list (after third colon) should always include "memory"; this prevents
122  * gcc from thinking it can cache the values of shared-memory fields
123  * across the asm code.  Add "cc" if your asm code changes the condition
124  * code register, and also list any temp registers the code uses.
125  *----------
126  */
127
128
129 #ifdef __i386__         /* 32-bit i386 */
130 #define HAS_TEST_AND_SET
131
132 typedef unsigned char slock_t;
133
134 #define TAS(lock) tas(lock)
135
136 static __inline__ int
137 tas(volatile slock_t *lock)
138 {
139         register slock_t _res = 1;
140
141         /*
142          * Use a non-locking test before asserting the bus lock.  Note that the
143          * extra test appears to be a small loss on some x86 platforms and a small
144          * win on others; it's by no means clear that we should keep it.
145          *
146          * When this was last tested, we didn't have separate TAS() and TAS_SPIN()
147          * macros.  Nowadays it probably would be better to do a non-locking test
148          * in TAS_SPIN() but not in TAS(), like on x86_64, but no-one's done the
149          * testing to verify that.  Without some empirical evidence, better to
150          * leave it alone.
151          */
152         __asm__ __volatile__(
153                 "       cmpb    $0,%1   \n"
154                 "       jne             1f              \n"
155                 "       lock                    \n"
156                 "       xchgb   %0,%1   \n"
157                 "1: \n"
158 :               "+q"(_res), "+m"(*lock)
159 :
160 :               "memory", "cc");
161         return (int) _res;
162 }
163
164 #define SPIN_DELAY() spin_delay()
165
166 static __inline__ void
167 spin_delay(void)
168 {
169         /*
170          * This sequence is equivalent to the PAUSE instruction ("rep" is
171          * ignored by old IA32 processors if the following instruction is
172          * not a string operation); the IA-32 Architecture Software
173          * Developer's Manual, Vol. 3, Section 7.7.2 describes why using
174          * PAUSE in the inner loop of a spin lock is necessary for good
175          * performance:
176          *
177          *     The PAUSE instruction improves the performance of IA-32
178          *     processors supporting Hyper-Threading Technology when
179          *     executing spin-wait loops and other routines where one
180          *     thread is accessing a shared lock or semaphore in a tight
181          *     polling loop. When executing a spin-wait loop, the
182          *     processor can suffer a severe performance penalty when
183          *     exiting the loop because it detects a possible memory order
184          *     violation and flushes the core processor's pipeline. The
185          *     PAUSE instruction provides a hint to the processor that the
186          *     code sequence is a spin-wait loop. The processor uses this
187          *     hint to avoid the memory order violation and prevent the
188          *     pipeline flush. In addition, the PAUSE instruction
189          *     de-pipelines the spin-wait loop to prevent it from
190          *     consuming execution resources excessively.
191          */
192         __asm__ __volatile__(
193                 " rep; nop                      \n");
194 }
195
196 #endif   /* __i386__ */
197
198
199 #ifdef __x86_64__               /* AMD Opteron, Intel EM64T */
200 #define HAS_TEST_AND_SET
201
202 typedef unsigned char slock_t;
203
204 #define TAS(lock) tas(lock)
205
206 /*
207  * On Intel EM64T, it's a win to use a non-locking test before the xchg proper,
208  * but only when spinning.
209  *
210  * See also Implementing Scalable Atomic Locks for Multi-Core Intel(tm) EM64T
211  * and IA32, by Michael Chynoweth and Mary R. Lee. As of this writing, it is
212  * available at:
213  * http://software.intel.com/en-us/articles/implementing-scalable-atomic-locks-for-multi-core-intel-em64t-and-ia32-architectures
214  */
215 #define TAS_SPIN(lock)    (*(lock) ? 1 : TAS(lock))
216
217 static __inline__ int
218 tas(volatile slock_t *lock)
219 {
220         register slock_t _res = 1;
221
222         __asm__ __volatile__(
223                 "       lock                    \n"
224                 "       xchgb   %0,%1   \n"
225 :               "+q"(_res), "+m"(*lock)
226 :
227 :               "memory", "cc");
228         return (int) _res;
229 }
230
231 #define SPIN_DELAY() spin_delay()
232
233 static __inline__ void
234 spin_delay(void)
235 {
236         /*
237          * Adding a PAUSE in the spin delay loop is demonstrably a no-op on
238          * Opteron, but it may be of some use on EM64T, so we keep it.
239          */
240         __asm__ __volatile__(
241                 " rep; nop                      \n");
242 }
243
244 #endif   /* __x86_64__ */
245
246
247 #if defined(__ia64__) || defined(__ia64)
248 /*
249  * Intel Itanium, gcc or Intel's compiler.
250  *
251  * Itanium has weak memory ordering, but we rely on the compiler to enforce
252  * strict ordering of accesses to volatile data.  In particular, while the
253  * xchg instruction implicitly acts as a memory barrier with 'acquire'
254  * semantics, we do not have an explicit memory fence instruction in the
255  * S_UNLOCK macro.  We use a regular assignment to clear the spinlock, and
256  * trust that the compiler marks the generated store instruction with the
257  * ".rel" opcode.
258  *
259  * Testing shows that assumption to hold on gcc, although I could not find
260  * any explicit statement on that in the gcc manual.  In Intel's compiler,
261  * the -m[no-]serialize-volatile option controls that, and testing shows that
262  * it is enabled by default.
263  */
264 #define HAS_TEST_AND_SET
265
266 typedef unsigned int slock_t;
267
268 #define TAS(lock) tas(lock)
269
270 /* On IA64, it's a win to use a non-locking test before the xchg proper */
271 #define TAS_SPIN(lock)  (*(lock) ? 1 : TAS(lock))
272
273 #ifndef __INTEL_COMPILER
274
275 static __inline__ int
276 tas(volatile slock_t *lock)
277 {
278         long int        ret;
279
280         __asm__ __volatile__(
281                 "       xchg4   %0=%1,%2        \n"
282 :               "=r"(ret), "+m"(*lock)
283 :               "r"(1)
284 :               "memory");
285         return (int) ret;
286 }
287
288 #else /* __INTEL_COMPILER */
289
290 static __inline__ int
291 tas(volatile slock_t *lock)
292 {
293         int             ret;
294
295         ret = _InterlockedExchange(lock,1);     /* this is a xchg asm macro */
296
297         return ret;
298 }
299
300 #endif /* __INTEL_COMPILER */
301 #endif   /* __ia64__ || __ia64 */
302
303
304 /*
305  * On ARM, we use __sync_lock_test_and_set(int *, int) if available, and if
306  * not fall back on the SWPB instruction.  SWPB does not work on ARMv6 or
307  * later, so the compiler builtin is preferred if available.  Note also that
308  * the int-width variant of the builtin works on more chips than other widths.
309  */
310 #if defined(__arm__) || defined(__arm)
311 #define HAS_TEST_AND_SET
312
313 #define TAS(lock) tas(lock)
314
315 #ifdef HAVE_GCC_INT_ATOMICS
316
317 typedef int slock_t;
318
319 static __inline__ int
320 tas(volatile slock_t *lock)
321 {
322         return __sync_lock_test_and_set(lock, 1);
323 }
324
325 #define S_UNLOCK(lock) __sync_lock_release(lock)
326
327 #else /* !HAVE_GCC_INT_ATOMICS */
328
329 typedef unsigned char slock_t;
330
331 static __inline__ int
332 tas(volatile slock_t *lock)
333 {
334         register slock_t _res = 1;
335
336         __asm__ __volatile__(
337                 "       swpb    %0, %0, [%2]    \n"
338 :               "+r"(_res), "+m"(*lock)
339 :               "r"(lock)
340 :               "memory");
341         return (int) _res;
342 }
343
344 #endif   /* HAVE_GCC_INT_ATOMICS */
345 #endif   /* __arm__ */
346
347
348 /*
349  * On ARM64, we use __sync_lock_test_and_set(int *, int) if available.
350  */
351 #if defined(__aarch64__) || defined(__aarch64)
352 #ifdef HAVE_GCC_INT_ATOMICS
353 #define HAS_TEST_AND_SET
354
355 #define TAS(lock) tas(lock)
356
357 typedef int slock_t;
358
359 static __inline__ int
360 tas(volatile slock_t *lock)
361 {
362         return __sync_lock_test_and_set(lock, 1);
363 }
364
365 #define S_UNLOCK(lock) __sync_lock_release(lock)
366
367 #endif   /* HAVE_GCC_INT_ATOMICS */
368 #endif   /* __aarch64__ */
369
370
371 /* S/390 and S/390x Linux (32- and 64-bit zSeries) */
372 #if defined(__s390__) || defined(__s390x__)
373 #define HAS_TEST_AND_SET
374
375 typedef unsigned int slock_t;
376
377 #define TAS(lock)          tas(lock)
378
379 static __inline__ int
380 tas(volatile slock_t *lock)
381 {
382         int                     _res = 0;
383
384         __asm__ __volatile__(
385                 "       cs      %0,%3,0(%2)             \n"
386 :               "+d"(_res), "+m"(*lock)
387 :               "a"(lock), "d"(1)
388 :               "memory", "cc");
389         return _res;
390 }
391
392 #endif   /* __s390__ || __s390x__ */
393
394
395 #if defined(__sparc__)          /* Sparc */
396 #define HAS_TEST_AND_SET
397
398 typedef unsigned char slock_t;
399
400 #define TAS(lock) tas(lock)
401
402 static __inline__ int
403 tas(volatile slock_t *lock)
404 {
405         register slock_t _res;
406
407         /*
408          *      See comment in /pg/backend/port/tas/solaris_sparc.s for why this
409          *      uses "ldstub", and that file uses "cas".  gcc currently generates
410          *      sparcv7-targeted binaries, so "cas" use isn't possible.
411          */
412         __asm__ __volatile__(
413                 "       ldstub  [%2], %0        \n"
414 :               "=r"(_res), "+m"(*lock)
415 :               "r"(lock)
416 :               "memory");
417         return (int) _res;
418 }
419
420 #endif   /* __sparc__ */
421
422
423 /* PowerPC */
424 #if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
425 #define HAS_TEST_AND_SET
426
427 typedef unsigned int slock_t;
428
429 #define TAS(lock) tas(lock)
430
431 /* On PPC, it's a win to use a non-locking test before the lwarx */
432 #define TAS_SPIN(lock)  (*(lock) ? 1 : TAS(lock))
433
434 /*
435  * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002,
436  * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop.
437  * On newer machines, we can use lwsync instead for better performance.
438  */
439 static __inline__ int
440 tas(volatile slock_t *lock)
441 {
442         slock_t _t;
443         int _res;
444
445         __asm__ __volatile__(
446 #ifdef USE_PPC_LWARX_MUTEX_HINT
447 "       lwarx   %0,0,%3,1       \n"
448 #else
449 "       lwarx   %0,0,%3         \n"
450 #endif
451 "       cmpwi   %0,0            \n"
452 "       bne     1f                      \n"
453 "       addi    %0,%0,1         \n"
454 "       stwcx.  %0,0,%3         \n"
455 "       beq     2f              \n"
456 "1:     li      %1,1            \n"
457 "       b               3f                      \n"
458 "2:                                             \n"
459 #ifdef USE_PPC_LWSYNC
460 "       lwsync                          \n"
461 #else
462 "       isync                           \n"
463 #endif
464 "       li      %1,0            \n"
465 "3:                                             \n"
466
467 :       "=&r"(_t), "=r"(_res), "+m"(*lock)
468 :       "r"(lock)
469 :       "memory", "cc");
470         return _res;
471 }
472
473 /*
474  * PowerPC S_UNLOCK is almost standard but requires a "sync" instruction.
475  * On newer machines, we can use lwsync instead for better performance.
476  */
477 #ifdef USE_PPC_LWSYNC
478 #define S_UNLOCK(lock)  \
479 do \
480 { \
481         __asm__ __volatile__ (" lwsync \n"); \
482         *((volatile slock_t *) (lock)) = 0; \
483 } while (0)
484 #else
485 #define S_UNLOCK(lock)  \
486 do \
487 { \
488         __asm__ __volatile__ (" sync \n"); \
489         *((volatile slock_t *) (lock)) = 0; \
490 } while (0)
491 #endif /* USE_PPC_LWSYNC */
492
493 #endif /* powerpc */
494
495
496 /* Linux Motorola 68k */
497 #if (defined(__mc68000__) || defined(__m68k__)) && defined(__linux__)
498 #define HAS_TEST_AND_SET
499
500 typedef unsigned char slock_t;
501
502 #define TAS(lock) tas(lock)
503
504 static __inline__ int
505 tas(volatile slock_t *lock)
506 {
507         register int rv;
508
509         __asm__ __volatile__(
510                 "       clrl    %0              \n"
511                 "       tas             %1              \n"
512                 "       sne             %0              \n"
513 :               "=d"(rv), "+m"(*lock)
514 :
515 :               "memory", "cc");
516         return rv;
517 }
518
519 #endif   /* (__mc68000__ || __m68k__) && __linux__ */
520
521
522 /*
523  * VAXen -- even multiprocessor ones
524  * (thanks to Tom Ivar Helbekkmo)
525  */
526 #if defined(__vax__)
527 #define HAS_TEST_AND_SET
528
529 typedef unsigned char slock_t;
530
531 #define TAS(lock) tas(lock)
532
533 static __inline__ int
534 tas(volatile slock_t *lock)
535 {
536         register int    _res;
537
538         __asm__ __volatile__(
539                 "       movl    $1, %0                  \n"
540                 "       bbssi   $0, (%2), 1f    \n"
541                 "       clrl    %0                              \n"
542                 "1: \n"
543 :               "=&r"(_res), "+m"(*lock)
544 :               "r"(lock)
545 :               "memory");
546         return _res;
547 }
548
549 #endif   /* __vax__ */
550
551
552 #if defined(__mips__) && !defined(__sgi)        /* non-SGI MIPS */
553 /* Note: on SGI we use the OS' mutex ABI, see below */
554 /* Note: R10000 processors require a separate SYNC */
555 #define HAS_TEST_AND_SET
556
557 typedef unsigned int slock_t;
558
559 #define TAS(lock) tas(lock)
560
561 static __inline__ int
562 tas(volatile slock_t *lock)
563 {
564         register volatile slock_t *_l = lock;
565         register int _res;
566         register int _tmp;
567
568         __asm__ __volatile__(
569                 "       .set push           \n"
570                 "       .set mips2          \n"
571                 "       .set noreorder      \n"
572                 "       .set nomacro        \n"
573                 "       ll      %0, %2      \n"
574                 "       or      %1, %0, 1   \n"
575                 "       sc      %1, %2      \n"
576                 "       xori    %1, 1       \n"
577                 "       or      %0, %0, %1  \n"
578                 "       sync                \n"
579                 "       .set pop              "
580 :               "=&r" (_res), "=&r" (_tmp), "+R" (*_l)
581 :
582 :               "memory");
583         return _res;
584 }
585
586 /* MIPS S_UNLOCK is almost standard but requires a "sync" instruction */
587 #define S_UNLOCK(lock)  \
588 do \
589 { \
590         __asm__ __volatile__( \
591                 "       .set push           \n" \
592                 "       .set mips2          \n" \
593                 "       .set noreorder      \n" \
594                 "       .set nomacro        \n" \
595                 "       sync                \n" \
596                 "       .set pop              "); \
597         *((volatile slock_t *) (lock)) = 0; \
598 } while (0)
599
600 #endif /* __mips__ && !__sgi */
601
602
603 #if defined(__m32r__) && defined(HAVE_SYS_TAS_H)        /* Renesas' M32R */
604 #define HAS_TEST_AND_SET
605
606 #include <sys/tas.h>
607
608 typedef int slock_t;
609
610 #define TAS(lock) tas(lock)
611
612 #endif /* __m32r__ */
613
614
615 #if defined(__sh__)                             /* Renesas' SuperH */
616 #define HAS_TEST_AND_SET
617
618 typedef unsigned char slock_t;
619
620 #define TAS(lock) tas(lock)
621
622 static __inline__ int
623 tas(volatile slock_t *lock)
624 {
625         register int _res;
626
627         /*
628          * This asm is coded as if %0 could be any register, but actually SuperH
629          * restricts the target of xor-immediate to be R0.  That's handled by
630          * the "z" constraint on _res.
631          */
632         __asm__ __volatile__(
633                 "       tas.b @%2    \n"
634                 "       movt  %0     \n"
635                 "       xor   #1,%0  \n"
636 :               "=z"(_res), "+m"(*lock)
637 :               "r"(lock)
638 :               "memory", "t");
639         return _res;
640 }
641
642 #endif   /* __sh__ */
643
644
645 /* These live in s_lock.c, but only for gcc */
646
647
648 #if defined(__m68k__) && !defined(__linux__)    /* non-Linux Motorola 68k */
649 #define HAS_TEST_AND_SET
650
651 typedef unsigned char slock_t;
652 #endif
653
654
655 #endif  /* defined(__GNUC__) || defined(__INTEL_COMPILER) */
656
657
658
659 /*
660  * ---------------------------------------------------------------------
661  * Platforms that use non-gcc inline assembly:
662  * ---------------------------------------------------------------------
663  */
664
665 #if !defined(HAS_TEST_AND_SET)  /* We didn't trigger above, let's try here */
666
667
668 #if defined(USE_UNIVEL_CC)              /* Unixware compiler */
669 #define HAS_TEST_AND_SET
670
671 typedef unsigned char slock_t;
672
673 #define TAS(lock)       tas(lock)
674
675 asm int
676 tas(volatile slock_t *s_lock)
677 {
678 /* UNIVEL wants %mem in column 1, so we don't pg_indent this file */
679 %mem s_lock
680         pushl %ebx
681         movl s_lock, %ebx
682         movl $255, %eax
683         lock
684         xchgb %al, (%ebx)
685         popl %ebx
686 }
687
688 #endif   /* defined(USE_UNIVEL_CC) */
689
690
691 #if defined(__hppa) || defined(__hppa__)        /* HP PA-RISC, GCC and HP compilers */
692 /*
693  * HP's PA-RISC
694  *
695  * See src/backend/port/hpux/tas.c.template for details about LDCWX.  Because
696  * LDCWX requires a 16-byte-aligned address, we declare slock_t as a 16-byte
697  * struct.  The active word in the struct is whichever has the aligned address;
698  * the other three words just sit at -1.
699  *
700  * When using gcc, we can inline the required assembly code.
701  */
702 #define HAS_TEST_AND_SET
703
704 typedef struct
705 {
706         int                     sema[4];
707 } slock_t;
708
709 #define TAS_ACTIVE_WORD(lock)   ((volatile int *) (((uintptr_t) (lock) + 15) & ~15))
710
711 #if defined(__GNUC__)
712
713 static __inline__ int
714 tas(volatile slock_t *lock)
715 {
716         volatile int *lockword = TAS_ACTIVE_WORD(lock);
717         register int lockval;
718
719         __asm__ __volatile__(
720                 "       ldcwx   0(0,%2),%0      \n"
721 :               "=r"(lockval), "+m"(*lockword)
722 :               "r"(lockword)
723 :               "memory");
724         return (lockval == 0);
725 }
726
727 #endif /* __GNUC__ */
728
729 #define S_UNLOCK(lock)  (*TAS_ACTIVE_WORD(lock) = -1)
730
731 #define S_INIT_LOCK(lock) \
732         do { \
733                 volatile slock_t *lock_ = (lock); \
734                 lock_->sema[0] = -1; \
735                 lock_->sema[1] = -1; \
736                 lock_->sema[2] = -1; \
737                 lock_->sema[3] = -1; \
738         } while (0)
739
740 #define S_LOCK_FREE(lock)       (*TAS_ACTIVE_WORD(lock) != 0)
741
742 #endif   /* __hppa || __hppa__ */
743
744
745 #if defined(__hpux) && defined(__ia64) && !defined(__GNUC__)
746 /*
747  * HP-UX on Itanium, non-gcc compiler
748  *
749  * We assume that the compiler enforces strict ordering of loads/stores on
750  * volatile data (see comments on the gcc-version earlier in this file).
751  * Note that this assumption does *not* hold if you use the
752  * +Ovolatile=__unordered option on the HP-UX compiler, so don't do that.
753  *
754  * See also Implementing Spinlocks on the Intel Itanium Architecture and
755  * PA-RISC, by Tor Ekqvist and David Graves, for more information.  As of
756  * this writing, version 1.0 of the manual is available at:
757  * http://h21007.www2.hp.com/portal/download/files/unprot/itanium/spinlocks.pdf
758  */
759 #define HAS_TEST_AND_SET
760
761 typedef unsigned int slock_t;
762
763 #include <ia64/sys/inline.h>
764 #define TAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE)
765 /* On IA64, it's a win to use a non-locking test before the xchg proper */
766 #define TAS_SPIN(lock)  (*(lock) ? 1 : TAS(lock))
767
768 #endif  /* HPUX on IA64, non gcc */
769
770 #if defined(_AIX)       /* AIX */
771 /*
772  * AIX (POWER)
773  */
774 #define HAS_TEST_AND_SET
775
776 #include <sys/atomic_op.h>
777
778 typedef int slock_t;
779
780 #define TAS(lock)                       _check_lock((slock_t *) (lock), 0, 1)
781 #define S_UNLOCK(lock)          _clear_lock((slock_t *) (lock), 0)
782 #endif   /* _AIX */
783
784
785 /* These are in s_lock.c */
786
787 #if defined(__SUNPRO_C) && (defined(__i386) || defined(__x86_64__) || defined(__sparc__) || defined(__sparc))
788 #define HAS_TEST_AND_SET
789
790 #if defined(__i386) || defined(__x86_64__) || defined(__sparcv9) || defined(__sparcv8plus)
791 typedef unsigned int slock_t;
792 #else
793 typedef unsigned char slock_t;
794 #endif
795
796 extern slock_t pg_atomic_cas(volatile slock_t *lock, slock_t with,
797                                                                           slock_t cmp);
798
799 #define TAS(a) (pg_atomic_cas((a), 1, 0) != 0)
800 #endif
801
802
803 #ifdef WIN32_ONLY_COMPILER
804 typedef LONG slock_t;
805
806 #define HAS_TEST_AND_SET
807 #define TAS(lock) (InterlockedCompareExchange(lock, 1, 0))
808
809 #define SPIN_DELAY() spin_delay()
810
811 /* If using Visual C++ on Win64, inline assembly is unavailable.
812  * Use a _mm_pause instrinsic instead of rep nop.
813  */
814 #if defined(_WIN64)
815 static __forceinline void
816 spin_delay(void)
817 {
818         _mm_pause();
819 }
820 #else
821 static __forceinline void
822 spin_delay(void)
823 {
824         /* See comment for gcc code. Same code, MASM syntax */
825         __asm rep nop;
826 }
827 #endif
828
829 #endif
830
831
832 #endif  /* !defined(HAS_TEST_AND_SET) */
833
834
835 /* Blow up if we didn't have any way to do spinlocks */
836 #ifndef HAS_TEST_AND_SET
837 #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.
838 #endif
839
840
841 #else   /* !HAVE_SPINLOCKS */
842
843
844 /*
845  * Fake spinlock implementation using semaphores --- slow and prone
846  * to fall foul of kernel limits on number of semaphores, so don't use this
847  * unless you must!  The subroutines appear in spin.c.
848  */
849 typedef int slock_t;
850
851 extern bool s_lock_free_sema(volatile slock_t *lock);
852 extern void s_unlock_sema(volatile slock_t *lock);
853 extern void s_init_lock_sema(volatile slock_t *lock);
854 extern int      tas_sema(volatile slock_t *lock);
855
856 #define S_LOCK_FREE(lock)       s_lock_free_sema(lock)
857 #define S_UNLOCK(lock)   s_unlock_sema(lock)
858 #define S_INIT_LOCK(lock)       s_init_lock_sema(lock)
859 #define TAS(lock)       tas_sema(lock)
860
861
862 #endif  /* HAVE_SPINLOCKS */
863
864
865 /*
866  * Default Definitions - override these above as needed.
867  */
868
869 #if !defined(S_LOCK)
870 #define S_LOCK(lock) \
871         (TAS(lock) ? s_lock((lock), __FILE__, __LINE__) : 0)
872 #endif   /* S_LOCK */
873
874 #if !defined(S_LOCK_FREE)
875 #define S_LOCK_FREE(lock)       (*(lock) == 0)
876 #endif   /* S_LOCK_FREE */
877
878 #if !defined(S_UNLOCK)
879 #define S_UNLOCK(lock)          (*((volatile slock_t *) (lock)) = 0)
880 #endif   /* S_UNLOCK */
881
882 #if !defined(S_INIT_LOCK)
883 #define S_INIT_LOCK(lock)       S_UNLOCK(lock)
884 #endif   /* S_INIT_LOCK */
885
886 #if !defined(SPIN_DELAY)
887 #define SPIN_DELAY()    ((void) 0)
888 #endif   /* SPIN_DELAY */
889
890 #if !defined(TAS)
891 extern int      tas(volatile slock_t *lock);            /* in port/.../tas.s, or
892                                                                                                  * s_lock.c */
893
894 #define TAS(lock)               tas(lock)
895 #endif   /* TAS */
896
897 #if !defined(TAS_SPIN)
898 #define TAS_SPIN(lock)  TAS(lock)
899 #endif   /* TAS_SPIN */
900
901
902 /*
903  * Platform-independent out-of-line support routines
904  */
905 extern int s_lock(volatile slock_t *lock, const char *file, int line);
906
907 /* Support for dynamic adjustment of spins_per_delay */
908 #define DEFAULT_SPINS_PER_DELAY  100
909
910 extern void set_spins_per_delay(int shared_spins_per_delay);
911 extern int      update_spins_per_delay(int shared_spins_per_delay);
912
913 #endif   /* S_LOCK_H */