Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
chromium /chromium /src /refs/heads/main /. /base /sequence_checker_impl.cc
blob: 737041866fef2fac4f78ac454684083c22d09d7f [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:06[diff] [blame]1// Copyright 2012 The Chromium Authors
akalin@chromium.org399ed422012-12-27 19:58:00[diff] [blame]2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include"base/sequence_checker_impl.h"
6
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]7#include<algorithm>
David Bienvenu5f4d4f02020-09-27 16:55:03[diff] [blame]8#include<utility>
9
Hans Wennborgc3cffa62020-04-27 10:09:12[diff] [blame]10#include"base/check.h"
Peter Boström079702a2023-03-29 19:30:59[diff] [blame]11#include"base/compiler_specific.h"
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]12#include"base/containers/contains.h"
danakj894364e2021-01-27 21:51:29[diff] [blame]13#include"base/debug/stack_trace.h"
tzik0c2fcf52017-02-16 08:52:31[diff] [blame]14#include"base/sequence_token.h"
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]15#include"base/synchronization/lock_subtle.h"
François Doray524d2a22024-01-04 09:54:16[diff] [blame]16#include"base/threading/platform_thread.h"
17#include"base/threading/platform_thread_ref.h"
danakj894364e2021-01-27 21:51:29[diff] [blame]18#include"base/threading/thread_checker.h"
tzik0c2fcf52017-02-16 08:52:31[diff] [blame]19#include"base/threading/thread_checker_impl.h"
Scott Violet909058d2019-07-29 23:07:42[diff] [blame]20#include"base/threading/thread_local_storage.h"
fdorayeed5fa72016-07-26 22:28:45[diff] [blame]21
akalin@chromium.org399ed422012-12-27 19:58:00[diff] [blame]22namespace base{
23
François Doray524d2a22024-01-04 09:54:16[diff] [blame]24namespace{
25bool g_log_stack=false;
26}
27
danakj894364e2021-01-27 21:51:29[diff] [blame]28// static
29voidSequenceCheckerImpl::EnableStackLogging(){
François Doray524d2a22024-01-04 09:54:16[diff] [blame]30 g_log_stack=true;
danakj894364e2021-01-27 21:51:29[diff] [blame]31ThreadChecker::EnableStackLogging();
32}
33
François Doray524d2a22024-01-04 09:54:16[diff] [blame]34SequenceCheckerImpl::SequenceCheckerImpl(){
35AutoLock auto_lock(lock_);
36EnsureAssigned();
37}
38
fdorayeed5fa72016-07-26 22:28:45[diff] [blame]39SequenceCheckerImpl::~SequenceCheckerImpl()=default;
akalin@chromium.org399ed422012-12-27 19:58:00[diff] [blame]40
François Doray524d2a22024-01-04 09:54:16[diff] [blame]41SequenceCheckerImpl::SequenceCheckerImpl(SequenceCheckerImpl&& other){
42// Verify that `other` is called on the correct thread.
43// Note: This binds `other` if not already bound.
44 CHECK(other.CalledOnValidSequence());
45
46 bound_at_= std::move(other.bound_at_);
47 sequence_token_= other.sequence_token_;
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]48#if DCHECK_IS_ON()
49 locks_= std::move(other.locks_);
50#endif// DCHECK_IS_ON()
François Doray524d2a22024-01-04 09:54:16[diff] [blame]51 thread_ref_= other.thread_ref_;
52
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]53// `other.bound_at_` and `other.locks_` were moved so they're null.
54 DCHECK(!other.bound_at_);
55#if DCHECK_IS_ON()
56 DCHECK(other.locks_.empty());
57#endif// DCHECK_IS_ON()
François Doray524d2a22024-01-04 09:54:16[diff] [blame]58 other.sequence_token_= internal::SequenceToken();
59 other.thread_ref_=PlatformThreadRef();
60}
61
Gabriel Charette9746ffce2019-07-30 20:27:17[diff] [blame]62SequenceCheckerImpl&SequenceCheckerImpl::operator=(
François Doray524d2a22024-01-04 09:54:16[diff] [blame]63SequenceCheckerImpl&& other){
64// Verify that `other` is called on the correct thread.
65// Note: This binds `other` if not already bound.
66 CHECK(other.CalledOnValidSequence());
67
68 TS_UNCHECKED_READ(bound_at_)= std::move(TS_UNCHECKED_READ(other.bound_at_));
69 TS_UNCHECKED_READ(sequence_token_)= TS_UNCHECKED_READ(other.sequence_token_);
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]70#if DCHECK_IS_ON()
71 TS_UNCHECKED_READ(locks_)= std::move(TS_UNCHECKED_READ(other.locks_));
72#endif// DCHECK_IS_ON()
François Doray311bf142024-01-17 19:59:30[diff] [blame]73 TS_UNCHECKED_READ(thread_ref_)= TS_UNCHECKED_READ(other.thread_ref_);
François Doray524d2a22024-01-04 09:54:16[diff] [blame]74
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]75// `other.bound_at_` and `other.locks_` were moved so they're null.
76 DCHECK(!TS_UNCHECKED_READ(other.bound_at_));
77#if DCHECK_IS_ON()
78 DCHECK(TS_UNCHECKED_READ(other.locks_).empty());
79#endif// DCHECK_IS_ON()
François Doray524d2a22024-01-04 09:54:16[diff] [blame]80 TS_UNCHECKED_READ(other.sequence_token_)= internal::SequenceToken();
81 TS_UNCHECKED_READ(other.thread_ref_)=PlatformThreadRef();
82
83return*this;
84}
Gabriel Charette9746ffce2019-07-30 20:27:17[diff] [blame]85
danakj894364e2021-01-27 21:51:29[diff] [blame]86boolSequenceCheckerImpl::CalledOnValidSequence(
François Doray524d2a22024-01-04 09:54:16[diff] [blame]87 std::unique_ptr<debug::StackTrace>* out_bound_at)const{
88AutoLock auto_lock(lock_);
François Doray524d2a22024-01-04 09:54:16[diff] [blame]89EnsureAssigned();
François Doray311bf142024-01-17 19:59:30[diff] [blame]90 CHECK(!thread_ref_.is_null());
91
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]92// Valid if current sequence is the bound sequence.
93bool is_valid=
94(sequence_token_== internal::SequenceToken::GetForCurrentThread());
95
96// Valid if holding a bound lock.
97if(!is_valid){
98#if DCHECK_IS_ON()
François Doray6671c402024-06-21 17:47:39[diff] [blame]99for(uintptr_t lock: subtle::GetTrackedLocksHeldByCurrentThread()){
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]100if(Contains(locks_, lock)){
101 is_valid=true;
102break;
103}
104}
105#endif// DCHECK_IS_ON()
Peter Boström03c6f32a2023-04-03 18:34:23[diff] [blame]106}
107
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]108// Valid if called from the bound thread after TLS destruction.
François Doray524d2a22024-01-04 09:54:16[diff] [blame]109//
110// TODO(pbos): This preserves existing behavior that `sequence_token_` is
111// ignored after TLS shutdown. It should either be documented here why that is
112// necessary (shouldn't this destroy on sequence?) or
113// SequenceCheckerTest.FromThreadDestruction should be updated to reflect the
114// expected behavior.
115//
116// crrev.com/682023 added this TLS-check to solve an edge case but that edge
117// case was probably only a problem before TLS-destruction order was fixed in
118// crrev.com/1119244. crrev.com/1117059 further improved TLS-destruction order
119// of tokens by using `thread_local` and making it deterministic.
120//
121// See https://timsong-cpp.github.io/cppwp/n4140/basic.start.term: "If the
122// completion of the constructor or dynamic initialization of an object with
123// thread storage duration is sequenced before that of another, the completion
124// of the destructor of the second is sequenced before the initiation of the
125// destructor of the first."
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]126if(!is_valid){
127 is_valid=ThreadLocalStorage::HasBeenDestroyed()&&
128 thread_ref_==PlatformThread::CurrentRef();
François Doray524d2a22024-01-04 09:54:16[diff] [blame]129}
130
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]131if(!is_valid){
132// Return false without modifying the state if this call is not guaranteed
133// to be mutually exclusive with others that returned true. Not modifying
134// the state allows future calls to return true if they are mutually
135// exclusive with other calls that returned true.
136
137// On failure, set the `out_bound_at` argument.
138if(out_bound_at&& bound_at_){
139*out_bound_at= std::make_unique<debug::StackTrace>(*bound_at_);
140}
141
142returnfalse;
François Doray524d2a22024-01-04 09:54:16[diff] [blame]143}
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]144
145// Before returning true, modify the state so future calls only return true if
146// they are guaranteed to be mutually exclusive with this one.
147
148#if DCHECK_IS_ON()
149// `locks_` must contain locks held at binding time and for all calls to
150// `CalledOnValidSequence` that returned true afterwards.
151 std::erase_if(locks_,[](uintptr_t lock_ptr){
François Doray6671c402024-06-21 17:47:39[diff] [blame]152return!Contains(subtle::GetTrackedLocksHeldByCurrentThread(), lock_ptr);
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]153});
154#endif// DCHECK_IS_ON()
155
156// `sequence_token_` is reset if this returns true from a different sequence.
157if(sequence_token_!= internal::SequenceToken::GetForCurrentThread()){
158 sequence_token_= internal::SequenceToken();
159}
160
161returntrue;
akalin@chromium.org399ed422012-12-27 19:58:00[diff] [blame]162}
163
tommycli@chromium.orgd52426c2013-07-30 19:26:40[diff] [blame]164voidSequenceCheckerImpl::DetachFromSequence(){
François Doray524d2a22024-01-04 09:54:16[diff] [blame]165AutoLock auto_lock(lock_);
166 bound_at_.reset();
167 sequence_token_= internal::SequenceToken();
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]168#if DCHECK_IS_ON()
169 locks_.clear();
170#endif// DCHECK_IS_ON()
François Doray524d2a22024-01-04 09:54:16[diff] [blame]171 thread_ref_=PlatformThreadRef();
172}
173
174voidSequenceCheckerImpl::EnsureAssigned()const{
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]175// Use `thread_ref_` to determine if this checker is already bound, as it is
176// always set when bound (unlike `sequence_token_` and `locks_` which may be
177// cleared by `CalledOnValidSequence()` while this checker is still bound).
178if(!thread_ref_.is_null()){
François Doray524d2a22024-01-04 09:54:16[diff] [blame]179return;
180}
181
182if(g_log_stack){
183 bound_at_= std::make_unique<debug::StackTrace>(size_t{10});
184}
185
186 sequence_token_= internal::SequenceToken::GetForCurrentThread();
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]187
188#if DCHECK_IS_ON()
189// Copy all held locks to `locks_`, except `&lock_` (this is an implementation
190// detail of `SequenceCheckerImpl` and doesn't provide mutual exclusion
191// guarantees to the caller).
192 DCHECK(locks_.empty());
Peter Kasting025a94252025-01-29 21:28:37[diff] [blame]193 std::ranges::remove_copy(subtle::GetTrackedLocksHeldByCurrentThread(),
194 std::back_inserter(locks_),
195reinterpret_cast<uintptr_t>(&lock_));
François Doray62cb8e92024-06-05 14:49:02[diff] [blame]196#endif// DCHECK_IS_ON()
197
François Doray524d2a22024-01-04 09:54:16[diff] [blame]198 DCHECK(sequence_token_.IsValid());
199 thread_ref_=PlatformThread::CurrentRef();
200 DCHECK(!thread_ref_.is_null());
akalin@chromium.org399ed422012-12-27 19:58:00[diff] [blame]201}
202
akalin@chromium.org399ed422012-12-27 19:58:00[diff] [blame]203}// namespace base

[8]ページ先頭

©2009-2025 Movatter.jp