run_loop.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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/run_loop.h"
  5. #include "base/bind.h"
  6. #include "base/callback.h"
  7. #include "base/cancelable_callback.h"
  8. #include "base/check.h"
  9. #include "base/no_destructor.h"
  10. #include "base/observer_list.h"
  11. #include "base/task/single_thread_task_runner.h"
  12. #include "base/threading/thread_local.h"
  13. #include "base/threading/thread_task_runner_handle.h"
  14. #include "base/trace_event/base_tracing.h"
  15. #include "build/build_config.h"
  16. namespace base {
  17. namespace {
  18. ThreadLocalPointer<RunLoop::Delegate>& GetTlsDelegate() {
  19. static NoDestructor<ThreadLocalPointer<RunLoop::Delegate>> instance;
  20. return *instance;
  21. }
  22. // Runs |closure| immediately if this is called on |task_runner|, otherwise
  23. // forwards |closure| to it.
  24. void ProxyToTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner,
  25. OnceClosure closure) {
  26. if (task_runner->RunsTasksInCurrentSequence()) {
  27. std::move(closure).Run();
  28. return;
  29. }
  30. task_runner->PostTask(FROM_HERE, std::move(closure));
  31. }
  32. ThreadLocalPointer<const RunLoop::RunLoopTimeout>& RunLoopTimeoutTLS() {
  33. static NoDestructor<ThreadLocalPointer<const RunLoop::RunLoopTimeout>> tls;
  34. return *tls;
  35. }
  36. void OnRunLoopTimeout(RunLoop* run_loop,
  37. const Location& location,
  38. OnceCallback<void(const Location&)> on_timeout) {
  39. run_loop->Quit();
  40. std::move(on_timeout).Run(location);
  41. }
  42. } // namespace
  43. RunLoop::Delegate::Delegate() {
  44. // The Delegate can be created on another thread. It is only bound in
  45. // RegisterDelegateForCurrentThread().
  46. DETACH_FROM_THREAD(bound_thread_checker_);
  47. }
  48. RunLoop::Delegate::~Delegate() {
  49. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
  50. DCHECK(active_run_loops_.empty());
  51. // A RunLoop::Delegate may be destroyed before it is bound, if so it may still
  52. // be on its creation thread (e.g. a Thread that fails to start) and
  53. // shouldn't disrupt that thread's state.
  54. if (bound_) {
  55. DCHECK_EQ(this, GetTlsDelegate().Get());
  56. GetTlsDelegate().Set(nullptr);
  57. }
  58. }
  59. bool RunLoop::Delegate::ShouldQuitWhenIdle() {
  60. const auto* top_loop = active_run_loops_.top();
  61. if (top_loop->quit_when_idle_) {
  62. TRACE_EVENT_WITH_FLOW0("toplevel.flow", "RunLoop_ExitedOnIdle",
  63. TRACE_ID_LOCAL(top_loop), TRACE_EVENT_FLAG_FLOW_IN);
  64. return true;
  65. }
  66. return false;
  67. }
  68. // static
  69. void RunLoop::RegisterDelegateForCurrentThread(Delegate* delegate) {
  70. // Bind |delegate| to this thread.
  71. DCHECK(!delegate->bound_);
  72. DCHECK_CALLED_ON_VALID_THREAD(delegate->bound_thread_checker_);
  73. // There can only be one RunLoop::Delegate per thread.
  74. DCHECK(!GetTlsDelegate().Get())
  75. << "Error: Multiple RunLoop::Delegates registered on the same thread.\n\n"
  76. "Hint: You perhaps instantiated a second "
  77. "MessageLoop/TaskEnvironment on a thread that already had one?";
  78. GetTlsDelegate().Set(delegate);
  79. delegate->bound_ = true;
  80. }
  81. RunLoop::RunLoop(Type type)
  82. : delegate_(GetTlsDelegate().Get()),
  83. type_(type),
  84. origin_task_runner_(ThreadTaskRunnerHandle::Get()) {
  85. DCHECK(delegate_) << "A RunLoop::Delegate must be bound to this thread prior "
  86. "to using RunLoop.";
  87. DCHECK(origin_task_runner_);
  88. }
  89. RunLoop::~RunLoop() {
  90. // ~RunLoop() must happen-after the RunLoop is done running but it doesn't
  91. // have to be on |sequence_checker_| (it usually is but sometimes it can be a
  92. // member of a RefCountedThreadSafe object and be destroyed on another thread
  93. // after being quit).
  94. DCHECK(!running_);
  95. }
  96. void RunLoop::Run(const Location& location) {
  97. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  98. // "test" tracing category is used here because in regular scenarios RunLoop
  99. // trace events are not useful (each process normally has one RunLoop covering
  100. // its entire lifetime) and might be confusing (they make idle processes look
  101. // non-idle). In tests, however, creating a RunLoop is a frequent and an
  102. // explicit action making this trace event very useful.
  103. TRACE_EVENT("test", "RunLoop::Run", "location", location);
  104. if (!BeforeRun())
  105. return;
  106. // If there is a RunLoopTimeout active then set the timeout.
  107. // TODO(crbug.com/905412): Use real-time for Run() timeouts so that they
  108. // can be applied even in tests which mock TimeTicks::Now().
  109. CancelableOnceClosure cancelable_timeout;
  110. const RunLoopTimeout* run_timeout = GetTimeoutForCurrentThread();
  111. if (run_timeout) {
  112. cancelable_timeout.Reset(BindOnce(&OnRunLoopTimeout, Unretained(this),
  113. location, run_timeout->on_timeout));
  114. origin_task_runner_->PostDelayedTask(
  115. FROM_HERE, cancelable_timeout.callback(), run_timeout->timeout);
  116. }
  117. DCHECK_EQ(this, delegate_->active_run_loops_.top());
  118. const bool application_tasks_allowed =
  119. delegate_->active_run_loops_.size() == 1U ||
  120. type_ == Type::kNestableTasksAllowed;
  121. delegate_->Run(application_tasks_allowed, TimeDelta::Max());
  122. AfterRun();
  123. }
  124. void RunLoop::RunUntilIdle() {
  125. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  126. quit_when_idle_ = true;
  127. Run();
  128. if (!AnyQuitCalled()) {
  129. quit_when_idle_ = false;
  130. #if DCHECK_IS_ON()
  131. run_allowed_ = true;
  132. #endif
  133. }
  134. }
  135. void RunLoop::Quit() {
  136. // Thread-safe.
  137. // This can only be hit if RunLoop::Quit() is called directly (QuitClosure()
  138. // proxies through ProxyToTaskRunner() as it can only deref its WeakPtr on
  139. // |origin_task_runner_|).
  140. if (!origin_task_runner_->RunsTasksInCurrentSequence()) {
  141. origin_task_runner_->PostTask(FROM_HERE,
  142. BindOnce(&RunLoop::Quit, Unretained(this)));
  143. return;
  144. }
  145. // While Quit() is an "OUT" call to reach one of the quit-states ("IN"),
  146. // OUT|IN is used to visually link multiple Quit*() together which can help
  147. // when debugging flaky tests.
  148. TRACE_EVENT_WITH_FLOW0("toplevel.flow", "RunLoop::Quit", TRACE_ID_LOCAL(this),
  149. TRACE_EVENT_FLAG_FLOW_OUT | TRACE_EVENT_FLAG_FLOW_IN);
  150. quit_called_ = true;
  151. if (running_ && delegate_->active_run_loops_.top() == this) {
  152. // This is the inner-most RunLoop, so quit now.
  153. delegate_->Quit();
  154. }
  155. }
  156. void RunLoop::QuitWhenIdle() {
  157. // Thread-safe.
  158. // This can only be hit if RunLoop::QuitWhenIdle() is called directly
  159. // (QuitWhenIdleClosure() proxies through ProxyToTaskRunner() as it can only
  160. // deref its WeakPtr on |origin_task_runner_|).
  161. if (!origin_task_runner_->RunsTasksInCurrentSequence()) {
  162. origin_task_runner_->PostTask(
  163. FROM_HERE, BindOnce(&RunLoop::QuitWhenIdle, Unretained(this)));
  164. return;
  165. }
  166. // OUT|IN as in Quit() to link all Quit*() together should there be multiple.
  167. TRACE_EVENT_WITH_FLOW0("toplevel.flow", "RunLoop::QuitWhenIdle",
  168. TRACE_ID_LOCAL(this),
  169. TRACE_EVENT_FLAG_FLOW_OUT | TRACE_EVENT_FLAG_FLOW_IN);
  170. quit_when_idle_ = true;
  171. quit_when_idle_called_ = true;
  172. }
  173. RepeatingClosure RunLoop::QuitClosure() {
  174. // Obtaining the QuitClosure() is not thread-safe; either obtain the
  175. // QuitClosure() from the owning thread before Run() or invoke Quit() directly
  176. // (which is thread-safe).
  177. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  178. allow_quit_current_deprecated_ = false;
  179. return BindRepeating(
  180. &ProxyToTaskRunner, origin_task_runner_,
  181. BindRepeating(&RunLoop::Quit, weak_factory_.GetWeakPtr()));
  182. }
  183. RepeatingClosure RunLoop::QuitWhenIdleClosure() {
  184. // Obtaining the QuitWhenIdleClosure() is not thread-safe; either obtain the
  185. // QuitWhenIdleClosure() from the owning thread before Run() or invoke
  186. // QuitWhenIdle() directly (which is thread-safe).
  187. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  188. allow_quit_current_deprecated_ = false;
  189. return BindRepeating(
  190. &ProxyToTaskRunner, origin_task_runner_,
  191. BindRepeating(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()));
  192. }
  193. bool RunLoop::AnyQuitCalled() {
  194. return quit_called_ || quit_when_idle_called_;
  195. }
  196. // static
  197. bool RunLoop::IsRunningOnCurrentThread() {
  198. Delegate* delegate = GetTlsDelegate().Get();
  199. return delegate && !delegate->active_run_loops_.empty();
  200. }
  201. // static
  202. bool RunLoop::IsNestedOnCurrentThread() {
  203. Delegate* delegate = GetTlsDelegate().Get();
  204. return delegate && delegate->active_run_loops_.size() > 1;
  205. }
  206. // static
  207. void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
  208. Delegate* delegate = GetTlsDelegate().Get();
  209. DCHECK(delegate);
  210. delegate->nesting_observers_.AddObserver(observer);
  211. }
  212. // static
  213. void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
  214. Delegate* delegate = GetTlsDelegate().Get();
  215. DCHECK(delegate);
  216. delegate->nesting_observers_.RemoveObserver(observer);
  217. }
  218. // static
  219. void RunLoop::QuitCurrentDeprecated() {
  220. DCHECK(IsRunningOnCurrentThread());
  221. Delegate* delegate = GetTlsDelegate().Get();
  222. DCHECK(delegate->active_run_loops_.top()->allow_quit_current_deprecated_)
  223. << "Please migrate off QuitCurrentDeprecated(), e.g. to QuitClosure().";
  224. delegate->active_run_loops_.top()->Quit();
  225. }
  226. // static
  227. void RunLoop::QuitCurrentWhenIdleDeprecated() {
  228. DCHECK(IsRunningOnCurrentThread());
  229. Delegate* delegate = GetTlsDelegate().Get();
  230. DCHECK(delegate->active_run_loops_.top()->allow_quit_current_deprecated_)
  231. << "Please migrate off QuitCurrentWhenIdleDeprecated(), e.g. to "
  232. "QuitWhenIdleClosure().";
  233. delegate->active_run_loops_.top()->QuitWhenIdle();
  234. }
  235. // static
  236. RepeatingClosure RunLoop::QuitCurrentWhenIdleClosureDeprecated() {
  237. // TODO(844016): Fix callsites and enable this check, or remove the API.
  238. // Delegate* delegate = GetTlsDelegate().Get();
  239. // DCHECK(delegate->active_run_loops_.top()->allow_quit_current_deprecated_)
  240. // << "Please migrate off QuitCurrentWhenIdleClosureDeprecated(), e.g to "
  241. // "QuitWhenIdleClosure().";
  242. return BindRepeating(&RunLoop::QuitCurrentWhenIdleDeprecated);
  243. }
  244. #if DCHECK_IS_ON()
  245. ScopedDisallowRunningRunLoop::ScopedDisallowRunningRunLoop()
  246. : current_delegate_(GetTlsDelegate().Get()),
  247. previous_run_allowance_(
  248. current_delegate_ ? current_delegate_->allow_running_for_testing_
  249. : false) {
  250. if (current_delegate_)
  251. current_delegate_->allow_running_for_testing_ = false;
  252. }
  253. ScopedDisallowRunningRunLoop::~ScopedDisallowRunningRunLoop() {
  254. DCHECK_EQ(current_delegate_, GetTlsDelegate().Get());
  255. if (current_delegate_)
  256. current_delegate_->allow_running_for_testing_ = previous_run_allowance_;
  257. }
  258. #else // DCHECK_IS_ON()
  259. // Defined out of line so that the compiler doesn't inline these and realize
  260. // the scope has no effect and then throws an "unused variable" warning in
  261. // non-dcheck builds.
  262. ScopedDisallowRunningRunLoop::ScopedDisallowRunningRunLoop() = default;
  263. ScopedDisallowRunningRunLoop::~ScopedDisallowRunningRunLoop() = default;
  264. #endif // DCHECK_IS_ON()
  265. RunLoop::RunLoopTimeout::RunLoopTimeout() = default;
  266. RunLoop::RunLoopTimeout::~RunLoopTimeout() = default;
  267. // static
  268. void RunLoop::SetTimeoutForCurrentThread(const RunLoopTimeout* timeout) {
  269. RunLoopTimeoutTLS().Set(timeout);
  270. }
  271. // static
  272. const RunLoop::RunLoopTimeout* RunLoop::GetTimeoutForCurrentThread() {
  273. return RunLoopTimeoutTLS().Get();
  274. }
  275. bool RunLoop::BeforeRun() {
  276. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  277. #if DCHECK_IS_ON()
  278. DCHECK(delegate_->allow_running_for_testing_)
  279. << "RunLoop::Run() isn't allowed in the scope of a "
  280. "ScopedDisallowRunningRunLoop. Hint: if mixing "
  281. "TestMockTimeTaskRunners on same thread, use TestMockTimeTaskRunner's "
  282. "API instead of RunLoop to drive individual task runners.";
  283. DCHECK(run_allowed_);
  284. run_allowed_ = false;
  285. #endif // DCHECK_IS_ON()
  286. // Allow Quit to be called before Run.
  287. if (quit_called_) {
  288. TRACE_EVENT_WITH_FLOW0("toplevel.flow", "RunLoop_ExitedEarly",
  289. TRACE_ID_LOCAL(this), TRACE_EVENT_FLAG_FLOW_IN);
  290. return false;
  291. }
  292. auto& active_run_loops = delegate_->active_run_loops_;
  293. active_run_loops.push(this);
  294. const bool is_nested = active_run_loops.size() > 1;
  295. if (is_nested) {
  296. for (auto& observer : delegate_->nesting_observers_)
  297. observer.OnBeginNestedRunLoop();
  298. if (type_ == Type::kNestableTasksAllowed)
  299. delegate_->EnsureWorkScheduled();
  300. }
  301. running_ = true;
  302. return true;
  303. }
  304. void RunLoop::AfterRun() {
  305. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  306. running_ = false;
  307. TRACE_EVENT_WITH_FLOW0("toplevel.flow", "RunLoop_Exited",
  308. TRACE_ID_LOCAL(this), TRACE_EVENT_FLAG_FLOW_IN);
  309. auto& active_run_loops = delegate_->active_run_loops_;
  310. DCHECK_EQ(active_run_loops.top(), this);
  311. active_run_loops.pop();
  312. // Exiting a nested RunLoop?
  313. if (!active_run_loops.empty()) {
  314. for (auto& observer : delegate_->nesting_observers_)
  315. observer.OnExitNestedRunLoop();
  316. // Execute deferred Quit, if any:
  317. if (active_run_loops.top()->quit_called_)
  318. delegate_->Quit();
  319. }
  320. }
  321. } // namespace base