summaryrefslogtreecommitdiffstats
path: root/watchdog.hpp
blob: 34b04116de1df179a9ee735548bd0976ea7c9ac8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#pragma once

#include <functional>
#include <optional>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/server/object.hpp>
#include <sdeventplus/event.hpp>
#include <sdeventplus/utility/timer.hpp>
#include <unordered_map>
#include <utility>
#include <xyz/openbmc_project/State/Watchdog/server.hpp>

namespace phosphor
{
namespace watchdog
{

namespace Base = sdbusplus::xyz::openbmc_project::State::server;
using WatchdogInherits = sdbusplus::server::object::object<Base::Watchdog>;

/** @class Watchdog
 *  @brief OpenBMC watchdog implementation.
 *  @details A concrete implementation for the
 *  xyz.openbmc_project.State.Watchdog DBus API.
 */
class Watchdog : public WatchdogInherits
{
  public:
    Watchdog() = delete;
    ~Watchdog() = default;
    Watchdog(const Watchdog&) = delete;
    Watchdog& operator=(const Watchdog&) = delete;
    Watchdog(Watchdog&&) = delete;
    Watchdog& operator=(Watchdog&&) = delete;

    /** @brief Type used to hold the name of a systemd target.
     */
    using TargetName = std::string;

    /** @brief Type used to store the mapping of a Watchdog timeout
     *         action to a systemd target.
     */
    using ActionTargetMap = std::unordered_map<Action, TargetName>;

    /** @brief Type used to specify the parameters of a fallback watchdog
     */
    struct Fallback
    {
        Action action;
        uint64_t interval;
        bool always;
    };

    /** @brief Constructs the Watchdog object
     *
     *  @param[in] bus            - DBus bus to attach to.
     *  @param[in] objPath        - Object path to attach to.
     *  @param[in] event          - reference to sdeventplus::Event loop
     *  @param[in] actionTargets  - map of systemd targets called on timeout
     *  @param[in] fallback
     */
    Watchdog(sdbusplus::bus::bus& bus, const char* objPath,
             const sdeventplus::Event& event,
             ActionTargetMap&& actionTargetMap = {},
             std::optional<Fallback>&& fallback = std::nullopt) :
        WatchdogInherits(bus, objPath),
        bus(bus), actionTargetMap(std::move(actionTargetMap)),
        fallback(std::move(fallback)),
        timer(event, std::bind(&Watchdog::timeOutHandler, this))
    {
        // 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 Resets the TimeRemaining to the configured Interval
     *         Optionally enables the watchdog.
     *
     *  @param[in] enableWatchdog - Should the call enable the watchdog
     */
    void resetTimeRemaining(bool enableWatchdog) override;

    /** @brief Since we are overriding the setter-enabled but not the
     *         getter-enabled, we need to have this using in order to
     *         allow passthrough usage of the getter-enabled.
     */
    using Base::Watchdog::enabled;

    /** @brief Enable or disable watchdog
     *         If a watchdog state is changed from disable to enable,
     *         the watchdog timer is set with the default expiration
     *         interval and it starts counting down.
     *         If a watchdog is already enabled, setting @value to true
     *         has no effect.
     *
     *  @param[in] value - 'true' to enable. 'false' to disable
     *
     *  @return : applied value if success, previous value otherwise
     */
    bool enabled(bool value) override;

    /** @brief Gets the remaining time before watchdog expires.
     *
     *  @return 0 if watchdog is expired.
     *          Remaining time in milliseconds otherwise.
     */
    uint64_t timeRemaining() const override;

    /** @brief Reset timer to expire after new timeout in milliseconds.
     *
     *  @param[in] value - the time in milliseconds after which
     *                     the watchdog will expire
     *
     *  @return: updated timeout value if watchdog is enabled.
     *           0 otherwise.
     */
    uint64_t timeRemaining(uint64_t value) override;

    /** @brief Tells if the referenced timer is expired or not */
    inline auto timerExpired() const
    {
        return timer.hasExpired();
    }

    /** @brief Tells if the timer is running or not */
    inline bool timerEnabled() const
    {
        return timer.isEnabled();
    }

  private:
    /** @brief sdbusplus handle */
    sdbusplus::bus::bus& bus;

    /** @brief Map of systemd units to be started when the timer expires */
    ActionTargetMap actionTargetMap;

    /** @brief Fallback timer options */
    std::optional<Fallback> fallback;

    /** @brief Contained timer object */
    sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer;

    /** @brief Optional Callback handler on timer expirartion */
    void timeOutHandler();

    /** @brief Attempt to enter the fallback watchdog or disables it */
    void tryFallbackOrDisable();
};

} // namespace watchdog
} // namespace phosphor
OpenPOWER on IntegriCloud