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