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