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 Workervoid 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 Workervoid 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 WorkerScopedDisallowBlocking::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 WorkerScopedDisallowBlocking::~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 WorkerScopedAllowBlocking::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 WorkerScopedAllowBlocking::~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 Workervoid 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 WorkerScopedAllowBaseSyncPrimitives::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 WorkerScopedAllowBaseSyncPrimitives::~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 Workervoid 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 Workervoid 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 WorkerThreadRestrictions::ScopedAllowIO::ScopedAllowIO() 122*635a8641SAndroid Build Coastguard Worker : was_allowed_(SetIOAllowed(true)) {} 123*635a8641SAndroid Build Coastguard Worker ~ScopedAllowIO()124*635a8641SAndroid Build Coastguard WorkerThreadRestrictions::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 Workerbool 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 Workerbool 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 Workervoid 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 Workervoid 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 Workerbool 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 WorkerThreadRestrictions::ScopedAllowWait::ScopedAllowWait() 168*635a8641SAndroid Build Coastguard Worker : was_allowed_(SetWaitAllowed(true)) {} 169*635a8641SAndroid Build Coastguard Worker ~ScopedAllowWait()170*635a8641SAndroid Build Coastguard WorkerThreadRestrictions::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