xref: /aosp_15_r20/external/libchrome/base/threading/thread_restrictions.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
8*635a8641SAndroid Build Coastguard Worker 
9*635a8641SAndroid Build Coastguard Worker #include "base/lazy_instance.h"
10*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_local.h"
12*635a8641SAndroid Build Coastguard Worker 
13*635a8641SAndroid Build Coastguard Worker namespace base {
14*635a8641SAndroid Build Coastguard Worker 
15*635a8641SAndroid Build Coastguard Worker namespace {
16*635a8641SAndroid Build Coastguard Worker 
17*635a8641SAndroid Build Coastguard Worker LazyInstance<ThreadLocalBoolean>::Leaky g_blocking_disallowed =
18*635a8641SAndroid Build Coastguard Worker     LAZY_INSTANCE_INITIALIZER;
19*635a8641SAndroid Build Coastguard Worker 
20*635a8641SAndroid Build Coastguard Worker LazyInstance<ThreadLocalBoolean>::Leaky
21*635a8641SAndroid Build Coastguard Worker     g_singleton_disallowed = LAZY_INSTANCE_INITIALIZER;
22*635a8641SAndroid Build Coastguard Worker 
23*635a8641SAndroid Build Coastguard Worker LazyInstance<ThreadLocalBoolean>::Leaky g_base_sync_primitives_disallowed =
24*635a8641SAndroid Build Coastguard Worker     LAZY_INSTANCE_INITIALIZER;
25*635a8641SAndroid Build Coastguard Worker 
26*635a8641SAndroid Build Coastguard Worker }  // namespace
27*635a8641SAndroid Build Coastguard Worker 
AssertBlockingAllowed()28*635a8641SAndroid Build Coastguard Worker void AssertBlockingAllowed() {
29*635a8641SAndroid Build Coastguard Worker   DCHECK(!g_blocking_disallowed.Get().Get())
30*635a8641SAndroid Build Coastguard Worker       << "Function marked as blocking was called from a scope that disallows "
31*635a8641SAndroid Build Coastguard Worker          "blocking! If this task is running inside the TaskScheduler, it needs "
32*635a8641SAndroid Build Coastguard Worker          "to have MayBlock() in its TaskTraits. Otherwise, consider making "
33*635a8641SAndroid Build Coastguard Worker          "this blocking work asynchronous or, as a last resort, you may use "
34*635a8641SAndroid Build Coastguard Worker          "ScopedAllowBlocking (see its documentation for best practices).";
35*635a8641SAndroid Build Coastguard Worker }
36*635a8641SAndroid Build Coastguard Worker 
DisallowBlocking()37*635a8641SAndroid Build Coastguard Worker void DisallowBlocking() {
38*635a8641SAndroid Build Coastguard Worker   g_blocking_disallowed.Get().Set(true);
39*635a8641SAndroid Build Coastguard Worker }
40*635a8641SAndroid Build Coastguard Worker 
ScopedDisallowBlocking()41*635a8641SAndroid Build Coastguard Worker ScopedDisallowBlocking::ScopedDisallowBlocking()
42*635a8641SAndroid Build Coastguard Worker     : was_disallowed_(g_blocking_disallowed.Get().Get()) {
43*635a8641SAndroid Build Coastguard Worker   g_blocking_disallowed.Get().Set(true);
44*635a8641SAndroid Build Coastguard Worker }
45*635a8641SAndroid Build Coastguard Worker 
~ScopedDisallowBlocking()46*635a8641SAndroid Build Coastguard Worker ScopedDisallowBlocking::~ScopedDisallowBlocking() {
47*635a8641SAndroid Build Coastguard Worker   DCHECK(g_blocking_disallowed.Get().Get());
48*635a8641SAndroid Build Coastguard Worker   g_blocking_disallowed.Get().Set(was_disallowed_);
49*635a8641SAndroid Build Coastguard Worker }
50*635a8641SAndroid Build Coastguard Worker 
ScopedAllowBlocking()51*635a8641SAndroid Build Coastguard Worker ScopedAllowBlocking::ScopedAllowBlocking()
52*635a8641SAndroid Build Coastguard Worker     : was_disallowed_(g_blocking_disallowed.Get().Get()) {
53*635a8641SAndroid Build Coastguard Worker   g_blocking_disallowed.Get().Set(false);
54*635a8641SAndroid Build Coastguard Worker }
55*635a8641SAndroid Build Coastguard Worker 
~ScopedAllowBlocking()56*635a8641SAndroid Build Coastguard Worker ScopedAllowBlocking::~ScopedAllowBlocking() {
57*635a8641SAndroid Build Coastguard Worker   DCHECK(!g_blocking_disallowed.Get().Get());
58*635a8641SAndroid Build Coastguard Worker   g_blocking_disallowed.Get().Set(was_disallowed_);
59*635a8641SAndroid Build Coastguard Worker }
60*635a8641SAndroid Build Coastguard Worker 
DisallowBaseSyncPrimitives()61*635a8641SAndroid Build Coastguard Worker void DisallowBaseSyncPrimitives() {
62*635a8641SAndroid Build Coastguard Worker   g_base_sync_primitives_disallowed.Get().Set(true);
63*635a8641SAndroid Build Coastguard Worker }
64*635a8641SAndroid Build Coastguard Worker 
ScopedAllowBaseSyncPrimitives()65*635a8641SAndroid Build Coastguard Worker ScopedAllowBaseSyncPrimitives::ScopedAllowBaseSyncPrimitives()
66*635a8641SAndroid Build Coastguard Worker     : was_disallowed_(g_base_sync_primitives_disallowed.Get().Get()) {
67*635a8641SAndroid Build Coastguard Worker   DCHECK(!g_blocking_disallowed.Get().Get())
68*635a8641SAndroid Build Coastguard Worker       << "To allow //base sync primitives in a scope where blocking is "
69*635a8641SAndroid Build Coastguard Worker          "disallowed use ScopedAllowBaseSyncPrimitivesOutsideBlockingScope.";
70*635a8641SAndroid Build Coastguard Worker   g_base_sync_primitives_disallowed.Get().Set(false);
71*635a8641SAndroid Build Coastguard Worker }
72*635a8641SAndroid Build Coastguard Worker 
~ScopedAllowBaseSyncPrimitives()73*635a8641SAndroid Build Coastguard Worker ScopedAllowBaseSyncPrimitives::~ScopedAllowBaseSyncPrimitives() {
74*635a8641SAndroid Build Coastguard Worker   DCHECK(!g_base_sync_primitives_disallowed.Get().Get());
75*635a8641SAndroid Build Coastguard Worker   g_base_sync_primitives_disallowed.Get().Set(was_disallowed_);
76*635a8641SAndroid Build Coastguard Worker }
77*635a8641SAndroid Build Coastguard Worker 
78*635a8641SAndroid Build Coastguard Worker ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
ScopedAllowBaseSyncPrimitivesOutsideBlockingScope()79*635a8641SAndroid Build Coastguard Worker     ScopedAllowBaseSyncPrimitivesOutsideBlockingScope()
80*635a8641SAndroid Build Coastguard Worker     : was_disallowed_(g_base_sync_primitives_disallowed.Get().Get()) {
81*635a8641SAndroid Build Coastguard Worker   g_base_sync_primitives_disallowed.Get().Set(false);
82*635a8641SAndroid Build Coastguard Worker }
83*635a8641SAndroid Build Coastguard Worker 
84*635a8641SAndroid Build Coastguard Worker ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope()85*635a8641SAndroid Build Coastguard Worker     ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope() {
86*635a8641SAndroid Build Coastguard Worker   DCHECK(!g_base_sync_primitives_disallowed.Get().Get());
87*635a8641SAndroid Build Coastguard Worker   g_base_sync_primitives_disallowed.Get().Set(was_disallowed_);
88*635a8641SAndroid Build Coastguard Worker }
89*635a8641SAndroid Build Coastguard Worker 
90*635a8641SAndroid Build Coastguard Worker ScopedAllowBaseSyncPrimitivesForTesting::
ScopedAllowBaseSyncPrimitivesForTesting()91*635a8641SAndroid Build Coastguard Worker     ScopedAllowBaseSyncPrimitivesForTesting()
92*635a8641SAndroid Build Coastguard Worker     : was_disallowed_(g_base_sync_primitives_disallowed.Get().Get()) {
93*635a8641SAndroid Build Coastguard Worker   g_base_sync_primitives_disallowed.Get().Set(false);
94*635a8641SAndroid Build Coastguard Worker }
95*635a8641SAndroid Build Coastguard Worker 
96*635a8641SAndroid Build Coastguard Worker ScopedAllowBaseSyncPrimitivesForTesting::
~ScopedAllowBaseSyncPrimitivesForTesting()97*635a8641SAndroid Build Coastguard Worker     ~ScopedAllowBaseSyncPrimitivesForTesting() {
98*635a8641SAndroid Build Coastguard Worker   DCHECK(!g_base_sync_primitives_disallowed.Get().Get());
99*635a8641SAndroid Build Coastguard Worker   g_base_sync_primitives_disallowed.Get().Set(was_disallowed_);
100*635a8641SAndroid Build Coastguard Worker }
101*635a8641SAndroid Build Coastguard Worker 
102*635a8641SAndroid Build Coastguard Worker namespace internal {
103*635a8641SAndroid Build Coastguard Worker 
AssertBaseSyncPrimitivesAllowed()104*635a8641SAndroid Build Coastguard Worker void AssertBaseSyncPrimitivesAllowed() {
105*635a8641SAndroid Build Coastguard Worker   DCHECK(!g_base_sync_primitives_disallowed.Get().Get())
106*635a8641SAndroid Build Coastguard Worker       << "Waiting on a //base sync primitive is not allowed on this thread to "
107*635a8641SAndroid Build Coastguard Worker          "prevent jank and deadlock. If waiting on a //base sync primitive is "
108*635a8641SAndroid Build Coastguard Worker          "unavoidable, do it within the scope of a "
109*635a8641SAndroid Build Coastguard Worker          "ScopedAllowBaseSyncPrimitives. If in a test, "
110*635a8641SAndroid Build Coastguard Worker          "use ScopedAllowBaseSyncPrimitivesForTesting.";
111*635a8641SAndroid Build Coastguard Worker }
112*635a8641SAndroid Build Coastguard Worker 
ResetThreadRestrictionsForTesting()113*635a8641SAndroid Build Coastguard Worker void ResetThreadRestrictionsForTesting() {
114*635a8641SAndroid Build Coastguard Worker   g_blocking_disallowed.Get().Set(false);
115*635a8641SAndroid Build Coastguard Worker   g_singleton_disallowed.Get().Set(false);
116*635a8641SAndroid Build Coastguard Worker   g_base_sync_primitives_disallowed.Get().Set(false);
117*635a8641SAndroid Build Coastguard Worker }
118*635a8641SAndroid Build Coastguard Worker 
119*635a8641SAndroid Build Coastguard Worker }  // namespace internal
120*635a8641SAndroid Build Coastguard Worker 
ScopedAllowIO()121*635a8641SAndroid Build Coastguard Worker ThreadRestrictions::ScopedAllowIO::ScopedAllowIO()
122*635a8641SAndroid Build Coastguard Worker     : was_allowed_(SetIOAllowed(true)) {}
123*635a8641SAndroid Build Coastguard Worker 
~ScopedAllowIO()124*635a8641SAndroid Build Coastguard Worker ThreadRestrictions::ScopedAllowIO::~ScopedAllowIO() {
125*635a8641SAndroid Build Coastguard Worker   SetIOAllowed(was_allowed_);
126*635a8641SAndroid Build Coastguard Worker }
127*635a8641SAndroid Build Coastguard Worker 
128*635a8641SAndroid Build Coastguard Worker // static
SetIOAllowed(bool allowed)129*635a8641SAndroid Build Coastguard Worker bool ThreadRestrictions::SetIOAllowed(bool allowed) {
130*635a8641SAndroid Build Coastguard Worker   bool previous_disallowed = g_blocking_disallowed.Get().Get();
131*635a8641SAndroid Build Coastguard Worker   g_blocking_disallowed.Get().Set(!allowed);
132*635a8641SAndroid Build Coastguard Worker   return !previous_disallowed;
133*635a8641SAndroid Build Coastguard Worker }
134*635a8641SAndroid Build Coastguard Worker 
135*635a8641SAndroid Build Coastguard Worker // static
SetSingletonAllowed(bool allowed)136*635a8641SAndroid Build Coastguard Worker bool ThreadRestrictions::SetSingletonAllowed(bool allowed) {
137*635a8641SAndroid Build Coastguard Worker   bool previous_disallowed = g_singleton_disallowed.Get().Get();
138*635a8641SAndroid Build Coastguard Worker   g_singleton_disallowed.Get().Set(!allowed);
139*635a8641SAndroid Build Coastguard Worker   return !previous_disallowed;
140*635a8641SAndroid Build Coastguard Worker }
141*635a8641SAndroid Build Coastguard Worker 
142*635a8641SAndroid Build Coastguard Worker // static
AssertSingletonAllowed()143*635a8641SAndroid Build Coastguard Worker void ThreadRestrictions::AssertSingletonAllowed() {
144*635a8641SAndroid Build Coastguard Worker   if (g_singleton_disallowed.Get().Get()) {
145*635a8641SAndroid Build Coastguard Worker     NOTREACHED() << "LazyInstance/Singleton is not allowed to be used on this "
146*635a8641SAndroid Build Coastguard Worker                  << "thread.  Most likely it's because this thread is not "
147*635a8641SAndroid Build Coastguard Worker                  << "joinable (or the current task is running with "
148*635a8641SAndroid Build Coastguard Worker                  << "TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN semantics), so "
149*635a8641SAndroid Build Coastguard Worker                  << "AtExitManager may have deleted the object on shutdown, "
150*635a8641SAndroid Build Coastguard Worker                  << "leading to a potential shutdown crash. If you need to use "
151*635a8641SAndroid Build Coastguard Worker                  << "the object from this context, it'll have to be updated to "
152*635a8641SAndroid Build Coastguard Worker                  << "use Leaky traits.";
153*635a8641SAndroid Build Coastguard Worker   }
154*635a8641SAndroid Build Coastguard Worker }
155*635a8641SAndroid Build Coastguard Worker 
156*635a8641SAndroid Build Coastguard Worker // static
DisallowWaiting()157*635a8641SAndroid Build Coastguard Worker void ThreadRestrictions::DisallowWaiting() {
158*635a8641SAndroid Build Coastguard Worker   DisallowBaseSyncPrimitives();
159*635a8641SAndroid Build Coastguard Worker }
160*635a8641SAndroid Build Coastguard Worker 
SetWaitAllowed(bool allowed)161*635a8641SAndroid Build Coastguard Worker bool ThreadRestrictions::SetWaitAllowed(bool allowed) {
162*635a8641SAndroid Build Coastguard Worker   bool previous_disallowed = g_base_sync_primitives_disallowed.Get().Get();
163*635a8641SAndroid Build Coastguard Worker   g_base_sync_primitives_disallowed.Get().Set(!allowed);
164*635a8641SAndroid Build Coastguard Worker   return !previous_disallowed;
165*635a8641SAndroid Build Coastguard Worker }
166*635a8641SAndroid Build Coastguard Worker 
ScopedAllowWait()167*635a8641SAndroid Build Coastguard Worker ThreadRestrictions::ScopedAllowWait::ScopedAllowWait()
168*635a8641SAndroid Build Coastguard Worker     : was_allowed_(SetWaitAllowed(true)) {}
169*635a8641SAndroid Build Coastguard Worker 
~ScopedAllowWait()170*635a8641SAndroid Build Coastguard Worker ThreadRestrictions::ScopedAllowWait::~ScopedAllowWait() {
171*635a8641SAndroid Build Coastguard Worker   SetWaitAllowed(was_allowed_);
172*635a8641SAndroid Build Coastguard Worker }
173*635a8641SAndroid Build Coastguard Worker 
174*635a8641SAndroid Build Coastguard Worker }  // namespace base
175*635a8641SAndroid Build Coastguard Worker 
176*635a8641SAndroid Build Coastguard Worker #endif  // DCHECK_IS_ON()
177