1 /* Copyright (c) 2006, Google Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * Author: Sanjay Ghemawat
35 // Fast spinlocks (at least on x86, a lock/unlock pair is approximately
36 // half the cost of a Mutex because the unlock just does a store instead
37 // of a compare-and-swap which is expensive).
39 // SpinLock is async signal safe.
40 // If used within a signal handler, all lock holders
41 // should block the signal even outside the signal handler.
43 #ifndef BASE_SPINLOCK_H_
44 #define BASE_SPINLOCK_H_
47 #include "base/atomicops.h"
48 #include "base/basictypes.h"
49 #include "base/dynamic_annotations.h"
50 #include "base/thread_annotations.h"
52 class LOCKABLE SpinLock
{
54 SpinLock() : lockword_(kSpinLockFree
) { }
56 // Special constructor for use with static SpinLock objects. E.g.,
58 // static SpinLock lock(base::LINKER_INITIALIZED);
60 // When intialized using this constructor, we depend on the fact
61 // that the linker has already initialized the memory appropriately.
62 // A SpinLock constructed like this can be freely used from global
63 // initializers without worrying about the order in which global
65 explicit SpinLock(base::LinkerInitialized
/*x*/) {
66 // Does nothing; lockword_ is already initialized
69 // Acquire this SpinLock.
70 // TODO(csilvers): uncomment the annotation when we figure out how to
71 // support this macro with 0 args (see thread_annotations.h)
72 inline void Lock() /*EXCLUSIVE_LOCK_FUNCTION()*/ {
73 if (base::subtle::Acquire_CompareAndSwap(&lockword_
, kSpinLockFree
,
74 kSpinLockHeld
) != kSpinLockFree
) {
77 ANNOTATE_RWLOCK_ACQUIRED(this, 1);
80 // Try to acquire this SpinLock without blocking and return true if the
81 // acquisition was successful. If the lock was not acquired, false is
82 // returned. If this SpinLock is free at the time of the call, TryLock
83 // will return true with high probability.
84 inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
86 (base::subtle::Acquire_CompareAndSwap(&lockword_
, kSpinLockFree
,
87 kSpinLockHeld
) == kSpinLockFree
);
89 ANNOTATE_RWLOCK_ACQUIRED(this, 1);
94 // Release this SpinLock, which must be held by the calling thread.
95 // TODO(csilvers): uncomment the annotation when we figure out how to
96 // support this macro with 0 args (see thread_annotations.h)
97 inline void Unlock() /*UNLOCK_FUNCTION()*/ {
99 static_cast<uint64
>(base::subtle::NoBarrier_Load(&lockword_
));
100 ANNOTATE_RWLOCK_RELEASED(this, 1);
101 base::subtle::Release_Store(&lockword_
, kSpinLockFree
);
102 if (wait_cycles
!= kSpinLockHeld
) {
103 // Collect contentionz profile info, and speed the wakeup of any waiter.
104 // The wait_cycles value indicates how long this thread spent waiting
106 SlowUnlock(wait_cycles
);
110 // Determine if the lock is held. When the lock is held by the invoking
111 // thread, true will always be returned. Intended to be used as
112 // CHECK(lock.IsHeld()).
113 inline bool IsHeld() const {
114 return base::subtle::NoBarrier_Load(&lockword_
) != kSpinLockFree
;
117 static const base::LinkerInitialized LINKER_INITIALIZED
; // backwards compat
119 enum { kSpinLockFree
= 0 };
120 enum { kSpinLockHeld
= 1 };
121 enum { kSpinLockSleeper
= 2 };
123 volatile Atomic32 lockword_
;
126 void SlowUnlock(uint64 wait_cycles
);
127 Atomic32
SpinLoop(int64 initial_wait_timestamp
, Atomic32
* wait_cycles
);
128 inline int32
CalculateWaitCycles(int64 wait_start_time
);
130 DISALLOW_COPY_AND_ASSIGN(SpinLock
);
133 // Corresponding locker object that arranges to acquire a spinlock for
134 // the duration of a C++ scope.
135 class SCOPED_LOCKABLE SpinLockHolder
{
139 inline explicit SpinLockHolder(SpinLock
* l
) EXCLUSIVE_LOCK_FUNCTION(l
)
143 // TODO(csilvers): uncomment the annotation when we figure out how to
144 // support this macro with 0 args (see thread_annotations.h)
145 inline ~SpinLockHolder() /*UNLOCK_FUNCTION()*/ { lock_
->Unlock(); }
147 // Catch bug where variable name is omitted, e.g. SpinLockHolder (&lock);
148 #define SpinLockHolder(x) COMPILE_ASSERT(0, spin_lock_decl_missing_var_name)
151 #endif // BASE_SPINLOCK_H_