1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/dcheck_is_on.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr_exclusion.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/memory/stack_allocated.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/thread_annotations.h"
14*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
17*6777b538SAndroid Build Coastguard Worker #include "base/win/windows_types.h"
18*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
19*6777b538SAndroid Build Coastguard Worker #include <errno.h>
20*6777b538SAndroid Build Coastguard Worker #include <pthread.h>
21*6777b538SAndroid Build Coastguard Worker #include <string.h>
22*6777b538SAndroid Build Coastguard Worker #endif
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker namespace base {
25*6777b538SAndroid Build Coastguard Worker class Lock;
26*6777b538SAndroid Build Coastguard Worker class ConditionVariable;
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker namespace win {
29*6777b538SAndroid Build Coastguard Worker namespace internal {
30*6777b538SAndroid Build Coastguard Worker class AutoNativeLock;
31*6777b538SAndroid Build Coastguard Worker class ScopedHandleVerifier;
32*6777b538SAndroid Build Coastguard Worker } // namespace internal
33*6777b538SAndroid Build Coastguard Worker } // namespace win
34*6777b538SAndroid Build Coastguard Worker
35*6777b538SAndroid Build Coastguard Worker namespace internal {
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker // This class implements the underlying platform-specific spin-lock mechanism
38*6777b538SAndroid Build Coastguard Worker // used for the Lock class. Do not use, use Lock instead.
39*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT LockImpl {
40*6777b538SAndroid Build Coastguard Worker public:
41*6777b538SAndroid Build Coastguard Worker LockImpl(const LockImpl&) = delete;
42*6777b538SAndroid Build Coastguard Worker LockImpl& operator=(const LockImpl&) = delete;
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Worker private:
45*6777b538SAndroid Build Coastguard Worker friend class base::Lock;
46*6777b538SAndroid Build Coastguard Worker friend class base::ConditionVariable;
47*6777b538SAndroid Build Coastguard Worker friend class base::win::internal::AutoNativeLock;
48*6777b538SAndroid Build Coastguard Worker friend class base::win::internal::ScopedHandleVerifier;
49*6777b538SAndroid Build Coastguard Worker
50*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
51*6777b538SAndroid Build Coastguard Worker using NativeHandle = CHROME_SRWLOCK;
52*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
53*6777b538SAndroid Build Coastguard Worker using NativeHandle = pthread_mutex_t;
54*6777b538SAndroid Build Coastguard Worker #endif
55*6777b538SAndroid Build Coastguard Worker
56*6777b538SAndroid Build Coastguard Worker LockImpl();
57*6777b538SAndroid Build Coastguard Worker ~LockImpl();
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker // If the lock is not held, take it and return true. If the lock is already
60*6777b538SAndroid Build Coastguard Worker // held by something else, immediately return false.
61*6777b538SAndroid Build Coastguard Worker inline bool Try();
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Worker // Take the lock, blocking until it is available if necessary.
64*6777b538SAndroid Build Coastguard Worker inline void Lock();
65*6777b538SAndroid Build Coastguard Worker
66*6777b538SAndroid Build Coastguard Worker // Release the lock. This must only be called by the lock's holder: after
67*6777b538SAndroid Build Coastguard Worker // a successful call to Try, or a call to Lock.
68*6777b538SAndroid Build Coastguard Worker inline void Unlock();
69*6777b538SAndroid Build Coastguard Worker
70*6777b538SAndroid Build Coastguard Worker // Return the native underlying lock.
71*6777b538SAndroid Build Coastguard Worker // TODO(awalker): refactor lock and condition variables so that this is
72*6777b538SAndroid Build Coastguard Worker // unnecessary.
native_handle()73*6777b538SAndroid Build Coastguard Worker NativeHandle* native_handle() { return &native_handle_; }
74*6777b538SAndroid Build Coastguard Worker
75*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
76*6777b538SAndroid Build Coastguard Worker // Whether this lock will attempt to use priority inheritance.
77*6777b538SAndroid Build Coastguard Worker static bool PriorityInheritanceAvailable();
78*6777b538SAndroid Build Coastguard Worker #endif
79*6777b538SAndroid Build Coastguard Worker
80*6777b538SAndroid Build Coastguard Worker void LockInternal();
81*6777b538SAndroid Build Coastguard Worker NativeHandle native_handle_;
82*6777b538SAndroid Build Coastguard Worker };
83*6777b538SAndroid Build Coastguard Worker
Lock()84*6777b538SAndroid Build Coastguard Worker void LockImpl::Lock() {
85*6777b538SAndroid Build Coastguard Worker // Try the lock first to acquire it cheaply if it's not contended. Try() is
86*6777b538SAndroid Build Coastguard Worker // cheap on platforms with futex-type locks, as it doesn't call into the
87*6777b538SAndroid Build Coastguard Worker // kernel. Not marked LIKELY(), as:
88*6777b538SAndroid Build Coastguard Worker // 1. We don't know how much contention the lock would experience
89*6777b538SAndroid Build Coastguard Worker // 2. This may lead to weird-looking code layout when inlined into a caller
90*6777b538SAndroid Build Coastguard Worker // with (UN)LIKELY() annotations.
91*6777b538SAndroid Build Coastguard Worker if (Try()) {
92*6777b538SAndroid Build Coastguard Worker return;
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard Worker LockInternal();
96*6777b538SAndroid Build Coastguard Worker }
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
Try()99*6777b538SAndroid Build Coastguard Worker bool LockImpl::Try() {
100*6777b538SAndroid Build Coastguard Worker return !!::TryAcquireSRWLockExclusive(
101*6777b538SAndroid Build Coastguard Worker reinterpret_cast<PSRWLOCK>(&native_handle_));
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker
Unlock()104*6777b538SAndroid Build Coastguard Worker void LockImpl::Unlock() {
105*6777b538SAndroid Build Coastguard Worker ::ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&native_handle_));
106*6777b538SAndroid Build Coastguard Worker }
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
109*6777b538SAndroid Build Coastguard Worker
110*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
111*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void dcheck_trylock_result(int rv);
112*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void dcheck_unlock_result(int rv);
113*6777b538SAndroid Build Coastguard Worker #endif
114*6777b538SAndroid Build Coastguard Worker
Try()115*6777b538SAndroid Build Coastguard Worker bool LockImpl::Try() {
116*6777b538SAndroid Build Coastguard Worker int rv = pthread_mutex_trylock(&native_handle_);
117*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
118*6777b538SAndroid Build Coastguard Worker dcheck_trylock_result(rv);
119*6777b538SAndroid Build Coastguard Worker #endif
120*6777b538SAndroid Build Coastguard Worker return rv == 0;
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker
Unlock()123*6777b538SAndroid Build Coastguard Worker void LockImpl::Unlock() {
124*6777b538SAndroid Build Coastguard Worker [[maybe_unused]] int rv = pthread_mutex_unlock(&native_handle_);
125*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
126*6777b538SAndroid Build Coastguard Worker dcheck_unlock_result(rv);
127*6777b538SAndroid Build Coastguard Worker #endif
128*6777b538SAndroid Build Coastguard Worker }
129*6777b538SAndroid Build Coastguard Worker #endif
130*6777b538SAndroid Build Coastguard Worker
131*6777b538SAndroid Build Coastguard Worker // This is an implementation used for AutoLock templated on the lock type.
132*6777b538SAndroid Build Coastguard Worker template <class LockType>
133*6777b538SAndroid Build Coastguard Worker class SCOPED_LOCKABLE BasicAutoLock {
134*6777b538SAndroid Build Coastguard Worker public:
135*6777b538SAndroid Build Coastguard Worker struct AlreadyAcquired {};
136*6777b538SAndroid Build Coastguard Worker
BasicAutoLock(LockType & lock)137*6777b538SAndroid Build Coastguard Worker explicit BasicAutoLock(LockType& lock) EXCLUSIVE_LOCK_FUNCTION(lock)
138*6777b538SAndroid Build Coastguard Worker : lock_(lock) {
139*6777b538SAndroid Build Coastguard Worker lock_.Acquire();
140*6777b538SAndroid Build Coastguard Worker }
141*6777b538SAndroid Build Coastguard Worker
BasicAutoLock(LockType & lock,const AlreadyAcquired &)142*6777b538SAndroid Build Coastguard Worker BasicAutoLock(LockType& lock, const AlreadyAcquired&)
143*6777b538SAndroid Build Coastguard Worker EXCLUSIVE_LOCKS_REQUIRED(lock)
144*6777b538SAndroid Build Coastguard Worker : lock_(lock) {
145*6777b538SAndroid Build Coastguard Worker lock_.AssertAcquired();
146*6777b538SAndroid Build Coastguard Worker }
147*6777b538SAndroid Build Coastguard Worker
148*6777b538SAndroid Build Coastguard Worker BasicAutoLock(const BasicAutoLock&) = delete;
149*6777b538SAndroid Build Coastguard Worker BasicAutoLock& operator=(const BasicAutoLock&) = delete;
150*6777b538SAndroid Build Coastguard Worker
UNLOCK_FUNCTION()151*6777b538SAndroid Build Coastguard Worker ~BasicAutoLock() UNLOCK_FUNCTION() {
152*6777b538SAndroid Build Coastguard Worker lock_.AssertAcquired();
153*6777b538SAndroid Build Coastguard Worker lock_.Release();
154*6777b538SAndroid Build Coastguard Worker }
155*6777b538SAndroid Build Coastguard Worker
156*6777b538SAndroid Build Coastguard Worker private:
157*6777b538SAndroid Build Coastguard Worker // RAW_PTR_EXCLUSION: crbug.com/1521343 crbug.com/1520734 crbug.com/1519816
158*6777b538SAndroid Build Coastguard Worker RAW_PTR_EXCLUSION LockType& lock_;
159*6777b538SAndroid Build Coastguard Worker };
160*6777b538SAndroid Build Coastguard Worker
161*6777b538SAndroid Build Coastguard Worker // This is an implementation used for AutoTryLock templated on the lock type.
162*6777b538SAndroid Build Coastguard Worker template <class LockType>
163*6777b538SAndroid Build Coastguard Worker class SCOPED_LOCKABLE BasicAutoTryLock {
164*6777b538SAndroid Build Coastguard Worker STACK_ALLOCATED();
165*6777b538SAndroid Build Coastguard Worker
166*6777b538SAndroid Build Coastguard Worker public:
BasicAutoTryLock(LockType & lock)167*6777b538SAndroid Build Coastguard Worker explicit BasicAutoTryLock(LockType& lock) EXCLUSIVE_LOCK_FUNCTION(lock)
168*6777b538SAndroid Build Coastguard Worker : lock_(lock), is_acquired_(lock_.Try()) {}
169*6777b538SAndroid Build Coastguard Worker
170*6777b538SAndroid Build Coastguard Worker BasicAutoTryLock(const BasicAutoTryLock&) = delete;
171*6777b538SAndroid Build Coastguard Worker BasicAutoTryLock& operator=(const BasicAutoTryLock&) = delete;
172*6777b538SAndroid Build Coastguard Worker
UNLOCK_FUNCTION()173*6777b538SAndroid Build Coastguard Worker ~BasicAutoTryLock() UNLOCK_FUNCTION() {
174*6777b538SAndroid Build Coastguard Worker if (is_acquired_) {
175*6777b538SAndroid Build Coastguard Worker lock_.AssertAcquired();
176*6777b538SAndroid Build Coastguard Worker lock_.Release();
177*6777b538SAndroid Build Coastguard Worker }
178*6777b538SAndroid Build Coastguard Worker }
179*6777b538SAndroid Build Coastguard Worker
is_acquired()180*6777b538SAndroid Build Coastguard Worker bool is_acquired() const { return is_acquired_; }
181*6777b538SAndroid Build Coastguard Worker
182*6777b538SAndroid Build Coastguard Worker private:
183*6777b538SAndroid Build Coastguard Worker LockType& lock_;
184*6777b538SAndroid Build Coastguard Worker const bool is_acquired_;
185*6777b538SAndroid Build Coastguard Worker };
186*6777b538SAndroid Build Coastguard Worker
187*6777b538SAndroid Build Coastguard Worker // This is an implementation used for AutoUnlock templated on the lock type.
188*6777b538SAndroid Build Coastguard Worker template <class LockType>
189*6777b538SAndroid Build Coastguard Worker class BasicAutoUnlock {
190*6777b538SAndroid Build Coastguard Worker STACK_ALLOCATED();
191*6777b538SAndroid Build Coastguard Worker
192*6777b538SAndroid Build Coastguard Worker public:
BasicAutoUnlock(LockType & lock)193*6777b538SAndroid Build Coastguard Worker explicit BasicAutoUnlock(LockType& lock) : lock_(lock) {
194*6777b538SAndroid Build Coastguard Worker // We require our caller to have the lock.
195*6777b538SAndroid Build Coastguard Worker lock_.AssertAcquired();
196*6777b538SAndroid Build Coastguard Worker lock_.Release();
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker
199*6777b538SAndroid Build Coastguard Worker BasicAutoUnlock(const BasicAutoUnlock&) = delete;
200*6777b538SAndroid Build Coastguard Worker BasicAutoUnlock& operator=(const BasicAutoUnlock&) = delete;
201*6777b538SAndroid Build Coastguard Worker
~BasicAutoUnlock()202*6777b538SAndroid Build Coastguard Worker ~BasicAutoUnlock() { lock_.Acquire(); }
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Worker private:
205*6777b538SAndroid Build Coastguard Worker LockType& lock_;
206*6777b538SAndroid Build Coastguard Worker };
207*6777b538SAndroid Build Coastguard Worker
208*6777b538SAndroid Build Coastguard Worker // This is an implementation used for AutoLockMaybe templated on the lock type.
209*6777b538SAndroid Build Coastguard Worker template <class LockType>
210*6777b538SAndroid Build Coastguard Worker class SCOPED_LOCKABLE BasicAutoLockMaybe {
211*6777b538SAndroid Build Coastguard Worker STACK_ALLOCATED();
212*6777b538SAndroid Build Coastguard Worker
213*6777b538SAndroid Build Coastguard Worker public:
BasicAutoLockMaybe(LockType * lock)214*6777b538SAndroid Build Coastguard Worker explicit BasicAutoLockMaybe(LockType* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
215*6777b538SAndroid Build Coastguard Worker : lock_(lock) {
216*6777b538SAndroid Build Coastguard Worker if (lock_)
217*6777b538SAndroid Build Coastguard Worker lock_->Acquire();
218*6777b538SAndroid Build Coastguard Worker }
219*6777b538SAndroid Build Coastguard Worker
220*6777b538SAndroid Build Coastguard Worker BasicAutoLockMaybe(const BasicAutoLockMaybe&) = delete;
221*6777b538SAndroid Build Coastguard Worker BasicAutoLockMaybe& operator=(const BasicAutoLockMaybe&) = delete;
222*6777b538SAndroid Build Coastguard Worker
UNLOCK_FUNCTION()223*6777b538SAndroid Build Coastguard Worker ~BasicAutoLockMaybe() UNLOCK_FUNCTION() {
224*6777b538SAndroid Build Coastguard Worker if (lock_) {
225*6777b538SAndroid Build Coastguard Worker lock_->AssertAcquired();
226*6777b538SAndroid Build Coastguard Worker lock_->Release();
227*6777b538SAndroid Build Coastguard Worker }
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker
230*6777b538SAndroid Build Coastguard Worker private:
231*6777b538SAndroid Build Coastguard Worker LockType* const lock_;
232*6777b538SAndroid Build Coastguard Worker };
233*6777b538SAndroid Build Coastguard Worker
234*6777b538SAndroid Build Coastguard Worker // This is an implementation used for ReleasableAutoLock templated on the lock
235*6777b538SAndroid Build Coastguard Worker // type.
236*6777b538SAndroid Build Coastguard Worker template <class LockType>
237*6777b538SAndroid Build Coastguard Worker class SCOPED_LOCKABLE BasicReleasableAutoLock {
238*6777b538SAndroid Build Coastguard Worker STACK_ALLOCATED();
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker public:
BasicReleasableAutoLock(LockType * lock)241*6777b538SAndroid Build Coastguard Worker explicit BasicReleasableAutoLock(LockType* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
242*6777b538SAndroid Build Coastguard Worker : lock_(lock) {
243*6777b538SAndroid Build Coastguard Worker DCHECK(lock_);
244*6777b538SAndroid Build Coastguard Worker lock_->Acquire();
245*6777b538SAndroid Build Coastguard Worker }
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Worker BasicReleasableAutoLock(const BasicReleasableAutoLock&) = delete;
248*6777b538SAndroid Build Coastguard Worker BasicReleasableAutoLock& operator=(const BasicReleasableAutoLock&) = delete;
249*6777b538SAndroid Build Coastguard Worker
UNLOCK_FUNCTION()250*6777b538SAndroid Build Coastguard Worker ~BasicReleasableAutoLock() UNLOCK_FUNCTION() {
251*6777b538SAndroid Build Coastguard Worker if (lock_) {
252*6777b538SAndroid Build Coastguard Worker lock_->AssertAcquired();
253*6777b538SAndroid Build Coastguard Worker lock_->Release();
254*6777b538SAndroid Build Coastguard Worker }
255*6777b538SAndroid Build Coastguard Worker }
256*6777b538SAndroid Build Coastguard Worker
Release()257*6777b538SAndroid Build Coastguard Worker void Release() UNLOCK_FUNCTION() {
258*6777b538SAndroid Build Coastguard Worker DCHECK(lock_);
259*6777b538SAndroid Build Coastguard Worker lock_->AssertAcquired();
260*6777b538SAndroid Build Coastguard Worker lock_->Release();
261*6777b538SAndroid Build Coastguard Worker lock_ = nullptr;
262*6777b538SAndroid Build Coastguard Worker }
263*6777b538SAndroid Build Coastguard Worker
264*6777b538SAndroid Build Coastguard Worker private:
265*6777b538SAndroid Build Coastguard Worker LockType* lock_;
266*6777b538SAndroid Build Coastguard Worker };
267*6777b538SAndroid Build Coastguard Worker
268*6777b538SAndroid Build Coastguard Worker } // namespace internal
269*6777b538SAndroid Build Coastguard Worker } // namespace base
270*6777b538SAndroid Build Coastguard Worker
271*6777b538SAndroid Build Coastguard Worker #endif // BASE_SYNCHRONIZATION_LOCK_IMPL_H_
272