blob: 5ba083629a6cb4741d7de1f92fdf25fc8e0a3cfe [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
William A. Kennington III1726df62018-04-23 10:28:28 -070017void Watchdog::resetTimeRemaining(bool enableWatchdog)
18{
19 timeRemaining(interval());
20 if (enableWatchdog)
21 {
22 enabled(true);
23 }
24}
25
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053026// Enable or disable watchdog
27bool Watchdog::enabled(bool value)
28{
William A. Kennington III825f4982018-02-27 19:10:56 -080029 if (!value)
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053030 {
William A. Kennington IIId1331082018-02-27 18:47:05 -080031 // Make sure we accurately reflect our enabled state to the
32 // tryFallbackOrDisable() call
33 WatchdogInherits::enabled(value);
34
35 // Attempt to fallback or disable our timer if needed
36 tryFallbackOrDisable();
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053037
William A. Kennington III825f4982018-02-27 19:10:56 -080038 return false;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053039 }
William A. Kennington III825f4982018-02-27 19:10:56 -080040 else if (!this->enabled())
41 {
42 // Start ONESHOT timer. Timer handles all in usec
43 auto usec = duration_cast<microseconds>(
44 milliseconds(this->interval()));
45
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",
54 entry("INTERVAL=%llu", this->interval()));
55 }
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
70 auto expiry = duration_cast<milliseconds>(
71 timer.getRemaining());
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053072
William A. Kennington III1c9515f2018-02-27 18:54:36 -080073 // convert to msec per interface expectation.
74 auto timeNow = duration_cast<milliseconds>(
75 Timer::getCurrentTime());
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053076
William A. Kennington III1c9515f2018-02-27 18:54:36 -080077 // Its possible that timer may have expired by now.
78 // So need to cross verify.
79 timeRemain = (expiry > timeNow) ?
80 (expiry - timeNow).count() : 0;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053081 }
82 return timeRemain;
83}
84
85// Reset the timer to a new expiration value
86uint64_t Watchdog::timeRemaining(uint64_t value)
87{
William A. Kennington III0650a3f2018-03-01 10:53:25 -080088 if (!timerEnabled())
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053089 {
William A. Kennington III5e3f8772018-02-27 18:59:58 -080090 // We don't need to update the timer because it is off
91 return 0;
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053092 }
William A. Kennington III5e3f8772018-02-27 18:59:58 -080093
William A. Kennington IIId1331082018-02-27 18:47:05 -080094 if (!this->enabled())
95 {
96 // Having a timer but not displaying an enabled value means we
97 // are inside of the fallback
98 value = fallback->interval;
99 }
100
William A. Kennington III5e3f8772018-02-27 18:59:58 -0800101 // Update new expiration
102 auto usec = duration_cast<microseconds>(milliseconds(value));
103 timer.start(usec);
104
105 // Update Base class data.
106 return WatchdogInherits::timeRemaining(value);
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +0530107}
108
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +0530109// Optional callback function on timer expiration
110void Watchdog::timeOutHandler()
111{
William A. Kennington IIId1331082018-02-27 18:47:05 -0800112 Action action = expireAction();
113 if (!this->enabled())
114 {
115 action = fallback->action;
116 }
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530117
William A. Kennington IIId1331082018-02-27 18:47:05 -0800118 auto target = actionTargets.find(action);
William A. Kennington III1232a152018-02-02 15:57:34 -0800119 if (target == actionTargets.end())
120 {
121 log<level::INFO>("watchdog: Timed out with no target",
122 entry("ACTION=%s", convertForMessage(action).c_str()));
William A. Kennington III825f4982018-02-27 19:10:56 -0800123 }
124 else
125 {
126 auto method = bus.new_method_call(SYSTEMD_SERVICE,
127 SYSTEMD_ROOT,
128 SYSTEMD_INTERFACE,
129 "StartUnit");
130 method.append(target->second);
131 method.append("replace");
132
133 log<level::INFO>("watchdog: Timed out",
134 entry("ACTION=%s", convertForMessage(action).c_str()),
135 entry("TARGET=%s", target->second.c_str()));
136 bus.call_noreply(method);
Vishwanatha Subbanna3473d702017-05-30 16:38:50 +0530137 }
William A. Kennington III1232a152018-02-02 15:57:34 -0800138
William A. Kennington IIId1331082018-02-27 18:47:05 -0800139 tryFallbackOrDisable();
William A. Kennington III825f4982018-02-27 19:10:56 -0800140}
William A. Kennington III1232a152018-02-02 15:57:34 -0800141
William A. Kennington IIId1331082018-02-27 18:47:05 -0800142void Watchdog::tryFallbackOrDisable()
William A. Kennington III825f4982018-02-27 19:10:56 -0800143{
William A. Kennington IIId1331082018-02-27 18:47:05 -0800144 // We only re-arm the watchdog if we were already enabled and have
145 // a possible fallback
William A. Kennington III22352192018-02-27 18:51:44 -0800146 if (fallback && (fallback->always || this->enabled()))
William A. Kennington IIId1331082018-02-27 18:47:05 -0800147 {
148 auto interval_ms = fallback->interval;
149 auto interval_us = duration_cast<microseconds>(milliseconds(interval_ms));
150
151 timer.clearExpired();
152 timer.start(interval_us);
153 timer.setEnabled<std::true_type>();
154
155 log<level::INFO>("watchdog: falling back",
156 entry("INTERVAL=%llu", interval_ms));
157 }
158 else if (timerEnabled())
William A. Kennington III825f4982018-02-27 19:10:56 -0800159 {
160 timer.setEnabled<std::false_type>();
161
162 log<level::INFO>("watchdog: disabled");
163 }
164
165 // Make sure we accurately reflect our enabled state to the
166 // dbus interface.
167 WatchdogInherits::enabled(false);
Vishwanatha Subbanna8c5a2292017-05-30 15:34:23 +0530168}
169
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +0530170} // namespace watchdog
171} // namepsace phosphor