| // Copyright 2026 The Abseil Authors. | |
| // | |
| // 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 | |
| // | |
| // https://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. | |
| // | |
| // ----------------------------------------------------------------------------- | |
| // File: simulated_clock.h | |
| // ----------------------------------------------------------------------------- | |
| #ifndef ABSL_TIME_SIMULATED_CLOCK_H_ | |
| #define ABSL_TIME_SIMULATED_CLOCK_H_ | |
| #include <cstdint> | |
| #include <map> | |
| #include <memory> | |
| #include <optional> | |
| #include "absl/base/config.h" | |
| #include "absl/base/macros.h" | |
| #include "absl/base/nullability.h" | |
| #include "absl/base/thread_annotations.h" | |
| #include "absl/synchronization/mutex.h" | |
| #include "absl/time/clock.h" | |
| #include "absl/time/clock_interface.h" | |
| #include "absl/time/time.h" | |
| namespace absl { | |
| ABSL_NAMESPACE_BEGIN | |
| // A simulated clock is a concrete Clock implementation that does not "tick" | |
| // on its own. Time is advanced by explicit calls to the AdvanceTime() or | |
| // SetTime() functions. | |
| // | |
| // Example: | |
| // absl::SimulatedClock sim_clock; | |
| // absl::Time now = sim_clock.TimeNow(); | |
| // // now == absl::UnixEpoch() | |
| // | |
| // now = sim_clock.TimeNow(); | |
| // // now == absl::UnixEpoch() (still) | |
| // | |
| // sim_clock.AdvanceTime(absl::Seconds(3)); | |
| // now = sim_clock.TimeNow(); | |
| // // now == absl::UnixEpoch() + absl::Seconds(3) | |
| // | |
| // This class is thread-safe. | |
| class SimulatedClock : public Clock { | |
| public: | |
| explicit SimulatedClock(absl::Time t); | |
| SimulatedClock() : SimulatedClock(absl::UnixEpoch()) {} | |
| // The destructor should be called only if all Sleep(), etc. and | |
| // AdvanceTime() calls have completed. The code does its best to let | |
| // any pending calls finish gracefully, but there are no guarantees. | |
| ~SimulatedClock() override; | |
| // Returns the simulated time. | |
| absl::Time TimeNow() override; | |
| // Sleeps until the specified duration has elapsed according to this clock. | |
| void Sleep(absl::Duration d) override; | |
| // Sleeps until the specified wakeup_time. | |
| void SleepUntil(absl::Time wakeup_time) override; | |
| // Sets the simulated time to the argument. Wakes up any threads whose | |
| // sleeps have now expired. Returns the number of woken threads. | |
| int64_t SetTime(absl::Time t); | |
| // Advances the simulated time by the specified duration. Wakes up any | |
| // threads whose sleeps have now expired. Returns the number of woken threads. | |
| int64_t AdvanceTime(absl::Duration d); | |
| // Blocks until the condition is true or until the simulated clock is | |
| // advanced to or beyond the wakeup time (or both). | |
| bool AwaitWithDeadline(absl::Mutex* absl_nonnull mu, | |
| const absl::Condition& cond, | |
| absl::Time deadline) override | |
| ABSL_SHARED_LOCKS_REQUIRED(mu); | |
| // Returns the earliest wakeup time. | |
| std::optional<absl::Time> GetEarliestWakeupTime() const; | |
| private: | |
| template <class T> | |
| int64_t UpdateTime(const T& now_updater) ABSL_LOCKS_EXCLUDED(lock_); | |
| class WakeUpInfo; | |
| using WaiterList = std::multimap<absl::Time, std::shared_ptr<WakeUpInfo>>; | |
| mutable absl::Mutex lock_; | |
| absl::Time now_ ABSL_GUARDED_BY(lock_); | |
| WaiterList waiters_ ABSL_GUARDED_BY(lock_); | |
| int64_t num_await_calls_ ABSL_GUARDED_BY(lock_) = 0; | |
| }; | |
| ABSL_NAMESPACE_END | |
| } // namespace absl | |
| #endif // ABSL_TIME_SIMULATED_CLOCK_H_ |