1 #pragma once 2 3 #include <sdbusplus/bus.hpp> 4 #include <sdbusplus/server/object.hpp> 5 #include <sdeventplus/event.hpp> 6 #include <sdeventplus/utility/timer.hpp> 7 #include <xyz/openbmc_project/State/Watchdog/server.hpp> 8 9 #include <functional> 10 #include <optional> 11 #include <string_view> 12 #include <unordered_map> 13 #include <utility> 14 15 namespace phosphor 16 { 17 namespace watchdog 18 { 19 20 constexpr auto DEFAULT_MIN_INTERVAL_MS = 0; 21 namespace Base = sdbusplus::xyz::openbmc_project::State::server; 22 using WatchdogInherits = sdbusplus::server::object_t<Base::Watchdog>; 23 24 /** @class Watchdog 25 * @brief OpenBMC watchdog implementation. 26 * @details A concrete implementation for the 27 * xyz.openbmc_project.State.Watchdog DBus API. 28 */ 29 class Watchdog : public WatchdogInherits 30 { 31 public: 32 Watchdog() = delete; 33 ~Watchdog() = default; 34 Watchdog(const Watchdog&) = delete; 35 Watchdog& operator=(const Watchdog&) = delete; 36 Watchdog(Watchdog&&) = delete; 37 Watchdog& operator=(Watchdog&&) = delete; 38 39 /** @brief Type used to hold the name of a systemd target. 40 */ 41 using TargetName = std::string; 42 43 /** @brief Type used to store the mapping of a Watchdog timeout 44 * action to a systemd target. 45 */ 46 using ActionTargetMap = std::unordered_map<Action, TargetName>; 47 48 /** @brief Type used to specify the parameters of a fallback watchdog 49 */ 50 struct Fallback 51 { 52 Action action; 53 uint64_t interval; 54 bool always; 55 }; 56 57 /** @brief Constructs the Watchdog object 58 * 59 * @param[in] bus - DBus bus to attach to. 60 * @param[in] objPath - Object path to attach to. 61 * @param[in] event - reference to sdeventplus::Event loop 62 * @param[in] actionTargets - map of systemd targets called on timeout 63 * @param[in] fallback - fallback watchdog 64 * @param[in] minInterval - minimum intervale value allowed 65 * @param[in] defaultInterval - default interval to start with 66 * @param[in] exitAfterTimeout - should the event loop be terminated 67 */ 68 Watchdog(sdbusplus::bus_t& bus, const char* objPath, 69 const sdeventplus::Event& event, 70 ActionTargetMap&& actionTargetMap = {}, 71 std::optional<Fallback>&& fallback = std::nullopt, 72 uint64_t minInterval = DEFAULT_MIN_INTERVAL_MS, 73 uint64_t defaultInterval = 0, bool exitAfterTimeout = false) : 74 WatchdogInherits(bus, objPath), bus(bus), 75 actionTargetMap(std::move(actionTargetMap)), fallback(fallback), 76 minInterval(minInterval), 77 timer(event, std::bind(&Watchdog::timeOutHandler, this)), 78 objPath(objPath), exitAfterTimeout(exitAfterTimeout) 79 { 80 // Use default if passed in otherwise just use default that comes 81 // with object 82 if (defaultInterval) 83 { 84 interval(defaultInterval); 85 } 86 else 87 { 88 interval(interval()); 89 } 90 // We need to poke the enable mechanism to make sure that the timer 91 // enters the fallback state if the fallback is always enabled. 92 tryFallbackOrDisable(); 93 } 94 95 /** @brief Resets the TimeRemaining to the configured Interval 96 * Optionally enables the watchdog. 97 * 98 * @param[in] enableWatchdog - Should the call enable the watchdog 99 */ 100 void resetTimeRemaining(bool enableWatchdog) override; 101 102 /** @brief Since we are overriding the setter-enabled but not the 103 * getter-enabled, we need to have this using in order to 104 * allow passthrough usage of the getter-enabled. 105 */ 106 using Base::Watchdog::enabled; 107 108 /** @brief Enable or disable watchdog 109 * If a watchdog state is changed from disable to enable, 110 * the watchdog timer is set with the default expiration 111 * interval and it starts counting down. 112 * If a watchdog is already enabled, setting @value to true 113 * has no effect. 114 * 115 * @param[in] value - 'true' to enable. 'false' to disable 116 * 117 * @return : applied value if success, previous value otherwise 118 */ 119 bool enabled(bool value) override; 120 121 /** @brief Gets the remaining time before watchdog expires. 122 * 123 * @return 0 if watchdog is expired. 124 * Remaining time in milliseconds otherwise. 125 */ 126 uint64_t timeRemaining() const override; 127 128 /** @brief Reset timer to expire after new timeout in milliseconds. 129 * 130 * @param[in] value - the time in milliseconds after which 131 * the watchdog will expire 132 * 133 * @return: updated timeout value if watchdog is enabled. 134 * 0 otherwise. 135 */ 136 uint64_t timeRemaining(uint64_t value) override; 137 138 /** @brief Get value of Interval 139 * 140 * 141 * @return: current interval 142 * 143 */ 144 using WatchdogInherits::interval; 145 146 /** @brief Set value of Interval 147 * 148 * @param[in] value - interval time to set 149 * 150 * @return: interval that was set 151 * 152 */ 153 uint64_t interval(uint64_t value) override; 154 155 /** @brief Tells if the referenced timer is expired or not */ 156 inline auto timerExpired() const 157 { 158 return timer.hasExpired(); 159 } 160 161 /** @brief Tells if the timer is running or not */ 162 inline bool timerEnabled() const 163 { 164 return timer.isEnabled(); 165 } 166 167 private: 168 /** @brief sdbusplus handle */ 169 sdbusplus::bus_t& bus; 170 171 /** @brief Map of systemd units to be started when the timer expires */ 172 ActionTargetMap actionTargetMap; 173 174 /** @brief Fallback timer options */ 175 std::optional<Fallback> fallback; 176 177 /** @brief Minimum watchdog interval value */ 178 uint64_t minInterval; 179 180 /** @brief Contained timer object */ 181 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer; 182 183 /** @brief Optional Callback handler on timer expirartion */ 184 void timeOutHandler(); 185 186 /** @brief Attempt to enter the fallback watchdog or disables it */ 187 void tryFallbackOrDisable(); 188 189 /** @brief Object path of the watchdog */ 190 std::string_view objPath; 191 192 /** @brief Do we terminate after exit */ 193 bool exitAfterTimeout; 194 }; 195 196 } // namespace watchdog 197 } // namespace phosphor 198