diff options
author | William A. Kennington III <wak@google.com> | 2018-02-27 18:51:44 -0800 |
---|---|---|
committer | Brad Bishop <bradleyb@fuzziesquirrel.com> | 2018-03-07 11:23:16 +0000 |
commit | 2235219dd319e2d1b7d6a31d05d8001fad26b5e8 (patch) | |
tree | 1bae42b7827c5b844ff69e8705af7a1a06039658 | |
parent | d13310864134b8e5a237397a9e08607cb2a01013 (diff) | |
download | phosphor-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.cpp | 6 | ||||
-rw-r--r-- | mainapp.cpp | 12 | ||||
-rw-r--r-- | test/watchdog_test.cpp | 61 | ||||
-rw-r--r-- | watchdog.cpp | 2 | ||||
-rw-r--r-- | watchdog.hpp | 5 |
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 |