1 // Copyright 2013 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/message_loop/message_loop.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/debug/task_annotator.h"
13 #include "base/logging.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/message_loop/message_pump_default.h"
16 #include "base/message_loop/message_pump_for_io.h"
17 #include "base/message_loop/message_pump_for_ui.h"
18 #include "base/metrics/histogram_macros.h"
19 #include "base/run_loop.h"
20 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
21 #include "base/threading/thread_id_name_manager.h"
22 #include "base/threading/thread_task_runner_handle.h"
23 #include "base/trace_event/trace_event.h"
24
25 #if defined(OS_MACOSX)
26 #include "base/message_loop/message_pump_mac.h"
27 #endif
28
29 namespace base {
30
31 namespace {
32
33 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = nullptr;
34
ReturnPump(std::unique_ptr<MessagePump> pump)35 std::unique_ptr<MessagePump> ReturnPump(std::unique_ptr<MessagePump> pump) {
36 return pump;
37 }
38
39 enum class ScheduledWakeupResult {
40 // The MessageLoop went to sleep with a timeout and woke up because of that
41 // timeout.
42 kCompleted,
43 // The MessageLoop went to sleep with a timeout but was woken up before it
44 // fired.
45 kInterrupted,
46 };
47
48 // Reports a ScheduledWakeup's result when waking up from a non-infinite sleep.
49 // Reports are using a 14 day spread (maximum examined delay for
50 // https://crbug.com/850450#c3), with 50 buckets that still yields 7 buckets
51 // under 16ms and hence plenty of resolution.
ReportScheduledWakeupResult(ScheduledWakeupResult result,TimeDelta intended_sleep)52 void ReportScheduledWakeupResult(ScheduledWakeupResult result,
53 TimeDelta intended_sleep) {
54 switch (result) {
55 case ScheduledWakeupResult::kCompleted:
56 UMA_HISTOGRAM_CUSTOM_TIMES("MessageLoop.ScheduledSleep.Completed",
57 intended_sleep,
58 base::TimeDelta::FromMilliseconds(1),
59 base::TimeDelta::FromDays(14), 50);
60 break;
61 case ScheduledWakeupResult::kInterrupted:
62 UMA_HISTOGRAM_CUSTOM_TIMES("MessageLoop.ScheduledSleep.Interrupted",
63 intended_sleep,
64 base::TimeDelta::FromMilliseconds(1),
65 base::TimeDelta::FromDays(14), 50);
66 break;
67 }
68 }
69
70 } // namespace
71
72 class MessageLoop::Controller : public internal::IncomingTaskQueue::Observer {
73 public:
74 // Constructs a MessageLoopController which controls |message_loop|, notifying
75 // |task_annotator_| when tasks are queued scheduling work on |message_loop|
76 // as fits. |message_loop| and |task_annotator_| will not be used after
77 // DisconnectFromParent() returns.
78 Controller(MessageLoop* message_loop);
79
80 ~Controller() override;
81
82 // IncomingTaskQueue::Observer:
83 void WillQueueTask(PendingTask* task) final;
84 void DidQueueTask(bool was_empty) final;
85
86 void StartScheduling();
87
88 // Disconnects |message_loop_| from this Controller instance (DidQueueTask()
89 // will no-op from this point forward).
90 void DisconnectFromParent();
91
92 // Shares this Controller's TaskAnnotator with MessageLoop as TaskAnnotator
93 // requires DidQueueTask(x)/RunTask(x) to be invoked on the same TaskAnnotator
94 // instance.
task_annotator()95 debug::TaskAnnotator& task_annotator() { return task_annotator_; }
96
97 private:
98 // A TaskAnnotator which is owned by this Controller to be able to use it
99 // without locking |message_loop_lock_|. It cannot be owned by MessageLoop
100 // because this Controller cannot access |message_loop_| safely without the
101 // lock. Note: the TaskAnnotator API itself is thread-safe.
102 debug::TaskAnnotator task_annotator_;
103
104 // Lock that serializes |message_loop_->ScheduleWork()| and access to all
105 // members below.
106 base::Lock message_loop_lock_;
107
108 // Points to this Controller's outer MessageLoop instance. Null after
109 // DisconnectFromParent().
110 MessageLoop* message_loop_;
111
112 // False until StartScheduling() is called.
113 bool is_ready_for_scheduling_ = false;
114
115 // True if DidQueueTask() has been called before StartScheduling(); letting it
116 // know whether it needs to ScheduleWork() right away or not.
117 bool pending_schedule_work_ = false;
118
119 DISALLOW_COPY_AND_ASSIGN(Controller);
120 };
121
Controller(MessageLoop * message_loop)122 MessageLoop::Controller::Controller(MessageLoop* message_loop)
123 : message_loop_(message_loop) {}
124
~Controller()125 MessageLoop::Controller::~Controller() {
126 DCHECK(!message_loop_)
127 << "DisconnectFromParent() needs to be invoked before destruction.";
128 }
129
WillQueueTask(PendingTask * task)130 void MessageLoop::Controller::WillQueueTask(PendingTask* task) {
131 task_annotator_.WillQueueTask("MessageLoop::PostTask", task);
132 }
133
DidQueueTask(bool was_empty)134 void MessageLoop::Controller::DidQueueTask(bool was_empty) {
135 // Avoid locking if we don't need to schedule.
136 if (!was_empty)
137 return;
138
139 AutoLock auto_lock(message_loop_lock_);
140
141 if (message_loop_ && is_ready_for_scheduling_)
142 message_loop_->ScheduleWork();
143 else
144 pending_schedule_work_ = true;
145 }
146
StartScheduling()147 void MessageLoop::Controller::StartScheduling() {
148 AutoLock lock(message_loop_lock_);
149 DCHECK(message_loop_);
150 DCHECK(!is_ready_for_scheduling_);
151 is_ready_for_scheduling_ = true;
152 if (pending_schedule_work_)
153 message_loop_->ScheduleWork();
154 }
155
DisconnectFromParent()156 void MessageLoop::Controller::DisconnectFromParent() {
157 AutoLock lock(message_loop_lock_);
158 message_loop_ = nullptr;
159 }
160
161 //------------------------------------------------------------------------------
162
MessageLoop(Type type)163 MessageLoop::MessageLoop(Type type)
164 : MessageLoop(type, MessagePumpFactoryCallback()) {
165 BindToCurrentThread();
166 }
167
MessageLoop(std::unique_ptr<MessagePump> pump)168 MessageLoop::MessageLoop(std::unique_ptr<MessagePump> pump)
169 : MessageLoop(TYPE_CUSTOM, BindOnce(&ReturnPump, std::move(pump))) {
170 BindToCurrentThread();
171 }
172
~MessageLoop()173 MessageLoop::~MessageLoop() {
174 // If |pump_| is non-null, this message loop has been bound and should be the
175 // current one on this thread. Otherwise, this loop is being destructed before
176 // it was bound to a thread, so a different message loop (or no loop at all)
177 // may be current.
178 DCHECK((pump_ && MessageLoopCurrent::IsBoundToCurrentThreadInternal(this)) ||
179 (!pump_ && !MessageLoopCurrent::IsBoundToCurrentThreadInternal(this)));
180
181 // iOS just attaches to the loop, it doesn't Run it.
182 // TODO(stuartmorgan): Consider wiring up a Detach().
183 #if !defined(OS_IOS)
184 // There should be no active RunLoops on this thread, unless this MessageLoop
185 // isn't bound to the current thread (see other condition at the top of this
186 // method).
187 DCHECK(
188 (!pump_ && !MessageLoopCurrent::IsBoundToCurrentThreadInternal(this)) ||
189 !RunLoop::IsRunningOnCurrentThread());
190 #endif // !defined(OS_IOS)
191
192 #if defined(OS_WIN)
193 if (in_high_res_mode_)
194 Time::ActivateHighResolutionTimer(false);
195 #endif
196 // Clean up any unprocessed tasks, but take care: deleting a task could
197 // result in the addition of more tasks (e.g., via DeleteSoon). We set a
198 // limit on the number of times we will allow a deleted task to generate more
199 // tasks. Normally, we should only pass through this loop once or twice. If
200 // we end up hitting the loop limit, then it is probably due to one task that
201 // is being stubborn. Inspect the queues to see who is left.
202 bool tasks_remain;
203 for (int i = 0; i < 100; ++i) {
204 DeletePendingTasks();
205 // If we end up with empty queues, then break out of the loop.
206 tasks_remain = incoming_task_queue_->triage_tasks().HasTasks();
207 if (!tasks_remain)
208 break;
209 }
210 DCHECK(!tasks_remain);
211
212 // Let interested parties have one last shot at accessing this.
213 for (auto& observer : destruction_observers_)
214 observer.WillDestroyCurrentMessageLoop();
215
216 thread_task_runner_handle_.reset();
217
218 // Tell the incoming queue that we are dying.
219 message_loop_controller_->DisconnectFromParent();
220 incoming_task_queue_->Shutdown();
221 incoming_task_queue_ = nullptr;
222 unbound_task_runner_ = nullptr;
223 task_runner_ = nullptr;
224
225 // OK, now make it so that no one can find us.
226 if (MessageLoopCurrent::IsBoundToCurrentThreadInternal(this))
227 MessageLoopCurrent::UnbindFromCurrentThreadInternal(this);
228 }
229
230 // static
current()231 MessageLoopCurrent MessageLoop::current() {
232 return MessageLoopCurrent::Get();
233 }
234
235 // static
InitMessagePumpForUIFactory(MessagePumpFactory * factory)236 bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) {
237 if (message_pump_for_ui_factory_)
238 return false;
239
240 message_pump_for_ui_factory_ = factory;
241 return true;
242 }
243
244 // static
CreateMessagePumpForType(Type type)245 std::unique_ptr<MessagePump> MessageLoop::CreateMessagePumpForType(Type type) {
246 if (type == MessageLoop::TYPE_UI) {
247 if (message_pump_for_ui_factory_)
248 return message_pump_for_ui_factory_();
249 #if defined(OS_IOS) || defined(OS_MACOSX)
250 return MessagePumpMac::Create();
251 #elif defined(OS_NACL) || defined(OS_AIX)
252 // Currently NaCl and AIX don't have a UI MessageLoop.
253 // TODO(abarth): Figure out if we need this.
254 NOTREACHED();
255 return nullptr;
256 #else
257 return std::make_unique<MessagePumpForUI>();
258 #endif
259 }
260
261 if (type == MessageLoop::TYPE_IO)
262 return std::unique_ptr<MessagePump>(new MessagePumpForIO());
263
264 #if defined(OS_ANDROID)
265 if (type == MessageLoop::TYPE_JAVA)
266 return std::unique_ptr<MessagePump>(new MessagePumpForUI());
267 #endif
268
269 DCHECK_EQ(MessageLoop::TYPE_DEFAULT, type);
270 #if defined(OS_IOS)
271 // On iOS, a native runloop is always required to pump system work.
272 return std::make_unique<MessagePumpCFRunLoop>();
273 #else
274 return std::make_unique<MessagePumpDefault>();
275 #endif
276 }
277
IsType(Type type) const278 bool MessageLoop::IsType(Type type) const {
279 return type_ == type;
280 }
281
282 // TODO(gab): Migrate TaskObservers to RunLoop as part of separating concerns
283 // between MessageLoop and RunLoop and making MessageLoop a swappable
284 // implementation detail. http://crbug.com/703346
AddTaskObserver(TaskObserver * task_observer)285 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) {
286 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
287 task_observers_.AddObserver(task_observer);
288 }
289
RemoveTaskObserver(TaskObserver * task_observer)290 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) {
291 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
292 task_observers_.RemoveObserver(task_observer);
293 }
294
IsIdleForTesting()295 bool MessageLoop::IsIdleForTesting() {
296 // Have unprocessed tasks? (this reloads the work queue if necessary)
297 if (incoming_task_queue_->triage_tasks().HasTasks())
298 return false;
299
300 // Have unprocessed deferred tasks which can be processed at this run-level?
301 if (incoming_task_queue_->deferred_tasks().HasTasks() &&
302 !RunLoop::IsNestedOnCurrentThread()) {
303 return false;
304 }
305
306 return true;
307 }
308
309 //------------------------------------------------------------------------------
310
311 // static
CreateUnbound(Type type,MessagePumpFactoryCallback pump_factory)312 std::unique_ptr<MessageLoop> MessageLoop::CreateUnbound(
313 Type type,
314 MessagePumpFactoryCallback pump_factory) {
315 return WrapUnique(new MessageLoop(type, std::move(pump_factory)));
316 }
317
318 // TODO(gab): Avoid bare new + WrapUnique below when introducing
319 // SequencedTaskSource in follow-up @
320 // https://chromium-review.googlesource.com/c/chromium/src/+/1088762.
MessageLoop(Type type,MessagePumpFactoryCallback pump_factory)321 MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory)
322 : MessageLoopCurrent(this),
323 type_(type),
324 pump_factory_(std::move(pump_factory)),
325 message_loop_controller_(new Controller(this)),
326 incoming_task_queue_(MakeRefCounted<internal::IncomingTaskQueue>(
327 WrapUnique(message_loop_controller_))),
328 unbound_task_runner_(MakeRefCounted<internal::MessageLoopTaskRunner>(
329 incoming_task_queue_)),
330 task_runner_(unbound_task_runner_) {
331 // If type is TYPE_CUSTOM non-null pump_factory must be given.
332 DCHECK(type_ != TYPE_CUSTOM || !pump_factory_.is_null());
333
334 // Bound in BindToCurrentThread();
335 DETACH_FROM_THREAD(bound_thread_checker_);
336 }
337
BindToCurrentThread()338 void MessageLoop::BindToCurrentThread() {
339 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
340
341 DCHECK(!pump_);
342 if (!pump_factory_.is_null())
343 pump_ = std::move(pump_factory_).Run();
344 else
345 pump_ = CreateMessagePumpForType(type_);
346
347 DCHECK(!MessageLoopCurrent::IsSet())
348 << "should only have one message loop per thread";
349 MessageLoopCurrent::BindToCurrentThreadInternal(this);
350
351 message_loop_controller_->StartScheduling();
352 unbound_task_runner_->BindToCurrentThread();
353 unbound_task_runner_ = nullptr;
354 SetThreadTaskRunnerHandle();
355 thread_id_ = PlatformThread::CurrentId();
356
357 scoped_set_sequence_local_storage_map_for_current_thread_ = std::make_unique<
358 internal::ScopedSetSequenceLocalStorageMapForCurrentThread>(
359 &sequence_local_storage_map_);
360
361 RunLoop::RegisterDelegateForCurrentThread(this);
362
363 #if defined(OS_ANDROID)
364 // On Android, attach to the native loop when there is one.
365 if (type_ == TYPE_UI || type_ == TYPE_JAVA)
366 static_cast<MessagePumpForUI*>(pump_.get())->Attach(this);
367 #endif
368 }
369
GetThreadName() const370 std::string MessageLoop::GetThreadName() const {
371 DCHECK_NE(kInvalidThreadId, thread_id_)
372 << "GetThreadName() must only be called after BindToCurrentThread()'s "
373 << "side-effects have been synchronized with this thread.";
374 return ThreadIdNameManager::GetInstance()->GetName(thread_id_);
375 }
376
SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner)377 void MessageLoop::SetTaskRunner(
378 scoped_refptr<SingleThreadTaskRunner> task_runner) {
379 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
380
381 DCHECK(task_runner);
382 DCHECK(task_runner->BelongsToCurrentThread());
383 DCHECK(!unbound_task_runner_);
384 task_runner_ = std::move(task_runner);
385 SetThreadTaskRunnerHandle();
386 }
387
ClearTaskRunnerForTesting()388 void MessageLoop::ClearTaskRunnerForTesting() {
389 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
390
391 DCHECK(!unbound_task_runner_);
392 task_runner_ = nullptr;
393 thread_task_runner_handle_.reset();
394 }
395
Run(bool application_tasks_allowed)396 void MessageLoop::Run(bool application_tasks_allowed) {
397 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
398 if (application_tasks_allowed && !task_execution_allowed_) {
399 // Allow nested task execution as explicitly requested.
400 DCHECK(RunLoop::IsNestedOnCurrentThread());
401 task_execution_allowed_ = true;
402 pump_->Run(this);
403 task_execution_allowed_ = false;
404 } else {
405 pump_->Run(this);
406 }
407 }
408
Quit()409 void MessageLoop::Quit() {
410 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
411 pump_->Quit();
412 }
413
EnsureWorkScheduled()414 void MessageLoop::EnsureWorkScheduled() {
415 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
416 if (incoming_task_queue_->triage_tasks().HasTasks())
417 pump_->ScheduleWork();
418 }
419
SetThreadTaskRunnerHandle()420 void MessageLoop::SetThreadTaskRunnerHandle() {
421 DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
422 // Clear the previous thread task runner first, because only one can exist at
423 // a time.
424 thread_task_runner_handle_.reset();
425 thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_));
426 }
427
ProcessNextDelayedNonNestableTask()428 bool MessageLoop::ProcessNextDelayedNonNestableTask() {
429 if (RunLoop::IsNestedOnCurrentThread())
430 return false;
431
432 while (incoming_task_queue_->deferred_tasks().HasTasks()) {
433 PendingTask pending_task = incoming_task_queue_->deferred_tasks().Pop();
434 if (!pending_task.task.IsCancelled()) {
435 RunTask(&pending_task);
436 return true;
437 }
438 }
439
440 return false;
441 }
442
RunTask(PendingTask * pending_task)443 void MessageLoop::RunTask(PendingTask* pending_task) {
444 DCHECK(task_execution_allowed_);
445
446 // Execute the task and assume the worst: It is probably not reentrant.
447 task_execution_allowed_ = false;
448
449 TRACE_TASK_EXECUTION("MessageLoop::RunTask", *pending_task);
450
451 for (auto& observer : task_observers_)
452 observer.WillProcessTask(*pending_task);
453 message_loop_controller_->task_annotator().RunTask("MessageLoop::PostTask",
454 pending_task);
455 for (auto& observer : task_observers_)
456 observer.DidProcessTask(*pending_task);
457
458 task_execution_allowed_ = true;
459 }
460
DeferOrRunPendingTask(PendingTask pending_task)461 bool MessageLoop::DeferOrRunPendingTask(PendingTask pending_task) {
462 if (pending_task.nestable == Nestable::kNestable ||
463 !RunLoop::IsNestedOnCurrentThread()) {
464 RunTask(&pending_task);
465 // Show that we ran a task (Note: a new one might arrive as a
466 // consequence!).
467 return true;
468 }
469
470 // We couldn't run the task now because we're in a nested run loop
471 // and the task isn't nestable.
472 incoming_task_queue_->deferred_tasks().Push(std::move(pending_task));
473 return false;
474 }
475
DeletePendingTasks()476 void MessageLoop::DeletePendingTasks() {
477 incoming_task_queue_->triage_tasks().Clear();
478 incoming_task_queue_->deferred_tasks().Clear();
479 // TODO(robliao): Determine if we can move delayed task destruction before
480 // deferred tasks to maintain the MessagePump DoWork, DoDelayedWork, and
481 // DoIdleWork processing order.
482 incoming_task_queue_->delayed_tasks().Clear();
483 }
484
ScheduleWork()485 void MessageLoop::ScheduleWork() {
486 pump_->ScheduleWork();
487 }
488
DoWork()489 bool MessageLoop::DoWork() {
490 if (!task_execution_allowed_)
491 return false;
492
493 // Execute oldest task.
494 while (incoming_task_queue_->triage_tasks().HasTasks()) {
495 if (!scheduled_wakeup_.next_run_time.is_null()) {
496 // While the frontmost task may racily be ripe. The MessageLoop was awaken
497 // without needing the timeout anyways. Since this metric is about
498 // determining whether sleeping for long periods ever succeeds: it's
499 // easier to just consider any untriaged task as an interrupt (this also
500 // makes the logic simpler for untriaged delayed tasks which may alter the
501 // top of the task queue prior to DoDelayedWork() but did cause a wakeup
502 // regardless -- per currently requiring this immediate triage step even
503 // for long delays).
504 ReportScheduledWakeupResult(ScheduledWakeupResult::kInterrupted,
505 scheduled_wakeup_.intended_sleep);
506 scheduled_wakeup_ = ScheduledWakeup();
507 }
508
509 PendingTask pending_task = incoming_task_queue_->triage_tasks().Pop();
510 if (pending_task.task.IsCancelled())
511 continue;
512
513 if (!pending_task.delayed_run_time.is_null()) {
514 int sequence_num = pending_task.sequence_num;
515 TimeTicks delayed_run_time = pending_task.delayed_run_time;
516 incoming_task_queue_->delayed_tasks().Push(std::move(pending_task));
517 // If we changed the topmost task, then it is time to reschedule.
518 if (incoming_task_queue_->delayed_tasks().Peek().sequence_num ==
519 sequence_num) {
520 pump_->ScheduleDelayedWork(delayed_run_time);
521 }
522 } else if (DeferOrRunPendingTask(std::move(pending_task))) {
523 return true;
524 }
525 }
526
527 // Nothing happened.
528 return false;
529 }
530
DoDelayedWork(TimeTicks * next_delayed_work_time)531 bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
532 if (!task_execution_allowed_) {
533 *next_delayed_work_time = TimeTicks();
534 // |scheduled_wakeup_| isn't used in nested loops that don't process
535 // application tasks.
536 DCHECK(scheduled_wakeup_.next_run_time.is_null());
537 return false;
538 }
539
540 if (!incoming_task_queue_->delayed_tasks().HasTasks()) {
541 *next_delayed_work_time = TimeTicks();
542
543 // It's possible to be woken up by a system event and have it cancel the
544 // upcoming delayed task from under us before DoDelayedWork() -- see comment
545 // under |next_run_time > recent_time_|. This condition covers the special
546 // case where such a system event cancelled *all* pending delayed tasks.
547 if (!scheduled_wakeup_.next_run_time.is_null()) {
548 ReportScheduledWakeupResult(ScheduledWakeupResult::kInterrupted,
549 scheduled_wakeup_.intended_sleep);
550 scheduled_wakeup_ = ScheduledWakeup();
551 }
552
553 return false;
554 }
555
556 // When we "fall behind", there will be a lot of tasks in the delayed work
557 // queue that are ready to run. To increase efficiency when we fall behind,
558 // we will only call Time::Now() intermittently, and then process all tasks
559 // that are ready to run before calling it again. As a result, the more we
560 // fall behind (and have a lot of ready-to-run delayed tasks), the more
561 // efficient we'll be at handling the tasks.
562
563 TimeTicks next_run_time =
564 incoming_task_queue_->delayed_tasks().Peek().delayed_run_time;
565
566 if (next_run_time > recent_time_) {
567 recent_time_ = TimeTicks::Now(); // Get a better view of Now();
568 if (next_run_time > recent_time_) {
569 *next_delayed_work_time = next_run_time;
570
571 // If the loop was woken up early by an untriaged task:
572 // |scheduled_wakeup_| will have been handled already in DoWork(). If it
573 // wasn't, it means the early wake up was caused by a system event (e.g.
574 // MessageLoopForUI or IO).
575 if (!scheduled_wakeup_.next_run_time.is_null()) {
576 // Handling the system event may have resulted in cancelling the
577 // upcoming delayed task (and then it being pruned by
578 // DelayedTaskQueue::HasTasks()); hence, we cannot check for strict
579 // equality here. We can however check that the pending task is either
580 // still there or that a later delay replaced it in front of the queue.
581 // There shouldn't have been new tasks added in |delayed_tasks()| per
582 // DoWork() not having triaged new tasks since the last DoIdleWork().
583 DCHECK_GE(next_run_time, scheduled_wakeup_.next_run_time);
584
585 ReportScheduledWakeupResult(ScheduledWakeupResult::kInterrupted,
586 scheduled_wakeup_.intended_sleep);
587 scheduled_wakeup_ = ScheduledWakeup();
588 }
589
590 return false;
591 }
592 }
593
594 if (next_run_time == scheduled_wakeup_.next_run_time) {
595 ReportScheduledWakeupResult(ScheduledWakeupResult::kCompleted,
596 scheduled_wakeup_.intended_sleep);
597 scheduled_wakeup_ = ScheduledWakeup();
598 }
599
600 PendingTask pending_task = incoming_task_queue_->delayed_tasks().Pop();
601
602 if (incoming_task_queue_->delayed_tasks().HasTasks()) {
603 *next_delayed_work_time =
604 incoming_task_queue_->delayed_tasks().Peek().delayed_run_time;
605 }
606
607 return DeferOrRunPendingTask(std::move(pending_task));
608 }
609
DoIdleWork()610 bool MessageLoop::DoIdleWork() {
611 if (ProcessNextDelayedNonNestableTask())
612 return true;
613
614 #if defined(OS_WIN)
615 bool need_high_res_timers = false;
616 #endif
617
618 // Do not report idle metrics nor do any logic related to delayed tasks if
619 // about to quit the loop and/or in a nested loop where
620 // |!task_execution_allowed_|. In the former case, the loop isn't going to
621 // sleep and in the latter case DoDelayedWork() will not actually do the work
622 // this is prepping for.
623 if (ShouldQuitWhenIdle()) {
624 pump_->Quit();
625 } else if (task_execution_allowed_) {
626 incoming_task_queue_->ReportMetricsOnIdle();
627
628 if (incoming_task_queue_->delayed_tasks().HasTasks()) {
629 TimeTicks scheduled_wakeup_time =
630 incoming_task_queue_->delayed_tasks().Peek().delayed_run_time;
631
632 if (!scheduled_wakeup_.next_run_time.is_null()) {
633 // It's possible for DoIdleWork() to be invoked twice in a row (e.g. if
634 // the MessagePump processed system work and became idle twice in a row
635 // without application tasks in between -- some pumps with a native
636 // message loop do not invoke DoWork() / DoDelayedWork() when awaken for
637 // system work only). As in DoDelayedWork(), we cannot check for strict
638 // equality below as the system work may have cancelled the frontmost
639 // task.
640 DCHECK_GE(scheduled_wakeup_time, scheduled_wakeup_.next_run_time);
641
642 ReportScheduledWakeupResult(ScheduledWakeupResult::kInterrupted,
643 scheduled_wakeup_.intended_sleep);
644 scheduled_wakeup_ = ScheduledWakeup();
645 }
646
647 // Store the remaining delay as well as the programmed wakeup time in
648 // order to know next time this MessageLoop wakes up whether it woke up
649 // because of this pending task (is it still the frontmost task in the
650 // queue?) and be able to report the slept delta (which is lost if not
651 // saved here).
652 scheduled_wakeup_ = ScheduledWakeup{
653 scheduled_wakeup_time, scheduled_wakeup_time - TimeTicks::Now()};
654 }
655
656 #if defined(OS_WIN)
657 // On Windows we activate the high resolution timer so that the wait
658 // _if_ triggered by the timer happens with good resolution. If we don't
659 // do this the default resolution is 15ms which might not be acceptable
660 // for some tasks.
661 need_high_res_timers =
662 incoming_task_queue_->HasPendingHighResolutionTasks();
663 #endif
664 }
665
666 #if defined(OS_WIN)
667 if (in_high_res_mode_ != need_high_res_timers) {
668 in_high_res_mode_ = need_high_res_timers;
669 Time::ActivateHighResolutionTimer(in_high_res_mode_);
670 }
671 #endif
672
673 // When we return we will do a kernel wait for more tasks.
674 return false;
675 }
676
677 #if !defined(OS_NACL)
678
679 //------------------------------------------------------------------------------
680 // MessageLoopForUI
681
MessageLoopForUI(Type type)682 MessageLoopForUI::MessageLoopForUI(Type type) : MessageLoop(type) {
683 #if defined(OS_ANDROID)
684 DCHECK(type == TYPE_UI || type == TYPE_JAVA);
685 #else
686 DCHECK_EQ(type, TYPE_UI);
687 #endif
688 }
689
690 // static
current()691 MessageLoopCurrentForUI MessageLoopForUI::current() {
692 return MessageLoopCurrentForUI::Get();
693 }
694
695 // static
IsCurrent()696 bool MessageLoopForUI::IsCurrent() {
697 return MessageLoopCurrentForUI::IsSet();
698 }
699
700 #if defined(OS_IOS)
Attach()701 void MessageLoopForUI::Attach() {
702 static_cast<MessagePumpUIApplication*>(pump_.get())->Attach(this);
703 }
704 #endif // defined(OS_IOS)
705
706 #if defined(OS_ANDROID)
Abort()707 void MessageLoopForUI::Abort() {
708 static_cast<MessagePumpForUI*>(pump_.get())->Abort();
709 }
710
IsAborted()711 bool MessageLoopForUI::IsAborted() {
712 return static_cast<MessagePumpForUI*>(pump_.get())->IsAborted();
713 }
714
QuitWhenIdle(base::OnceClosure callback)715 void MessageLoopForUI::QuitWhenIdle(base::OnceClosure callback) {
716 static_cast<MessagePumpForUI*>(pump_.get())
717 ->QuitWhenIdle(std::move(callback));
718 }
719 #endif // defined(OS_ANDROID)
720
721 #if defined(OS_WIN)
EnableWmQuit()722 void MessageLoopForUI::EnableWmQuit() {
723 static_cast<MessagePumpForUI*>(pump_.get())->EnableWmQuit();
724 }
725 #endif // defined(OS_WIN)
726
727 #endif // !defined(OS_NACL)
728
729 //------------------------------------------------------------------------------
730 // MessageLoopForIO
731
732 // static
current()733 MessageLoopCurrentForIO MessageLoopForIO::current() {
734 return MessageLoopCurrentForIO::Get();
735 }
736
737 // static
IsCurrent()738 bool MessageLoopForIO::IsCurrent() {
739 return MessageLoopCurrentForIO::IsSet();
740 }
741
742 } // namespace base
743