1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 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/sequence_checker_impl.h" 6*6777b538SAndroid Build Coastguard Worker 7*6777b538SAndroid Build Coastguard Worker #include <utility> 8*6777b538SAndroid Build Coastguard Worker 9*6777b538SAndroid Build Coastguard Worker #include "base/check.h" 10*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h" 11*6777b538SAndroid Build Coastguard Worker #include "base/debug/stack_trace.h" 12*6777b538SAndroid Build Coastguard Worker #include "base/sequence_token.h" 13*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h" 14*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread_ref.h" 15*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_checker.h" 16*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_checker_impl.h" 17*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_local_storage.h" 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard Worker namespace base { 20*6777b538SAndroid Build Coastguard Worker 21*6777b538SAndroid Build Coastguard Worker namespace { 22*6777b538SAndroid Build Coastguard Worker bool g_log_stack = false; 23*6777b538SAndroid Build Coastguard Worker } 24*6777b538SAndroid Build Coastguard Worker 25*6777b538SAndroid Build Coastguard Worker // static EnableStackLogging()26*6777b538SAndroid Build Coastguard Workervoid SequenceCheckerImpl::EnableStackLogging() { 27*6777b538SAndroid Build Coastguard Worker g_log_stack = true; 28*6777b538SAndroid Build Coastguard Worker ThreadChecker::EnableStackLogging(); 29*6777b538SAndroid Build Coastguard Worker } 30*6777b538SAndroid Build Coastguard Worker SequenceCheckerImpl()31*6777b538SAndroid Build Coastguard WorkerSequenceCheckerImpl::SequenceCheckerImpl() { 32*6777b538SAndroid Build Coastguard Worker AutoLock auto_lock(lock_); 33*6777b538SAndroid Build Coastguard Worker EnsureAssigned(); 34*6777b538SAndroid Build Coastguard Worker } 35*6777b538SAndroid Build Coastguard Worker 36*6777b538SAndroid Build Coastguard Worker SequenceCheckerImpl::~SequenceCheckerImpl() = default; 37*6777b538SAndroid Build Coastguard Worker SequenceCheckerImpl(SequenceCheckerImpl && other)38*6777b538SAndroid Build Coastguard WorkerSequenceCheckerImpl::SequenceCheckerImpl(SequenceCheckerImpl&& other) { 39*6777b538SAndroid Build Coastguard Worker // Verify that `other` is called on the correct thread. 40*6777b538SAndroid Build Coastguard Worker // Note: This binds `other` if not already bound. 41*6777b538SAndroid Build Coastguard Worker CHECK(other.CalledOnValidSequence()); 42*6777b538SAndroid Build Coastguard Worker 43*6777b538SAndroid Build Coastguard Worker bound_at_ = std::move(other.bound_at_); 44*6777b538SAndroid Build Coastguard Worker sequence_token_ = other.sequence_token_; 45*6777b538SAndroid Build Coastguard Worker thread_ref_ = other.thread_ref_; 46*6777b538SAndroid Build Coastguard Worker 47*6777b538SAndroid Build Coastguard Worker // `other.bound_at_` was moved from so it's null. 48*6777b538SAndroid Build Coastguard Worker other.sequence_token_ = internal::SequenceToken(); 49*6777b538SAndroid Build Coastguard Worker other.thread_ref_ = PlatformThreadRef(); 50*6777b538SAndroid Build Coastguard Worker } 51*6777b538SAndroid Build Coastguard Worker operator =(SequenceCheckerImpl && other)52*6777b538SAndroid Build Coastguard WorkerSequenceCheckerImpl& SequenceCheckerImpl::operator=( 53*6777b538SAndroid Build Coastguard Worker SequenceCheckerImpl&& other) { 54*6777b538SAndroid Build Coastguard Worker // Verify that `other` is called on the correct thread. 55*6777b538SAndroid Build Coastguard Worker // Note: This binds `other` if not already bound. 56*6777b538SAndroid Build Coastguard Worker CHECK(other.CalledOnValidSequence()); 57*6777b538SAndroid Build Coastguard Worker 58*6777b538SAndroid Build Coastguard Worker TS_UNCHECKED_READ(bound_at_) = std::move(TS_UNCHECKED_READ(other.bound_at_)); 59*6777b538SAndroid Build Coastguard Worker TS_UNCHECKED_READ(sequence_token_) = TS_UNCHECKED_READ(other.sequence_token_); 60*6777b538SAndroid Build Coastguard Worker TS_UNCHECKED_READ(thread_ref_) = TS_UNCHECKED_READ(other.thread_ref_); 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Worker // `other.bound_at_` was moved from so it's null. 63*6777b538SAndroid Build Coastguard Worker TS_UNCHECKED_READ(other.sequence_token_) = internal::SequenceToken(); 64*6777b538SAndroid Build Coastguard Worker TS_UNCHECKED_READ(other.thread_ref_) = PlatformThreadRef(); 65*6777b538SAndroid Build Coastguard Worker 66*6777b538SAndroid Build Coastguard Worker return *this; 67*6777b538SAndroid Build Coastguard Worker } 68*6777b538SAndroid Build Coastguard Worker CalledOnValidSequence(std::unique_ptr<debug::StackTrace> * out_bound_at) const69*6777b538SAndroid Build Coastguard Workerbool SequenceCheckerImpl::CalledOnValidSequence( 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 75*6777b538SAndroid Build Coastguard Worker CHECK(!thread_ref_.is_null()); 76*6777b538SAndroid Build Coastguard Worker 77*6777b538SAndroid Build Coastguard Worker // Return true if called from the bound sequence. 78*6777b538SAndroid Build Coastguard Worker if (sequence_token_ == internal::SequenceToken::GetForCurrentThread()) { 79*6777b538SAndroid Build Coastguard Worker return true; 80*6777b538SAndroid Build Coastguard Worker } 81*6777b538SAndroid Build Coastguard Worker 82*6777b538SAndroid Build Coastguard Worker // Return true if called from the bound thread after TLS destruction. 83*6777b538SAndroid Build Coastguard Worker // 84*6777b538SAndroid Build Coastguard Worker // TODO(pbos): This preserves existing behavior that `sequence_token_` is 85*6777b538SAndroid Build Coastguard Worker // ignored after TLS shutdown. It should either be documented here why that is 86*6777b538SAndroid Build Coastguard Worker // necessary (shouldn't this destroy on sequence?) or 87*6777b538SAndroid Build Coastguard Worker // SequenceCheckerTest.FromThreadDestruction should be updated to reflect the 88*6777b538SAndroid Build Coastguard Worker // expected behavior. 89*6777b538SAndroid Build Coastguard Worker // 90*6777b538SAndroid Build Coastguard Worker // crrev.com/682023 added this TLS-check to solve an edge case but that edge 91*6777b538SAndroid Build Coastguard Worker // case was probably only a problem before TLS-destruction order was fixed in 92*6777b538SAndroid Build Coastguard Worker // crrev.com/1119244. crrev.com/1117059 further improved TLS-destruction order 93*6777b538SAndroid Build Coastguard Worker // of tokens by using `thread_local` and making it deterministic. 94*6777b538SAndroid Build Coastguard Worker // 95*6777b538SAndroid Build Coastguard Worker // See https://timsong-cpp.github.io/cppwp/n4140/basic.start.term: "If the 96*6777b538SAndroid Build Coastguard Worker // completion of the constructor or dynamic initialization of an object with 97*6777b538SAndroid Build Coastguard Worker // thread storage duration is sequenced before that of another, the completion 98*6777b538SAndroid Build Coastguard Worker // of the destructor of the second is sequenced before the initiation of the 99*6777b538SAndroid Build Coastguard Worker // destructor of the first." 100*6777b538SAndroid Build Coastguard Worker if (ThreadLocalStorage::HasBeenDestroyed() && 101*6777b538SAndroid Build Coastguard Worker thread_ref_ == PlatformThread::CurrentRef()) { 102*6777b538SAndroid Build Coastguard Worker return true; 103*6777b538SAndroid Build Coastguard Worker } 104*6777b538SAndroid Build Coastguard Worker 105*6777b538SAndroid Build Coastguard Worker // On failure, set the `out_bound_at` argument. 106*6777b538SAndroid Build Coastguard Worker if (out_bound_at && bound_at_) { 107*6777b538SAndroid Build Coastguard Worker *out_bound_at = std::make_unique<debug::StackTrace>(*bound_at_); 108*6777b538SAndroid Build Coastguard Worker } 109*6777b538SAndroid Build Coastguard Worker return false; 110*6777b538SAndroid Build Coastguard Worker } 111*6777b538SAndroid Build Coastguard Worker DetachFromSequence()112*6777b538SAndroid Build Coastguard Workervoid SequenceCheckerImpl::DetachFromSequence() { 113*6777b538SAndroid Build Coastguard Worker AutoLock auto_lock(lock_); 114*6777b538SAndroid Build Coastguard Worker bound_at_.reset(); 115*6777b538SAndroid Build Coastguard Worker sequence_token_ = internal::SequenceToken(); 116*6777b538SAndroid Build Coastguard Worker thread_ref_ = PlatformThreadRef(); 117*6777b538SAndroid Build Coastguard Worker } 118*6777b538SAndroid Build Coastguard Worker EnsureAssigned() const119*6777b538SAndroid Build Coastguard Workervoid SequenceCheckerImpl::EnsureAssigned() const { 120*6777b538SAndroid Build Coastguard Worker if (sequence_token_.IsValid()) { 121*6777b538SAndroid Build Coastguard Worker return; 122*6777b538SAndroid Build Coastguard Worker } 123*6777b538SAndroid Build Coastguard Worker 124*6777b538SAndroid Build Coastguard Worker if (g_log_stack) { 125*6777b538SAndroid Build Coastguard Worker bound_at_ = std::make_unique<debug::StackTrace>(size_t{10}); 126*6777b538SAndroid Build Coastguard Worker } 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Worker sequence_token_ = internal::SequenceToken::GetForCurrentThread(); 129*6777b538SAndroid Build Coastguard Worker DCHECK(sequence_token_.IsValid()); 130*6777b538SAndroid Build Coastguard Worker thread_ref_ = PlatformThread::CurrentRef(); 131*6777b538SAndroid Build Coastguard Worker DCHECK(!thread_ref_.is_null()); 132*6777b538SAndroid Build Coastguard Worker } 133*6777b538SAndroid Build Coastguard Worker 134*6777b538SAndroid Build Coastguard Worker } // namespace base 135