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