| Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2011 The Chromium Authors |
| license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. | ||||
| initial.commit | d7cae12 | 2008-07-26 21:49:38 | [diff] [blame] | 4 | |
| [email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 5 | // This file is used for debugging assertion support. The Lock class |
| 6 | // is functionally a wrapper around the LockImpl class, so the only | ||||
| 7 | // real intelligence in the class is in the debugging logic. | ||||
| [email protected] | ba198cae | 2014-02-23 22:19:29 | [diff] [blame] | 8 | |
| [email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 9 | #include "base/synchronization/lock.h" |
| olli.raula | 7e1b4584 | 2015-09-11 13:06:10 | [diff] [blame] | 10 | |
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 11 | #include <cstdint> |
| Lei Zhang | 91450eb | 2021-12-24 02:11:11 | [diff] [blame] | 12 | |
| Tom Sepez | 38c4b2c | 2025-08-19 22:43:56 | [diff] [blame] | 13 | #include "base/compiler_specific.h" |
| 14 | |||||
| Lei Zhang | 91450eb | 2021-12-24 02:11:11 | [diff] [blame] | 15 | #if DCHECK_IS_ON() |
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 16 | #include <array> |
| Peter Kasting | e7fb794 | 2024-12-06 22:43:05 | [diff] [blame] | 17 | #include <memory> |
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 18 | |
| Peter Kasting | e7fb794 | 2024-12-06 22:43:05 | [diff] [blame] | 19 | #include "base/functional/function_ref.h" |
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 20 | #include "base/synchronization/lock_subtle.h" |
| 21 | #include "base/threading/platform_thread.h" | ||||
| [email protected] | ebd8dab6 | 2010-06-16 12:09:48 | [diff] [blame] | 22 | |
| [email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 23 | namespace base { |
| [email protected] | ce072a7 | 2010-12-31 20:02:16 | [diff] [blame] | 24 | |
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 25 | namespace { |
| 26 | |||||
| 27 | // List of locks held by a thread. | ||||
| 28 | // | ||||
| 29 | // As of May 2024, no more than 5 locks were held simultaneously by a thread in | ||||
| 30 | // a test browsing session or while running the CQ (% locks acquired in unit | ||||
| 31 | // tests "WaitSetTest.NoStarvation" and | ||||
| 32 | // "MessagePipeTest.DataPipeConsumerHandlePingPong"). An array of size 10 is | ||||
| 33 | // therefore considered sufficient to track all locks held by a thread. A | ||||
| 34 | // dynamic-size array (e.g. owned by a `ThreadLocalOwnedPointer`) would require | ||||
| 35 | // handling reentrancy issues with allocator shims that use `base::Lock`. | ||||
| Peter Boström | 5411965 | 2024-11-14 00:16:38 | [diff] [blame] | 36 | constexpr size_t kHeldLocksCapacity = 10; |
| François Doray | 6671c40 | 2024-06-21 17:47:39 | [diff] [blame] | 37 | thread_local std::array<uintptr_t, kHeldLocksCapacity> |
| 38 | g_tracked_locks_held_by_thread; | ||||
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 39 | |
| François Doray | 6671c40 | 2024-06-21 17:47:39 | [diff] [blame] | 40 | // Number of non-nullptr elements in `g_tracked_locks_held_by_thread`. |
| 41 | thread_local size_t g_num_tracked_locks_held_by_thread = 0; | ||||
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 42 | |
| 43 | } // namespace | ||||
| [email protected] | 34143d0 | 2013-04-09 01:40:20 | [diff] [blame] | 44 | |
| Peter Kasting | e7fb794 | 2024-12-06 22:43:05 | [diff] [blame] | 45 | Lock::Lock() = default; |
| 46 | |||||
| 47 | Lock::Lock(FunctionRef<void()> check_invariants) | ||||
| 48 | : check_invariants_( | ||||
| 49 | std::make_unique<FunctionRef<void()>>(check_invariants)) {} | ||||
| 50 | |||||
| [email protected] | 34143d0 | 2013-04-09 01:40:20 | [diff] [blame] | 51 | Lock::~Lock() { |
| [email protected] | 82952df | 2014-05-24 12:53:32 | [diff] [blame] | 52 | DCHECK(owning_thread_ref_.is_null()); |
| [email protected] | ebd8dab6 | 2010-06-16 12:09:48 | [diff] [blame] | 53 | } |
| 54 | |||||
| François Doray | 6671c40 | 2024-06-21 17:47:39 | [diff] [blame] | 55 | void Lock::Acquire(subtle::LockTracking tracking) { |
| 56 | lock_.Lock(); | ||||
| 57 | if (tracking == subtle::LockTracking::kEnabled) { | ||||
| 58 | AddToLocksHeldOnCurrentThread(); | ||||
| 59 | } | ||||
| 60 | CheckUnheldAndMark(); | ||||
| 61 | } | ||||
| 62 | |||||
| 63 | void Lock::Release() { | ||||
| 64 | CheckHeldAndUnmark(); | ||||
| 65 | if (in_tracked_locks_held_by_current_thread_) { | ||||
| 66 | RemoveFromLocksHeldOnCurrentThread(); | ||||
| 67 | } | ||||
| 68 | lock_.Unlock(); | ||||
| 69 | } | ||||
| 70 | |||||
| 71 | bool Lock::Try(subtle::LockTracking tracking) { | ||||
| 72 | const bool rv = lock_.Try(); | ||||
| 73 | if (rv) { | ||||
| 74 | if (tracking == subtle::LockTracking::kEnabled) { | ||||
| 75 | AddToLocksHeldOnCurrentThread(); | ||||
| 76 | } | ||||
| 77 | CheckUnheldAndMark(); | ||||
| 78 | } | ||||
| 79 | return rv; | ||||
| 80 | } | ||||
| 81 | |||||
| [email protected] | ebd8dab6 | 2010-06-16 12:09:48 | [diff] [blame] | 82 | void Lock::AssertAcquired() const { |
| Gabriel Charette | c91f4227 | 2021-07-22 17:36:29 | [diff] [blame] | 83 | DCHECK_EQ(owning_thread_ref_, PlatformThread::CurrentRef()); |
| [email protected] | ebd8dab6 | 2010-06-16 12:09:48 | [diff] [blame] | 84 | } |
| 85 | |||||
| Etienne Pierre-doray | 5c37231a | 2023-02-22 03:41:37 | [diff] [blame] | 86 | void Lock::AssertNotHeld() const { |
| 87 | DCHECK(owning_thread_ref_.is_null()); | ||||
| 88 | } | ||||
| 89 | |||||
| [email protected] | ebd8dab6 | 2010-06-16 12:09:48 | [diff] [blame] | 90 | void Lock::CheckHeldAndUnmark() { |
| Gabriel Charette | c91f4227 | 2021-07-22 17:36:29 | [diff] [blame] | 91 | DCHECK_EQ(owning_thread_ref_, PlatformThread::CurrentRef()); |
| Peter Kasting | e7fb794 | 2024-12-06 22:43:05 | [diff] [blame] | 92 | if (check_invariants_) { |
| 93 | (*check_invariants_)(); | ||||
| 94 | } | ||||
| [email protected] | 82952df | 2014-05-24 12:53:32 | [diff] [blame] | 95 | owning_thread_ref_ = PlatformThreadRef(); |
| [email protected] | ebd8dab6 | 2010-06-16 12:09:48 | [diff] [blame] | 96 | } |
| 97 | |||||
| 98 | void Lock::CheckUnheldAndMark() { | ||||
| [email protected] | 82952df | 2014-05-24 12:53:32 | [diff] [blame] | 99 | DCHECK(owning_thread_ref_.is_null()); |
| 100 | owning_thread_ref_ = PlatformThread::CurrentRef(); | ||||
| Peter Kasting | e7fb794 | 2024-12-06 22:43:05 | [diff] [blame] | 101 | if (check_invariants_) { |
| 102 | (*check_invariants_)(); | ||||
| 103 | } | ||||
| François Doray | 6671c40 | 2024-06-21 17:47:39 | [diff] [blame] | 104 | } |
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 105 | |
| François Doray | 6671c40 | 2024-06-21 17:47:39 | [diff] [blame] | 106 | void Lock::AddToLocksHeldOnCurrentThread() { |
| 107 | CHECK(!in_tracked_locks_held_by_current_thread_); | ||||
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 108 | |
| François Doray | 6671c40 | 2024-06-21 17:47:39 | [diff] [blame] | 109 | // Check if capacity is exceeded. |
| Peter Boström | 5411965 | 2024-11-14 00:16:38 | [diff] [blame] | 110 | CHECK_LT(g_num_tracked_locks_held_by_thread, kHeldLocksCapacity) |
| 111 | << "This thread holds more than " << kHeldLocksCapacity | ||||
| 112 | << " tracked locks simultaneously. Reach out to //base OWNERS to " | ||||
| 113 | "determine whether `kHeldLocksCapacity` should be increased."; | ||||
| François Doray | 6671c40 | 2024-06-21 17:47:39 | [diff] [blame] | 114 | |
| 115 | // Add to the list of held locks. | ||||
| 116 | g_tracked_locks_held_by_thread[g_num_tracked_locks_held_by_thread] = | ||||
| 117 | reinterpret_cast<uintptr_t>(this); | ||||
| 118 | ++g_num_tracked_locks_held_by_thread; | ||||
| 119 | in_tracked_locks_held_by_current_thread_ = true; | ||||
| 120 | } | ||||
| 121 | |||||
| 122 | void Lock::RemoveFromLocksHeldOnCurrentThread() { | ||||
| 123 | CHECK(in_tracked_locks_held_by_current_thread_); | ||||
| 124 | for (size_t i = 0; i < g_num_tracked_locks_held_by_thread; ++i) { | ||||
| 125 | // Traverse from the end since locks are typically acquired and released in | ||||
| 126 | // opposite order. | ||||
| 127 | const size_t index = g_num_tracked_locks_held_by_thread - i - 1; | ||||
| 128 | if (g_tracked_locks_held_by_thread[index] == | ||||
| 129 | reinterpret_cast<uintptr_t>(this)) { | ||||
| 130 | g_tracked_locks_held_by_thread[index] = | ||||
| 131 | g_tracked_locks_held_by_thread[g_num_tracked_locks_held_by_thread - | ||||
| 132 | 1]; | ||||
| 133 | g_tracked_locks_held_by_thread[g_num_tracked_locks_held_by_thread - 1] = | ||||
| 134 | reinterpret_cast<uintptr_t>(nullptr); | ||||
| 135 | --g_num_tracked_locks_held_by_thread; | ||||
| 136 | break; | ||||
| 137 | } | ||||
| 138 | } | ||||
| 139 | in_tracked_locks_held_by_current_thread_ = false; | ||||
| [email protected] | ebd8dab6 | 2010-06-16 12:09:48 | [diff] [blame] | 140 | } |
| 141 | |||||
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 142 | namespace subtle { |
| 143 | |||||
| François Doray | 6671c40 | 2024-06-21 17:47:39 | [diff] [blame] | 144 | span<const uintptr_t> GetTrackedLocksHeldByCurrentThread() { |
| Tom Sepez | 38c4b2c | 2025-08-19 22:43:56 | [diff] [blame] | 145 | return UNSAFE_TODO( |
| 146 | span<const uintptr_t>(g_tracked_locks_held_by_thread.begin(), | ||||
| 147 | g_num_tracked_locks_held_by_thread)); | ||||
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 148 | } |
| 149 | |||||
| François Doray | efe18b9 | 2024-05-31 21:44:59 | [diff] [blame] | 150 | } // namespace subtle |
| 151 | |||||
| [email protected] | bc581a68 | 2011-01-01 23:16:20 | [diff] [blame] | 152 | } // namespace base |
| [email protected] | 32f3c23 | 2014-02-24 02:09:29 | [diff] [blame] | 153 | |
| olli.raula | 7e1b4584 | 2015-09-11 13:06:10 | [diff] [blame] | 154 | #endif // DCHECK_IS_ON() |