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