xref: /aosp_15_r20/external/cronet/base/sequence_checker_impl.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 Worker void 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 Worker SequenceCheckerImpl::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 Worker SequenceCheckerImpl::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 Worker SequenceCheckerImpl& 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 Worker bool 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 Worker void 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 Worker void 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