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