Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 7a2dd779b641e71e3946e8c5b683b4790921e617 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2011 The Chromium Authors
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
[email protected]bc581a682011-01-01 23:16:205#ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
6#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
[email protected]08048c72008-08-08 16:19:437
Jose Dapena Paz48e39d62024-06-11 10:43:368#include <utility>
9
avi9b6f42932015-12-26 22:15:1410#include "base/base_export.h"
Nico Weberf718af82022-03-21 16:56:2911#include "base/check.h"
David Sandersfc1f17fa2022-04-15 00:15:4912#include "base/dcheck_is_on.h"
Bartek Nowierskiaaa105f72024-01-31 07:25:0713#include "base/memory/raw_ptr_exclusion.h"
Bartek Nowierski3bc98062024-03-28 02:41:3614#include "base/memory/stack_allocated.h"
François Doray6671c402024-06-21 17:47:3915#include "base/synchronization/lock_subtle.h"
Anand Ravi9d185cd682025-03-27 16:41:5216#include "base/synchronization/synchronization_buildflags.h"
Etienne Pierre-doray8760a0952019-03-07 03:13:1217#include "base/thread_annotations.h"
[email protected]08048c72008-08-08 16:19:4318#include "build/build_config.h"
19
Xiaohan Wang94424e32022-01-15 14:51:3220#if BUILDFLAG(IS_WIN)
Bruce Dawsonbfdc3fd2018-01-03 20:32:3621#include "base/win/windows_types.h"
Xiaohan Wang94424e32022-01-15 14:51:3222#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
hans73f022a2017-06-21 02:34:1723#include <errno.h>
[email protected]08048c72008-08-08 16:19:4324#include <pthread.h>
Hidehiko Abeb63733e2020-04-17 18:35:3925#include <string.h>
[email protected]08048c72008-08-08 16:19:4326#endif
initial.commitd7cae122008-07-26 21:49:3827
[email protected]bc581a682011-01-01 23:16:2028namespace base {
Benoit Lizeb3b9e142020-09-01 09:48:1129class Lock;
30class ConditionVariable;
31
32namespace win {
33namespace internal {
34class AutoNativeLock;
35class ScopedHandleVerifier;
36} // namespace internal
37} // namespace win
38
[email protected]bc581a682011-01-01 23:16:2039namespace internal {
40
initial.commitd7cae122008-07-26 21:49:3841// This class implements the underlying platform-specific spin-lock mechanism
Benoit Lizeb3b9e142020-09-01 09:48:1142// used for the Lock class. Do not use, use Lock instead.
[email protected]0bea7252011-08-05 15:34:0043class BASE_EXPORT LockImpl {
Peter Boström75cd3c02021-09-28 15:23:1844 public:
45 LockImpl(const LockImpl&) = delete;
46 LockImpl& operator=(const LockImpl&) = delete;
47
48 private:
Benoit Lizeb3b9e142020-09-01 09:48:1149 friend class base::Lock;
50 friend class base::ConditionVariable;
51 friend class base::win::internal::AutoNativeLock;
52 friend class base::win::internal::ScopedHandleVerifier;
53
Xiaohan Wang94424e32022-01-15 14:51:3254#if BUILDFLAG(IS_WIN)
Bruce Dawsonbfdc3fd2018-01-03 20:32:3655 using NativeHandle = CHROME_SRWLOCK;
Xiaohan Wang94424e32022-01-15 14:51:3256#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
hans73f022a2017-06-21 02:34:1757 using NativeHandle = pthread_mutex_t;
[email protected]08048c72008-08-08 16:19:4358#endif
59
initial.commitd7cae122008-07-26 21:49:3860 LockImpl();
61 ~LockImpl();
62
63 // If the lock is not held, take it and return true. If the lock is already
64 // held by something else, immediately return false.
Benoit Lize7d86528b2020-09-08 17:41:0065 inline bool Try();
initial.commitd7cae122008-07-26 21:49:3866
67 // Take the lock, blocking until it is available if necessary.
Benoit Lize7d86528b2020-09-08 17:41:0068 inline void Lock();
initial.commitd7cae122008-07-26 21:49:3869
70 // Release the lock. This must only be called by the lock's holder: after
71 // a successful call to Try, or a call to Lock.
hans73f022a2017-06-21 02:34:1772 inline void Unlock();
initial.commitd7cae122008-07-26 21:49:3873
[email protected]7f197422011-12-15 18:57:2374 // Return the native underlying lock.
[email protected]08048c72008-08-08 16:19:4375 // TODO(awalker): refactor lock and condition variables so that this is
76 // unnecessary.
[email protected]8fe650c22013-09-14 05:27:0877 NativeHandle* native_handle() { return &native_handle_; }
initial.commitd7cae122008-07-26 21:49:3878
Xiaohan Wang94424e32022-01-15 14:51:3279#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
robliao2060718382016-08-01 20:59:4280 // Whether this lock will attempt to use priority inheritance.
81 static bool PriorityInheritanceAvailable();
82#endif
83
Joe Masona0ba58b052023-02-22 20:46:2984 void LockInternal();
[email protected]8fe650c22013-09-14 05:27:0885 NativeHandle native_handle_;
initial.commitd7cae122008-07-26 21:49:3886};
87
Benoit Lize7d86528b2020-09-08 17:41:0088void LockImpl::Lock() {
Joe Masona0ba58b052023-02-22 20:46:2989 // Try the lock first to acquire it cheaply if it's not contended. Try() is
Benoit Lize7d86528b2020-09-08 17:41:0090 // cheap on platforms with futex-type locks, as it doesn't call into the
Peter Kastingfa488992024-08-06 07:48:1491 // kernel. Not marked `[[likely]]`, as:
Joe Masona0ba58b052023-02-22 20:46:2992 // 1. We don't know how much contention the lock would experience
93 // 2. This may lead to weird-looking code layout when inlined into a caller
Peter Kastingfa488992024-08-06 07:48:1494 // with `[[(un)likely]]` attributes.
Joe Masona0ba58b052023-02-22 20:46:2995 if (Try()) {
Benoit Lize7d86528b2020-09-08 17:41:0096 return;
Joe Masona0ba58b052023-02-22 20:46:2997 }
Benoit Lize7d86528b2020-09-08 17:41:0098
Joe Masona0ba58b052023-02-22 20:46:2999 LockInternal();
Benoit Lize7d86528b2020-09-08 17:41:00100}
101
Xiaohan Wang94424e32022-01-15 14:51:32102#if BUILDFLAG(IS_WIN)
Benoit Lize7d86528b2020-09-08 17:41:00103bool LockImpl::Try() {
104 return !!::TryAcquireSRWLockExclusive(
105 reinterpret_cast<PSRWLOCK>(&native_handle_));
106}
107
hans73f022a2017-06-21 02:34:17108void LockImpl::Unlock() {
Bruce Dawsonbfdc3fd2018-01-03 20:32:36109 ::ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&native_handle_));
hans73f022a2017-06-21 02:34:17110}
Benoit Lize7d86528b2020-09-08 17:41:00111
Xiaohan Wang94424e32022-01-15 14:51:32112#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
Benoit Lize7d86528b2020-09-08 17:41:00113
Nico Weberf718af82022-03-21 16:56:29114#if DCHECK_IS_ON()
115BASE_EXPORT void dcheck_trylock_result(int rv);
116BASE_EXPORT void dcheck_unlock_result(int rv);
117#endif
Benoit Lize50bbea92021-08-18 21:10:58118
Benoit Lize7d86528b2020-09-08 17:41:00119bool LockImpl::Try() {
120 int rv = pthread_mutex_trylock(&native_handle_);
Nico Weberf718af82022-03-21 16:56:29121#if DCHECK_IS_ON()
122 dcheck_trylock_result(rv);
123#endif
Benoit Lize7d86528b2020-09-08 17:41:00124 return rv == 0;
125}
126
hans73f022a2017-06-21 02:34:17127void LockImpl::Unlock() {
Nico Weberf718af82022-03-21 16:56:29128 [[maybe_unused]] int rv = pthread_mutex_unlock(&native_handle_);
129#if DCHECK_IS_ON()
130 dcheck_unlock_result(rv);
131#endif
hans73f022a2017-06-21 02:34:17132}
133#endif
134
Etienne Pierre-doray8760a0952019-03-07 03:13:12135// This is an implementation used for AutoLock templated on the lock type.
136template <class LockType>
David Baron440f7cc2025-03-20 21:19:04137class [[nodiscard]] SCOPED_LOCKABLE BasicAutoLock {
Bartek Nowierski6e340a22024-06-06 00:14:50138 STACK_ALLOCATED();
139
Etienne Pierre-doray8760a0952019-03-07 03:13:12140 public:
141 struct AlreadyAcquired {};
142
François Doray6671c402024-06-21 17:47:39143 explicit BasicAutoLock(
144 LockType& lock,
145 subtle::LockTracking tracking = subtle::LockTracking::kDisabled)
146 EXCLUSIVE_LOCK_FUNCTION(lock)
Etienne Pierre-doray8760a0952019-03-07 03:13:12147 : lock_(lock) {
François Doray6671c402024-06-21 17:47:39148 lock_.Acquire(tracking);
Etienne Pierre-doray8760a0952019-03-07 03:13:12149 }
150
151 BasicAutoLock(LockType& lock, const AlreadyAcquired&)
152 EXCLUSIVE_LOCKS_REQUIRED(lock)
153 : lock_(lock) {
Jeremie Boulic89730422024-01-23 10:42:54154 lock_.AssertAcquired();
Etienne Pierre-doray8760a0952019-03-07 03:13:12155 }
156
Peter Boström7319bbd2021-09-15 22:59:38157 BasicAutoLock(const BasicAutoLock&) = delete;
158 BasicAutoLock& operator=(const BasicAutoLock&) = delete;
159
Etienne Pierre-doray8760a0952019-03-07 03:13:12160 ~BasicAutoLock() UNLOCK_FUNCTION() {
Jeremie Boulic89730422024-01-23 10:42:54161 lock_.AssertAcquired();
162 lock_.Release();
Etienne Pierre-doray8760a0952019-03-07 03:13:12163 }
164
165 private:
Bartek Nowierski6e340a22024-06-06 00:14:50166 LockType& lock_;
Etienne Pierre-doray8760a0952019-03-07 03:13:12167};
168
Bartek Nowierskibd320532024-06-04 23:58:52169// This is an implementation used for MovableAutoLock templated on the lock
170// type.
171template <class LockType>
David Baron440f7cc2025-03-20 21:19:04172class [[nodiscard]] SCOPED_LOCKABLE BasicMovableAutoLock {
Bartek Nowierskibd320532024-06-04 23:58:52173 public:
François Doray6671c402024-06-21 17:47:39174 explicit BasicMovableAutoLock(
175 LockType& lock,
176 subtle::LockTracking tracking = subtle::LockTracking::kDisabled)
177 EXCLUSIVE_LOCK_FUNCTION(lock)
Bartek Nowierskibd320532024-06-04 23:58:52178 : lock_(&lock) {
François Doray6671c402024-06-21 17:47:39179 lock_->Acquire(tracking);
Bartek Nowierskibd320532024-06-04 23:58:52180 }
181
182 BasicMovableAutoLock(const BasicMovableAutoLock&) = delete;
183 BasicMovableAutoLock& operator=(const BasicMovableAutoLock&) = delete;
Peter Kasting134ef9af2024-12-28 02:30:09184 BasicMovableAutoLock(BasicMovableAutoLock&& other)
185 : lock_(std::exchange(other.lock_, nullptr)) {}
Bartek Nowierskibd320532024-06-04 23:58:52186 BasicMovableAutoLock& operator=(BasicMovableAutoLock&& other) = delete;
187
188 ~BasicMovableAutoLock() UNLOCK_FUNCTION() {
189 // The lock may have been moved out.
190 if (lock_) {
191 lock_->AssertAcquired();
192 lock_->Release();
193 }
194 }
195
196 private:
197 // RAW_PTR_EXCLUSION: Stack-scoped.
198 RAW_PTR_EXCLUSION LockType* lock_;
199};
200
Koji Ishii22c70712021-10-20 22:21:09201// This is an implementation used for AutoTryLock templated on the lock type.
202template <class LockType>
David Baron440f7cc2025-03-20 21:19:04203class [[nodiscard]] SCOPED_LOCKABLE BasicAutoTryLock {
Bartek Nowierski3bc98062024-03-28 02:41:36204 STACK_ALLOCATED();
205
Koji Ishii22c70712021-10-20 22:21:09206 public:
Dan McArdlef97ab602024-05-16 15:44:59207 // The `LOCKS_EXCLUDED(lock)` annotation requires that the caller has not
208 // acquired `lock`. Without the annotation, Clang's Thread Safety Analysis
209 // would generate a false positive despite correct usage. For instance, a
210 // caller that checks `is_acquired()` before writing to guarded data would be
211 // flagged with "writing variable 'foo' requires holding 'lock' exclusively."
212 // See <https://crbug.com/340196356>.
François Doray6671c402024-06-21 17:47:39213 explicit BasicAutoTryLock(
214 LockType& lock,
215 subtle::LockTracking tracking = subtle::LockTracking::kDisabled)
216 LOCKS_EXCLUDED(lock)
217 : lock_(lock), is_acquired_(lock_.Try(tracking)) {}
Koji Ishii22c70712021-10-20 22:21:09218
219 BasicAutoTryLock(const BasicAutoTryLock&) = delete;
220 BasicAutoTryLock& operator=(const BasicAutoTryLock&) = delete;
221
222 ~BasicAutoTryLock() UNLOCK_FUNCTION() {
223 if (is_acquired_) {
Bartek Nowierski3bc98062024-03-28 02:41:36224 lock_.AssertAcquired();
225 lock_.Release();
Koji Ishii22c70712021-10-20 22:21:09226 }
227 }
228
Dan McArdlef97ab602024-05-16 15:44:59229 bool is_acquired() const EXCLUSIVE_TRYLOCK_FUNCTION(true) {
230 return is_acquired_;
231 }
Koji Ishii22c70712021-10-20 22:21:09232
233 private:
Bartek Nowierski3bc98062024-03-28 02:41:36234 LockType& lock_;
Koji Ishii22c70712021-10-20 22:21:09235 const bool is_acquired_;
236};
237
Etienne Pierre-doray8760a0952019-03-07 03:13:12238// This is an implementation used for AutoUnlock templated on the lock type.
239template <class LockType>
David Baron440f7cc2025-03-20 21:19:04240class [[nodiscard]] BasicAutoUnlock {
Bartek Nowierski3bc98062024-03-28 02:41:36241 STACK_ALLOCATED();
242
Etienne Pierre-doray8760a0952019-03-07 03:13:12243 public:
244 explicit BasicAutoUnlock(LockType& lock) : lock_(lock) {
245 // We require our caller to have the lock.
Bartek Nowierski3bc98062024-03-28 02:41:36246 lock_.AssertAcquired();
247 lock_.Release();
Etienne Pierre-doray8760a0952019-03-07 03:13:12248 }
249
Peter Boström7319bbd2021-09-15 22:59:38250 BasicAutoUnlock(const BasicAutoUnlock&) = delete;
251 BasicAutoUnlock& operator=(const BasicAutoUnlock&) = delete;
252
Bartek Nowierski3bc98062024-03-28 02:41:36253 ~BasicAutoUnlock() { lock_.Acquire(); }
Etienne Pierre-doray8760a0952019-03-07 03:13:12254
255 private:
Bartek Nowierski3bc98062024-03-28 02:41:36256 LockType& lock_;
Etienne Pierre-doray8760a0952019-03-07 03:13:12257};
258
Gabriel Charetted773f122019-03-19 22:06:38259// This is an implementation used for AutoLockMaybe templated on the lock type.
260template <class LockType>
David Baron440f7cc2025-03-20 21:19:04261class [[nodiscard]] SCOPED_LOCKABLE BasicAutoLockMaybe {
Bartek Nowierski3bc98062024-03-28 02:41:36262 STACK_ALLOCATED();
263
Gabriel Charetted773f122019-03-19 22:06:38264 public:
François Doray6671c402024-06-21 17:47:39265 explicit BasicAutoLockMaybe(
266 LockType* lock,
267 subtle::LockTracking tracking = subtle::LockTracking::kDisabled)
268 EXCLUSIVE_LOCK_FUNCTION(lock)
Gabriel Charetted773f122019-03-19 22:06:38269 : lock_(lock) {
Peter Kasting134ef9af2024-12-28 02:30:09270 if (lock_) {
François Doray6671c402024-06-21 17:47:39271 lock_->Acquire(tracking);
Peter Kasting134ef9af2024-12-28 02:30:09272 }
Gabriel Charetted773f122019-03-19 22:06:38273 }
274
Peter Boström7319bbd2021-09-15 22:59:38275 BasicAutoLockMaybe(const BasicAutoLockMaybe&) = delete;
276 BasicAutoLockMaybe& operator=(const BasicAutoLockMaybe&) = delete;
277
Gabriel Charetted773f122019-03-19 22:06:38278 ~BasicAutoLockMaybe() UNLOCK_FUNCTION() {
279 if (lock_) {
280 lock_->AssertAcquired();
281 lock_->Release();
282 }
283 }
284
285 private:
Bartek Nowierski3bc98062024-03-28 02:41:36286 LockType* const lock_;
Gabriel Charetted773f122019-03-19 22:06:38287};
288
289// This is an implementation used for ReleasableAutoLock templated on the lock
290// type.
291template <class LockType>
David Baron440f7cc2025-03-20 21:19:04292class [[nodiscard]] SCOPED_LOCKABLE BasicReleasableAutoLock {
Bartek Nowierski3bc98062024-03-28 02:41:36293 STACK_ALLOCATED();
294
Gabriel Charetted773f122019-03-19 22:06:38295 public:
François Doray6671c402024-06-21 17:47:39296 explicit BasicReleasableAutoLock(
297 LockType* lock,
298 subtle::LockTracking tracking = subtle::LockTracking::kDisabled)
299 EXCLUSIVE_LOCK_FUNCTION(lock)
Gabriel Charetted773f122019-03-19 22:06:38300 : lock_(lock) {
301 DCHECK(lock_);
François Doray6671c402024-06-21 17:47:39302 lock_->Acquire(tracking);
Gabriel Charetted773f122019-03-19 22:06:38303 }
304
Peter Boström7319bbd2021-09-15 22:59:38305 BasicReleasableAutoLock(const BasicReleasableAutoLock&) = delete;
306 BasicReleasableAutoLock& operator=(const BasicReleasableAutoLock&) = delete;
307
Gabriel Charetted773f122019-03-19 22:06:38308 ~BasicReleasableAutoLock() UNLOCK_FUNCTION() {
309 if (lock_) {
310 lock_->AssertAcquired();
311 lock_->Release();
312 }
313 }
314
315 void Release() UNLOCK_FUNCTION() {
316 DCHECK(lock_);
317 lock_->AssertAcquired();
318 lock_->Release();
319 lock_ = nullptr;
320 }
321
322 private:
Bartek Nowierski3bc98062024-03-28 02:41:36323 LockType* lock_;
Gabriel Charetted773f122019-03-19 22:06:38324};
325
[email protected]bc581a682011-01-01 23:16:20326} // namespace internal
Anand Ravi9d185cd682025-03-27 16:41:52327
Anand Ravi9d185cd682025-03-27 16:41:52328// Check to see whether the current kernel supports priority inheritance
329// properly by adjusting process priorities to boost the futex owner.
330BASE_EXPORT bool KernelSupportsPriorityInheritanceFutex();
Anand Ravi9d185cd682025-03-27 16:41:52331
[email protected]bc581a682011-01-01 23:16:20332} // namespace base
initial.commitd7cae122008-07-26 21:49:38333
[email protected]bc581a682011-01-01 23:16:20334#endif // BASE_SYNCHRONIZATION_LOCK_IMPL_H_