Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0709b7e

Browse files
committed
Change the spinlock primitives to function as compiler barriers.
Previously, they functioned as barriers against CPU reordering but notcompiler reordering, an odd API that required extensive use of volatileeverywhere that spinlocks are used. That's error-prone and has negativeimplications for performance, so change it.In theory, this makes it safe to remove many of the uses of volatilethat we currently have in our code base, but we may find that there aresome bugs in this effort when we do. In the long run, though, thisshould make for much more maintainable code.Patch by me. Review by Andres Freund.
1 parente80252d commit0709b7e

File tree

2 files changed

+79
-16
lines changed

2 files changed

+79
-16
lines changed

‎src/backend/storage/lmgr/s_lock.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,18 @@ s_lock(volatile slock_t *lock, const char *file, int line)
154154
returndelays;
155155
}
156156

157+
#ifdefUSE_DEFAULT_S_UNLOCK
158+
void
159+
s_unlock(slock_t*lock)
160+
{
161+
#ifdefTAS_ACTIVE_WORD
162+
/* HP's PA-RISC */
163+
*TAS_ACTIVE_WORD(lock)=-1;
164+
#else
165+
*lock=0;
166+
#endif
167+
}
168+
#endif
157169

158170
/*
159171
* Set local copy of spins_per_delay during backend startup.

‎src/include/storage/s_lock.h

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,16 @@
5555
*on Alpha TAS() will "fail" if interrupted. Therefore a retry loop must
5656
*always be used, even if you are certain the lock is free.
5757
*
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.
58+
*It is the responsibility of these macros to make sure that the compiler
59+
*does not re-order accesses to shared memory to precede the actual lock
60+
*acquisition, or follow the lock release. Prior to PostgreSQL 9.5, this
61+
*was the caller's responsibility, which meant that callers had to use
62+
*volatile-qualified pointers to refer to both the spinlock itself and the
63+
*shared data being accessed within the spinlocked critical section. This
64+
*was notationally awkward, easy to forget (and thus error-prone), and
65+
*prevented some useful compiler optimizations. For these reasons, we
66+
*now require that the macros themselves prevent compiler re-ordering,
67+
*so that the caller doesn't need to take special precautions.
6668
*
6769
*On platforms with weak memory ordering, the TAS(), TAS_SPIN(), and
6870
*S_UNLOCK() macros must further include hardware-level memory fence
@@ -399,9 +401,9 @@ tas(volatile slock_t *lock)
399401
#if defined(__sparcv7)
400402
/*
401403
* No stbar or membar available, luckily no actually produced hardware
402-
* requires a barrier.
404+
* requires a barrier. We fall through to the default gcc definition of
405+
* S_UNLOCK in this case.
403406
*/
404-
#defineS_UNLOCK(lock)(*((volatile slock_t *) (lock)) = 0)
405407
#elif__sparcv8
406408
/* stbar is available (and required for both PSO, RMO), membar isn't */
407409
#defineS_UNLOCK(lock)\
@@ -484,14 +486,14 @@ tas(volatile slock_t *lock)
484486
#defineS_UNLOCK(lock)\
485487
do \
486488
{ \
487-
__asm__ __volatile__ ("lwsync \n"); \
489+
__asm__ __volatile__ ("lwsync \n" ::: "memory"); \
488490
*((volatile slock_t *) (lock)) = 0; \
489491
} while (0)
490492
#else
491493
#defineS_UNLOCK(lock)\
492494
do \
493495
{ \
494-
__asm__ __volatile__ ("sync \n"); \
496+
__asm__ __volatile__ ("sync \n" ::: "memory"); \
495497
*((volatile slock_t *) (lock)) = 0; \
496498
} while (0)
497499
#endif/* USE_PPC_LWSYNC */
@@ -599,7 +601,9 @@ do \
599601
" .set noreorder \n" \
600602
" .set nomacro \n" \
601603
" sync \n" \
602-
" .set pop "); \
604+
" .set pop "
605+
:
606+
:"memory");
603607
*((volatileslock_t*) (lock))=0; \
604608
}while (0)
605609

