blob: 3def8f730d84de8eb2fae7d8dd49fa5d46f388ef [file] [log] [blame]
// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "google/cacheinvalidation/test/deterministic-scheduler.h"
namespace invalidation {
void DeterministicScheduler::StopScheduler() {
run_state_.Stop();
// Delete any tasks that haven't been run.
while (!work_queue_.empty()) {
TaskEntry top_elt = work_queue_.top();
work_queue_.pop();
delete top_elt.task;
}
}
void DeterministicScheduler::Schedule(TimeDelta delay, Closure* task) {
CHECK(IsCallbackRepeatable(task));
CHECK(run_state_.IsStarted());
TLOG(logger_, INFO, "(Now: %d) Enqueuing %p with delay %d",
current_time_.ToInternalValue(), task, delay.InMilliseconds());
work_queue_.push(TaskEntry(GetCurrentTime() + delay, current_id_++, task));
}
void DeterministicScheduler::PassTime(TimeDelta delta_time, TimeDelta step) {
CHECK(delta_time >= TimeDelta()) << "cannot pass a negative amount of time";
TimeDelta cumulative = TimeDelta();
// Run tasks that are ready to run now.
RunReadyTasks();
// Advance in increments of |step| until doing so would cause us to go past
// the requested |delta_time|.
while ((cumulative + step) < delta_time) {
ModifyTime(step);
cumulative += step;
RunReadyTasks();
}
// Then advance one final time to finish out the interval.
ModifyTime(delta_time - cumulative);
RunReadyTasks();
}
void DeterministicScheduler::RunReadyTasks() {
running_internal_ = true;
while (RunNextTask()) {
continue;
}
running_internal_ = false;
}
bool DeterministicScheduler::RunNextTask() {
if (!work_queue_.empty()) {
// The queue is not empty, so get the first task and see if its scheduled
// execution time has passed.
TaskEntry top_elt = work_queue_.top();
if (top_elt.time <= GetCurrentTime()) {
// The task is scheduled to run in the past or present, so remove it
// from the queue and run the task.
work_queue_.pop();
TLOG(logger_, FINE, "(Now: %d) Running task %p",
current_time_.ToInternalValue(), top_elt.task);
top_elt.task->Run();
delete top_elt.task;
return true;
}
}
return false;
}
} // namespace invalidation