93 lines
2.7 KiB
C++
93 lines
2.7 KiB
C++
#include "config.hpp"
|
||
#include <ranczo-io/utils/asio_watchdog.hpp>
|
||
|
||
namespace ranczo {
|
||
SoftWatchdog::SoftWatchdog(boost::asio::any_io_executor ex, Dur period, AlarmFn alarm, bool periodic_alarm)
|
||
: strand_(boost::asio::make_strand(ex)), timer_(strand_), period_(period), alarm_(std::move(alarm)), periodic_alarm_(periodic_alarm) {}
|
||
|
||
void SoftWatchdog::start() {
|
||
boost::asio::dispatch(strand_, [this] {
|
||
if(active_)
|
||
return;
|
||
active_ = true;
|
||
last_touch_ = Clock::now(); // zaczynamy liczyć od teraz
|
||
arm_from_now_(); // uzbrój timer
|
||
});
|
||
}
|
||
|
||
void SoftWatchdog::stop() {
|
||
boost::asio::dispatch(strand_, [this] {
|
||
active_ = false;
|
||
timer_.cancel();
|
||
});
|
||
}
|
||
|
||
void SoftWatchdog::touch() { // alias: kick()
|
||
boost::asio::dispatch(strand_, [this] {
|
||
if(!active_)
|
||
return;
|
||
last_touch_ = Clock::now();
|
||
timer_.cancel(); // handler rozpozna cancel i uzbroi timer od nowa
|
||
});
|
||
}
|
||
|
||
void SoftWatchdog::arm_from_now_() {
|
||
timer_.expires_after(period_);
|
||
timer_.async_wait(boost::asio::bind_executor(strand_, [this](const boost::system::error_code & ec) { on_timer_(ec); }));
|
||
}
|
||
|
||
void SoftWatchdog::set_period(Dur d) {
|
||
boost::asio::dispatch(strand_, [this, d] {
|
||
period_ = d;
|
||
timer_.cancel();
|
||
});
|
||
}
|
||
|
||
void SoftWatchdog::on_timer_(const boost::system::error_code & ec) {
|
||
if(!active_)
|
||
return;
|
||
|
||
if(ec == boost::asio::error::operation_aborted) {
|
||
// Został wykonany touch() / set_period() / stop(); ustaw ponownie
|
||
if(active_)
|
||
arm_from_now_();
|
||
return;
|
||
}
|
||
if(ec) {
|
||
// Inny błąd — uzbrój ponownie „na wszelki wypadek”
|
||
if(active_)
|
||
arm_from_now_();
|
||
return;
|
||
}
|
||
|
||
// Timer naturalnie wygasł – sprawdź, czy rzeczywiście NIKT nie dotknął
|
||
auto now = Clock::now();
|
||
auto since_touch = now - last_touch_;
|
||
if(since_touch >= period_) {
|
||
// faktycznie timeout bez touch()
|
||
try {
|
||
if(alarm_)
|
||
alarm_();
|
||
} catch(...) {
|
||
}
|
||
|
||
if(!periodic_alarm_) {
|
||
// Tryb one-shot: czekamy na następne touch() (nie uzbrajamy automatycznie)
|
||
return;
|
||
}
|
||
// Tryb periodyczny: jeśli nadal brak touch(), chcemy bić co „period_”
|
||
// Ustawiamy nowy okres od teraz; kolejne alarmy będą co „period_”
|
||
if(active_)
|
||
arm_from_now_();
|
||
} else {
|
||
// ktoś dotknął tuż przed wygaśnięciem; przeliczymy okres od teraz
|
||
if(active_)
|
||
arm_from_now_();
|
||
}
|
||
}
|
||
|
||
// bool SoftWatchdog::is_armed() const noexcept {
|
||
// return active_.load(std::memory_order_relaxed);
|
||
// }
|
||
} // namespace ranczo
|