xref: /aosp_15_r20/external/cronet/base/threading/thread_checker_impl.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_checker_impl.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/debug/stack_trace.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/sequence_token.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/task/single_thread_task_runner.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_checker.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_local.h"
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker namespace {
16*6777b538SAndroid Build Coastguard Worker bool g_log_stack = false;
17*6777b538SAndroid Build Coastguard Worker }
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker namespace base {
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker // static
EnableStackLogging()22*6777b538SAndroid Build Coastguard Worker void ThreadCheckerImpl::EnableStackLogging() {
23*6777b538SAndroid Build Coastguard Worker   g_log_stack = true;
24*6777b538SAndroid Build Coastguard Worker }
25*6777b538SAndroid Build Coastguard Worker 
ThreadCheckerImpl()26*6777b538SAndroid Build Coastguard Worker ThreadCheckerImpl::ThreadCheckerImpl() {
27*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(lock_);
28*6777b538SAndroid Build Coastguard Worker   EnsureAssigned();
29*6777b538SAndroid Build Coastguard Worker }
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker ThreadCheckerImpl::~ThreadCheckerImpl() = default;
32*6777b538SAndroid Build Coastguard Worker 
ThreadCheckerImpl(ThreadCheckerImpl && other)33*6777b538SAndroid Build Coastguard Worker ThreadCheckerImpl::ThreadCheckerImpl(ThreadCheckerImpl&& other) {
34*6777b538SAndroid Build Coastguard Worker   // Verify that `other` is called on the correct thread.
35*6777b538SAndroid Build Coastguard Worker   // Note: This binds `other` if not already bound.
36*6777b538SAndroid Build Coastguard Worker   CHECK(other.CalledOnValidThread());
37*6777b538SAndroid Build Coastguard Worker 
38*6777b538SAndroid Build Coastguard Worker   //  Not using `other.lock_` to let TSAN catch racy construct from `other`.
39*6777b538SAndroid Build Coastguard Worker   bound_at_ = std::move(other.bound_at_);
40*6777b538SAndroid Build Coastguard Worker   thread_ref_ = other.thread_ref_;
41*6777b538SAndroid Build Coastguard Worker   task_token_ = other.task_token_;
42*6777b538SAndroid Build Coastguard Worker   sequence_token_ = other.sequence_token_;
43*6777b538SAndroid Build Coastguard Worker 
44*6777b538SAndroid Build Coastguard Worker   // `other.bound_at_` was moved from so it's null.
45*6777b538SAndroid Build Coastguard Worker   other.thread_ref_ = PlatformThreadRef();
46*6777b538SAndroid Build Coastguard Worker   other.task_token_ = internal::TaskToken();
47*6777b538SAndroid Build Coastguard Worker   other.sequence_token_ = internal::SequenceToken();
48*6777b538SAndroid Build Coastguard Worker }
49*6777b538SAndroid Build Coastguard Worker 
operator =(ThreadCheckerImpl && other)50*6777b538SAndroid Build Coastguard Worker ThreadCheckerImpl& ThreadCheckerImpl::operator=(ThreadCheckerImpl&& other) {
51*6777b538SAndroid Build Coastguard Worker   CHECK(CalledOnValidThread());
52*6777b538SAndroid Build Coastguard Worker 
53*6777b538SAndroid Build Coastguard Worker   // Verify that `other` is called on the correct thread.
54*6777b538SAndroid Build Coastguard Worker   // Note: This binds `other` if not already bound.
55*6777b538SAndroid Build Coastguard Worker   CHECK(other.CalledOnValidThread());
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker   // Intentionally not using either |lock_| to let TSAN catch racy assign.
58*6777b538SAndroid Build Coastguard Worker   TS_UNCHECKED_READ(thread_ref_) = TS_UNCHECKED_READ(other.thread_ref_);
59*6777b538SAndroid Build Coastguard Worker   TS_UNCHECKED_READ(task_token_) = TS_UNCHECKED_READ(other.task_token_);
60*6777b538SAndroid Build Coastguard Worker   TS_UNCHECKED_READ(sequence_token_) = TS_UNCHECKED_READ(other.sequence_token_);
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker   TS_UNCHECKED_READ(other.thread_ref_) = PlatformThreadRef();
63*6777b538SAndroid Build Coastguard Worker   TS_UNCHECKED_READ(other.task_token_) = internal::TaskToken();
64*6777b538SAndroid Build Coastguard Worker   TS_UNCHECKED_READ(other.sequence_token_) = internal::SequenceToken();
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker   return *this;
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker 
CalledOnValidThread(std::unique_ptr<debug::StackTrace> * out_bound_at) const69*6777b538SAndroid Build Coastguard Worker bool ThreadCheckerImpl::CalledOnValidThread(
70*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<debug::StackTrace>* out_bound_at) const {
71*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(lock_);
72*6777b538SAndroid Build Coastguard Worker   // If we're detached, bind to current state.
73*6777b538SAndroid Build Coastguard Worker   EnsureAssigned();
74*6777b538SAndroid Build Coastguard Worker   DCHECK(sequence_token_.IsValid());
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   // Cases to handle:
77*6777b538SAndroid Build Coastguard Worker   //
78*6777b538SAndroid Build Coastguard Worker   // 1. Bound outside a task and used on the same thread: return true.
79*6777b538SAndroid Build Coastguard Worker   // 2. Used on the same thread, TLS destroyed: return true.
80*6777b538SAndroid Build Coastguard Worker   //         Note: This case exists for historical reasons and should be
81*6777b538SAndroid Build Coastguard Worker   //         removed. See details in `SequenceCheckerImpl`.
82*6777b538SAndroid Build Coastguard Worker   // 3. Same sequence as when this was bound:
83*6777b538SAndroid Build Coastguard Worker   //   3a. Sequence is associated with a thread: return true.
84*6777b538SAndroid Build Coastguard Worker   //   3b. Sequence may run on any thread: return false.
85*6777b538SAndroid Build Coastguard Worker   //         Note: Return false even if this happens on the same thread as when
86*6777b538SAndroid Build Coastguard Worker   //         this was bound, because that would be fortuitous.
87*6777b538SAndroid Build Coastguard Worker   // 4. Different sequence than when this was bound: return false.
88*6777b538SAndroid Build Coastguard Worker 
89*6777b538SAndroid Build Coastguard Worker   if (thread_ref_ == PlatformThread::CurrentRef()) {
90*6777b538SAndroid Build Coastguard Worker     // If this runs on the bound thread:
91*6777b538SAndroid Build Coastguard Worker 
92*6777b538SAndroid Build Coastguard Worker     // Return true if the checker was bound outside of a `TaskScope`.
93*6777b538SAndroid Build Coastguard Worker     if (!task_token_.IsValid()) {
94*6777b538SAndroid Build Coastguard Worker       return true;
95*6777b538SAndroid Build Coastguard Worker     }
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker     // Return true if the checker was bound in the same `TaskScope`.
98*6777b538SAndroid Build Coastguard Worker     if (task_token_ == internal::TaskToken::GetForCurrentThread()) {
99*6777b538SAndroid Build Coastguard Worker       return true;
100*6777b538SAndroid Build Coastguard Worker     }
101*6777b538SAndroid Build Coastguard Worker 
102*6777b538SAndroid Build Coastguard Worker     // Return true if TLS has been destroyed.
103*6777b538SAndroid Build Coastguard Worker     //
104*6777b538SAndroid Build Coastguard Worker     // This exists for historical reasons and can probably be removed. See
105*6777b538SAndroid Build Coastguard Worker     // details in `SequenceCheckerImpl::CalledOnValidSequence()`.
106*6777b538SAndroid Build Coastguard Worker     if (ThreadLocalStorage::HasBeenDestroyed()) {
107*6777b538SAndroid Build Coastguard Worker       return true;
108*6777b538SAndroid Build Coastguard Worker     }
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker     // Return true if the checker was bound in the same thread-bound sequence.
111*6777b538SAndroid Build Coastguard Worker     // `CurrentTaskIsThreadBound()` avoids returning true when non-thread-bound
112*6777b538SAndroid Build Coastguard Worker     // tasks from the same sequence run on the same thread by chance.
113*6777b538SAndroid Build Coastguard Worker     if (sequence_token_ == internal::SequenceToken::GetForCurrentThread() &&
114*6777b538SAndroid Build Coastguard Worker         internal::CurrentTaskIsThreadBound()) {
115*6777b538SAndroid Build Coastguard Worker       return true;
116*6777b538SAndroid Build Coastguard Worker     }
117*6777b538SAndroid Build Coastguard Worker   }
118*6777b538SAndroid Build Coastguard Worker 
119*6777b538SAndroid Build Coastguard Worker   // On failure, set the `out_bound_at` argument.
120*6777b538SAndroid Build Coastguard Worker   if (out_bound_at && bound_at_) {
121*6777b538SAndroid Build Coastguard Worker     *out_bound_at = std::make_unique<debug::StackTrace>(*bound_at_);
122*6777b538SAndroid Build Coastguard Worker   }
123*6777b538SAndroid Build Coastguard Worker   return false;
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker 
DetachFromThread()126*6777b538SAndroid Build Coastguard Worker void ThreadCheckerImpl::DetachFromThread() {
127*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(lock_);
128*6777b538SAndroid Build Coastguard Worker   bound_at_ = nullptr;
129*6777b538SAndroid Build Coastguard Worker   thread_ref_ = PlatformThreadRef();
130*6777b538SAndroid Build Coastguard Worker   task_token_ = internal::TaskToken();
131*6777b538SAndroid Build Coastguard Worker   sequence_token_ = internal::SequenceToken();
132*6777b538SAndroid Build Coastguard Worker }
133*6777b538SAndroid Build Coastguard Worker 
EnsureAssigned() const134*6777b538SAndroid Build Coastguard Worker void ThreadCheckerImpl::EnsureAssigned() const {
135*6777b538SAndroid Build Coastguard Worker   if (!thread_ref_.is_null()) {
136*6777b538SAndroid Build Coastguard Worker     return;
137*6777b538SAndroid Build Coastguard Worker   }
138*6777b538SAndroid Build Coastguard Worker   if (g_log_stack) {
139*6777b538SAndroid Build Coastguard Worker     bound_at_ = std::make_unique<debug::StackTrace>(size_t{10});
140*6777b538SAndroid Build Coastguard Worker   }
141*6777b538SAndroid Build Coastguard Worker   thread_ref_ = PlatformThread::CurrentRef();
142*6777b538SAndroid Build Coastguard Worker   task_token_ = internal::TaskToken::GetForCurrentThread();
143*6777b538SAndroid Build Coastguard Worker   sequence_token_ = internal::SequenceToken::GetForCurrentThread();
144*6777b538SAndroid Build Coastguard Worker }
145*6777b538SAndroid Build Coastguard Worker 
146*6777b538SAndroid Build Coastguard Worker }  // namespace base
147