#pragma once #include #include #include #include #include #include #include namespace utils { /** * @brief - Keeps track of how long it's been since `Notify` method was called. * If it wasn't called for a sufficiently long time interval (randomly chosen * between `min_timeout` and `max_timeout`), the watchdog will periodically call * `callback` until it is notified or destroyed. If `blocked` is set to true, * watchdog will be blocked on startup. */ class Watchdog { public: Watchdog(const std::chrono::milliseconds &min_timeout, const std::chrono::milliseconds &max_timeout, const std::function &callback, bool blocked = false); ~Watchdog(); Watchdog(Watchdog &&) = delete; Watchdog(const Watchdog &) = delete; Watchdog &operator=(Watchdog &&) = delete; Watchdog &operator=(const Watchdog &) = delete; void Notify(); /** Calling `Block` is equivalent to continuously calling `Notify` * until `Unblock` is called. */ void Block(); void Unblock(); private: void Run(); std::chrono::milliseconds min_timeout_; std::chrono::milliseconds max_timeout_; std::mutex mutex_; // Used to generate callback timeouts. std::mt19937 generator_; std::uniform_int_distribution distribution_; std::chrono::steady_clock::time_point callback_threshold_; std::function callback_; // Used to notify the watchdog loop it should stop. std::atomic draining_; std::atomic blocked_; std::thread thread_; }; } // namespace utils