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