diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c index 1b678075a80..1aa9912572e 100644 --- a/src/backend/storage/lmgr/s_lock.c +++ b/src/backend/storage/lmgr/s_lock.c @@ -96,7 +96,7 @@ s_lock(volatile slock_t *lock, const char *file, int line) int delays = 0; int cur_delay = 0; - while (TAS(lock)) + while (TAS_SPIN(lock)) { /* CPU-specific delay each time through the loop */ SPIN_DELAY(); diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h index 7fe01aac616..ac4549d7bb9 100644 --- a/src/include/storage/s_lock.h +++ b/src/include/storage/s_lock.h @@ -31,25 +31,33 @@ * macros at the bottom of the file. Check if your platform can use * these or needs to override them. * - * Usually, S_LOCK() is implemented in terms of an even lower-level macro - * TAS(): + * Usually, S_LOCK() is implemented in terms of even lower-level macros + * TAS() and TAS_SPIN(): * * int TAS(slock_t *lock) * Atomic test-and-set instruction. Attempt to acquire the lock, * but do *not* wait. Returns 0 if successful, nonzero if unable * to acquire the lock. * - * TAS() is NOT part of the API, and should never be called directly. + * int TAS_SPIN(slock_t *lock) + * Like TAS(), but this version is used when waiting for a lock + * previously found to be contended. Typically, this is the + * same as TAS(), but on some architectures it's better to poll a + * contended lock using an unlocked instruction and retry the + * atomic test-and-set only when it appears free. * - * CAUTION: on some platforms TAS() may sometimes report failure to acquire - * a lock even when the lock is not locked. For example, on Alpha TAS() - * will "fail" if interrupted. Therefore TAS() should always be invoked - * in a retry loop, even if you are certain the lock is free. + * TAS() and TAS_SPIN() are NOT part of the API, and should never be called + * directly. * - * ANOTHER CAUTION: be sure that TAS() and S_UNLOCK() represent sequence - * points, ie, loads and stores of other values must not be moved across - * a lock or unlock. In most cases it suffices to make the operation be - * done through a "volatile" pointer. + * CAUTION: on some platforms TAS() and/or TAS_SPIN() may sometimes report + * failure to acquire a lock even when the lock is not locked. For example, + * on Alpha TAS() will "fail" if interrupted. Therefore a retry loop must + * always be used, even if you are certain the lock is free. + * + * ANOTHER CAUTION: be sure that TAS(), TAS_SPIN(), and S_UNLOCK() represent + * sequence points, ie, loads and stores of other values must not be moved + * across a lock or unlock. In most cases it suffices to make the operation + * be done through a "volatile" pointer. * * On most supported platforms, TAS() uses a tas() function written * in assembly language to execute a hardware atomic-test-and-set @@ -727,6 +735,7 @@ typedef unsigned int slock_t; #include #define TAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE) +#define TAS_SPIN(lock) (*(lock) ? 1 : TAS(lock)) #endif /* HPUX on IA64, non gcc */ @@ -925,6 +934,10 @@ extern int tas(volatile slock_t *lock); /* in port/.../tas.s, or #define TAS(lock) tas(lock) #endif /* TAS */ +#if !defined(TAS_SPIN) +#define TAS_SPIN(lock) TAS(lock) +#endif /* TAS_SPIN */ + /* * Platform-independent out-of-line support routines