blob: e99090624b635c7ba5c7aeb2235cf33c6b3aecb5 [file]
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#pragma once
#include <condition_variable>
#include <mutex>
#include <string_view>
#include "Clock.hpp"
#include "KAssert.h"
#include "concurrent/UtilityThread.hpp"
#include "Utils.hpp"
namespace kotlin {
template <typename Clock = steady_clock>
class RepeatedTimer : private Pinned {
public:
template <typename Rep, typename Period, typename F>
RepeatedTimer(std::string_view name, std::chrono::duration<Rep, Period> interval, F&& f) noexcept :
interval_(interval),
next_(Clock::now() + interval_),
thread_(name, &RepeatedTimer::Run<F>, this, std::forward<F>(f)) {}
template <typename Rep, typename Period, typename F>
RepeatedTimer(std::chrono::duration<Rep, Period> interval, F&& f) noexcept :
RepeatedTimer("Timer thread", interval, std::forward<F>(f)) {}
~RepeatedTimer() {
{
std::unique_lock lock(mutex_);
run_ = false;
scheduledInterrupt_ = true;
}
wait_.notify_all();
// Make sure we wait for the thread to finish before starting to destroy the fields.
thread_.join();
}
template <typename Rep, typename Period>
void restart(std::chrono::duration<Rep, Period> interval) noexcept {
{
std::unique_lock lock(mutex_);
interval_ = interval;
next_ = Clock::now() + interval_;
scheduledInterrupt_ = true;
}
wait_.notify_all();
}
private:
template <typename F>
void Run(F&& f) noexcept {
std::unique_lock lock(mutex_);
while (run_) {
scheduledInterrupt_ = false;
if (Clock::wait_until(wait_, lock, next_, [this] { return scheduledInterrupt_; })) {
continue;
}
// The function must be executed in the unlocked environment.
lock.unlock();
std::invoke(std::forward<F>(f));
lock.lock();
next_ = Clock::now() + interval_;
}
}
std::mutex mutex_;
std::condition_variable wait_;
bool run_ = true;
typename Clock::duration interval_;
std::chrono::time_point<Clock> next_;
bool scheduledInterrupt_ = false;
UtilityThread thread_;
};
} // namespace kotlin