// 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 #include #include #include #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 GetEarliestWakeupTime() const; private: template int64_t UpdateTime(const T& now_updater) ABSL_LOCKS_EXCLUDED(lock_); class WakeUpInfo; using WaiterList = std::multimap>; 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_