xref: /aosp_15_r20/external/cronet/base/synchronization/lock_impl.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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