• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium OS 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 <brillo/message_loops/fake_message_loop.h>
6 
7 #include <base/logging.h>
8 #include <brillo/location_logging.h>
9 
10 namespace brillo {
11 
FakeMessageLoop(base::SimpleTestClock * clock)12 FakeMessageLoop::FakeMessageLoop(base::SimpleTestClock* clock)
13   : test_clock_(clock) {
14 }
15 
PostDelayedTask(const base::Location & from_here,base::OnceClosure task,base::TimeDelta delay)16 MessageLoop::TaskId FakeMessageLoop::PostDelayedTask(
17     const base::Location& from_here,
18     base::OnceClosure task,
19     base::TimeDelta delay) {
20   // If no SimpleTestClock was provided, we use the last time we fired a
21   // callback. In this way, tasks scheduled from a Closure will have the right
22   // time.
23   if (test_clock_)
24     current_time_ = test_clock_->Now();
25   MessageLoop::TaskId current_id = ++last_id_;
26   // FakeMessageLoop is limited to only 2^64 tasks. That should be enough.
27   CHECK(current_id);
28   tasks_.emplace(current_id, ScheduledTask{from_here, std::move(task)});
29   fire_order_.push(std::make_pair(current_time_ + delay, current_id));
30   VLOG_LOC(from_here, 1) << "Scheduling delayed task_id " << current_id
31                          << " to run at " << current_time_ + delay
32                          << " (in " << delay << ").";
33   return current_id;
34 }
35 
CancelTask(TaskId task_id)36 bool FakeMessageLoop::CancelTask(TaskId task_id) {
37   if (task_id == MessageLoop::kTaskIdNull)
38     return false;
39   bool ret = tasks_.erase(task_id) > 0;
40   VLOG_IF(1, ret) << "Removing task_id " << task_id;
41   return ret;
42 }
43 
RunOnce(bool may_block)44 bool FakeMessageLoop::RunOnce(bool may_block) {
45   if (test_clock_)
46     current_time_ = test_clock_->Now();
47   // Try to fire time-based callbacks afterwards.
48   while (!fire_order_.empty() &&
49          (may_block || fire_order_.top().first <= current_time_)) {
50     const auto task_ref = fire_order_.top();
51     fire_order_.pop();
52     // We need to skip tasks in the priority_queue not in the |tasks_| map.
53     // This is normal if the task was canceled, as there is no efficient way
54     // to remove a task from the priority_queue.
55     const auto scheduled_task_ref = tasks_.find(task_ref.second);
56     if (scheduled_task_ref == tasks_.end())
57       continue;
58     // Advance the clock to the task firing time, if needed.
59     if (current_time_ < task_ref.first) {
60       current_time_ = task_ref.first;
61       if (test_clock_)
62         test_clock_->SetNow(current_time_);
63     }
64     // Move the Closure out of the map before delete it. We need to delete the
65     // entry from the map before we call the callback, since calling CancelTask
66     // for the task you are running now should fail and return false.
67     base::OnceClosure callback = std::move(scheduled_task_ref->second.callback);
68     VLOG_LOC(scheduled_task_ref->second.location, 1)
69         << "Running task_id " << task_ref.second
70         << " at time " << current_time_ << " from this location.";
71     tasks_.erase(scheduled_task_ref);
72 
73     std::move(callback).Run();
74     return true;
75   }
76   return false;
77 }
78 
PendingTasks()79 bool FakeMessageLoop::PendingTasks() {
80   for (const auto& task : tasks_) {
81     VLOG_LOC(task.second.location, 1)
82         << "Pending task_id " << task.first << " scheduled from here.";
83   }
84   return !tasks_.empty();
85 }
86 
87 }  // namespace brillo
88