third_party/abseil-cpp/absl/base/internal/spinlock.h
Go to the documentation of this file.
1 //
2 // Copyright 2017 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 // Most users requiring mutual exclusion should use Mutex.
18 // SpinLock is provided for use in two situations:
19 // - for use by Abseil internal code that Mutex itself depends on
20 // - for async signal safety (see below)
21 
22 // SpinLock is async signal safe. If a spinlock is used within a signal
23 // handler, all code that acquires the lock must ensure that the signal cannot
24 // arrive while they are holding the lock. Typically, this is done by blocking
25 // the signal.
26 //
27 // Threads waiting on a SpinLock may be woken in an arbitrary order.
28 
29 #ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_
30 #define ABSL_BASE_INTERNAL_SPINLOCK_H_
31 
32 #include <stdint.h>
33 #include <sys/types.h>
34 
35 #include <atomic>
36 
37 #include "absl/base/attributes.h"
38 #include "absl/base/const_init.h"
39 #include "absl/base/dynamic_annotations.h"
40 #include "absl/base/internal/low_level_scheduling.h"
41 #include "absl/base/internal/raw_logging.h"
42 #include "absl/base/internal/scheduling_mode.h"
43 #include "absl/base/internal/tsan_mutex_interface.h"
44 #include "absl/base/macros.h"
45 #include "absl/base/port.h"
46 #include "absl/base/thread_annotations.h"
47 
48 namespace absl {
50 namespace base_internal {
51 
53  public:
54  SpinLock() : lockword_(kSpinLockCooperative) {
55  ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
56  }
57 
58  // Constructors that allow non-cooperative spinlocks to be created for use
59  // inside thread schedulers. Normal clients should not use these.
61 
62  // Constructor for global SpinLock instances. See absl/base/const_init.h.
64  : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
65 
66  // For global SpinLock instances prefer trivial destructor when possible.
67  // Default but non-trivial destructor in some build configurations causes an
68  // extra static initializer.
69 #ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
70  ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
71 #else
72  ~SpinLock() = default;
73 #endif
74 
75  // Acquire this SpinLock.
77  ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
78  if (!TryLockImpl()) {
79  SlowLock();
80  }
81  ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
82  }
83 
84  // Try to acquire this SpinLock without blocking and return true if the
85  // acquisition was successful. If the lock was not acquired, false is
86  // returned. If this SpinLock is free at the time of the call, TryLock
87  // will return true with high probability.
89  ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
90  bool res = TryLockImpl();
92  this, __tsan_mutex_try_lock | (res ? 0 : __tsan_mutex_try_lock_failed),
93  0);
94  return res;
95  }
96 
97  // Release this SpinLock, which must be held by the calling thread.
98  inline void Unlock() ABSL_UNLOCK_FUNCTION() {
100  uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
101  lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
102  std::memory_order_release);
103 
104  if ((lock_value & kSpinLockDisabledScheduling) != 0) {
106  }
107  if ((lock_value & kWaitTimeMask) != 0) {
108  // Collect contentionz profile info, and speed the wakeup of any waiter.
109  // The wait_cycles value indicates how long this thread spent waiting
110  // for the lock.
111  SlowUnlock(lock_value);
112  }
114  }
115 
116  // Determine if the lock is held. When the lock is held by the invoking
117  // thread, true will always be returned. Intended to be used as
118  // CHECK(lock.IsHeld()).
119  inline bool IsHeld() const {
120  return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
121  }
122 
123  // Return immediately if this thread holds the SpinLock exclusively.
124  // Otherwise, report an error by crashing with a diagnostic.
126  if (!IsHeld()) {
127  ABSL_RAW_LOG(FATAL, "thread should hold the lock on SpinLock");
128  }
129  }
130 
131  protected:
132  // These should not be exported except for testing.
133 
134  // Store number of cycles between wait_start_time and wait_end_time in a
135  // lock value.
136  static uint32_t EncodeWaitCycles(int64_t wait_start_time,
137  int64_t wait_end_time);
138 
139  // Extract number of wait cycles in a lock value.
140  static uint64_t DecodeWaitCycles(uint32_t lock_value);
141 
142  // Provide access to protected method above. Use for testing only.
143  friend struct SpinLockTest;
144 
145  private:
146  // lockword_ is used to store the following:
147  //
148  // bit[0] encodes whether a lock is being held.
149  // bit[1] encodes whether a lock uses cooperative scheduling.
150  // bit[2] encodes whether the current lock holder disabled scheduling when
151  // acquiring the lock. Only set when kSpinLockHeld is also set.
152  // bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
153  // This is set by the lock holder to indicate how long it waited on
154  // the lock before eventually acquiring it. The number of cycles is
155  // encoded as a 29-bit unsigned int, or in the case that the current
156  // holder did not wait but another waiter is queued, the LSB
157  // (kSpinLockSleeper) is set. The implementation does not explicitly
158  // track the number of queued waiters beyond this. It must always be
159  // assumed that waiters may exist if the current holder was required to
160  // queue.
161  //
162  // Invariant: if the lock is not held, the value is either 0 or
163  // kSpinLockCooperative.
164  static constexpr uint32_t kSpinLockHeld = 1;
165  static constexpr uint32_t kSpinLockCooperative = 2;
166  static constexpr uint32_t kSpinLockDisabledScheduling = 4;
167  static constexpr uint32_t kSpinLockSleeper = 8;
168  // Includes kSpinLockSleeper.
169  static constexpr uint32_t kWaitTimeMask =
170  ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);
171 
172  // Returns true if the provided scheduling mode is cooperative.
173  static constexpr bool IsCooperative(
174  base_internal::SchedulingMode scheduling_mode) {
175  return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
176  }
177 
178  uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
179  void SlowLock() ABSL_ATTRIBUTE_COLD;
180  void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
181  uint32_t SpinLoop();
182 
183  inline bool TryLockImpl() {
184  uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
185  return (TryLockInternal(lock_value, 0) & kSpinLockHeld) == 0;
186  }
187 
188  std::atomic<uint32_t> lockword_;
189 
190  SpinLock(const SpinLock&) = delete;
191  SpinLock& operator=(const SpinLock&) = delete;
192 };
193 
194 // Corresponding locker object that arranges to acquire a spinlock for
195 // the duration of a C++ scope.
197  public:
199  : lock_(l) {
200  l->Lock();
201  }
202  inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION() { lock_->Unlock(); }
203 
204  SpinLockHolder(const SpinLockHolder&) = delete;
205  SpinLockHolder& operator=(const SpinLockHolder&) = delete;
206 
207  private:
209 };
210 
211 // Register a hook for profiling support.
212 //
213 // The function pointer registered here will be called whenever a spinlock is
214 // contended. The callback is given an opaque handle to the contended spinlock
215 // and the number of wait cycles. This is thread-safe, but only a single
216 // profiler can be registered. It is an error to call this function multiple
217 // times with different arguments.
218 void RegisterSpinLockProfiler(void (*fn)(const void* lock,
219  int64_t wait_cycles));
220 
221 //------------------------------------------------------------------------------
222 // Public interface ends here.
223 //------------------------------------------------------------------------------
224 
225 // If (result & kSpinLockHeld) == 0, then *this was successfully locked.
226 // Otherwise, returns last observed value for lockword_.
228  uint32_t wait_cycles) {
229  if ((lock_value & kSpinLockHeld) != 0) {
230  return lock_value;
231  }
232 
233  uint32_t sched_disabled_bit = 0;
234  if ((lock_value & kSpinLockCooperative) == 0) {
235  // For non-cooperative locks we must make sure we mark ourselves as
236  // non-reschedulable before we attempt to CompareAndSwap.
238  sched_disabled_bit = kSpinLockDisabledScheduling;
239  }
240  }
241 
242  if (!lockword_.compare_exchange_strong(
243  lock_value,
244  kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
245  std::memory_order_acquire, std::memory_order_relaxed)) {
247  }
248 
249  return lock_value;
250 }
251 
252 } // namespace base_internal
254 } // namespace absl
255 
256 #endif // ABSL_BASE_INTERNAL_SPINLOCK_H_
absl::base_internal::SpinLockHolder
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:196
const
#define const
Definition: bloaty/third_party/zlib/zconf.h:230
absl::base_internal::SpinLockHolder::~SpinLockHolder
~SpinLockHolder() ABSL_UNLOCK_FUNCTION()
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:202
ABSL_TSAN_MUTEX_POST_LOCK
#define ABSL_TSAN_MUTEX_POST_LOCK(...)
Definition: abseil-cpp/absl/base/internal/tsan_mutex_interface.h:58
absl::base_internal::SpinLock::kSpinLockCooperative
static constexpr uint32_t kSpinLockCooperative
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:165
absl::base_internal::SpinLock
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:52
mode
const char int mode
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::base_internal::SpinLock::kSpinLockDisabledScheduling
static constexpr uint32_t kSpinLockDisabledScheduling
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:166
true
#define true
Definition: setup_once.h:324
ABSL_TSAN_MUTEX_PRE_UNLOCK
#define ABSL_TSAN_MUTEX_PRE_UNLOCK(...)
Definition: abseil-cpp/absl/base/internal/tsan_mutex_interface.h:59
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
absl::base_internal::SchedulingGuard::EnableRescheduling
static void EnableRescheduling(bool disable_result)
Definition: abseil-cpp/absl/base/internal/low_level_scheduling.h:120
absl::base_internal::SpinLock::AssertHeld
void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK()
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:125
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::base_internal::SpinLockHolder::SpinLockHolder
SpinLockHolder(SpinLock *l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:198
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
absl::base_internal::SpinLock::kSpinLockHeld
static constexpr uint32_t kSpinLockHeld
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:164
generate-asm-lcov.fn
fn
Definition: generate-asm-lcov.py:146
ABSL_TSAN_MUTEX_CREATE
#define ABSL_TSAN_MUTEX_CREATE(...)
Definition: abseil-cpp/absl/base/internal/tsan_mutex_interface.h:55
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
absl::base_internal::SpinLockHolder::lock_
SpinLock * lock_
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:208
ABSL_TSAN_MUTEX_POST_UNLOCK
#define ABSL_TSAN_MUTEX_POST_UNLOCK(...)
Definition: abseil-cpp/absl/base/internal/tsan_mutex_interface.h:60
ABSL_EXCLUSIVE_TRYLOCK_FUNCTION
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: abseil-cpp/absl/base/thread_annotations.h:243
absl::base_internal::SpinLock::Unlock
void Unlock() ABSL_UNLOCK_FUNCTION()
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:98
absl::base_internal::SpinLock::TryLockInternal
uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles)
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:227
absl::base_internal::SpinLock::IsHeld
bool IsHeld() const
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:119
stdint.h
ABSL_TSAN_MUTEX_PRE_LOCK
#define ABSL_TSAN_MUTEX_PRE_LOCK(...)
Definition: abseil-cpp/absl/base/internal/tsan_mutex_interface.h:57
absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL
@ SCHEDULE_COOPERATIVE_AND_KERNEL
Definition: abseil-cpp/absl/base/internal/scheduling_mode.h:51
ABSL_TSAN_MUTEX_DESTROY
#define ABSL_TSAN_MUTEX_DESTROY(...)
Definition: abseil-cpp/absl/base/internal/tsan_mutex_interface.h:56
absl::ConstInitType
ConstInitType
Definition: abseil-cpp/absl/base/const_init.h:69
absl::base_internal::SchedulingMode
SchedulingMode
Definition: abseil-cpp/absl/base/internal/scheduling_mode.h:49
FATAL
#define FATAL(msg)
Definition: task.h:88
absl::base_internal::SpinLock::SpinLock
SpinLock()
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:54
absl::base_internal::SpinLockTest
Definition: abseil-cpp/absl/base/spinlock_test_common.cc:46
ABSL_EXCLUSIVE_LOCK_FUNCTION
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)
Definition: abseil-cpp/absl/base/thread_annotations.h:207
absl::base_internal::SpinLock::TryLock
bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:88
absl::base_internal::RegisterSpinLockProfiler
void RegisterSpinLockProfiler(void(*fn)(const void *contendedlock, int64_t wait_cycles))
Definition: abseil-cpp/absl/base/internal/spinlock.cc:65
absl::base_internal::SpinLock::SpinLock
constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:63
ABSL_ATTRIBUTE_COLD
#define ABSL_ATTRIBUTE_COLD
Definition: abseil-cpp/absl/base/attributes.h:463
ABSL_ASSERT_EXCLUSIVE_LOCK
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...)
Definition: abseil-cpp/absl/base/thread_annotations.h:261
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::base_internal::SpinLock::lockword_
std::atomic< uint32_t > lockword_
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:188
ABSL_UNLOCK_FUNCTION
#define ABSL_UNLOCK_FUNCTION(...)
Definition: abseil-cpp/absl/base/thread_annotations.h:228
absl::base_internal::SpinLock::IsCooperative
static constexpr bool IsCooperative(base_internal::SchedulingMode scheduling_mode)
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:173
ABSL_LOCKABLE
#define ABSL_LOCKABLE
Definition: abseil-cpp/absl/base/thread_annotations.h:183
ABSL_RAW_LOG
#define ABSL_RAW_LOG(severity,...)
Definition: abseil-cpp/absl/base/internal/raw_logging.h:44
absl::base_internal::SchedulingGuard::DisableRescheduling
static bool DisableRescheduling()
Definition: abseil-cpp/absl/base/internal/low_level_scheduling.h:116
ABSL_SCOPED_LOCKABLE
#define ABSL_SCOPED_LOCKABLE
Definition: abseil-cpp/absl/base/thread_annotations.h:196
absl::base_internal::SpinLock::Lock
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION()
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:76


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:15