Line data Source code
1 : #include "watchdog.hpp"
2 : #include <algorithm>
3 :
4 : namespace thinger::asio {
5 :
6 32622 : watchdog::watchdog(boost::asio::any_io_executor executor, std::function<void()> on_expired)
7 32622 : : state_(std::make_shared<state>(boost::asio::steady_timer{std::move(executor)}, std::move(on_expired))) {}
8 :
9 32622 : watchdog::~watchdog() {
10 32622 : cancel();
11 32622 : }
12 :
13 324429 : void watchdog::expires_at(clock::time_point time) {
14 324429 : state_->deadline = time;
15 : // A running timer checks the new deadline when it expires, unless it is earlier
16 324429 : if (!state_->armed || std::max(state_->deadline, state_->hold) < state_->timer.expiry()) arm(state_);
17 324429 : }
18 :
19 12 : void watchdog::hold_until(clock::time_point time) {
20 : // A running timer checks the hold when it expires
21 12 : state_->hold = std::max(state_->hold, time);
22 12 : }
23 :
24 73178 : void watchdog::cancel() {
25 73178 : state_->armed = false;
26 73178 : state_->timer.cancel();
27 73178 : }
28 :
29 35773 : void watchdog::arm(const std::shared_ptr<state>& s) {
30 35773 : s->armed = true;
31 : // Re-arming cancels the wait in progress, whose handler then returns
32 35773 : s->timer.expires_at(std::max(s->deadline, s->hold));
33 35773 : s->timer.async_wait([weak = std::weak_ptr<state>(s)](const boost::system::error_code& ec) {
34 30996 : on_timer(weak, ec);
35 30996 : });
36 35773 : }
37 :
38 30996 : void watchdog::on_timer(const std::weak_ptr<state>& weak, const boost::system::error_code& ec) {
39 31622 : if (ec) return; // cancelled or re-armed
40 5598 : auto s = weak.lock();
41 5598 : if (!s || !s->armed) return; // gone, or cancelled once the timer had expired
42 5588 : auto now = clock::now();
43 : // The timer was set again after this wait had expired: the wait of the new expiry checks
44 5588 : if (now < s->timer.expiry()) return;
45 : // Some activity moved the deadline meanwhile, or a hold keeps it
46 5588 : if (now < std::max(s->deadline, s->hold)) {
47 616 : arm(s);
48 616 : return;
49 : }
50 4972 : s->armed = false;
51 : // `s` keeps the callback alive if it destroys the watchdog; nothing touches it afterwards
52 4972 : s->on_expired();
53 5598 : }
54 :
55 : }
|