blob: 2ee82828d1b421914e98fad1e4689a45d6087bca [file] [log] [blame]
Brad Bishopc1283ae2017-05-20 21:42:38 -04001#pragma once
2
3#include "data_types.hpp"
4
William A. Kennington III223c4092018-10-19 15:56:09 -07005#include <sdeventplus/clock.hpp>
6#include <sdeventplus/event.hpp>
7#include <sdeventplus/utility/timer.hpp>
Patrick Venture3d6d3182018-08-31 09:33:09 -07008
George Liu3fe976c2022-06-21 09:37:04 +08009#include <chrono>
10#include <cstddef>
11
Brad Bishopc1283ae2017-05-20 21:42:38 -040012namespace phosphor
13{
14namespace dbus
15{
16namespace monitoring
17{
18
19/** @class Callback
20 * @brief Callback interface.
21 *
22 * Callbacks of any type can be run.
23 */
24class Callback
25{
Brad Bishopd1eac882018-03-29 10:34:05 -040026 public:
27 Callback() = default;
28 Callback(const Callback&) = delete;
29 Callback(Callback&&) = default;
30 Callback& operator=(const Callback&) = delete;
31 Callback& operator=(Callback&&) = default;
32 virtual ~Callback() = default;
Brad Bishopc1283ae2017-05-20 21:42:38 -040033
Brad Bishopd1eac882018-03-29 10:34:05 -040034 /** @brief Run the callback.
35 * @param[in] ctx - caller context
36 * Context could be Startup or Signal
37 * Startup: Callback is called as part of process startup.
38 * Signal: Callback is called as part of watch condition has been met.
39 *
40 */
George Liu5e6b51d2022-06-21 16:59:39 +080041 virtual void operator()(Context /* ctx */) = 0;
Marri Devender Rao70aafbb2018-04-12 01:11:48 -050042
43 /** @brief Run the callback.
44 * @param[in] ctx - caller context
45 * Context could be Startup or Signal
46 * Startup: Callback is called as part of process startup.
47 * Signal: Callback is called as part of watch condition has been met.
48 * @param[in] msg - The sdbusplus signal message
49 */
George Liu5e6b51d2022-06-21 16:59:39 +080050 virtual void operator()(Context /* ctx */,
Patrick Williams413a4852022-07-22 19:26:52 -050051 sdbusplus::message_t& /* msg */){};
Brad Bishopc1283ae2017-05-20 21:42:38 -040052};
53
Brad Bishop4041d722017-05-21 10:06:07 -040054/** @class Conditional
55 * @brief Condition interface.
56 *
57 * Conditions of any type can be tested for true or false.
58 */
59class Conditional
60{
Brad Bishopd1eac882018-03-29 10:34:05 -040061 public:
62 Conditional() = default;
63 Conditional(const Conditional&) = delete;
64 Conditional(Conditional&&) = default;
65 Conditional& operator=(const Conditional&) = delete;
66 Conditional& operator=(Conditional&&) = default;
67 virtual ~Conditional() = default;
Brad Bishop4041d722017-05-21 10:06:07 -040068
Brad Bishopd1eac882018-03-29 10:34:05 -040069 /** @brief Test the condition. */
70 virtual bool operator()() = 0;
Brad Bishop4041d722017-05-21 10:06:07 -040071};
72
73/** @class IndexedConditional
74 * @brief Condition with an index.
75 */
76class IndexedConditional : public Conditional
77{
Brad Bishopd1eac882018-03-29 10:34:05 -040078 public:
79 IndexedConditional() = delete;
80 IndexedConditional(const IndexedConditional&) = delete;
81 IndexedConditional(IndexedConditional&&) = default;
82 IndexedConditional& operator=(const IndexedConditional&) = delete;
83 IndexedConditional& operator=(IndexedConditional&&) = default;
84 virtual ~IndexedConditional() = default;
Brad Bishop4041d722017-05-21 10:06:07 -040085
Brad Bishopd1eac882018-03-29 10:34:05 -040086 explicit IndexedConditional(const PropertyIndex& conditionIndex) :
87 Conditional(), index(conditionIndex)
George Liu3fe976c2022-06-21 09:37:04 +080088 {}
Brad Bishop4041d722017-05-21 10:06:07 -040089
Brad Bishopd1eac882018-03-29 10:34:05 -040090 /** @brief Test the condition. */
91 virtual bool operator()() override = 0;
Brad Bishop4041d722017-05-21 10:06:07 -040092
Brad Bishopd1eac882018-03-29 10:34:05 -040093 protected:
94 /** @brief Property names and their associated storage. */
95 const PropertyIndex& index;
Brad Bishop4041d722017-05-21 10:06:07 -040096};
97
Brad Bishopc1283ae2017-05-20 21:42:38 -040098/** @class IndexedCallback
99 * @brief Callback with an index.
100 */
101class IndexedCallback : public Callback
102{
Brad Bishopd1eac882018-03-29 10:34:05 -0400103 public:
104 IndexedCallback() = delete;
105 IndexedCallback(const IndexedCallback&) = delete;
106 IndexedCallback(IndexedCallback&&) = default;
107 IndexedCallback& operator=(const IndexedCallback&) = delete;
108 IndexedCallback& operator=(IndexedCallback&&) = default;
109 virtual ~IndexedCallback() = default;
110 explicit IndexedCallback(const PropertyIndex& callbackIndex) :
111 Callback(), index(callbackIndex)
George Liu3fe976c2022-06-21 09:37:04 +0800112 {}
Brad Bishopc1283ae2017-05-20 21:42:38 -0400113
Brad Bishopd1eac882018-03-29 10:34:05 -0400114 /** @brief Run the callback. */
115 virtual void operator()(Context ctx) override = 0;
Brad Bishopc1283ae2017-05-20 21:42:38 -0400116
Brad Bishopd1eac882018-03-29 10:34:05 -0400117 protected:
118 /** @brief Property names and their associated storage. */
119 const PropertyIndex& index;
Brad Bishopc1283ae2017-05-20 21:42:38 -0400120};
121
Brad Bishop49e66172017-05-23 19:16:21 -0400122/** @class GroupOfCallbacks
123 * @brief Invoke multiple callbacks.
124 *
Gunnar Mills78199b42017-10-25 16:30:18 -0500125 * A group of callbacks is implemented as a vector of array indices
Brad Bishop49e66172017-05-23 19:16:21 -0400126 * into an external array of callbacks. The group function call
Gunnar Mills78199b42017-10-25 16:30:18 -0500127 * operator traverses the vector of indices, invoking each
Brad Bishop49e66172017-05-23 19:16:21 -0400128 * callback.
129 *
130 * @tparam CallbackAccess - Access to the array of callbacks.
131 */
Patrick Venture3d6d3182018-08-31 09:33:09 -0700132template <typename CallbackAccess>
133class GroupOfCallbacks : public Callback
Brad Bishop49e66172017-05-23 19:16:21 -0400134{
Brad Bishopd1eac882018-03-29 10:34:05 -0400135 public:
136 GroupOfCallbacks() = delete;
137 GroupOfCallbacks(const GroupOfCallbacks&) = delete;
138 GroupOfCallbacks(GroupOfCallbacks&&) = default;
139 GroupOfCallbacks& operator=(const GroupOfCallbacks&) = delete;
140 GroupOfCallbacks& operator=(GroupOfCallbacks&&) = default;
141 ~GroupOfCallbacks() = default;
142 explicit GroupOfCallbacks(const std::vector<size_t>& graphEntry) :
143 graph(graphEntry)
George Liu3fe976c2022-06-21 09:37:04 +0800144 {}
Brad Bishop49e66172017-05-23 19:16:21 -0400145
Brad Bishopd1eac882018-03-29 10:34:05 -0400146 /** @brief Run the callbacks. */
147 void operator()(Context ctx) override
148 {
149 for (auto e : graph)
Brad Bishop49e66172017-05-23 19:16:21 -0400150 {
Brad Bishopd1eac882018-03-29 10:34:05 -0400151 (*CallbackAccess::get()[e])(ctx);
Brad Bishop49e66172017-05-23 19:16:21 -0400152 }
Brad Bishopd1eac882018-03-29 10:34:05 -0400153 }
Brad Bishop49e66172017-05-23 19:16:21 -0400154
Brad Bishopd1eac882018-03-29 10:34:05 -0400155 private:
156 /** @brief The offsets of the callbacks in the group. */
157 const std::vector<size_t>& graph;
Brad Bishop49e66172017-05-23 19:16:21 -0400158};
159
Brad Bishop4041d722017-05-21 10:06:07 -0400160/** @class ConditionalCallback
161 * @brief Callback adaptor that asssociates a condition with a callback.
162 */
Patrick Venture3d6d3182018-08-31 09:33:09 -0700163template <typename CallbackAccess>
164class ConditionalCallback : public Callback
Brad Bishop4041d722017-05-21 10:06:07 -0400165{
Brad Bishopd1eac882018-03-29 10:34:05 -0400166 public:
167 ConditionalCallback() = delete;
168 ConditionalCallback(const ConditionalCallback&) = delete;
169 ConditionalCallback(ConditionalCallback&&) = default;
170 ConditionalCallback& operator=(const ConditionalCallback&) = delete;
171 ConditionalCallback& operator=(ConditionalCallback&&) = default;
172 virtual ~ConditionalCallback() = default;
173 ConditionalCallback(const std::vector<size_t>& graphEntry,
174 Conditional& cond) :
175 graph(graphEntry),
176 condition(cond)
George Liu3fe976c2022-06-21 09:37:04 +0800177 {}
Brad Bishop4041d722017-05-21 10:06:07 -0400178
Brad Bishopd1eac882018-03-29 10:34:05 -0400179 /** @brief Run the callback if the condition is satisfied. */
180 virtual void operator()(Context ctx) override
181 {
182 if (condition())
Brad Bishop4041d722017-05-21 10:06:07 -0400183 {
Brad Bishopd1eac882018-03-29 10:34:05 -0400184 (*CallbackAccess::get()[graph[0]])(ctx);
Brad Bishop4041d722017-05-21 10:06:07 -0400185 }
Brad Bishopd1eac882018-03-29 10:34:05 -0400186 }
Brad Bishop4041d722017-05-21 10:06:07 -0400187
Brad Bishopd1eac882018-03-29 10:34:05 -0400188 protected:
189 /** @brief The index of the callback to conditionally invoke. */
190 const std::vector<size_t>& graph;
Brad Bishop4041d722017-05-21 10:06:07 -0400191
Brad Bishopd1eac882018-03-29 10:34:05 -0400192 /** @brief The condition to test. */
193 Conditional& condition;
Brad Bishop4041d722017-05-21 10:06:07 -0400194};
195
Brad Bishop3539db62017-05-30 14:21:12 -0400196/** @class DeferrableCallback
197 *
198 * Deferrable callbacks wait a configurable period before
199 * invoking their associated callback.
200 *
Gunnar Mills78199b42017-10-25 16:30:18 -0500201 * When the callback condition is initially met, start a timer. If the
Brad Bishop3539db62017-05-30 14:21:12 -0400202 * condition is tested again before the timer expires and it is not
203 * met cancel the timer. If the timer expires invoke the associated
204 * callback.
205 *
206 * @tparam CallbackAccess - Provide access to callback group instances.
Brad Bishop3539db62017-05-30 14:21:12 -0400207 */
William A. Kennington III223c4092018-10-19 15:56:09 -0700208template <typename CallbackAccess>
Brad Bishop3539db62017-05-30 14:21:12 -0400209class DeferrableCallback : public ConditionalCallback<CallbackAccess>
210{
Brad Bishopd1eac882018-03-29 10:34:05 -0400211 public:
William A. Kennington III223c4092018-10-19 15:56:09 -0700212 using TimerType =
213 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
214
Brad Bishopd1eac882018-03-29 10:34:05 -0400215 DeferrableCallback() = delete;
216 DeferrableCallback(const DeferrableCallback&) = delete;
William A. Kennington III223c4092018-10-19 15:56:09 -0700217 DeferrableCallback(DeferrableCallback&&) = delete;
Brad Bishopd1eac882018-03-29 10:34:05 -0400218 DeferrableCallback& operator=(const DeferrableCallback&) = delete;
William A. Kennington III223c4092018-10-19 15:56:09 -0700219 DeferrableCallback& operator=(DeferrableCallback&&) = delete;
Brad Bishopd1eac882018-03-29 10:34:05 -0400220 ~DeferrableCallback() = default;
Brad Bishop3539db62017-05-30 14:21:12 -0400221
Brad Bishopd1eac882018-03-29 10:34:05 -0400222 DeferrableCallback(const std::vector<size_t>& graphEntry, Conditional& cond,
223 const std::chrono::microseconds& delay) :
224 ConditionalCallback<CallbackAccess>(graphEntry, cond),
George Liuecef1192022-07-07 08:59:12 +0800225 delayInterval(delay)
George Liu3fe976c2022-06-21 09:37:04 +0800226 {}
Brad Bishop3539db62017-05-30 14:21:12 -0400227
Alexander Soldatov78a5df92018-11-23 14:37:50 +0300228 /** @brief Start internal timer if the condition is satisfied.
229 *
230 * When the timer expires, it calls operator() for the
231 * ConditionalCallback with the context saved in
232 * DeferrableCallback instance.
233 */
Brad Bishopd1eac882018-03-29 10:34:05 -0400234 void operator()(Context ctx) override
235 {
236 if (!timer)
Brad Bishop3539db62017-05-30 14:21:12 -0400237 {
Brad Bishopd1eac882018-03-29 10:34:05 -0400238 timer = std::make_unique<TimerType>(
William A. Kennington III223c4092018-10-19 15:56:09 -0700239 sdeventplus::Event::get_default(),
Brad Bishopd1eac882018-03-29 10:34:05 -0400240 // **INDENT-OFF**
George Liu5e6b51d2022-06-21 16:59:39 +0800241 [this](auto& /* source */) {
Alexander Soldatov78a5df92018-11-23 14:37:50 +0300242 // The timer uses the context saved on timer enable
243 this->ConditionalCallback<CallbackAccess>::operator()(
244 this->ctx);
Brad Bishopd1eac882018-03-29 10:34:05 -0400245 });
246 // **INDENT-ON**
Brad Bishop3539db62017-05-30 14:21:12 -0400247 }
248
Brad Bishopd1eac882018-03-29 10:34:05 -0400249 if (this->condition())
250 {
William A. Kennington III223c4092018-10-19 15:56:09 -0700251 if (!timer->isEnabled())
Brad Bishopd1eac882018-03-29 10:34:05 -0400252 {
253 // This is the first time the condition evaluated.
Alexander Soldatov78a5df92018-11-23 14:37:50 +0300254 // Save current context for timer use.
255 this->ctx = ctx;
Brad Bishopd1eac882018-03-29 10:34:05 -0400256 // Start the countdown.
William A. Kennington III223c4092018-10-19 15:56:09 -0700257 timer->restartOnce(delayInterval);
Brad Bishopd1eac882018-03-29 10:34:05 -0400258 }
259 }
260 else
261 {
262 // The condition did not evaluate. Stop the countdown.
William A. Kennington III223c4092018-10-19 15:56:09 -0700263 timer->setEnabled(false);
Brad Bishopd1eac882018-03-29 10:34:05 -0400264 }
265 }
Brad Bishop3539db62017-05-30 14:21:12 -0400266
Brad Bishopd1eac882018-03-29 10:34:05 -0400267 private:
268 /** @brief The length to wait for the condition to stop evaluating. */
269 std::chrono::microseconds delayInterval;
270
271 /** @brief Delegated timer functions. */
George Liuecef1192022-07-07 08:59:12 +0800272 std::unique_ptr<TimerType> timer = nullptr;
Alexander Soldatov78a5df92018-11-23 14:37:50 +0300273
274 /** @brief Current context for timer. */
George Liuecef1192022-07-07 08:59:12 +0800275 Context ctx = Context::START;
Brad Bishop3539db62017-05-30 14:21:12 -0400276};
277
Brad Bishopc1283ae2017-05-20 21:42:38 -0400278} // namespace monitoring
279} // namespace dbus
280} // namespace phosphor