Skip to content

Commit c01c25f

Browse files
committed
Improve spinlock performance for HP-UX, ia64, non-gcc.
At least on this architecture, it's very important to spin on a non-atomic instruction and only retry the atomic once it appears that it will succeed. To fix this, split TAS() into two macros: TAS(), for trying to grab the lock the first time, and TAS_SPIN(), for spinning until we get it. TAS_SPIN() defaults to same as TAS(), but we can override it when we know there's a better way. It's likely that some of the other cases in s_lock.h require similar treatment, but this is the only one we've got conclusive evidence for at present.
1 parent 6e1f1fe commit c01c25f

File tree

2 files changed

+25
-12
lines changed

2 files changed

+25
-12
lines changed

src/backend/storage/lmgr/s_lock.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ s_lock(volatile slock_t *lock, const char *file, int line)
9696
int delays = 0;
9797
int cur_delay = 0;
9898

99-
while (TAS(lock))
99+
while (TAS_SPIN(lock))
100100
{
101101
/* CPU-specific delay each time through the loop */
102102
SPIN_DELAY();

src/include/storage/s_lock.h

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,33 @@
3131
* macros at the bottom of the file. Check if your platform can use
3232
* these or needs to override them.
3333
*
34-
* Usually, S_LOCK() is implemented in terms of an even lower-level macro
35-
* TAS():
34+
* Usually, S_LOCK() is implemented in terms of even lower-level macros
35+
* TAS() and TAS_SPIN():
3636
*
3737
* int TAS(slock_t *lock)
3838
* Atomic test-and-set instruction. Attempt to acquire the lock,
3939
* but do *not* wait. Returns 0 if successful, nonzero if unable
4040
* to acquire the lock.
4141
*
42-
* TAS() is NOT part of the API, and should never be called directly.
42+
* int TAS_SPIN(slock_t *lock)
43+
* Like TAS(), but this version is used when waiting for a lock
44+
* previously found to be contended. Typically, this is the
45+
* same as TAS(), but on some architectures it's better to poll a
46+
* contended lock using an unlocked instruction and retry the
47+
* atomic test-and-set only when it appears free.
4348
*
44-
* CAUTION: on some platforms TAS() may sometimes report failure to acquire
45-
* a lock even when the lock is not locked. For example, on Alpha TAS()
46-
* will "fail" if interrupted. Therefore TAS() should always be invoked
47-
* in a retry loop, even if you are certain the lock is free.
49+
* TAS() and TAS_SPIN() are NOT part of the API, and should never be called
50+
* directly.
4851
*
49-
* ANOTHER CAUTION: be sure that TAS() and S_UNLOCK() represent sequence
50-
* points, ie, loads and stores of other values must not be moved across
51-
* a lock or unlock. In most cases it suffices to make the operation be
52-
* done through a "volatile" pointer.
52+
* CAUTION: on some platforms TAS() and/or TAS_SPIN() may sometimes report
53+
* failure to acquire a lock even when the lock is not locked. For example,
54+
* on Alpha TAS() will "fail" if interrupted. Therefore a retry loop must
55+
* always be used, even if you are certain the lock is free.
56+
*
57+
* ANOTHER CAUTION: be sure that TAS(), TAS_SPIN(), and S_UNLOCK() represent
58+
* sequence points, ie, loads and stores of other values must not be moved
59+
* across a lock or unlock. In most cases it suffices to make the operation
60+
* be done through a "volatile" pointer.
5361
*
5462
* On most supported platforms, TAS() uses a tas() function written
5563
* in assembly language to execute a hardware atomic-test-and-set
@@ -727,6 +735,7 @@ typedef unsigned int slock_t;
727735

728736
#include <ia64/sys/inline.h>
729737
#define TAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE)
738+
#define TAS_SPIN(lock) (*(lock) ? 1 : TAS(lock))
730739

731740
#endif /* HPUX on IA64, non gcc */
732741

@@ -925,6 +934,10 @@ extern int tas(volatile slock_t *lock); /* in port/.../tas.s, or
925934
#define TAS(lock) tas(lock)
926935
#endif /* TAS */
927936

937+
#if !defined(TAS_SPIN)
938+
#define TAS_SPIN(lock) TAS(lock)
939+
#endif /* TAS_SPIN */
940+
928941

929942
/*
930943
* Platform-independent out-of-line support routines

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy