blob: 9090760bdbc383389a58e59928262d8ef4828a69 [file] [log] [blame]
Patrick Venture8f6c5152018-09-11 17:45:33 -07001#include "watchdog.hpp"
2
Ofer Yehiellic35135d2019-06-14 11:30:25 -07003#include <algorithm>
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +05304#include <chrono>
William A. Kennington III7036c562018-10-03 23:36:16 -07005#include <phosphor-logging/elog.hpp>
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +05306#include <phosphor-logging/log.hpp>
William A. Kennington III7036c562018-10-03 23:36:16 -07007#include <sdbusplus/exception.hpp>
8#include <xyz/openbmc_project/Common/error.hpp>
9
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053010namespace phosphor
11{
12namespace watchdog
13{
14using namespace std::chrono;
15using namespace std::chrono_literals;
16using namespace phosphor::logging;
17
William A. Kennington III7036c562018-10-03 23:36:16 -070018using sdbusplus::exception::SdBusError;
19using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
20
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +053021// systemd service to kick start a target.
Patrick Venture8f6c5152018-09-11 17:45:33 -070022constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
23constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
24constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +053025
William A. Kennington III1726df62018-04-23 10:28:28 -070026void Watchdog::resetTimeRemaining(bool enableWatchdog)
27{
28 timeRemaining(interval());
29 if (enableWatchdog)
30 {
31 enabled(true);
32 }
33}
34
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053035// Enable or disable watchdog
36bool Watchdog::enabled(bool value)
37{
William A. Kennington III825f4982018-02-27 19:10:56 -080038 if (!value)
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053039 {
William A. Kennington IIId1331082018-02-27 18:47:05 -080040 // Make sure we accurately reflect our enabled state to the
41 // tryFallbackOrDisable() call
42 WatchdogInherits::enabled(value);
43
44 // Attempt to fallback or disable our timer if needed
45 tryFallbackOrDisable();
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053046
William A. Kennington III825f4982018-02-27 19:10:56 -080047 return false;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053048 }
William A. Kennington III825f4982018-02-27 19:10:56 -080049 else if (!this->enabled())
50 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070051 auto interval_ms = this->interval();
52 timer.restart(milliseconds(interval_ms));
William A. Kennington III825f4982018-02-27 19:10:56 -080053 log<level::INFO>("watchdog: enabled and started",
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070054 entry("INTERVAL=%llu", interval_ms));
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{
William A. Kennington III1c9515f2018-02-27 18:54:36 -080064 // timer may have already expired and disabled
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070065 if (!timerEnabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053066 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070067 return 0;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053068 }
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070069
70 return duration_cast<milliseconds>(timer.getRemaining()).count();
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053071}
72
73// Reset the timer to a new expiration value
74uint64_t Watchdog::timeRemaining(uint64_t value)
75{
William A. Kennington III0650a3f2018-03-01 10:53:25 -080076 if (!timerEnabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053077 {
William A. Kennington III5e3f8772018-02-27 18:59:58 -080078 // We don't need to update the timer because it is off
79 return 0;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053080 }
William A. Kennington III5e3f8772018-02-27 18:59:58 -080081
William A. Kennington IIId1331082018-02-27 18:47:05 -080082 if (!this->enabled())
83 {
84 // Having a timer but not displaying an enabled value means we
85 // are inside of the fallback
86 value = fallback->interval;
87 }
88
William A. Kennington III5e3f8772018-02-27 18:59:58 -080089 // Update new expiration
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070090 timer.setRemaining(milliseconds(value));
William A. Kennington III5e3f8772018-02-27 18:59:58 -080091
92 // Update Base class data.
93 return WatchdogInherits::timeRemaining(value);
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053094}
95
Ofer Yehiellic35135d2019-06-14 11:30:25 -070096// Set value of Interval
97uint64_t Watchdog::interval(uint64_t value)
98{
99 return WatchdogInherits::interval(std::max(value, minInterval));
100}
101
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +0530102// Optional callback function on timer expiration
103void Watchdog::timeOutHandler()
104{
William A. Kennington IIId1331082018-02-27 18:47:05 -0800105 Action action = expireAction();
106 if (!this->enabled())
107 {
108 action = fallback->action;
109 }
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530110
William A. Kennington III47a9ec42019-04-18 15:42:16 -0700111 expiredTimerUse(currentTimerUse());
Yong Li50ae4b12019-03-20 17:08:24 +0800112
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700113 auto target = actionTargetMap.find(action);
114 if (target == actionTargetMap.end())
William A. Kennington III1232a152018-02-02 15:57:34 -0800115 {
116 log<level::INFO>("watchdog: Timed out with no target",
William A. Kennington III47a9ec42019-04-18 15:42:16 -0700117 entry("ACTION=%s", convertForMessage(action).c_str()),
118 entry("TIMER_USE=%s",
119 convertForMessage(expiredTimerUse()).c_str()));
William A. Kennington III825f4982018-02-27 19:10:56 -0800120 }
121 else
122 {
William A. Kennington III47a9ec42019-04-18 15:42:16 -0700123 log<level::INFO>(
124 "watchdog: Timed out",
125 entry("ACTION=%s", convertForMessage(action).c_str()),
126 entry("TIMER_USE=%s", convertForMessage(expiredTimerUse()).c_str()),
127 entry("TARGET=%s", target->second.c_str()));
William A. Kennington III7036c562018-10-03 23:36:16 -0700128
129 try
130 {
131 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
132 SYSTEMD_INTERFACE, "StartUnit");
133 method.append(target->second);
134 method.append("replace");
135
136 bus.call_noreply(method);
137 }
138 catch (const SdBusError& e)
139 {
140 log<level::ERR>("watchdog: Failed to start unit",
141 entry("TARGET=%s", target->second.c_str()),
142 entry("ERROR=%s", e.what()));
143 commit<InternalFailure>();
144 }
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530145 }
William A. Kennington III1232a152018-02-02 15:57:34 -0800146
William A. Kennington IIId1331082018-02-27 18:47:05 -0800147 tryFallbackOrDisable();
William A. Kennington III825f4982018-02-27 19:10:56 -0800148}
William A. Kennington III1232a152018-02-02 15:57:34 -0800149
William A. Kennington IIId1331082018-02-27 18:47:05 -0800150void Watchdog::tryFallbackOrDisable()
William A. Kennington III825f4982018-02-27 19:10:56 -0800151{
William A. Kennington IIId1331082018-02-27 18:47:05 -0800152 // We only re-arm the watchdog if we were already enabled and have
153 // a possible fallback
William A. Kennington III22352192018-02-27 18:51:44 -0800154 if (fallback && (fallback->always || this->enabled()))
William A. Kennington IIId1331082018-02-27 18:47:05 -0800155 {
156 auto interval_ms = fallback->interval;
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700157 timer.restart(milliseconds(interval_ms));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800158 log<level::INFO>("watchdog: falling back",
Patrick Venture8f6c5152018-09-11 17:45:33 -0700159 entry("INTERVAL=%llu", interval_ms));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800160 }
161 else if (timerEnabled())
William A. Kennington III825f4982018-02-27 19:10:56 -0800162 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700163 timer.setEnabled(false);
William A. Kennington III825f4982018-02-27 19:10:56 -0800164
165 log<level::INFO>("watchdog: disabled");
166 }
167
168 // Make sure we accurately reflect our enabled state to the
169 // dbus interface.
170 WatchdogInherits::enabled(false);
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +0530171}
172
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +0530173} // namespace watchdog
Patrick Venture8f6c5152018-09-11 17:45:33 -0700174} // namespace phosphor