You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
88 lines
3.1 KiB
88 lines
3.1 KiB
// Copyright 2015 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include <brillo/message_loops/fake_message_loop.h>
|
|
|
|
#include <base/logging.h>
|
|
#include <brillo/location_logging.h>
|
|
|
|
namespace brillo {
|
|
|
|
FakeMessageLoop::FakeMessageLoop(base::SimpleTestClock* clock)
|
|
: test_clock_(clock) {
|
|
}
|
|
|
|
MessageLoop::TaskId FakeMessageLoop::PostDelayedTask(
|
|
const base::Location& from_here,
|
|
base::OnceClosure task,
|
|
base::TimeDelta delay) {
|
|
// If no SimpleTestClock was provided, we use the last time we fired a
|
|
// callback. In this way, tasks scheduled from a Closure will have the right
|
|
// time.
|
|
if (test_clock_)
|
|
current_time_ = test_clock_->Now();
|
|
MessageLoop::TaskId current_id = ++last_id_;
|
|
// FakeMessageLoop is limited to only 2^64 tasks. That should be enough.
|
|
CHECK(current_id);
|
|
tasks_.emplace(current_id, ScheduledTask{from_here, std::move(task)});
|
|
fire_order_.push(std::make_pair(current_time_ + delay, current_id));
|
|
VLOG_LOC(from_here, 1) << "Scheduling delayed task_id " << current_id
|
|
<< " to run at " << current_time_ + delay
|
|
<< " (in " << delay << ").";
|
|
return current_id;
|
|
}
|
|
|
|
bool FakeMessageLoop::CancelTask(TaskId task_id) {
|
|
if (task_id == MessageLoop::kTaskIdNull)
|
|
return false;
|
|
bool ret = tasks_.erase(task_id) > 0;
|
|
VLOG_IF(1, ret) << "Removing task_id " << task_id;
|
|
return ret;
|
|
}
|
|
|
|
bool FakeMessageLoop::RunOnce(bool may_block) {
|
|
if (test_clock_)
|
|
current_time_ = test_clock_->Now();
|
|
// Try to fire time-based callbacks afterwards.
|
|
while (!fire_order_.empty() &&
|
|
(may_block || fire_order_.top().first <= current_time_)) {
|
|
const auto task_ref = fire_order_.top();
|
|
fire_order_.pop();
|
|
// We need to skip tasks in the priority_queue not in the |tasks_| map.
|
|
// This is normal if the task was canceled, as there is no efficient way
|
|
// to remove a task from the priority_queue.
|
|
const auto scheduled_task_ref = tasks_.find(task_ref.second);
|
|
if (scheduled_task_ref == tasks_.end())
|
|
continue;
|
|
// Advance the clock to the task firing time, if needed.
|
|
if (current_time_ < task_ref.first) {
|
|
current_time_ = task_ref.first;
|
|
if (test_clock_)
|
|
test_clock_->SetNow(current_time_);
|
|
}
|
|
// Move the Closure out of the map before delete it. We need to delete the
|
|
// entry from the map before we call the callback, since calling CancelTask
|
|
// for the task you are running now should fail and return false.
|
|
base::OnceClosure callback = std::move(scheduled_task_ref->second.callback);
|
|
VLOG_LOC(scheduled_task_ref->second.location, 1)
|
|
<< "Running task_id " << task_ref.second
|
|
<< " at time " << current_time_ << " from this location.";
|
|
tasks_.erase(scheduled_task_ref);
|
|
|
|
std::move(callback).Run();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool FakeMessageLoop::PendingTasks() {
|
|
for (const auto& task : tasks_) {
|
|
VLOG_LOC(task.second.location, 1)
|
|
<< "Pending task_id " << task.first << " scheduled from here.";
|
|
}
|
|
return !tasks_.empty();
|
|
}
|
|
|
|
} // namespace brillo
|