summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam A. Kennington III <wak@google.com>2018-02-27 18:51:44 -0800
committerBrad Bishop <bradleyb@fuzziesquirrel.com>2018-03-07 11:23:16 +0000
commit2235219dd319e2d1b7d6a31d05d8001fad26b5e8 (patch)
tree1bae42b7827c5b844ff69e8705af7a1a06039658
parentd13310864134b8e5a237397a9e08607cb2a01013 (diff)
downloadphosphor-watchdog-2235219dd319e2d1b7d6a31d05d8001fad26b5e8.tar.gz
phosphor-watchdog-2235219dd319e2d1b7d6a31d05d8001fad26b5e8.zip
Implement a flag to enable fallback always
On some machines we want our watchdog running as long as the phosphor-watchdog daemon is alive. This patch adds an option to enter fallback mode any time the watchdog expires or is set to be disabled. Change-Id: Ic96d2f15c761aeb4e25158c5bd861076cca6497d Signed-off-by: William A. Kennington III <wak@google.com>
-rw-r--r--argument.cpp6
-rw-r--r--mainapp.cpp12
-rw-r--r--test/watchdog_test.cpp61
-rw-r--r--watchdog.cpp2
-rw-r--r--watchdog.hpp5
5 files changed, 83 insertions, 3 deletions
diff --git a/argument.cpp b/argument.cpp
index c2d99ce..770db87 100644
--- a/argument.cpp
+++ b/argument.cpp
@@ -28,7 +28,7 @@ using namespace std::string_literals;
const std::vector<std::string> emptyArg;
const std::string ArgumentParser::trueString = "true"s;
-const char* ArgumentParser::optionStr = "p:s:t:a:f:i:ch";
+const char* ArgumentParser::optionStr = "p:s:t:a:f:i:ech";
const option ArgumentParser::options[] =
{
{ "path", required_argument, nullptr, 'p' },
@@ -37,6 +37,7 @@ const option ArgumentParser::options[] =
{ "action_target", required_argument, nullptr, 'a' },
{ "fallback_action", required_argument, nullptr, 'f' },
{ "fallback_interval", required_argument, nullptr, 'i' },
+ { "fallback_always", no_argument, nullptr, 'e' },
{ "continue", no_argument, nullptr, 'c' },
{ "help", no_argument, nullptr, 'h' },
{ 0, 0, 0, 0},
@@ -111,6 +112,9 @@ void ArgumentParser::usage(char * const argv[])
"watchdog even when disabled via the dbus interface. "
"Waits for this interval before performing the fallback "
"action.\n";
+ std::cerr << " [--fallback_always] Enables the "
+ "watchdog even when disabled by the dbus interface. "
+ "This option is only valid with a fallback specified.\n";
std::cerr << " [--continue] Continue daemon "
"after watchdog timeout.\n";
}
diff --git a/mainapp.cpp b/mainapp.cpp
index 365fd50..de09ba3 100644
--- a/mainapp.cpp
+++ b/mainapp.cpp
@@ -172,9 +172,21 @@ int main(int argc, char** argv)
fallback = Watchdog::Fallback{
.action = action,
.interval = interval,
+ .always = false,
};
}
+ auto fallbackAlwaysParam = (options)["fallback_always"];
+ if (!fallbackAlwaysParam.empty())
+ {
+ if (!fallback)
+ {
+ exitWithError("Specified the fallback should always be enabled but "
+ "no fallback provided.", argv);
+ }
+ fallback->always = true;
+ }
+
sd_event* event = nullptr;
auto r = sd_event_default(&event);
if (r < 0)
diff --git a/test/watchdog_test.cpp b/test/watchdog_test.cpp
index af7c3ed..34d1d24 100644
--- a/test/watchdog_test.cpp
+++ b/test/watchdog_test.cpp
@@ -273,6 +273,7 @@ TEST_F(WdogTest, enableWdogWithFallbackReEnable)
Watchdog::Fallback fallback{
.action = Watchdog::Action::PowerOff,
.interval = static_cast<uint64_t>(fallbackIntervalMs),
+ .always = false,
};
std::map<Watchdog::Action, Watchdog::TargetName> emptyActionTargets;
wdog = std::make_unique<Watchdog>(bus, TEST_PATH, eventP,
@@ -305,3 +306,63 @@ TEST_F(WdogTest, enableWdogWithFallbackReEnable)
EXPECT_FALSE(wdog->timerExpired());
EXPECT_TRUE(wdog->timerEnabled());
}
+
+/** @brief Make sure the watchdog is started and with a fallback without
+ * sending an enable
+ * Then enable the watchdog
+ * Wait through the initial trip and ensure the fallback is observed
+ * Make sure that fallback runs to completion and ensure the watchdog
+ * is in the fallback state again
+ */
+TEST_F(WdogTest, enableWdogWithFallbackAlways)
+{
+ auto primaryInterval = 5s;
+ auto primaryIntervalMs = milliseconds(primaryInterval).count();
+ auto fallbackInterval = primaryInterval * 2;
+ auto fallbackIntervalMs = milliseconds(fallbackInterval).count();
+
+ // We need to make a wdog with the right fallback options
+ // The interval is set to be noticeably different from the default
+ // so we can always tell the difference
+ Watchdog::Fallback fallback{
+ .action = Watchdog::Action::PowerOff,
+ .interval = static_cast<uint64_t>(fallbackIntervalMs),
+ .always = true,
+ };
+ std::map<Watchdog::Action, Watchdog::TargetName> emptyActionTargets;
+ wdog = std::make_unique<Watchdog>(bus, TEST_PATH, eventP,
+ std::move(emptyActionTargets), std::move(fallback));
+ EXPECT_EQ(primaryInterval, milliseconds(wdog->interval(primaryIntervalMs)));
+ EXPECT_FALSE(wdog->enabled());
+ auto remaining = milliseconds(wdog->timeRemaining());
+ EXPECT_GE(fallbackInterval, remaining);
+ EXPECT_LT(primaryInterval, remaining);
+ EXPECT_FALSE(wdog->timerExpired());
+ EXPECT_TRUE(wdog->timerEnabled());
+
+ // Enable and then verify
+ EXPECT_TRUE(wdog->enabled(true));
+ EXPECT_GE(primaryInterval, milliseconds(wdog->timeRemaining()));
+
+ // Waiting default expiration
+ EXPECT_EQ(primaryInterval - 1s, waitForWatchdog(primaryInterval));
+
+ // We should now have entered the fallback once the primary expires
+ EXPECT_FALSE(wdog->enabled());
+ remaining = milliseconds(wdog->timeRemaining());
+ EXPECT_GE(fallbackInterval, remaining);
+ EXPECT_LT(primaryInterval, remaining);
+ EXPECT_FALSE(wdog->timerExpired());
+ EXPECT_TRUE(wdog->timerEnabled());
+
+ // Waiting fallback expiration
+ EXPECT_EQ(fallbackInterval - 1s, waitForWatchdog(fallbackInterval));
+
+ // We should now enter the fallback again
+ EXPECT_FALSE(wdog->enabled());
+ remaining = milliseconds(wdog->timeRemaining());
+ EXPECT_GE(fallbackInterval, remaining);
+ EXPECT_LT(primaryInterval, remaining);
+ EXPECT_FALSE(wdog->timerExpired());
+ EXPECT_TRUE(wdog->timerEnabled());
+}
diff --git a/watchdog.cpp b/watchdog.cpp
index b0c7b6f..2bfd9b7 100644
--- a/watchdog.cpp
+++ b/watchdog.cpp
@@ -134,7 +134,7 @@ void Watchdog::tryFallbackOrDisable()
{
// We only re-arm the watchdog if we were already enabled and have
// a possible fallback
- if (fallback && this->enabled())
+ if (fallback && (fallback->always || this->enabled()))
{
auto interval_ms = fallback->interval;
auto interval_us = duration_cast<microseconds>(milliseconds(interval_ms));
diff --git a/watchdog.hpp b/watchdog.hpp
index 60bad4e..7603689 100644
--- a/watchdog.hpp
+++ b/watchdog.hpp
@@ -37,6 +37,7 @@ class Watchdog : public WatchdogInherits
struct Fallback {
Action action;
uint64_t interval;
+ bool always;
};
/** @brief Constructs the Watchdog object
@@ -60,7 +61,9 @@ class Watchdog : public WatchdogInherits
fallback(std::move(fallback)),
timer(event, std::bind(&Watchdog::timeOutHandler, this))
{
- // Nothing
+ // We need to poke the enable mechanism to make sure that the timer
+ // enters the fallback state if the fallback is always enabled.
+ tryFallbackOrDisable();
}
/** @brief Since we are overriding the setter-enabled but not the
OpenPOWER on IntegriCloud