| // 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. |
| |
| // An implementation of the Scheduler interface for unit testing (in a |
| // single-threaded environment). |
| |
| #ifndef GOOGLE_CACHEINVALIDATION_TEST_DETERMINISTIC_SCHEDULER_H_ |
| #define GOOGLE_CACHEINVALIDATION_TEST_DETERMINISTIC_SCHEDULER_H_ |
| |
| #include <queue> |
| #include <string> |
| #include <utility> |
| |
| #include "google/cacheinvalidation/include/system-resources.h" |
| #include "google/cacheinvalidation/deps/callback.h" |
| #include "google/cacheinvalidation/deps/logging.h" |
| #include "google/cacheinvalidation/deps/string_util.h" |
| #include "google/cacheinvalidation/deps/time.h" |
| #include "google/cacheinvalidation/impl/log-macro.h" |
| #include "google/cacheinvalidation/impl/run-state.h" |
| |
| namespace invalidation { |
| |
| // An entry in the work queue. Ensures that tasks don't run until their |
| // scheduled time, and for a given time, they run in the order in which they |
| // were enqueued. |
| struct TaskEntry { |
| TaskEntry(Time time, int64 id, Closure* task) |
| : time(time), id(id), task(task) {} |
| |
| bool operator<(const TaskEntry& other) const { |
| // Priority queue returns *largest* element first. |
| return (time > other.time) || |
| ((time == other.time) && (id > other.id)); |
| } |
| Time time; // the time at which to run |
| int64 id; // the order in which this task was enqueued |
| Closure* task; // the task to be run |
| }; |
| |
| class DeterministicScheduler : public Scheduler { |
| public: |
| // Caller retains ownershup of |logger|. |
| explicit DeterministicScheduler(Logger* logger) |
| : current_id_(0), running_internal_(false), logger_(logger) {} |
| |
| virtual ~DeterministicScheduler() { |
| StopScheduler(); |
| } |
| |
| virtual void SetSystemResources(SystemResources* resources) { |
| // Nothing to do. |
| } |
| |
| virtual Time GetCurrentTime() const { |
| return current_time_; |
| } |
| |
| void StartScheduler() { |
| run_state_.Start(); |
| } |
| |
| void StopScheduler(); |
| |
| virtual void Schedule(TimeDelta delay, Closure* task); |
| |
| virtual bool IsRunningOnThread() const { |
| return running_internal_; |
| } |
| |
| void SetInitialTime(Time new_time) { |
| current_time_ = new_time; |
| } |
| |
| // Passes |delta_time| in increments of at most |step|, executing all pending |
| // tasks during that interval. |
| void PassTime(TimeDelta delta_time, TimeDelta step); |
| |
| // Passes |delta_time| in default-sized increments, executing all pending |
| // tasks. |
| void PassTime(TimeDelta delta_time) { |
| PassTime(delta_time, DefaultTimeStep()); |
| } |
| |
| private: |
| // Runs all the work in the queue that should be executed by the current time. |
| // Note that tasks run may enqueue additional immediate tasks, and this call |
| // won't return until they've completed as well. While these tasks are |
| // running, the running_internal_ flag is set, so IsRunningOnThread() |
| // will return true. |
| void RunReadyTasks(); |
| |
| // Default time step when simulating passage of time. Chosen to be |
| // significantly smaller than any scheduling interval used by the client |
| // library. |
| static TimeDelta DefaultTimeStep() { |
| return TimeDelta::FromMilliseconds(10); |
| } |
| |
| void ModifyTime(TimeDelta delta_time) { |
| current_time_ += delta_time; |
| } |
| |
| // Attempts to run a task, returning true is there was a task to run. |
| bool RunNextTask(); |
| |
| // The current time, which may be set by the test. |
| Time current_time_; |
| |
| // The id number of the next task. |
| uint64 current_id_; |
| |
| // Whether or not the scheduler has been started/stopped. |
| RunState run_state_; |
| |
| // Whether or not we're currently running internal tasks from the internal |
| // queue. |
| bool running_internal_; |
| |
| // A priority queue on which the actual tasks are enqueued. |
| std::priority_queue<TaskEntry> work_queue_; |
| |
| // A logger. |
| Logger* logger_; |
| }; |
| |
| // A simple deterministic scheduler that always indicates that it is on |
| // the correct thread. |
| class SimpleDeterministicScheduler : public DeterministicScheduler { |
| public: |
| explicit SimpleDeterministicScheduler(Logger* logger) |
| : DeterministicScheduler(logger) {} |
| |
| virtual bool IsRunningOnThread() const { |
| return true; |
| } |
| }; |
| |
| } // namespace invalidation |
| |
| #endif // GOOGLE_CACHEINVALIDATION_TEST_DETERMINISTIC_SCHEDULER_H_ |