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