blob: 9301fb0f0e5d00987899a63f570551d48588979f [file] [log] [blame]
Patrick Venture8f6c5152018-09-11 17:45:33 -07001#include "watchdog.hpp"
2
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +05303#include <chrono>
4#include <phosphor-logging/log.hpp>
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +05305namespace phosphor
6{
7namespace watchdog
8{
9using namespace std::chrono;
10using namespace std::chrono_literals;
11using namespace phosphor::logging;
12
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +053013// systemd service to kick start a target.
Patrick Venture8f6c5152018-09-11 17:45:33 -070014constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
15constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
16constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +053017
William A. Kennington III1726df62018-04-23 10:28:28 -070018void Watchdog::resetTimeRemaining(bool enableWatchdog)
19{
20 timeRemaining(interval());
21 if (enableWatchdog)
22 {
23 enabled(true);
24 }
25}
26
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053027// Enable or disable watchdog
28bool Watchdog::enabled(bool value)
29{
William A. Kennington III825f4982018-02-27 19:10:56 -080030 if (!value)
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053031 {
William A. Kennington IIId1331082018-02-27 18:47:05 -080032 // Make sure we accurately reflect our enabled state to the
33 // tryFallbackOrDisable() call
34 WatchdogInherits::enabled(value);
35
36 // Attempt to fallback or disable our timer if needed
37 tryFallbackOrDisable();
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053038
William A. Kennington III825f4982018-02-27 19:10:56 -080039 return false;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053040 }
William A. Kennington III825f4982018-02-27 19:10:56 -080041 else if (!this->enabled())
42 {
43 // Start ONESHOT timer. Timer handles all in usec
Patrick Venture8f6c5152018-09-11 17:45:33 -070044 auto usec = duration_cast<microseconds>(milliseconds(this->interval()));
William A. Kennington III825f4982018-02-27 19:10:56 -080045
46 // Update new expiration
47 timer.clearExpired();
48 timer.start(usec);
49
50 // Enable timer
51 timer.setEnabled<std::true_type>();
52
53 log<level::INFO>("watchdog: enabled and started",
Patrick Venture8f6c5152018-09-11 17:45:33 -070054 entry("INTERVAL=%llu", this->interval()));
William A. Kennington III825f4982018-02-27 19:10:56 -080055 }
56
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053057 return WatchdogInherits::enabled(value);
58}
59
60// Get the remaining time before timer expires.
61// If the timer is disabled, returns 0
62uint64_t Watchdog::timeRemaining() const
63{
64 uint64_t timeRemain = 0;
65
William A. Kennington III1c9515f2018-02-27 18:54:36 -080066 // timer may have already expired and disabled
William A. Kennington III0650a3f2018-03-01 10:53:25 -080067 if (timerEnabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053068 {
William A. Kennington III1c9515f2018-02-27 18:54:36 -080069 // the one-shot timer does not expire yet
Patrick Venture8f6c5152018-09-11 17:45:33 -070070 auto expiry = duration_cast<milliseconds>(timer.getRemaining());
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053071
William A. Kennington III1c9515f2018-02-27 18:54:36 -080072 // convert to msec per interface expectation.
Patrick Venture8f6c5152018-09-11 17:45:33 -070073 auto timeNow = duration_cast<milliseconds>(Timer::getCurrentTime());
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053074
William A. Kennington III1c9515f2018-02-27 18:54:36 -080075 // Its possible that timer may have expired by now.
76 // So need to cross verify.
Patrick Venture8f6c5152018-09-11 17:45:33 -070077 timeRemain = (expiry > timeNow) ? (expiry - timeNow).count() : 0;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053078 }
79 return timeRemain;
80}
81
82// Reset the timer to a new expiration value
83uint64_t Watchdog::timeRemaining(uint64_t value)
84{
William A. Kennington III0650a3f2018-03-01 10:53:25 -080085 if (!timerEnabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053086 {
William A. Kennington III5e3f8772018-02-27 18:59:58 -080087 // We don't need to update the timer because it is off
88 return 0;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053089 }
William A. Kennington III5e3f8772018-02-27 18:59:58 -080090
William A. Kennington IIId1331082018-02-27 18:47:05 -080091 if (!this->enabled())
92 {
93 // Having a timer but not displaying an enabled value means we
94 // are inside of the fallback
95 value = fallback->interval;
96 }
97
William A. Kennington III5e3f8772018-02-27 18:59:58 -080098 // Update new expiration
99 auto usec = duration_cast<microseconds>(milliseconds(value));
100 timer.start(usec);
101
102 // Update Base class data.
103 return WatchdogInherits::timeRemaining(value);
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +0530104}
105
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +0530106// Optional callback function on timer expiration
107void Watchdog::timeOutHandler()
108{
William A. Kennington IIId1331082018-02-27 18:47:05 -0800109 Action action = expireAction();
110 if (!this->enabled())
111 {
112 action = fallback->action;
113 }
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530114
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700115 auto target = actionTargetMap.find(action);
116 if (target == actionTargetMap.end())
William A. Kennington III1232a152018-02-02 15:57:34 -0800117 {
118 log<level::INFO>("watchdog: Timed out with no target",
Patrick Venture8f6c5152018-09-11 17:45:33 -0700119 entry("ACTION=%s", convertForMessage(action).c_str()));
William A. Kennington III825f4982018-02-27 19:10:56 -0800120 }
121 else
122 {
Patrick Venture8f6c5152018-09-11 17:45:33 -0700123 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
124 SYSTEMD_INTERFACE, "StartUnit");
William A. Kennington III825f4982018-02-27 19:10:56 -0800125 method.append(target->second);
126 method.append("replace");
127
128 log<level::INFO>("watchdog: Timed out",
Patrick Venture8f6c5152018-09-11 17:45:33 -0700129 entry("ACTION=%s", convertForMessage(action).c_str()),
130 entry("TARGET=%s", target->second.c_str()));
William A. Kennington III825f4982018-02-27 19:10:56 -0800131 bus.call_noreply(method);
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530132 }
William A. Kennington III1232a152018-02-02 15:57:34 -0800133
William A. Kennington IIId1331082018-02-27 18:47:05 -0800134 tryFallbackOrDisable();
William A. Kennington III825f4982018-02-27 19:10:56 -0800135}
William A. Kennington III1232a152018-02-02 15:57:34 -0800136
William A. Kennington IIId1331082018-02-27 18:47:05 -0800137void Watchdog::tryFallbackOrDisable()
William A. Kennington III825f4982018-02-27 19:10:56 -0800138{
William A. Kennington IIId1331082018-02-27 18:47:05 -0800139 // We only re-arm the watchdog if we were already enabled and have
140 // a possible fallback
William A. Kennington III22352192018-02-27 18:51:44 -0800141 if (fallback && (fallback->always || this->enabled()))
William A. Kennington IIId1331082018-02-27 18:47:05 -0800142 {
143 auto interval_ms = fallback->interval;
Patrick Venture8f6c5152018-09-11 17:45:33 -0700144 auto interval_us =
145 duration_cast<microseconds>(milliseconds(interval_ms));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800146
147 timer.clearExpired();
148 timer.start(interval_us);
149 timer.setEnabled<std::true_type>();
150
151 log<level::INFO>("watchdog: falling back",
Patrick Venture8f6c5152018-09-11 17:45:33 -0700152 entry("INTERVAL=%llu", interval_ms));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800153 }
154 else if (timerEnabled())
William A. Kennington III825f4982018-02-27 19:10:56 -0800155 {
156 timer.setEnabled<std::false_type>();
157
158 log<level::INFO>("watchdog: disabled");
159 }
160
161 // Make sure we accurately reflect our enabled state to the
162 // dbus interface.
163 WatchdogInherits::enabled(false);
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +0530164}
165
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +0530166} // namespace watchdog
Patrick Venture8f6c5152018-09-11 17:45:33 -0700167} // namespace phosphor