lock_impl.h (6662B)
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. 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 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) 97 bool LockImpl::Try() { 98 return !!::TryAcquireSRWLockExclusive( 99 reinterpret_cast<PSRWLOCK>(&native_handle_)); 100 } 101 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 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 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 135 explicit BasicAutoLock(LockType& lock) EXCLUSIVE_LOCK_FUNCTION(lock) 136 : lock_(lock) { 137 lock_.Acquire(); 138 } 139 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 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: 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 168 ~BasicAutoTryLock() UNLOCK_FUNCTION() { 169 if (is_acquired_) { 170 lock_.AssertAcquired(); 171 lock_.Release(); 172 } 173 } 174 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: 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 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: 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 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: 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 239 ~BasicReleasableAutoLock() UNLOCK_FUNCTION() { 240 if (lock_) { 241 lock_->AssertAcquired(); 242 lock_->Release(); 243 } 244 } 245 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_