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