[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
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_H_ | ||||
6 | #define BASE_SYNCHRONIZATION_LOCK_H_ | ||||
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 7 | |
[email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 8 | #include "base/base_export.h" |
Hans Wennborg | 7b53371 | 2020-06-22 20:52:27 | [diff] [blame] | 9 | #include "base/check_op.h" |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 10 | #include "base/macros.h" |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 11 | #include "base/synchronization/lock_impl.h" |
Lukasz Anforowicz | 5e71bd4 | 2018-09-17 19:28:57 | [diff] [blame] | 12 | #include "base/thread_annotations.h" |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 13 | #include "base/threading/platform_thread.h" |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 14 | #include "build/build_config.h" |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 15 | |
16 | namespace base { | ||||
17 | |||||
18 | // A convenient wrapper for an OS specific critical section. The only real | ||||
19 | // intelligence in this class is in debug mode for the support for the | ||||
20 | // AssertAcquired() method. | ||||
Lukasz Anforowicz | 5e71bd4 | 2018-09-17 19:28:57 | [diff] [blame] | 21 | class LOCKABLE BASE_EXPORT Lock { |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 22 | public: |
olli.raula | 7e1b4584 | 2015-09-11 13:06:10 | [diff] [blame] | 23 | #if !DCHECK_IS_ON() |
Lukasz Anforowicz | 5e71bd4 | 2018-09-17 19:28:57 | [diff] [blame] | 24 | // Optimized wrapper implementation |
[email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 25 | Lock() : lock_() {} |
26 | ~Lock() {} | ||||
Lukasz Anforowicz | 5e71bd4 | 2018-09-17 19:28:57 | [diff] [blame] | 27 | |
Benoît Lizé | a38dbf5d | 2020-03-11 08:33:58 | [diff] [blame] | 28 | void Acquire() EXCLUSIVE_LOCK_FUNCTION() { lock_.Lock(); } |
29 | void Release() UNLOCK_FUNCTION() { lock_.Unlock(); } | ||||
[email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 30 | |
31 | // If the lock is not held, take it and return true. If the lock is already | ||||
32 | // held by another thread, immediately return false. This must not be called | ||||
33 | // by a thread already holding the lock (what happens is undefined and an | ||||
34 | // assertion may fail). | ||||
Benoît Lizé | a38dbf5d | 2020-03-11 08:33:58 | [diff] [blame] | 35 | bool Try() EXCLUSIVE_TRYLOCK_FUNCTION(true) { return lock_.Try(); } |
[email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 36 | |
37 | // Null implementation if not debug. | ||||
Benoît Lizé | d65e44bab | 2019-11-29 11:10:17 | [diff] [blame] | 38 | void AssertAcquired() const ASSERT_EXCLUSIVE_LOCK() {} |
[email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 39 | #else |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 40 | Lock(); |
[email protected] | 34143d0 | 2013-04-09 01:40:20 | [diff] [blame] | 41 | ~Lock(); |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 42 | |
robliao | 7a8a904b | 2016-04-11 19:39:42 | [diff] [blame] | 43 | // NOTE: We do not permit recursive locks and will commonly fire a DCHECK() if |
44 | // a thread attempts to acquire the lock a second time (while already holding | ||||
45 | // it). | ||||
Benoît Lizé | a38dbf5d | 2020-03-11 08:33:58 | [diff] [blame] | 46 | void Acquire() EXCLUSIVE_LOCK_FUNCTION() { |
[email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 47 | lock_.Lock(); |
48 | CheckUnheldAndMark(); | ||||
49 | } | ||||
Benoît Lizé | a38dbf5d | 2020-03-11 08:33:58 | [diff] [blame] | 50 | void Release() UNLOCK_FUNCTION() { |
[email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 51 | CheckHeldAndUnmark(); |
52 | lock_.Unlock(); | ||||
53 | } | ||||
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 54 | |
Benoît Lizé | a38dbf5d | 2020-03-11 08:33:58 | [diff] [blame] | 55 | bool Try() EXCLUSIVE_TRYLOCK_FUNCTION(true) { |
[email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 56 | bool rv = lock_.Try(); |
57 | if (rv) { | ||||
58 | CheckUnheldAndMark(); | ||||
59 | } | ||||
60 | return rv; | ||||
61 | } | ||||
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 62 | |
Benoît Lizé | d65e44bab | 2019-11-29 11:10:17 | [diff] [blame] | 63 | void AssertAcquired() const ASSERT_EXCLUSIVE_LOCK(); |
olli.raula | 7e1b4584 | 2015-09-11 13:06:10 | [diff] [blame] | 64 | #endif // DCHECK_IS_ON() |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 65 | |
fdoray | d84dc06 | 2016-08-04 20:36:26 | [diff] [blame] | 66 | // Whether Lock mitigates priority inversion when used from different thread |
67 | // priorities. | ||||
68 | static bool HandlesMultipleThreadPriorities() { | ||||
Fabrice de Gans-Riberi | 306871de | 2018-05-16 19:38:39 | [diff] [blame] | 69 | #if defined(OS_WIN) |
fdoray | d84dc06 | 2016-08-04 20:36:26 | [diff] [blame] | 70 | // Windows mitigates priority inversion by randomly boosting the priority of |
71 | // ready threads. | ||||
72 | // https://msdn.microsoft.com/library/windows/desktop/ms684831.aspx | ||||
73 | return true; | ||||
Fabrice de Gans-Riberi | 306871de | 2018-05-16 19:38:39 | [diff] [blame] | 74 | #elif defined(OS_POSIX) || defined(OS_FUCHSIA) |
75 | // POSIX mitigates priority inversion by setting the priority of a thread | ||||
76 | // holding a Lock to the maximum priority of any other thread waiting on it. | ||||
77 | return internal::LockImpl::PriorityInheritanceAvailable(); | ||||
fdoray | d84dc06 | 2016-08-04 20:36:26 | [diff] [blame] | 78 | #else |
79 | #error Unsupported platform | ||||
robliao | 206071838 | 2016-08-01 20:59:42 | [diff] [blame] | 80 | #endif |
fdoray | d84dc06 | 2016-08-04 20:36:26 | [diff] [blame] | 81 | } |
robliao | 206071838 | 2016-08-01 20:59:42 | [diff] [blame] | 82 | |
robliao | f11a6c0 | 2016-04-07 04:54:42 | [diff] [blame] | 83 | // Both Windows and POSIX implementations of ConditionVariable need to be |
84 | // able to see our lock and tweak our debugging counters, as they release and | ||||
85 | // acquire locks inside of their condition variable APIs. | ||||
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 86 | friend class ConditionVariable; |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 87 | |
[email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 88 | private: |
olli.raula | 7e1b4584 | 2015-09-11 13:06:10 | [diff] [blame] | 89 | #if DCHECK_IS_ON() |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 90 | // Members and routines taking care of locks assertions. |
91 | // Note that this checks for recursive locks and allows them | ||||
92 | // if the variable is set. This is allowed by the underlying implementation | ||||
93 | // on windows but not on Posix, so we're doing unneeded checks on Posix. | ||||
94 | // It's worth it to share the code. | ||||
95 | void CheckHeldAndUnmark(); | ||||
96 | void CheckUnheldAndMark(); | ||||
97 | |||||
98 | // All private data is implicitly protected by lock_. | ||||
99 | // Be VERY careful to only access members under that lock. | ||||
[email protected] | 82952df | 2014-05-24 12:53:32 | [diff] [blame] | 100 | base::PlatformThreadRef owning_thread_ref_; |
olli.raula | 7e1b4584 | 2015-09-11 13:06:10 | [diff] [blame] | 101 | #endif // DCHECK_IS_ON() |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 102 | |
103 | // Platform specific underlying lock implementation. | ||||
104 | internal::LockImpl lock_; | ||||
105 | |||||
106 | DISALLOW_COPY_AND_ASSIGN(Lock); | ||||
107 | }; | ||||
108 | |||||
109 | // A helper class that acquires the given Lock while the AutoLock is in scope. | ||||
Etienne Pierre-doray | 8760a095 | 2019-03-07 03:13:12 | [diff] [blame] | 110 | using AutoLock = internal::BasicAutoLock<Lock>; |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 111 | |
112 | // AutoUnlock is a helper that will Release() the |lock| argument in the | ||||
113 | // constructor, and re-Acquire() it in the destructor. | ||||
Etienne Pierre-doray | 8760a095 | 2019-03-07 03:13:12 | [diff] [blame] | 114 | using AutoUnlock = internal::BasicAutoUnlock<Lock>; |
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 115 | |
Gabriel Charette | d773f12 | 2019-03-19 22:06:38 | [diff] [blame] | 116 | // Like AutoLock but is a no-op when the provided Lock* is null. Inspired from |
117 | // absl::MutexLockMaybe. Use this instead of base::Optional<base::AutoLock> to | ||||
118 | // get around -Wthread-safety-analysis warnings for conditional locking. | ||||
119 | using AutoLockMaybe = internal::BasicAutoLockMaybe<Lock>; | ||||
120 | |||||
121 | // Like AutoLock but permits Release() of its mutex before destruction. | ||||
122 | // Release() may be called at most once. Inspired from | ||||
123 | // absl::ReleasableMutexLock. Use this instead of base::Optional<base::AutoLock> | ||||
124 | // to get around -Wthread-safety-analysis warnings for AutoLocks that are | ||||
125 | // explicitly released early (prefer proper scoping to this). | ||||
126 | using ReleasableAutoLock = internal::BasicReleasableAutoLock<Lock>; | ||||
127 | |||||
[email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 128 | } // namespace base |
129 | |||||
130 | #endif // BASE_SYNCHRONIZATION_LOCK_H_ |