blob: c948d2741b7403a2e5cf3fee510f96c2dc139ab9 [file] [log] [blame]
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +05301#include <chrono>
2#include <phosphor-logging/log.hpp>
3#include "watchdog.hpp"
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +05304namespace phosphor
5{
6namespace watchdog
7{
8using namespace std::chrono;
9using namespace std::chrono_literals;
10using namespace phosphor::logging;
11
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +053012// systemd service to kick start a target.
13constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
14constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
15constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
16
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053017// Enable or disable watchdog
18bool Watchdog::enabled(bool value)
19{
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053020 if (this->enabled() != value)
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053021 {
22 if (value)
23 {
24 // Start ONESHOT timer. Timer handles all in usec
25 auto usec = duration_cast<microseconds>(
26 milliseconds(this->interval()));
27 // Update new expiration
28 timer.start(usec);
29
30 // Enable timer
31 timer.setEnabled<std::true_type>();
32
33 log<level::INFO>("watchdog: enabled and started",
34 entry("INTERVAL=%llu", this->interval()));
35 }
36 else
37 {
38 timer.setEnabled<std::false_type>();
Patrick Venture09eebe32017-08-11 15:23:17 -070039 timer.clearExpired();
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053040 log<level::INFO>("watchdog: disabled");
41 }
42 }
43 return WatchdogInherits::enabled(value);
44}
45
46// Get the remaining time before timer expires.
47// If the timer is disabled, returns 0
48uint64_t Watchdog::timeRemaining() const
49{
50 uint64_t timeRemain = 0;
51
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053052 if (this->enabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053053 {
54 // timer may have already expired and disabled
55 if (timer.getEnabled() != SD_EVENT_OFF)
56 {
57 // the one-shot timer does not expire yet
58 auto expiry = duration_cast<milliseconds>(
59 timer.getRemaining());
60
61 // convert to msec per interface expectation.
62 auto timeNow = duration_cast<milliseconds>(
63 Timer::getCurrentTime());
64
65 // Its possible that timer may have expired by now.
66 // So need to cross verify.
67 timeRemain = (expiry > timeNow) ?
68 (expiry - timeNow).count() : 0;
69 }
70 }
71 return timeRemain;
72}
73
74// Reset the timer to a new expiration value
75uint64_t Watchdog::timeRemaining(uint64_t value)
76{
Vishwanatha Subbanna00bd3772017-05-31 14:53:42 +053077 if (this->enabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053078 {
79 // Disable the timer
80 timer.setEnabled<std::false_type>();
81
82 // Timer handles all in microseconds and hence converting
83 auto usec = duration_cast<microseconds>(
84 milliseconds(value));
85 // Update new expiration
86 timer.start(usec);
87
88 // Enable the timer.
89 timer.setEnabled<std::true_type>();
90
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053091 // Update Base class data.
92 return WatchdogInherits::timeRemaining(value);
93 }
94 return 0;
95}
96
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +053097// Optional callback function on timer expiration
98void Watchdog::timeOutHandler()
99{
William A. Kennington III1232a152018-02-02 15:57:34 -0800100 auto action = expireAction();
101 auto target = actionTargets.find(action);
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530102
William A. Kennington III1232a152018-02-02 15:57:34 -0800103 if (target == actionTargets.end())
104 {
105 log<level::INFO>("watchdog: Timed out with no target",
106 entry("ACTION=%s", convertForMessage(action).c_str()));
107 return;
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530108 }
William A. Kennington III1232a152018-02-02 15:57:34 -0800109
110 auto method = bus.new_method_call(SYSTEMD_SERVICE,
111 SYSTEMD_ROOT,
112 SYSTEMD_INTERFACE,
113 "StartUnit");
114 method.append(target->second);
115 method.append("replace");
116
117 log<level::INFO>("watchdog: Timed out",
118 entry("ACTION=%s", convertForMessage(action).c_str()),
119 entry("TARGET=%s", target->second.c_str()));
120 bus.call_noreply(method);
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +0530121}
122
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +0530123} // namespace watchdog
124} // namepsace phosphor