// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/sequence_checker_impl.h" #include #include "base/check.h" #include "base/compiler_specific.h" #include "base/debug/stack_trace.h" #include "base/memory/ptr_util.h" #include "base/sequence_token.h" #include "base/threading/thread_checker.h" #include "base/threading/thread_checker_impl.h" #include "base/threading/thread_local_storage.h" namespace base { // static void SequenceCheckerImpl::EnableStackLogging() { ThreadChecker::EnableStackLogging(); } SequenceCheckerImpl::SequenceCheckerImpl() = default; SequenceCheckerImpl::~SequenceCheckerImpl() = default; SequenceCheckerImpl::SequenceCheckerImpl(SequenceCheckerImpl&& other) = default; SequenceCheckerImpl& SequenceCheckerImpl::operator=( SequenceCheckerImpl&& other) = default; bool SequenceCheckerImpl::CalledOnValidSequence( std::unique_ptr* bound_at) const { AutoLock auto_lock(thread_checker_.lock_); // When `sequence_token_` or SequenceToken::GetForCurrentThread() are // invalid fall back on ThreadChecker. We assume that SequenceChecker things // are mostly run on a sequence and that that is the correct sequence (hence // using LIKELY annotation). if (LIKELY(thread_checker_.sequence_token_.IsValid())) { if (LIKELY(thread_checker_.sequence_token_ == SequenceToken::GetForCurrentThread())) { return true; } // TODO(pbos): This preserves existing behavior that `sequence_token_` is // ignored after TLS shutdown. It should either be documented here why // that is necessary (shouldn't this destroy on sequence?) or // SequenceCheckerTest.CalledOnValidSequenceFromThreadDestruction should // be updated to reflect the expected behavior. // // crrev.com/682023 added this TLS-check to solve an edge case but that // edge case was probably only a problem before TLS-destruction order was // fixed in crrev.com/1119244. crrev.com/1117059 further improved // TLS-destruction order of tokens by using `thread_local` and making it // deterministic. // See https://timsong-cpp.github.io/cppwp/n4140/basic.start.term: "If the // completion of the constructor or dynamic initialization of an object // with thread storage duration is sequenced before that of another, the // completion of the destructor of the second is sequenced before the // initiation of the destructor of the first." if (!ThreadLocalStorage::HasBeenDestroyed()) { if (bound_at) { *bound_at = thread_checker_.GetBoundAt(); } return false; } } // SequenceChecker behaves as a ThreadChecker when it is not bound to a // valid sequence token. return thread_checker_.CalledOnValidThreadInternal( bound_at, ThreadLocalStorage::HasBeenDestroyed()); } void SequenceCheckerImpl::DetachFromSequence() { thread_checker_.DetachFromThread(); } } // namespace base