blob: b0c7b6f18c5e6516c9831f200d11aad261472f95 [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{
William A. Kennington III825f4982018-02-27 19:10:56 -080020 if (!value)
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053021 {
William A. Kennington IIId1331082018-02-27 18:47:05 -080022 // Make sure we accurately reflect our enabled state to the
23 // tryFallbackOrDisable() call
24 WatchdogInherits::enabled(value);
25
26 // Attempt to fallback or disable our timer if needed
27 tryFallbackOrDisable();
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053028
William A. Kennington III825f4982018-02-27 19:10:56 -080029 return false;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053030 }
William A. Kennington III825f4982018-02-27 19:10:56 -080031 else if (!this->enabled())
32 {
33 // Start ONESHOT timer. Timer handles all in usec
34 auto usec = duration_cast<microseconds>(
35 milliseconds(this->interval()));
36
37 // Update new expiration
38 timer.clearExpired();
39 timer.start(usec);
40
41 // Enable timer
42 timer.setEnabled<std::true_type>();
43
44 log<level::INFO>("watchdog: enabled and started",
45 entry("INTERVAL=%llu", this->interval()));
46 }
47
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053048 return WatchdogInherits::enabled(value);
49}
50
51// Get the remaining time before timer expires.
52// If the timer is disabled, returns 0
53uint64_t Watchdog::timeRemaining() const
54{
55 uint64_t timeRemain = 0;
56
William A. Kennington III1c9515f2018-02-27 18:54:36 -080057 // timer may have already expired and disabled
William A. Kennington III0650a3f2018-03-01 10:53:25 -080058 if (timerEnabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053059 {
William A. Kennington III1c9515f2018-02-27 18:54:36 -080060 // the one-shot timer does not expire yet
61 auto expiry = duration_cast<milliseconds>(
62 timer.getRemaining());
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053063
William A. Kennington III1c9515f2018-02-27 18:54:36 -080064 // convert to msec per interface expectation.
65 auto timeNow = duration_cast<milliseconds>(
66 Timer::getCurrentTime());
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053067
William A. Kennington III1c9515f2018-02-27 18:54:36 -080068 // Its possible that timer may have expired by now.
69 // So need to cross verify.
70 timeRemain = (expiry > timeNow) ?
71 (expiry - timeNow).count() : 0;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053072 }
73 return timeRemain;
74}
75
76// Reset the timer to a new expiration value
77uint64_t Watchdog::timeRemaining(uint64_t value)
78{
William A. Kennington III0650a3f2018-03-01 10:53:25 -080079 if (!timerEnabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053080 {
William A. Kennington III5e3f8772018-02-27 18:59:58 -080081 // We don't need to update the timer because it is off
82 return 0;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053083 }
William A. Kennington III5e3f8772018-02-27 18:59:58 -080084
William A. Kennington IIId1331082018-02-27 18:47:05 -080085 if (!this->enabled())
86 {
87 // Having a timer but not displaying an enabled value means we
88 // are inside of the fallback
89 value = fallback->interval;
90 }
91
William A. Kennington III5e3f8772018-02-27 18:59:58 -080092 // Update new expiration
93 auto usec = duration_cast<microseconds>(milliseconds(value));
94 timer.start(usec);
95
96 // Update Base class data.
97 return WatchdogInherits::timeRemaining(value);
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053098}
99
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +0530100// Optional callback function on timer expiration
101void Watchdog::timeOutHandler()
102{
William A. Kennington IIId1331082018-02-27 18:47:05 -0800103 Action action = expireAction();
104 if (!this->enabled())
105 {
106 action = fallback->action;
107 }
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530108
William A. Kennington IIId1331082018-02-27 18:47:05 -0800109 auto target = actionTargets.find(action);
William A. Kennington III1232a152018-02-02 15:57:34 -0800110 if (target == actionTargets.end())
111 {
112 log<level::INFO>("watchdog: Timed out with no target",
113 entry("ACTION=%s", convertForMessage(action).c_str()));
William A. Kennington III825f4982018-02-27 19:10:56 -0800114 }
115 else
116 {
117 auto method = bus.new_method_call(SYSTEMD_SERVICE,
118 SYSTEMD_ROOT,
119 SYSTEMD_INTERFACE,
120 "StartUnit");
121 method.append(target->second);
122 method.append("replace");
123
124 log<level::INFO>("watchdog: Timed out",
125 entry("ACTION=%s", convertForMessage(action).c_str()),
126 entry("TARGET=%s", target->second.c_str()));
127 bus.call_noreply(method);
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530128 }
William A. Kennington III1232a152018-02-02 15:57:34 -0800129
William A. Kennington IIId1331082018-02-27 18:47:05 -0800130 tryFallbackOrDisable();
William A. Kennington III825f4982018-02-27 19:10:56 -0800131}
William A. Kennington III1232a152018-02-02 15:57:34 -0800132
William A. Kennington IIId1331082018-02-27 18:47:05 -0800133void Watchdog::tryFallbackOrDisable()
William A. Kennington III825f4982018-02-27 19:10:56 -0800134{
William A. Kennington IIId1331082018-02-27 18:47:05 -0800135 // We only re-arm the watchdog if we were already enabled and have
136 // a possible fallback
137 if (fallback && this->enabled())
138 {
139 auto interval_ms = fallback->interval;
140 auto interval_us = duration_cast<microseconds>(milliseconds(interval_ms));
141
142 timer.clearExpired();
143 timer.start(interval_us);
144 timer.setEnabled<std::true_type>();
145
146 log<level::INFO>("watchdog: falling back",
147 entry("INTERVAL=%llu", interval_ms));
148 }
149 else if (timerEnabled())
William A. Kennington III825f4982018-02-27 19:10:56 -0800150 {
151 timer.setEnabled<std::false_type>();
152
153 log<level::INFO>("watchdog: disabled");
154 }
155
156 // Make sure we accurately reflect our enabled state to the
157 // dbus interface.
158 WatchdogInherits::enabled(false);
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +0530159}
160
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +0530161} // namespace watchdog
162} // namepsace phosphor