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 Workervoid 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 WorkerThreadCheckerImpl::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 WorkerThreadCheckerImpl::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 WorkerThreadCheckerImpl& 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 Workerbool 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 Workervoid 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 Workervoid 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