blob: 118f54133030268f690e8b64e5abce29b68327a4 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2/* Copyright (c) 2006, Google Inc.
3 * All rights reserved.
Brian Silverman20350ac2021-11-17 18:19:55 -08004 *
Austin Schuh745610d2015-09-06 18:19:50 -07005 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
Brian Silverman20350ac2021-11-17 18:19:55 -08008 *
Austin Schuh745610d2015-09-06 18:19:50 -07009 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
Brian Silverman20350ac2021-11-17 18:19:55 -080018 *
Austin Schuh745610d2015-09-06 18:19:50 -070019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * ---
32 * Author: Sanjay Ghemawat
33 */
34
35// SpinLock is async signal safe.
36// If used within a signal handler, all lock holders
37// should block the signal even outside the signal handler.
38
39#ifndef BASE_SPINLOCK_H_
40#define BASE_SPINLOCK_H_
41
42#include <config.h>
43#include "base/atomicops.h"
44#include "base/basictypes.h"
45#include "base/dynamic_annotations.h"
46#include "base/thread_annotations.h"
47
48class LOCKABLE SpinLock {
49 public:
50 SpinLock() : lockword_(kSpinLockFree) { }
51
52 // Special constructor for use with static SpinLock objects. E.g.,
53 //
54 // static SpinLock lock(base::LINKER_INITIALIZED);
55 //
56 // When intialized using this constructor, we depend on the fact
57 // that the linker has already initialized the memory appropriately.
58 // A SpinLock constructed like this can be freely used from global
59 // initializers without worrying about the order in which global
60 // initializers run.
61 explicit SpinLock(base::LinkerInitialized /*x*/) {
62 // Does nothing; lockword_ is already initialized
63 }
64
65 // Acquire this SpinLock.
Brian Silverman20350ac2021-11-17 18:19:55 -080066 inline void Lock() EXCLUSIVE_LOCK_FUNCTION() {
Austin Schuh745610d2015-09-06 18:19:50 -070067 if (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree,
68 kSpinLockHeld) != kSpinLockFree) {
69 SlowLock();
70 }
Austin Schuh745610d2015-09-06 18:19:50 -070071 }
72
73 // Try to acquire this SpinLock without blocking and return true if the
74 // acquisition was successful. If the lock was not acquired, false is
75 // returned. If this SpinLock is free at the time of the call, TryLock
76 // will return true with high probability.
77 inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
78 bool res =
79 (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree,
80 kSpinLockHeld) == kSpinLockFree);
Austin Schuh745610d2015-09-06 18:19:50 -070081 return res;
82 }
83
84 // Release this SpinLock, which must be held by the calling thread.
Brian Silverman20350ac2021-11-17 18:19:55 -080085 inline void Unlock() UNLOCK_FUNCTION() {
86 uint64 prev_value = static_cast<uint64>(
Austin Schuh745610d2015-09-06 18:19:50 -070087 base::subtle::Release_AtomicExchange(&lockword_, kSpinLockFree));
Brian Silverman20350ac2021-11-17 18:19:55 -080088 if (prev_value != kSpinLockHeld) {
89 // Speed the wakeup of any waiter.
90 SlowUnlock();
Austin Schuh745610d2015-09-06 18:19:50 -070091 }
92 }
93
94 // Determine if the lock is held. When the lock is held by the invoking
95 // thread, true will always be returned. Intended to be used as
96 // CHECK(lock.IsHeld()).
97 inline bool IsHeld() const {
98 return base::subtle::NoBarrier_Load(&lockword_) != kSpinLockFree;
99 }
100
101 static const base::LinkerInitialized LINKER_INITIALIZED; // backwards compat
102 private:
103 enum { kSpinLockFree = 0 };
104 enum { kSpinLockHeld = 1 };
105 enum { kSpinLockSleeper = 2 };
106
107 volatile Atomic32 lockword_;
108
109 void SlowLock();
Brian Silverman20350ac2021-11-17 18:19:55 -0800110 void SlowUnlock();
111 Atomic32 SpinLoop();
Austin Schuh745610d2015-09-06 18:19:50 -0700112
113 DISALLOW_COPY_AND_ASSIGN(SpinLock);
114};
115
116// Corresponding locker object that arranges to acquire a spinlock for
117// the duration of a C++ scope.
118class SCOPED_LOCKABLE SpinLockHolder {
119 private:
120 SpinLock* lock_;
121 public:
122 inline explicit SpinLockHolder(SpinLock* l) EXCLUSIVE_LOCK_FUNCTION(l)
123 : lock_(l) {
124 l->Lock();
125 }
Brian Silverman20350ac2021-11-17 18:19:55 -0800126 inline ~SpinLockHolder() UNLOCK_FUNCTION() { lock_->Unlock(); }
Austin Schuh745610d2015-09-06 18:19:50 -0700127};
128// Catch bug where variable name is omitted, e.g. SpinLockHolder (&lock);
129#define SpinLockHolder(x) COMPILE_ASSERT(0, spin_lock_decl_missing_var_name)
130
131
132#endif // BASE_SPINLOCK_H_