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