1919// - for use by Abseil internal code that Mutex itself depends on
2020// - for async signal safety (see below)
2121
22- // SpinLock with a base_internal:: SchedulingMode::SCHEDULE_KERNEL_ONLY is async
22+ // SpinLock with a SchedulingMode::SCHEDULE_KERNEL_ONLY is async
2323// signal safe. If a spinlock is used within a signal handler, all code that
2424// acquires the lock must ensure that the signal cannot arrive while they are
2525// holding the lock. Typically, this is done by blocking the signal.
3131
3232#include < atomic>
3333#include < cstdint>
34+ #include < type_traits>
3435
3536#include " absl/base/attributes.h"
37+ #include " absl/base/config.h"
3638#include " absl/base/const_init.h"
37- #include " absl/base/dynamic_annotations.h"
3839#include " absl/base/internal/low_level_scheduling.h"
3940#include " absl/base/internal/raw_logging.h"
4041#include " absl/base/internal/scheduling_mode.h"
4142#include " absl/base/internal/tsan_mutex_interface.h"
43+ #include " absl/base/macros.h"
4244#include " absl/base/thread_annotations.h"
4345
4446namespace tcmalloc {
@@ -55,17 +57,31 @@ namespace base_internal {
5557
5658class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock {
5759 public:
58- SpinLock () : lockword_(kSpinLockCooperative ) {
59- ABSL_TSAN_MUTEX_CREATE (this , __tsan_mutex_not_static);
60- }
60+ constexpr SpinLock () : lockword_(kSpinLockCooperative ) { RegisterWithTsan (); }
6161
6262 // Constructors that allow non-cooperative spinlocks to be created for use
6363 // inside thread schedulers. Normal clients should not use these.
64- explicit SpinLock (base_internal::SchedulingMode mode);
64+ constexpr explicit SpinLock (SchedulingMode mode)
65+ : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
66+ RegisterWithTsan ();
67+ }
68+
69+ #if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(_WIN32)
70+ // Constructor to inline users of the default scheduling mode.
71+ //
72+ // This only needs to exists for inliner runs, but doesn't work correctly in
73+ // clang+windows builds, likely due to mangling differences.
74+ ABSL_DEPRECATE_AND_INLINE ()
75+ constexpr explicit SpinLock(SchedulingMode mode)
76+ __attribute__((enable_if(mode == SCHEDULE_COOPERATIVE_AND_KERNEL,
77+ " Cooperative use default constructor" )))
78+ : SpinLock() {}
79+ #endif
6580
6681 // Constructor for global SpinLock instances. See absl/base/const_init.h.
67- constexpr SpinLock (absl::ConstInitType, base_internal::SchedulingMode mode)
68- : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
82+ ABSL_DEPRECATE_AND_INLINE ()
83+ constexpr SpinLock (absl::ConstInitType, SchedulingMode mode)
84+ : SpinLock(mode) {}
6985
7086 // For global SpinLock instances prefer trivial destructor when possible.
7187 // Default but non-trivial destructor in some build configurations causes an
@@ -106,7 +122,7 @@ class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock {
106122 std::memory_order_release);
107123
108124 if ((lock_value & kSpinLockDisabledScheduling ) != 0 ) {
109- base_internal:: SchedulingGuard::EnableRescheduling (true );
125+ SchedulingGuard::EnableRescheduling (true );
110126 }
111127 if ((lock_value & kWaitTimeMask ) != 0 ) {
112128 // Collect contentionz profile info, and speed the wakeup of any waiter.
@@ -175,9 +191,16 @@ class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock {
175191 ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling );
176192
177193 // Returns true if the provided scheduling mode is cooperative.
178- static constexpr bool IsCooperative (
179- base_internal::SchedulingMode scheduling_mode) {
180- return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
194+ static constexpr bool IsCooperative (SchedulingMode scheduling_mode) {
195+ return scheduling_mode == SCHEDULE_COOPERATIVE_AND_KERNEL;
196+ }
197+
198+ constexpr void RegisterWithTsan () {
199+ #if ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
200+ if (!__builtin_is_constant_evaluated ()) {
201+ ABSL_TSAN_MUTEX_CREATE (this , __tsan_mutex_not_static);
202+ }
203+ #endif
181204 }
182205
183206 bool IsCooperative () const {
@@ -243,7 +266,7 @@ inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
243266 if ((lock_value & kSpinLockCooperative ) == 0 ) {
244267 // For non-cooperative locks we must make sure we mark ourselves as
245268 // non-reschedulable before we attempt to CompareAndSwap.
246- if (base_internal:: SchedulingGuard::DisableRescheduling ()) {
269+ if (SchedulingGuard::DisableRescheduling ()) {
247270 sched_disabled_bit = kSpinLockDisabledScheduling ;
248271 }
249272 }
@@ -252,7 +275,7 @@ inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
252275 lock_value,
253276 kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
254277 std::memory_order_acquire, std::memory_order_relaxed)) {
255- base_internal:: SchedulingGuard::EnableRescheduling (sched_disabled_bit != 0 );
278+ SchedulingGuard::EnableRescheduling (sched_disabled_bit != 0 );
256279 }
257280
258281 return lock_value;
0 commit comments