blob: d5297469a21f8c476b4bdda3442a77f83ddf3cdb [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>
William A. Kennington III7036c562018-10-03 23:36:16 -07004#include <phosphor-logging/elog.hpp>
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +05305#include <phosphor-logging/log.hpp>
William A. Kennington III7036c562018-10-03 23:36:16 -07006#include <sdbusplus/exception.hpp>
7#include <xyz/openbmc_project/Common/error.hpp>
8
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +05309namespace phosphor
10{
11namespace watchdog
12{
13using namespace std::chrono;
14using namespace std::chrono_literals;
15using namespace phosphor::logging;
16
William A. Kennington III7036c562018-10-03 23:36:16 -070017using sdbusplus::exception::SdBusError;
18using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
19
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +053020// systemd service to kick start a target.
Patrick Venture8f6c5152018-09-11 17:45:33 -070021constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
22constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
23constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +053024
William A. Kennington III1726df62018-04-23 10:28:28 -070025void Watchdog::resetTimeRemaining(bool enableWatchdog)
26{
27 timeRemaining(interval());
28 if (enableWatchdog)
29 {
30 enabled(true);
31 }
32}
33
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053034// Enable or disable watchdog
35bool Watchdog::enabled(bool value)
36{
William A. Kennington III825f4982018-02-27 19:10:56 -080037 if (!value)
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053038 {
William A. Kennington IIId1331082018-02-27 18:47:05 -080039 // Make sure we accurately reflect our enabled state to the
40 // tryFallbackOrDisable() call
41 WatchdogInherits::enabled(value);
42
43 // Attempt to fallback or disable our timer if needed
44 tryFallbackOrDisable();
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053045
William A. Kennington III825f4982018-02-27 19:10:56 -080046 return false;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053047 }
William A. Kennington III825f4982018-02-27 19:10:56 -080048 else if (!this->enabled())
49 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070050 auto interval_ms = this->interval();
51 timer.restart(milliseconds(interval_ms));
William A. Kennington III825f4982018-02-27 19:10:56 -080052 log<level::INFO>("watchdog: enabled and started",
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070053 entry("INTERVAL=%llu", interval_ms));
William A. Kennington III825f4982018-02-27 19:10:56 -080054 }
55
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053056 return WatchdogInherits::enabled(value);
57}
58
59// Get the remaining time before timer expires.
60// If the timer is disabled, returns 0
61uint64_t Watchdog::timeRemaining() const
62{
William A. Kennington III1c9515f2018-02-27 18:54:36 -080063 // timer may have already expired and disabled
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070064 if (!timerEnabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053065 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070066 return 0;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053067 }
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070068
69 return duration_cast<milliseconds>(timer.getRemaining()).count();
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053070}
71
72// Reset the timer to a new expiration value
73uint64_t Watchdog::timeRemaining(uint64_t value)
74{
William A. Kennington III0650a3f2018-03-01 10:53:25 -080075 if (!timerEnabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053076 {
William A. Kennington III5e3f8772018-02-27 18:59:58 -080077 // We don't need to update the timer because it is off
78 return 0;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053079 }
William A. Kennington III5e3f8772018-02-27 18:59:58 -080080
William A. Kennington IIId1331082018-02-27 18:47:05 -080081 if (!this->enabled())
82 {
83 // Having a timer but not displaying an enabled value means we
84 // are inside of the fallback
85 value = fallback->interval;
86 }
87
William A. Kennington III5e3f8772018-02-27 18:59:58 -080088 // Update new expiration
William A. Kennington IIIf505fc02018-09-12 18:30:09 -070089 timer.setRemaining(milliseconds(value));
William A. Kennington III5e3f8772018-02-27 18:59:58 -080090
91 // Update Base class data.
92 return WatchdogInherits::timeRemaining(value);
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053093}
94
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +053095// Optional callback function on timer expiration
96void Watchdog::timeOutHandler()
97{
William A. Kennington IIId1331082018-02-27 18:47:05 -080098 Action action = expireAction();
99 if (!this->enabled())
100 {
101 action = fallback->action;
102 }
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530103
Yong Li50ae4b12019-03-20 17:08:24 +0800104 WatchdogInherits::expiredTimerUse(WatchdogInherits::currentTimerUse());
105
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700106 auto target = actionTargetMap.find(action);
107 if (target == actionTargetMap.end())
William A. Kennington III1232a152018-02-02 15:57:34 -0800108 {
109 log<level::INFO>("watchdog: Timed out with no target",
Patrick Venture8f6c5152018-09-11 17:45:33 -0700110 entry("ACTION=%s", convertForMessage(action).c_str()));
William A. Kennington III825f4982018-02-27 19:10:56 -0800111 }
112 else
113 {
William A. Kennington III825f4982018-02-27 19:10:56 -0800114 log<level::INFO>("watchdog: Timed out",
Patrick Venture8f6c5152018-09-11 17:45:33 -0700115 entry("ACTION=%s", convertForMessage(action).c_str()),
116 entry("TARGET=%s", target->second.c_str()));
William A. Kennington III7036c562018-10-03 23:36:16 -0700117
118 try
119 {
120 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
121 SYSTEMD_INTERFACE, "StartUnit");
122 method.append(target->second);
123 method.append("replace");
124
125 bus.call_noreply(method);
126 }
127 catch (const SdBusError& e)
128 {
129 log<level::ERR>("watchdog: Failed to start unit",
130 entry("TARGET=%s", target->second.c_str()),
131 entry("ERROR=%s", e.what()));
132 commit<InternalFailure>();
133 }
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530134 }
William A. Kennington III1232a152018-02-02 15:57:34 -0800135
William A. Kennington IIId1331082018-02-27 18:47:05 -0800136 tryFallbackOrDisable();
William A. Kennington III825f4982018-02-27 19:10:56 -0800137}
William A. Kennington III1232a152018-02-02 15:57:34 -0800138
William A. Kennington IIId1331082018-02-27 18:47:05 -0800139void Watchdog::tryFallbackOrDisable()
William A. Kennington III825f4982018-02-27 19:10:56 -0800140{
William A. Kennington IIId1331082018-02-27 18:47:05 -0800141 // We only re-arm the watchdog if we were already enabled and have
142 // a possible fallback
William A. Kennington III22352192018-02-27 18:51:44 -0800143 if (fallback && (fallback->always || this->enabled()))
William A. Kennington IIId1331082018-02-27 18:47:05 -0800144 {
145 auto interval_ms = fallback->interval;
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700146 timer.restart(milliseconds(interval_ms));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800147 log<level::INFO>("watchdog: falling back",
Patrick Venture8f6c5152018-09-11 17:45:33 -0700148 entry("INTERVAL=%llu", interval_ms));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800149 }
150 else if (timerEnabled())
William A. Kennington III825f4982018-02-27 19:10:56 -0800151 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700152 timer.setEnabled(false);
William A. Kennington III825f4982018-02-27 19:10:56 -0800153
154 log<level::INFO>("watchdog: disabled");
155 }
156
157 // Make sure we accurately reflect our enabled state to the
158 // dbus interface.
159 WatchdogInherits::enabled(false);
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +0530160}
161
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +0530162} // namespace watchdog
Patrick Venture8f6c5152018-09-11 17:45:33 -0700163} // namespace phosphor