@@ -657,6 +661,23 @@ tas(volatile slock_t *lock)
657661
typedefunsignedcharslock_t;
658662
#endif
659663

664+
/*
665+
* Note that this implementation is unsafe for any platform that can speculate
666+
* a memory access (either load or store) after a following store. That
667+
* happens not to be possible x86 and most legacy architectures (some are
668+
* single-processor!), but many modern systems have weaker memory ordering.
669+
* Those that do must define their own version S_UNLOCK() rather than relying
670+
* on this one.
671+
*/
672+
#if !defined(S_UNLOCK)
673+
#if defined(__INTEL_COMPILER)
674+
#defineS_UNLOCK(lock)\
675+
do { __memory_barrier(); *(lock) = 0; } while (0)
676+
#else
677+
#defineS_UNLOCK(lock)\
678+
do { __asm__ __volatile__("" : : : "memory"); *(lock) = 0; } while (0)
679+
#endif
680+
#endif
660681

661682
#endif/* defined(__GNUC__) || defined(__INTEL_COMPILER) */
662683

@@ -730,9 +751,13 @@ tas(volatile slock_t *lock)
730751
return (lockval==0);
731752
}
732753

733-
#endif/* __GNUC__ */
754+
#defineS_UNLOCK(lock)\
755+
do { \
756+
__asm__ __volatile__("" : : : "memory"); \
757+
*TAS_ACTIVE_WORD(lock) = -1; \
758+
} while (0)
734759

735-
#defineS_UNLOCK(lock)(*TAS_ACTIVE_WORD(lock) = -1)
760+
#endif/* __GNUC__ */
736761

737762
#defineS_INIT_LOCK(lock) \
738763
do { \
@@ -770,6 +795,8 @@ typedef unsigned int slock_t;
770795
#defineTAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE)
771796
/* On IA64, it's a win to use a non-locking test before the xchg proper */
772797
#defineTAS_SPIN(lock)(*(lock) ? 1 : TAS(lock))
798+
#defineS_UNLOCK(lock)\
799+
do { _Asm_sched_fence(); (*(lock)) = 0); } while (0)
773800

774801
#endif/* HPUX on IA64, non gcc */
775802

@@ -832,6 +859,12 @@ spin_delay(void)
832859
}
833860
#endif
834861

862+
#include<intrin.h>
863+
#pragma intrinsic(_ReadWriteBarrier)
864+
865+
#defineS_UNLOCK(lock)\
866+
do { _ReadWriteBarrier(); (*(lock)) = 0); } while (0)
867+
835868
#endif
836869

837870

@@ -882,7 +915,25 @@ extern inttas_sema(volatile slock_t *lock);
882915
#endif/* S_LOCK_FREE */
883916

884917
#if !defined(S_UNLOCK)
885-
#defineS_UNLOCK(lock)(*((volatile slock_t *) (lock)) = 0)
918+
/*
919+
* Our default implementation of S_UNLOCK is essentially *(lock) = 0. This
920+
* is unsafe if the platform can speculate a memory access (either load or
921+
* store) after a following store; platforms where this is possible must
922+
* define their own S_UNLOCK. But CPU reordering is not the only concern:
923+
* if we simply defined S_UNLOCK() as an inline macro, the compiler might
924+
* reorder instructions from inside the critical section to occur after the
925+
* lock release. Since the compiler probably can't know what the external
926+
* function s_unlock is doing, putting the same logic there should be adequate.
927+
* A sufficiently-smart globally optimizing compiler could break that
928+
* assumption, though, and the cost of a function call for every spinlock
929+
* release may hurt performance significantly, so we use this implementation
930+
* only for platforms where we don't know of a suitable intrinsic. For the
931+
* most part, those are relatively obscure platform/compiler combinations to
932+
* which the PostgreSQL project does not have access.
933+
*/
934+
#defineUSE_DEFAULT_S_UNLOCK
935+
externvoids_unlock(volatiles_lock*lock);
936+
#defineS_UNLOCK(lock)s_unlock(lock)
886937
#endif/* S_UNLOCK */
887938

888939
#if !defined(S_INIT_LOCK)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp