Header And Logo

PostgreSQL
| The world's most advanced open source database.

s_lock.h

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * s_lock.h
00004  *     Hardware-dependent implementation of spinlocks.
00005  *
00006  *  NOTE: none of the macros in this file are intended to be called directly.
00007  *  Call them through the hardware-independent macros in spin.h.
00008  *
00009  *  The following hardware-dependent macros must be provided for each
00010  *  supported platform:
00011  *
00012  *  void S_INIT_LOCK(slock_t *lock)
00013  *      Initialize a spinlock (to the unlocked state).
00014  *
00015  *  int S_LOCK(slock_t *lock)
00016  *      Acquire a spinlock, waiting if necessary.
00017  *      Time out and abort() if unable to acquire the lock in a
00018  *      "reasonable" amount of time --- typically ~ 1 minute.
00019  *      Should return number of "delays"; see s_lock.c
00020  *
00021  *  void S_UNLOCK(slock_t *lock)
00022  *      Unlock a previously acquired lock.
00023  *
00024  *  bool S_LOCK_FREE(slock_t *lock)
00025  *      Tests if the lock is free. Returns TRUE if free, FALSE if locked.
00026  *      This does *not* change the state of the lock.
00027  *
00028  *  void SPIN_DELAY(void)
00029  *      Delay operation to occur inside spinlock wait loop.
00030  *
00031  *  Note to implementors: there are default implementations for all these
00032  *  macros at the bottom of the file.  Check if your platform can use
00033  *  these or needs to override them.
00034  *
00035  *  Usually, S_LOCK() is implemented in terms of even lower-level macros
00036  *  TAS() and TAS_SPIN():
00037  *
00038  *  int TAS(slock_t *lock)
00039  *      Atomic test-and-set instruction.  Attempt to acquire the lock,
00040  *      but do *not* wait.  Returns 0 if successful, nonzero if unable
00041  *      to acquire the lock.
00042  *
00043  *  int TAS_SPIN(slock_t *lock)
00044  *      Like TAS(), but this version is used when waiting for a lock
00045  *      previously found to be contended.  By default, this is the
00046  *      same as TAS(), but on some architectures it's better to poll a
00047  *      contended lock using an unlocked instruction and retry the
00048  *      atomic test-and-set only when it appears free.
00049  *
00050  *  TAS() and TAS_SPIN() are NOT part of the API, and should never be called
00051  *  directly.
00052  *
00053  *  CAUTION: on some platforms TAS() and/or TAS_SPIN() may sometimes report
00054  *  failure to acquire a lock even when the lock is not locked.  For example,
00055  *  on Alpha TAS() will "fail" if interrupted.  Therefore a retry loop must
00056  *  always be used, even if you are certain the lock is free.
00057  *
00058  *  Another caution for users of these macros is that it is the caller's
00059  *  responsibility to ensure that the compiler doesn't re-order accesses
00060  *  to shared memory to precede the actual lock acquisition, or follow the
00061  *  lock release.  Typically we handle this by using volatile-qualified
00062  *  pointers to refer to both the spinlock itself and the shared data
00063  *  structure being accessed within the spinlocked critical section.
00064  *  That fixes it because compilers are not allowed to re-order accesses
00065  *  to volatile objects relative to other such accesses.
00066  *
00067  *  On platforms with weak memory ordering, the TAS(), TAS_SPIN(), and
00068  *  S_UNLOCK() macros must further include hardware-level memory fence
00069  *  instructions to prevent similar re-ordering at the hardware level.
00070  *  TAS() and TAS_SPIN() must guarantee that loads and stores issued after
00071  *  the macro are not executed until the lock has been obtained.  Conversely,
00072  *  S_UNLOCK() must guarantee that loads and stores issued before the macro
00073  *  have been executed before the lock is released.
00074  *
00075  *  On most supported platforms, TAS() uses a tas() function written
00076  *  in assembly language to execute a hardware atomic-test-and-set
00077  *  instruction.  Equivalent OS-supplied mutex routines could be used too.
00078  *
00079  *  If no system-specific TAS() is available (ie, HAVE_SPINLOCKS is not
00080  *  defined), then we fall back on an emulation that uses SysV semaphores
00081  *  (see spin.c).  This emulation will be MUCH MUCH slower than a proper TAS()
00082  *  implementation, because of the cost of a kernel call per lock or unlock.
00083  *  An old report is that Postgres spends around 40% of its time in semop(2)
00084  *  when using the SysV semaphore code.
00085  *
00086  *
00087  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00088  * Portions Copyright (c) 1994, Regents of the University of California
00089  *
00090  *    src/include/storage/s_lock.h
00091  *
00092  *-------------------------------------------------------------------------
00093  */
00094 #ifndef S_LOCK_H
00095 #define S_LOCK_H
00096 
00097 #include "storage/pg_sema.h"
00098 
00099 #ifdef HAVE_SPINLOCKS   /* skip spinlocks if requested */
00100 
00101 
00102 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
00103 /*************************************************************************
00104  * All the gcc inlines
00105  * Gcc consistently defines the CPU as __cpu__.
00106  * Other compilers use __cpu or __cpu__ so we test for both in those cases.
00107  */
00108 
00109 /*----------
00110  * Standard gcc asm format (assuming "volatile slock_t *lock"):
00111 
00112     __asm__ __volatile__(
00113         "   instruction \n"
00114         "   instruction \n"
00115         "   instruction \n"
00116 :       "=r"(_res), "+m"(*lock)     // return register, in/out lock value
00117 :       "r"(lock)                   // lock pointer, in input register
00118 :       "memory", "cc");            // show clobbered registers here
00119 
00120  * The output-operands list (after first colon) should always include
00121  * "+m"(*lock), whether or not the asm code actually refers to this
00122  * operand directly.  This ensures that gcc believes the value in the
00123  * lock variable is used and set by the asm code.  Also, the clobbers
00124  * list (after third colon) should always include "memory"; this prevents
00125  * gcc from thinking it can cache the values of shared-memory fields
00126  * across the asm code.  Add "cc" if your asm code changes the condition
00127  * code register, and also list any temp registers the code uses.
00128  *----------
00129  */
00130 
00131 
00132 #ifdef __i386__     /* 32-bit i386 */
00133 #define HAS_TEST_AND_SET
00134 
00135 typedef unsigned char slock_t;
00136 
00137 #define TAS(lock) tas(lock)
00138 
00139 static __inline__ int
00140 tas(volatile slock_t *lock)
00141 {
00142     register slock_t _res = 1;
00143 
00144     /*
00145      * Use a non-locking test before asserting the bus lock.  Note that the
00146      * extra test appears to be a small loss on some x86 platforms and a small
00147      * win on others; it's by no means clear that we should keep it.
00148      */
00149     __asm__ __volatile__(
00150         "   cmpb    $0,%1   \n"
00151         "   jne     1f      \n"
00152         "   lock            \n"
00153         "   xchgb   %0,%1   \n"
00154         "1: \n"
00155 :       "+q"(_res), "+m"(*lock)
00156 :
00157 :       "memory", "cc");
00158     return (int) _res;
00159 }
00160 
00161 #define SPIN_DELAY() spin_delay()
00162 
00163 static __inline__ void
00164 spin_delay(void)
00165 {
00166     /*
00167      * This sequence is equivalent to the PAUSE instruction ("rep" is
00168      * ignored by old IA32 processors if the following instruction is
00169      * not a string operation); the IA-32 Architecture Software
00170      * Developer's Manual, Vol. 3, Section 7.7.2 describes why using
00171      * PAUSE in the inner loop of a spin lock is necessary for good
00172      * performance:
00173      *
00174      *     The PAUSE instruction improves the performance of IA-32
00175      *     processors supporting Hyper-Threading Technology when
00176      *     executing spin-wait loops and other routines where one
00177      *     thread is accessing a shared lock or semaphore in a tight
00178      *     polling loop. When executing a spin-wait loop, the
00179      *     processor can suffer a severe performance penalty when
00180      *     exiting the loop because it detects a possible memory order
00181      *     violation and flushes the core processor's pipeline. The
00182      *     PAUSE instruction provides a hint to the processor that the
00183      *     code sequence is a spin-wait loop. The processor uses this
00184      *     hint to avoid the memory order violation and prevent the
00185      *     pipeline flush. In addition, the PAUSE instruction
00186      *     de-pipelines the spin-wait loop to prevent it from
00187      *     consuming execution resources excessively.
00188      */
00189     __asm__ __volatile__(
00190         " rep; nop          \n");
00191 }
00192 
00193 #endif   /* __i386__ */
00194 
00195 
00196 #ifdef __x86_64__       /* AMD Opteron, Intel EM64T */
00197 #define HAS_TEST_AND_SET
00198 
00199 typedef unsigned char slock_t;
00200 
00201 #define TAS(lock) tas(lock)
00202 
00203 static __inline__ int
00204 tas(volatile slock_t *lock)
00205 {
00206     register slock_t _res = 1;
00207 
00208     /*
00209      * On Opteron, using a non-locking test before the locking instruction
00210      * is a huge loss.  On EM64T, it appears to be a wash or small loss,
00211      * so we needn't bother to try to distinguish the sub-architectures.
00212      */
00213     __asm__ __volatile__(
00214         "   lock            \n"
00215         "   xchgb   %0,%1   \n"
00216 :       "+q"(_res), "+m"(*lock)
00217 :
00218 :       "memory", "cc");
00219     return (int) _res;
00220 }
00221 
00222 #define SPIN_DELAY() spin_delay()
00223 
00224 static __inline__ void
00225 spin_delay(void)
00226 {
00227     /*
00228      * Adding a PAUSE in the spin delay loop is demonstrably a no-op on
00229      * Opteron, but it may be of some use on EM64T, so we keep it.
00230      */
00231     __asm__ __volatile__(
00232         " rep; nop          \n");
00233 }
00234 
00235 #endif   /* __x86_64__ */
00236 
00237 
00238 #if defined(__ia64__) || defined(__ia64)
00239 /*
00240  * Intel Itanium, gcc or Intel's compiler.
00241  *
00242  * Itanium has weak memory ordering, but we rely on the compiler to enforce
00243  * strict ordering of accesses to volatile data.  In particular, while the
00244  * xchg instruction implicitly acts as a memory barrier with 'acquire'
00245  * semantics, we do not have an explicit memory fence instruction in the
00246  * S_UNLOCK macro.  We use a regular assignment to clear the spinlock, and
00247  * trust that the compiler marks the generated store instruction with the
00248  * ".rel" opcode.
00249  *
00250  * Testing shows that assumption to hold on gcc, although I could not find
00251  * any explicit statement on that in the gcc manual.  In Intel's compiler,
00252  * the -m[no-]serialize-volatile option controls that, and testing shows that
00253  * it is enabled by default.
00254  */
00255 #define HAS_TEST_AND_SET
00256 
00257 typedef unsigned int slock_t;
00258 
00259 #define TAS(lock) tas(lock)
00260 
00261 /* On IA64, it's a win to use a non-locking test before the xchg proper */
00262 #define TAS_SPIN(lock)  (*(lock) ? 1 : TAS(lock))
00263 
00264 #ifndef __INTEL_COMPILER
00265 
00266 static __inline__ int
00267 tas(volatile slock_t *lock)
00268 {
00269     long int    ret;
00270 
00271     __asm__ __volatile__(
00272         "   xchg4   %0=%1,%2    \n"
00273 :       "=r"(ret), "+m"(*lock)
00274 :       "r"(1)
00275 :       "memory");
00276     return (int) ret;
00277 }
00278 
00279 #else /* __INTEL_COMPILER */
00280 
00281 static __inline__ int
00282 tas(volatile slock_t *lock)
00283 {
00284     int     ret;
00285 
00286     ret = _InterlockedExchange(lock,1); /* this is a xchg asm macro */
00287 
00288     return ret;
00289 }
00290 
00291 #endif /* __INTEL_COMPILER */
00292 #endif   /* __ia64__ || __ia64 */
00293 
00294 
00295 /*
00296  * On ARM, we use __sync_lock_test_and_set(int *, int) if available, and if
00297  * not fall back on the SWPB instruction.  SWPB does not work on ARMv6 or
00298  * later, so the compiler builtin is preferred if available.  Note also that
00299  * the int-width variant of the builtin works on more chips than other widths.
00300  */
00301 #if defined(__arm__) || defined(__arm)
00302 #define HAS_TEST_AND_SET
00303 
00304 #define TAS(lock) tas(lock)
00305 
00306 #ifdef HAVE_GCC_INT_ATOMICS
00307 
00308 typedef int slock_t;
00309 
00310 static __inline__ int
00311 tas(volatile slock_t *lock)
00312 {
00313     return __sync_lock_test_and_set(lock, 1);
00314 }
00315 
00316 #define S_UNLOCK(lock) __sync_lock_release(lock)
00317 
00318 #else /* !HAVE_GCC_INT_ATOMICS */
00319 
00320 typedef unsigned char slock_t;
00321 
00322 static __inline__ int
00323 tas(volatile slock_t *lock)
00324 {
00325     register slock_t _res = 1;
00326 
00327     __asm__ __volatile__(
00328         "   swpb    %0, %0, [%2]    \n"
00329 :       "+r"(_res), "+m"(*lock)
00330 :       "r"(lock)
00331 :       "memory");
00332     return (int) _res;
00333 }
00334 
00335 #endif   /* HAVE_GCC_INT_ATOMICS */
00336 #endif   /* __arm__ */
00337 
00338 
00339 /* S/390 and S/390x Linux (32- and 64-bit zSeries) */
00340 #if defined(__s390__) || defined(__s390x__)
00341 #define HAS_TEST_AND_SET
00342 
00343 typedef unsigned int slock_t;
00344 
00345 #define TAS(lock)      tas(lock)
00346 
00347 static __inline__ int
00348 tas(volatile slock_t *lock)
00349 {
00350     int         _res = 0;
00351 
00352     __asm__ __volatile__(
00353         "   cs  %0,%3,0(%2)     \n"
00354 :       "+d"(_res), "+m"(*lock)
00355 :       "a"(lock), "d"(1)
00356 :       "memory", "cc");
00357     return _res;
00358 }
00359 
00360 #endif   /* __s390__ || __s390x__ */
00361 
00362 
00363 #if defined(__sparc__)      /* Sparc */
00364 #define HAS_TEST_AND_SET
00365 
00366 typedef unsigned char slock_t;
00367 
00368 #define TAS(lock) tas(lock)
00369 
00370 static __inline__ int
00371 tas(volatile slock_t *lock)
00372 {
00373     register slock_t _res;
00374 
00375     /*
00376      *  See comment in /pg/backend/port/tas/solaris_sparc.s for why this
00377      *  uses "ldstub", and that file uses "cas".  gcc currently generates
00378      *  sparcv7-targeted binaries, so "cas" use isn't possible.
00379      */
00380     __asm__ __volatile__(
00381         "   ldstub  [%2], %0    \n"
00382 :       "=r"(_res), "+m"(*lock)
00383 :       "r"(lock)
00384 :       "memory");
00385     return (int) _res;
00386 }
00387 
00388 #endif   /* __sparc__ */
00389 
00390 
00391 /* PowerPC */
00392 #if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
00393 #define HAS_TEST_AND_SET
00394 
00395 typedef unsigned int slock_t;
00396 
00397 #define TAS(lock) tas(lock)
00398 
00399 /* On PPC, it's a win to use a non-locking test before the lwarx */
00400 #define TAS_SPIN(lock)  (*(lock) ? 1 : TAS(lock))
00401 
00402 /*
00403  * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002,
00404  * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop.
00405  * On newer machines, we can use lwsync instead for better performance.
00406  */
00407 static __inline__ int
00408 tas(volatile slock_t *lock)
00409 {
00410     slock_t _t;
00411     int _res;
00412 
00413     __asm__ __volatile__(
00414 #ifdef USE_PPC_LWARX_MUTEX_HINT
00415 "   lwarx   %0,0,%3,1   \n"
00416 #else
00417 "   lwarx   %0,0,%3     \n"
00418 #endif
00419 "   cmpwi   %0,0        \n"
00420 "   bne     1f          \n"
00421 "   addi    %0,%0,1     \n"
00422 "   stwcx.  %0,0,%3     \n"
00423 "   beq     2f          \n"
00424 "1: li      %1,1        \n"
00425 "   b       3f          \n"
00426 "2:                     \n"
00427 #ifdef USE_PPC_LWSYNC
00428 "   lwsync              \n"
00429 #else
00430 "   isync               \n"
00431 #endif
00432 "   li      %1,0        \n"
00433 "3:                     \n"
00434 
00435 :   "=&r"(_t), "=r"(_res), "+m"(*lock)
00436 :   "r"(lock)
00437 :   "memory", "cc");
00438     return _res;
00439 }
00440 
00441 /*
00442  * PowerPC S_UNLOCK is almost standard but requires a "sync" instruction.
00443  * On newer machines, we can use lwsync instead for better performance.
00444  */
00445 #ifdef USE_PPC_LWSYNC
00446 #define S_UNLOCK(lock)  \
00447 do \
00448 { \
00449     __asm__ __volatile__ (" lwsync \n"); \
00450     *((volatile slock_t *) (lock)) = 0; \
00451 } while (0)
00452 #else
00453 #define S_UNLOCK(lock)  \
00454 do \
00455 { \
00456     __asm__ __volatile__ (" sync \n"); \
00457     *((volatile slock_t *) (lock)) = 0; \
00458 } while (0)
00459 #endif /* USE_PPC_LWSYNC */
00460 
00461 #endif /* powerpc */
00462 
00463 
00464 /* Linux Motorola 68k */
00465 #if (defined(__mc68000__) || defined(__m68k__)) && defined(__linux__)
00466 #define HAS_TEST_AND_SET
00467 
00468 typedef unsigned char slock_t;
00469 
00470 #define TAS(lock) tas(lock)
00471 
00472 static __inline__ int
00473 tas(volatile slock_t *lock)
00474 {
00475     register int rv;
00476 
00477     __asm__ __volatile__(
00478         "   clrl    %0      \n"
00479         "   tas     %1      \n"
00480         "   sne     %0      \n"
00481 :       "=d"(rv), "+m"(*lock)
00482 :
00483 :       "memory", "cc");
00484     return rv;
00485 }
00486 
00487 #endif   /* (__mc68000__ || __m68k__) && __linux__ */
00488 
00489 
00490 /*
00491  * VAXen -- even multiprocessor ones
00492  * (thanks to Tom Ivar Helbekkmo)
00493  */
00494 #if defined(__vax__)
00495 #define HAS_TEST_AND_SET
00496 
00497 typedef unsigned char slock_t;
00498 
00499 #define TAS(lock) tas(lock)
00500 
00501 static __inline__ int
00502 tas(volatile slock_t *lock)
00503 {
00504     register int    _res;
00505 
00506     __asm__ __volatile__(
00507         "   movl    $1, %0          \n"
00508         "   bbssi   $0, (%2), 1f    \n"
00509         "   clrl    %0              \n"
00510         "1: \n"
00511 :       "=&r"(_res), "+m"(*lock)
00512 :       "r"(lock)
00513 :       "memory");
00514     return _res;
00515 }
00516 
00517 #endif   /* __vax__ */
00518 
00519 
00520 #if defined(__ns32k__)      /* National Semiconductor 32K */
00521 #define HAS_TEST_AND_SET
00522 
00523 typedef unsigned char slock_t;
00524 
00525 #define TAS(lock) tas(lock)
00526 
00527 static __inline__ int
00528 tas(volatile slock_t *lock)
00529 {
00530     register int    _res;
00531 
00532     __asm__ __volatile__(
00533         "   sbitb   0, %1   \n"
00534         "   sfsd    %0      \n"
00535 :       "=r"(_res), "+m"(*lock)
00536 :
00537 :       "memory");
00538     return _res;
00539 }
00540 
00541 #endif   /* __ns32k__ */
00542 
00543 
00544 #if defined(__alpha) || defined(__alpha__)  /* Alpha */
00545 /*
00546  * Correct multi-processor locking methods are explained in section 5.5.3
00547  * of the Alpha AXP Architecture Handbook, which at this writing can be
00548  * found at ftp://ftp.netbsd.org/pub/NetBSD/misc/dec-docs/index.html.
00549  * For gcc we implement the handbook's code directly with inline assembler.
00550  */
00551 #define HAS_TEST_AND_SET
00552 
00553 typedef unsigned long slock_t;
00554 
00555 #define TAS(lock)  tas(lock)
00556 
00557 static __inline__ int
00558 tas(volatile slock_t *lock)
00559 {
00560     register slock_t _res;
00561 
00562     __asm__ __volatile__(
00563         "   ldq     $0, %1  \n"
00564         "   bne     $0, 2f  \n"
00565         "   ldq_l   %0, %1  \n"
00566         "   bne     %0, 2f  \n"
00567         "   mov     1,  $0  \n"
00568         "   stq_c   $0, %1  \n"
00569         "   beq     $0, 2f  \n"
00570         "   mb              \n"
00571         "   br      3f      \n"
00572         "2: mov     1, %0   \n"
00573         "3:                 \n"
00574 :       "=&r"(_res), "+m"(*lock)
00575 :
00576 :       "memory", "0");
00577     return (int) _res;
00578 }
00579 
00580 #define S_UNLOCK(lock)  \
00581 do \
00582 {\
00583     __asm__ __volatile__ (" mb \n"); \
00584     *((volatile slock_t *) (lock)) = 0; \
00585 } while (0)
00586 
00587 #endif /* __alpha || __alpha__ */
00588 
00589 
00590 #if defined(__mips__) && !defined(__sgi)    /* non-SGI MIPS */
00591 /* Note: on SGI we use the OS' mutex ABI, see below */
00592 /* Note: R10000 processors require a separate SYNC */
00593 #define HAS_TEST_AND_SET
00594 
00595 typedef unsigned int slock_t;
00596 
00597 #define TAS(lock) tas(lock)
00598 
00599 static __inline__ int
00600 tas(volatile slock_t *lock)
00601 {
00602     register volatile slock_t *_l = lock;
00603     register int _res;
00604     register int _tmp;
00605 
00606     __asm__ __volatile__(
00607         "       .set push           \n"
00608         "       .set mips2          \n"
00609         "       .set noreorder      \n"
00610         "       .set nomacro        \n"
00611         "       ll      %0, %2      \n"
00612         "       or      %1, %0, 1   \n"
00613         "       sc      %1, %2      \n"
00614         "       xori    %1, 1       \n"
00615         "       or      %0, %0, %1  \n"
00616         "       sync                \n"
00617         "       .set pop              "
00618 :       "=&r" (_res), "=&r" (_tmp), "+R" (*_l)
00619 :
00620 :       "memory");
00621     return _res;
00622 }
00623 
00624 /* MIPS S_UNLOCK is almost standard but requires a "sync" instruction */
00625 #define S_UNLOCK(lock)  \
00626 do \
00627 { \
00628     __asm__ __volatile__( \
00629         "       .set push           \n" \
00630         "       .set mips2          \n" \
00631         "       .set noreorder      \n" \
00632         "       .set nomacro        \n" \
00633         "       sync                \n" \
00634         "       .set pop              "); \
00635     *((volatile slock_t *) (lock)) = 0; \
00636 } while (0)
00637 
00638 #endif /* __mips__ && !__sgi */
00639 
00640 
00641 #if defined(__m32r__) && defined(HAVE_SYS_TAS_H)    /* Renesas' M32R */
00642 #define HAS_TEST_AND_SET
00643 
00644 #include <sys/tas.h>
00645 
00646 typedef int slock_t;
00647 
00648 #define TAS(lock) tas(lock)
00649 
00650 #endif /* __m32r__ */
00651 
00652 
00653 #if defined(__sh__)             /* Renesas' SuperH */
00654 #define HAS_TEST_AND_SET
00655 
00656 typedef unsigned char slock_t;
00657 
00658 #define TAS(lock) tas(lock)
00659 
00660 static __inline__ int
00661 tas(volatile slock_t *lock)
00662 {
00663     register int _res;
00664 
00665     /*
00666      * This asm is coded as if %0 could be any register, but actually SuperH
00667      * restricts the target of xor-immediate to be R0.  That's handled by
00668      * the "z" constraint on _res.
00669      */
00670     __asm__ __volatile__(
00671         "   tas.b @%2    \n"
00672         "   movt  %0     \n"
00673         "   xor   #1,%0  \n"
00674 :       "=z"(_res), "+m"(*lock)
00675 :       "r"(lock)
00676 :       "memory", "t");
00677     return _res;
00678 }
00679 
00680 #endif   /* __sh__ */
00681 
00682 
00683 /* These live in s_lock.c, but only for gcc */
00684 
00685 
00686 #if defined(__m68k__) && !defined(__linux__)    /* non-Linux Motorola 68k */
00687 #define HAS_TEST_AND_SET
00688 
00689 typedef unsigned char slock_t;
00690 #endif
00691 
00692 
00693 #endif  /* defined(__GNUC__) || defined(__INTEL_COMPILER) */
00694 
00695 
00696 
00697 /*
00698  * ---------------------------------------------------------------------
00699  * Platforms that use non-gcc inline assembly:
00700  * ---------------------------------------------------------------------
00701  */
00702 
00703 #if !defined(HAS_TEST_AND_SET)  /* We didn't trigger above, let's try here */
00704 
00705 
00706 #if defined(USE_UNIVEL_CC)      /* Unixware compiler */
00707 #define HAS_TEST_AND_SET
00708 
00709 typedef unsigned char slock_t;
00710 
00711 #define TAS(lock)   tas(lock)
00712 
00713 asm int
00714 tas(volatile slock_t *s_lock)
00715 {
00716 /* UNIVEL wants %mem in column 1, so we don't pg_indent this file */
00717 %mem s_lock
00718     pushl %ebx
00719     movl s_lock, %ebx
00720     movl $255, %eax
00721     lock
00722     xchgb %al, (%ebx)
00723     popl %ebx
00724 }
00725 
00726 #endif   /* defined(USE_UNIVEL_CC) */
00727 
00728 
00729 #if defined(__alpha) || defined(__alpha__)  /* Tru64 Unix Alpha compiler */
00730 /*
00731  * The Tru64 compiler doesn't support gcc-style inline asm, but it does
00732  * have some builtin functions that accomplish much the same results.
00733  * For simplicity, slock_t is defined as long (ie, quadword) on Alpha
00734  * regardless of the compiler in use.  LOCK_LONG and UNLOCK_LONG only
00735  * operate on an int (ie, longword), but that's OK as long as we define
00736  * S_INIT_LOCK to zero out the whole quadword.
00737  */
00738 #define HAS_TEST_AND_SET
00739 
00740 typedef unsigned long slock_t;
00741 
00742 #include <alpha/builtins.h>
00743 #define S_INIT_LOCK(lock)  (*(lock) = 0)
00744 #define TAS(lock)          (__LOCK_LONG_RETRY((lock), 1) == 0)
00745 #define S_UNLOCK(lock)     __UNLOCK_LONG(lock)
00746 
00747 #endif   /* __alpha || __alpha__ */
00748 
00749 
00750 #if defined(__hppa) || defined(__hppa__)    /* HP PA-RISC, GCC and HP compilers */
00751 /*
00752  * HP's PA-RISC
00753  *
00754  * See src/backend/port/hpux/tas.c.template for details about LDCWX.  Because
00755  * LDCWX requires a 16-byte-aligned address, we declare slock_t as a 16-byte
00756  * struct.  The active word in the struct is whichever has the aligned address;
00757  * the other three words just sit at -1.
00758  *
00759  * When using gcc, we can inline the required assembly code.
00760  */
00761 #define HAS_TEST_AND_SET
00762 
00763 typedef struct
00764 {
00765     int         sema[4];
00766 } slock_t;
00767 
00768 #define TAS_ACTIVE_WORD(lock)   ((volatile int *) (((uintptr_t) (lock) + 15) & ~15))
00769 
00770 #if defined(__GNUC__)
00771 
00772 static __inline__ int
00773 tas(volatile slock_t *lock)
00774 {
00775     volatile int *lockword = TAS_ACTIVE_WORD(lock);
00776     register int lockval;
00777 
00778     __asm__ __volatile__(
00779         "   ldcwx   0(0,%2),%0  \n"
00780 :       "=r"(lockval), "+m"(*lockword)
00781 :       "r"(lockword)
00782 :       "memory");
00783     return (lockval == 0);
00784 }
00785 
00786 #endif /* __GNUC__ */
00787 
00788 #define S_UNLOCK(lock)  (*TAS_ACTIVE_WORD(lock) = -1)
00789 
00790 #define S_INIT_LOCK(lock) \
00791     do { \
00792         volatile slock_t *lock_ = (lock); \
00793         lock_->sema[0] = -1; \
00794         lock_->sema[1] = -1; \
00795         lock_->sema[2] = -1; \
00796         lock_->sema[3] = -1; \
00797     } while (0)
00798 
00799 #define S_LOCK_FREE(lock)   (*TAS_ACTIVE_WORD(lock) != 0)
00800 
00801 #endif   /* __hppa || __hppa__ */
00802 
00803 
00804 #if defined(__hpux) && defined(__ia64) && !defined(__GNUC__)
00805 /*
00806  * HP-UX on Itanium, non-gcc compiler
00807  *
00808  * We assume that the compiler enforces strict ordering of loads/stores on
00809  * volatile data (see comments on the gcc-version earlier in this file).
00810  * Note that this assumption does *not* hold if you use the
00811  * +Ovolatile=__unordered option on the HP-UX compiler, so don't do that.
00812  *
00813  * See also Implementing Spinlocks on the Intel Itanium Architecture and
00814  * PA-RISC, by Tor Ekqvist and David Graves, for more information.  As of
00815  * this writing, version 1.0 of the manual is available at:
00816  * http://h21007.www2.hp.com/portal/download/files/unprot/itanium/spinlocks.pdf
00817  */
00818 #define HAS_TEST_AND_SET
00819 
00820 typedef unsigned int slock_t;
00821 
00822 #include <ia64/sys/inline.h>
00823 #define TAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE)
00824 /* On IA64, it's a win to use a non-locking test before the xchg proper */
00825 #define TAS_SPIN(lock)  (*(lock) ? 1 : TAS(lock))
00826 
00827 #endif  /* HPUX on IA64, non gcc */
00828 
00829 
00830 #if defined(__sgi)  /* SGI compiler */
00831 /*
00832  * SGI IRIX 5
00833  * slock_t is defined as a unsigned long. We use the standard SGI
00834  * mutex API.
00835  *
00836  * The following comment is left for historical reasons, but is probably
00837  * not a good idea since the mutex ABI is supported.
00838  *
00839  * This stuff may be supplemented in the future with Masato Kataoka's MIPS-II
00840  * assembly from his NECEWS SVR4 port, but we probably ought to retain this
00841  * for the R3000 chips out there.
00842  */
00843 #define HAS_TEST_AND_SET
00844 
00845 typedef unsigned long slock_t;
00846 
00847 #include "mutex.h"
00848 #define TAS(lock)   (test_and_set(lock,1))
00849 #define S_UNLOCK(lock)  (test_then_and(lock,0))
00850 #define S_INIT_LOCK(lock)   (test_then_and(lock,0))
00851 #define S_LOCK_FREE(lock)   (test_then_add(lock,0) == 0)
00852 #endif   /* __sgi */
00853 
00854 
00855 #if defined(sinix)      /* Sinix */
00856 /*
00857  * SINIX / Reliant UNIX
00858  * slock_t is defined as a struct abilock_t, which has a single unsigned long
00859  * member. (Basically same as SGI)
00860  */
00861 #define HAS_TEST_AND_SET
00862 
00863 #include "abi_mutex.h"
00864 typedef abilock_t slock_t;
00865 
00866 #define TAS(lock)   (!acquire_lock(lock))
00867 #define S_UNLOCK(lock)  release_lock(lock)
00868 #define S_INIT_LOCK(lock)   init_lock(lock)
00869 #define S_LOCK_FREE(lock)   (stat_lock(lock) == UNLOCKED)
00870 #endif   /* sinix */
00871 
00872 
00873 #if defined(_AIX)   /* AIX */
00874 /*
00875  * AIX (POWER)
00876  */
00877 #define HAS_TEST_AND_SET
00878 
00879 #include <sys/atomic_op.h>
00880 
00881 typedef int slock_t;
00882 
00883 #define TAS(lock)           _check_lock((slock_t *) (lock), 0, 1)
00884 #define S_UNLOCK(lock)      _clear_lock((slock_t *) (lock), 0)
00885 #endif   /* _AIX */
00886 
00887 
00888 /* These are in s_lock.c */
00889 
00890 
00891 #if defined(sun3)       /* Sun3 */
00892 #define HAS_TEST_AND_SET
00893 
00894 typedef unsigned char slock_t;
00895 #endif
00896 
00897 
00898 #if defined(__SUNPRO_C) && (defined(__i386) || defined(__x86_64__) || defined(__sparc__) || defined(__sparc))
00899 #define HAS_TEST_AND_SET
00900 
00901 #if defined(__i386) || defined(__x86_64__) || defined(__sparcv9) || defined(__sparcv8plus)
00902 typedef unsigned int slock_t;
00903 #else
00904 typedef unsigned char slock_t;
00905 #endif
00906 
00907 extern slock_t pg_atomic_cas(volatile slock_t *lock, slock_t with,
00908                                       slock_t cmp);
00909 
00910 #define TAS(a) (pg_atomic_cas((a), 1, 0) != 0)
00911 #endif
00912 
00913 
00914 #ifdef WIN32_ONLY_COMPILER
00915 typedef LONG slock_t;
00916 
00917 #define HAS_TEST_AND_SET
00918 #define TAS(lock) (InterlockedCompareExchange(lock, 1, 0))
00919 
00920 #define SPIN_DELAY() spin_delay()
00921 
00922 /* If using Visual C++ on Win64, inline assembly is unavailable.
00923  * Use a _mm_pause instrinsic instead of rep nop.
00924  */
00925 #if defined(_WIN64)
00926 static __forceinline void
00927 spin_delay(void)
00928 {
00929     _mm_pause();
00930 }
00931 #else
00932 static __forceinline void
00933 spin_delay(void)
00934 {
00935     /* See comment for gcc code. Same code, MASM syntax */
00936     __asm rep nop;
00937 }
00938 #endif
00939 
00940 #endif
00941 
00942 
00943 #endif  /* !defined(HAS_TEST_AND_SET) */
00944 
00945 
00946 /* Blow up if we didn't have any way to do spinlocks */
00947 #ifndef HAS_TEST_AND_SET
00948 #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 [email protected].
00949 #endif
00950 
00951 
00952 #else   /* !HAVE_SPINLOCKS */
00953 
00954 
00955 /*
00956  * Fake spinlock implementation using semaphores --- slow and prone
00957  * to fall foul of kernel limits on number of semaphores, so don't use this
00958  * unless you must!  The subroutines appear in spin.c.
00959  */
00960 typedef PGSemaphoreData slock_t;
00961 
00962 extern bool s_lock_free_sema(volatile slock_t *lock);
00963 extern void s_unlock_sema(volatile slock_t *lock);
00964 extern void s_init_lock_sema(volatile slock_t *lock);
00965 extern int  tas_sema(volatile slock_t *lock);
00966 
00967 #define S_LOCK_FREE(lock)   s_lock_free_sema(lock)
00968 #define S_UNLOCK(lock)   s_unlock_sema(lock)
00969 #define S_INIT_LOCK(lock)   s_init_lock_sema(lock)
00970 #define TAS(lock)   tas_sema(lock)
00971 
00972 
00973 #endif  /* HAVE_SPINLOCKS */
00974 
00975 
00976 /*
00977  * Default Definitions - override these above as needed.
00978  */
00979 
00980 #if !defined(S_LOCK)
00981 #define S_LOCK(lock) \
00982     (TAS(lock) ? s_lock((lock), __FILE__, __LINE__) : 0)
00983 #endif   /* S_LOCK */
00984 
00985 #if !defined(S_LOCK_FREE)
00986 #define S_LOCK_FREE(lock)   (*(lock) == 0)
00987 #endif   /* S_LOCK_FREE */
00988 
00989 #if !defined(S_UNLOCK)
00990 #define S_UNLOCK(lock)      (*((volatile slock_t *) (lock)) = 0)
00991 #endif   /* S_UNLOCK */
00992 
00993 #if !defined(S_INIT_LOCK)
00994 #define S_INIT_LOCK(lock)   S_UNLOCK(lock)
00995 #endif   /* S_INIT_LOCK */
00996 
00997 #if !defined(SPIN_DELAY)
00998 #define SPIN_DELAY()    ((void) 0)
00999 #endif   /* SPIN_DELAY */
01000 
01001 #if !defined(TAS)
01002 extern int  tas(volatile slock_t *lock);        /* in port/.../tas.s, or
01003                                                  * s_lock.c */
01004 
01005 #define TAS(lock)       tas(lock)
01006 #endif   /* TAS */
01007 
01008 #if !defined(TAS_SPIN)
01009 #define TAS_SPIN(lock)  TAS(lock)
01010 #endif   /* TAS_SPIN */
01011 
01012 
01013 /*
01014  * Platform-independent out-of-line support routines
01015  */
01016 extern int s_lock(volatile slock_t *lock, const char *file, int line);
01017 
01018 /* Support for dynamic adjustment of spins_per_delay */
01019 #define DEFAULT_SPINS_PER_DELAY  100
01020 
01021 extern void set_spins_per_delay(int shared_spins_per_delay);
01022 extern int  update_spins_per_delay(int shared_spins_per_delay);
01023 
01024 #endif   /* S_LOCK_H */