thread_restrictions.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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. #include "base/threading/thread_restrictions.h"
  5. #include "base/threading/hang_watcher.h"
  6. #include "base/trace_event/base_tracing.h"
  7. #include "build/build_config.h"
  8. #if DCHECK_IS_ON()
  9. #include <utility>
  10. #include "base/check_op.h"
  11. #include "base/debug/stack_trace.h"
  12. #include "base/no_destructor.h"
  13. #include "base/threading/thread_local.h"
  14. #include "base/trace_event/base_tracing.h"
  15. #include "build/build_config.h"
  16. #include "third_party/abseil-cpp/absl/types/optional.h"
  17. // NaCL doesn't support stack sampling and Android is slow at stack sampling and
  18. // this causes timeouts (crbug.com/959139).
  19. #if BUILDFLAG(IS_NACL) || BUILDFLAG(IS_ANDROID)
  20. constexpr bool kCaptureStackTraces = false;
  21. #else
  22. // Always disabled when !EXPENSIVE_DCHECKS_ARE_ON() because user-facing builds
  23. // typically drop log strings anyways.
  24. constexpr bool kCaptureStackTraces = EXPENSIVE_DCHECKS_ARE_ON();
  25. #endif
  26. namespace base {
  27. class BooleanWithStack {
  28. public:
  29. // Default value.
  30. BooleanWithStack() = default;
  31. // Value when explicitly set.
  32. explicit BooleanWithStack(bool value) : value_(value) {
  33. if (kCaptureStackTraces)
  34. stack_.emplace();
  35. }
  36. BooleanWithStack(const BooleanWithStack&) = delete;
  37. BooleanWithStack& operator=(const BooleanWithStack&) = delete;
  38. explicit operator bool() const { return value_; }
  39. friend std::ostream& operator<<(std::ostream& out,
  40. const BooleanWithStack& bws) {
  41. out << bws.value_;
  42. if (kCaptureStackTraces) {
  43. if (bws.stack_.has_value())
  44. out << " set by\n" << bws.stack_.value();
  45. else
  46. out << " (value by default)";
  47. }
  48. return out;
  49. }
  50. private:
  51. const bool value_ = false;
  52. absl::optional<debug::StackTrace> stack_;
  53. };
  54. namespace {
  55. ThreadLocalOwnedPointer<BooleanWithStack>& GetBlockingDisallowedTls() {
  56. static NoDestructor<ThreadLocalOwnedPointer<BooleanWithStack>> instance;
  57. auto& tls = *instance;
  58. if (!tls.Get())
  59. tls.Set(std::make_unique<BooleanWithStack>());
  60. return tls;
  61. }
  62. ThreadLocalOwnedPointer<BooleanWithStack>& GetSingletonDisallowedTls() {
  63. static NoDestructor<ThreadLocalOwnedPointer<BooleanWithStack>> instance;
  64. auto& tls = *instance;
  65. if (!tls.Get())
  66. tls.Set(std::make_unique<BooleanWithStack>());
  67. return tls;
  68. }
  69. ThreadLocalOwnedPointer<BooleanWithStack>&
  70. GetBaseSyncPrimitivesDisallowedTls() {
  71. static NoDestructor<ThreadLocalOwnedPointer<BooleanWithStack>> instance;
  72. auto& tls = *instance;
  73. if (!tls.Get())
  74. tls.Set(std::make_unique<BooleanWithStack>());
  75. return tls;
  76. }
  77. ThreadLocalOwnedPointer<BooleanWithStack>& GetCPUIntensiveWorkDisallowedTls() {
  78. static NoDestructor<ThreadLocalOwnedPointer<BooleanWithStack>> instance;
  79. auto& tls = *instance;
  80. if (!tls.Get())
  81. tls.Set(std::make_unique<BooleanWithStack>());
  82. return tls;
  83. }
  84. } // namespace
  85. namespace internal {
  86. void AssertBlockingAllowed() {
  87. DCHECK(!*GetBlockingDisallowedTls())
  88. << "Function marked as blocking was called from a scope that disallows "
  89. "blocking! If this task is running inside the ThreadPool, it needs "
  90. "to have MayBlock() in its TaskTraits. Otherwise, consider making "
  91. "this blocking work asynchronous or, as a last resort, you may use "
  92. "ScopedAllowBlocking (see its documentation for best practices).\n"
  93. << "g_blocking_disallowed " << *GetBlockingDisallowedTls();
  94. }
  95. void AssertBlockingDisallowedForTesting() {
  96. DCHECK(*GetBlockingDisallowedTls())
  97. << "g_blocking_disallowed " << *GetBlockingDisallowedTls();
  98. }
  99. } // namespace internal
  100. void DisallowBlocking() {
  101. GetBlockingDisallowedTls().Set(std::make_unique<BooleanWithStack>(true));
  102. }
  103. ScopedDisallowBlocking::ScopedDisallowBlocking()
  104. : was_disallowed_(GetBlockingDisallowedTls().Set(
  105. std::make_unique<BooleanWithStack>(true))) {}
  106. ScopedDisallowBlocking::~ScopedDisallowBlocking() {
  107. DCHECK(*GetBlockingDisallowedTls())
  108. << "~ScopedDisallowBlocking() running while surprisingly already no "
  109. "longer disallowed.\n"
  110. << "g_blocking_disallowed " << *GetBlockingDisallowedTls();
  111. GetBlockingDisallowedTls().Set(std::move(was_disallowed_));
  112. }
  113. void DisallowBaseSyncPrimitives() {
  114. GetBaseSyncPrimitivesDisallowedTls().Set(
  115. std::make_unique<BooleanWithStack>(true));
  116. }
  117. ScopedDisallowBaseSyncPrimitives::ScopedDisallowBaseSyncPrimitives()
  118. : was_disallowed_(GetBaseSyncPrimitivesDisallowedTls().Set(
  119. std::make_unique<BooleanWithStack>(true))) {}
  120. ScopedDisallowBaseSyncPrimitives::~ScopedDisallowBaseSyncPrimitives() {
  121. DCHECK(*GetBaseSyncPrimitivesDisallowedTls())
  122. << "~ScopedDisallowBaseSyncPrimitives() running while surprisingly "
  123. "already no longer disallowed.\n"
  124. << "g_base_sync_primitives_disallowed "
  125. << *GetBaseSyncPrimitivesDisallowedTls();
  126. GetBaseSyncPrimitivesDisallowedTls().Set(std::move(was_disallowed_));
  127. }
  128. ScopedAllowBaseSyncPrimitives::ScopedAllowBaseSyncPrimitives()
  129. : was_disallowed_(GetBaseSyncPrimitivesDisallowedTls().Set(
  130. std::make_unique<BooleanWithStack>(false))) {
  131. DCHECK(!*GetBlockingDisallowedTls())
  132. << "To allow //base sync primitives in a scope where blocking is "
  133. "disallowed use ScopedAllowBaseSyncPrimitivesOutsideBlockingScope.\n"
  134. << "g_blocking_disallowed " << *GetBlockingDisallowedTls();
  135. }
  136. ScopedAllowBaseSyncPrimitives::~ScopedAllowBaseSyncPrimitives() {
  137. DCHECK(!*GetBaseSyncPrimitivesDisallowedTls());
  138. GetBaseSyncPrimitivesDisallowedTls().Set(std::move(was_disallowed_));
  139. }
  140. ScopedAllowBaseSyncPrimitivesForTesting::
  141. ScopedAllowBaseSyncPrimitivesForTesting()
  142. : was_disallowed_(GetBaseSyncPrimitivesDisallowedTls().Set(
  143. std::make_unique<BooleanWithStack>(false))) {}
  144. ScopedAllowBaseSyncPrimitivesForTesting::
  145. ~ScopedAllowBaseSyncPrimitivesForTesting() {
  146. DCHECK(!*GetBaseSyncPrimitivesDisallowedTls());
  147. GetBaseSyncPrimitivesDisallowedTls().Set(std::move(was_disallowed_));
  148. }
  149. ScopedAllowUnresponsiveTasksForTesting::ScopedAllowUnresponsiveTasksForTesting()
  150. : was_disallowed_base_sync_(GetBaseSyncPrimitivesDisallowedTls().Set(
  151. std::make_unique<BooleanWithStack>(false))),
  152. was_disallowed_blocking_(GetBlockingDisallowedTls().Set(
  153. std::make_unique<BooleanWithStack>(false))),
  154. was_disallowed_cpu_(GetCPUIntensiveWorkDisallowedTls().Set(
  155. std::make_unique<BooleanWithStack>(false))) {}
  156. ScopedAllowUnresponsiveTasksForTesting::
  157. ~ScopedAllowUnresponsiveTasksForTesting() {
  158. DCHECK(!*GetBaseSyncPrimitivesDisallowedTls());
  159. DCHECK(!*GetBlockingDisallowedTls());
  160. DCHECK(!*GetCPUIntensiveWorkDisallowedTls());
  161. GetBaseSyncPrimitivesDisallowedTls().Set(
  162. std::move(was_disallowed_base_sync_));
  163. GetBlockingDisallowedTls().Set(std::move(was_disallowed_blocking_));
  164. GetCPUIntensiveWorkDisallowedTls().Set(std::move(was_disallowed_cpu_));
  165. }
  166. namespace internal {
  167. void AssertBaseSyncPrimitivesAllowed() {
  168. DCHECK(!*GetBaseSyncPrimitivesDisallowedTls())
  169. << "Waiting on a //base sync primitive is not allowed on this thread to "
  170. "prevent jank and deadlock. If waiting on a //base sync primitive is "
  171. "unavoidable, do it within the scope of a "
  172. "ScopedAllowBaseSyncPrimitives. If in a test, "
  173. "use ScopedAllowBaseSyncPrimitivesForTesting.\n"
  174. << "g_base_sync_primitives_disallowed "
  175. << *GetBaseSyncPrimitivesDisallowedTls()
  176. << "It can be useful to know that g_blocking_disallowed is "
  177. << *GetBlockingDisallowedTls();
  178. }
  179. void ResetThreadRestrictionsForTesting() {
  180. GetBlockingDisallowedTls().Set(std::make_unique<BooleanWithStack>(false));
  181. GetSingletonDisallowedTls().Set(std::make_unique<BooleanWithStack>(false));
  182. GetBaseSyncPrimitivesDisallowedTls().Set(
  183. std::make_unique<BooleanWithStack>(false));
  184. GetCPUIntensiveWorkDisallowedTls().Set(
  185. std::make_unique<BooleanWithStack>(false));
  186. }
  187. void AssertSingletonAllowed() {
  188. DCHECK(!*GetSingletonDisallowedTls())
  189. << "LazyInstance/Singleton is not allowed to be used on this thread. "
  190. "Most likely it's because this thread is not joinable (or the current "
  191. "task is running with TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN "
  192. "semantics), so AtExitManager may have deleted the object on "
  193. "shutdown, leading to a potential shutdown crash. If you need to use "
  194. "the object from this context, it'll have to be updated to use Leaky "
  195. "traits.\n"
  196. << "g_singleton_disallowed " << *GetSingletonDisallowedTls();
  197. }
  198. } // namespace internal
  199. void DisallowSingleton() {
  200. GetSingletonDisallowedTls().Set(std::make_unique<BooleanWithStack>(true));
  201. }
  202. ScopedDisallowSingleton::ScopedDisallowSingleton()
  203. : was_disallowed_(GetSingletonDisallowedTls().Set(
  204. std::make_unique<BooleanWithStack>(true))) {}
  205. ScopedDisallowSingleton::~ScopedDisallowSingleton() {
  206. DCHECK(*GetSingletonDisallowedTls())
  207. << "~ScopedDisallowSingleton() running while surprisingly already no "
  208. "longer disallowed.\n"
  209. << "g_singleton_disallowed " << *GetSingletonDisallowedTls();
  210. GetSingletonDisallowedTls().Set(std::move(was_disallowed_));
  211. }
  212. void AssertLongCPUWorkAllowed() {
  213. DCHECK(!*GetCPUIntensiveWorkDisallowedTls())
  214. << "Function marked as CPU intensive was called from a scope that "
  215. "disallows this kind of work! Consider making this work "
  216. "asynchronous.\n"
  217. << "g_cpu_intensive_work_disallowed "
  218. << *GetCPUIntensiveWorkDisallowedTls();
  219. }
  220. void DisallowUnresponsiveTasks() {
  221. DisallowBlocking();
  222. DisallowBaseSyncPrimitives();
  223. GetCPUIntensiveWorkDisallowedTls().Set(
  224. std::make_unique<BooleanWithStack>(true));
  225. }
  226. // static
  227. void PermanentThreadAllowance::AllowBlocking() {
  228. GetBlockingDisallowedTls().Set(std::make_unique<BooleanWithStack>(false));
  229. }
  230. // static
  231. void PermanentThreadAllowance::AllowBaseSyncPrimitives() {
  232. GetBaseSyncPrimitivesDisallowedTls().Set(
  233. std::make_unique<BooleanWithStack>(false));
  234. }
  235. // static
  236. void PermanentSingletonAllowance::AllowSingleton() {
  237. GetSingletonDisallowedTls().Set(std::make_unique<BooleanWithStack>(false));
  238. }
  239. } // namespace base
  240. #endif // DCHECK_IS_ON()
  241. namespace base {
  242. ScopedAllowBlocking::ScopedAllowBlocking(const Location& from_here)
  243. #if DCHECK_IS_ON()
  244. : was_disallowed_(GetBlockingDisallowedTls().Set(
  245. std::make_unique<BooleanWithStack>(false)))
  246. #endif
  247. {
  248. TRACE_EVENT_BEGIN(
  249. "base", "ScopedAllowBlocking", [&](perfetto::EventContext ctx) {
  250. ctx.event()->set_source_location_iid(
  251. base::trace_event::InternedSourceLocation::Get(&ctx, from_here));
  252. });
  253. }
  254. ScopedAllowBlocking::~ScopedAllowBlocking() {
  255. TRACE_EVENT_END0("base", "ScopedAllowBlocking");
  256. #if DCHECK_IS_ON()
  257. DCHECK(!*GetBlockingDisallowedTls());
  258. GetBlockingDisallowedTls().Set(std::move(was_disallowed_));
  259. #endif
  260. }
  261. ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
  262. ScopedAllowBaseSyncPrimitivesOutsideBlockingScope(const Location& from_here)
  263. #if DCHECK_IS_ON()
  264. : was_disallowed_(GetBaseSyncPrimitivesDisallowedTls().Set(
  265. std::make_unique<BooleanWithStack>(false)))
  266. #endif
  267. {
  268. TRACE_EVENT_BEGIN(
  269. "base", "ScopedAllowBaseSyncPrimitivesOutsideBlockingScope",
  270. [&](perfetto::EventContext ctx) {
  271. ctx.event()->set_source_location_iid(
  272. base::trace_event::InternedSourceLocation::Get(&ctx, from_here));
  273. });
  274. // Since this object is used to indicate that sync primitives will be used to
  275. // wait for an event ignore the current operation for hang watching purposes
  276. // since the wait time duration is unknown.
  277. base::HangWatcher::InvalidateActiveExpectations();
  278. }
  279. ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
  280. ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope() {
  281. TRACE_EVENT_END0("base", "ScopedAllowBaseSyncPrimitivesOutsideBlockingScope");
  282. #if DCHECK_IS_ON()
  283. DCHECK(!*GetBaseSyncPrimitivesDisallowedTls());
  284. GetBaseSyncPrimitivesDisallowedTls().Set(std::move(was_disallowed_));
  285. #endif
  286. }
  287. ThreadRestrictions::ScopedAllowIO::ScopedAllowIO(const Location& from_here)
  288. #if DCHECK_IS_ON()
  289. : was_disallowed_(GetBlockingDisallowedTls().Set(
  290. std::make_unique<BooleanWithStack>(false)))
  291. #endif
  292. {
  293. TRACE_EVENT_BEGIN("base", "ScopedAllowIO", [&](perfetto::EventContext ctx) {
  294. ctx.event()->set_source_location_iid(
  295. base::trace_event::InternedSourceLocation::Get(&ctx, from_here));
  296. });
  297. }
  298. ThreadRestrictions::ScopedAllowIO::~ScopedAllowIO() {
  299. TRACE_EVENT_END0("base", "ScopedAllowIO");
  300. #if DCHECK_IS_ON()
  301. GetBlockingDisallowedTls().Set(std::move(was_disallowed_));
  302. #endif
  303. }
  304. } // namespace base