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

blob: 0d3df094ddd6b802ceabe87a4053ab5617bba6ce [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]32f3c232014-02-24 02:09:295// 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]ba198cae2014-02-23 22:19:298
[email protected]32f3c232014-02-24 02:09:299#include "base/synchronization/lock.h"
olli.raula7e1b45842015-09-11 13:06:1010
François Dorayefe18b92024-05-31 21:44:5911#include <cstdint>
Lei Zhang91450eb2021-12-24 02:11:1112
Tom Sepez38c4b2c2025-08-19 22:43:5613#include "base/compiler_specific.h"
14
Lei Zhang91450eb2021-12-24 02:11:1115#if DCHECK_IS_ON()
François Dorayefe18b92024-05-31 21:44:5916#include <array>
Peter Kastinge7fb7942024-12-06 22:43:0517#include <memory>
François Dorayefe18b92024-05-31 21:44:5918
Peter Kastinge7fb7942024-12-06 22:43:0519#include "base/functional/function_ref.h"
François Dorayefe18b92024-05-31 21:44:5920#include "base/synchronization/lock_subtle.h"
21#include "base/threading/platform_thread.h"
[email protected]ebd8dab62010-06-16 12:09:4822
[email protected]bc581a682011-01-01 23:16:2023namespace base {
[email protected]ce072a72010-12-31 20:02:1624
François Dorayefe18b92024-05-31 21:44:5925namespace {
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öm54119652024-11-14 00:16:3836constexpr size_t kHeldLocksCapacity = 10;
François Doray6671c402024-06-21 17:47:3937thread_local std::array<uintptr_t, kHeldLocksCapacity>
38 g_tracked_locks_held_by_thread;
François Dorayefe18b92024-05-31 21:44:5939
François Doray6671c402024-06-21 17:47:3940// Number of non-nullptr elements in `g_tracked_locks_held_by_thread`.
41thread_local size_t g_num_tracked_locks_held_by_thread = 0;
François Dorayefe18b92024-05-31 21:44:5942
43} // namespace
[email protected]34143d02013-04-09 01:40:2044
Peter Kastinge7fb7942024-12-06 22:43:0545Lock::Lock() = default;
46
47Lock::Lock(FunctionRef<void()> check_invariants)
48 : check_invariants_(
49 std::make_unique<FunctionRef<void()>>(check_invariants)) {}
50
[email protected]34143d02013-04-09 01:40:2051Lock::~Lock() {
[email protected]82952df2014-05-24 12:53:3252 DCHECK(owning_thread_ref_.is_null());
[email protected]ebd8dab62010-06-16 12:09:4853}
54
François Doray6671c402024-06-21 17:47:3955void Lock::Acquire(subtle::LockTracking tracking) {
56 lock_.Lock();
57 if (tracking == subtle::LockTracking::kEnabled) {
58 AddToLocksHeldOnCurrentThread();
59 }
60 CheckUnheldAndMark();
61}
62
63void Lock::Release() {
64 CheckHeldAndUnmark();
65 if (in_tracked_locks_held_by_current_thread_) {
66 RemoveFromLocksHeldOnCurrentThread();
67 }
68 lock_.Unlock();
69}
70
71bool 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]ebd8dab62010-06-16 12:09:4882void Lock::AssertAcquired() const {
Gabriel Charettec91f42272021-07-22 17:36:2983 DCHECK_EQ(owning_thread_ref_, PlatformThread::CurrentRef());
[email protected]ebd8dab62010-06-16 12:09:4884}
85
Etienne Pierre-doray5c37231a2023-02-22 03:41:3786void Lock::AssertNotHeld() const {
87 DCHECK(owning_thread_ref_.is_null());
88}
89
[email protected]ebd8dab62010-06-16 12:09:4890void Lock::CheckHeldAndUnmark() {
Gabriel Charettec91f42272021-07-22 17:36:2991 DCHECK_EQ(owning_thread_ref_, PlatformThread::CurrentRef());
Peter Kastinge7fb7942024-12-06 22:43:0592 if (check_invariants_) {
93 (*check_invariants_)();
94 }
[email protected]82952df2014-05-24 12:53:3295 owning_thread_ref_ = PlatformThreadRef();
[email protected]ebd8dab62010-06-16 12:09:4896}
97
98void Lock::CheckUnheldAndMark() {
[email protected]82952df2014-05-24 12:53:3299 DCHECK(owning_thread_ref_.is_null());
100 owning_thread_ref_ = PlatformThread::CurrentRef();
Peter Kastinge7fb7942024-12-06 22:43:05101 if (check_invariants_) {
102 (*check_invariants_)();
103 }
François Doray6671c402024-06-21 17:47:39104}
François Dorayefe18b92024-05-31 21:44:59105
François Doray6671c402024-06-21 17:47:39106void Lock::AddToLocksHeldOnCurrentThread() {
107 CHECK(!in_tracked_locks_held_by_current_thread_);
François Dorayefe18b92024-05-31 21:44:59108
François Doray6671c402024-06-21 17:47:39109 // Check if capacity is exceeded.
Peter Boström54119652024-11-14 00:16:38110 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 Doray6671c402024-06-21 17:47:39114
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
122void 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]ebd8dab62010-06-16 12:09:48140}
141
François Dorayefe18b92024-05-31 21:44:59142namespace subtle {
143
François Doray6671c402024-06-21 17:47:39144span<const uintptr_t> GetTrackedLocksHeldByCurrentThread() {
Tom Sepez38c4b2c2025-08-19 22:43:56145 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 Dorayefe18b92024-05-31 21:44:59148}
149
François Dorayefe18b92024-05-31 21:44:59150} // namespace subtle
151
[email protected]bc581a682011-01-01 23:16:20152} // namespace base
[email protected]32f3c232014-02-24 02:09:29153
olli.raula7e1b45842015-09-11 13:06:10154#endif // DCHECK_IS_ON()