blob: d476d972d128a838e330045ea9a632e16418cc2f [file] [log] [blame]
Brad Bishopc1283ae2017-05-20 21:42:38 -04001#pragma once
2
Brad Bishop3539db62017-05-30 14:21:12 -04003#include <chrono>
Brad Bishopc1283ae2017-05-20 21:42:38 -04004#include "data_types.hpp"
5
6namespace phosphor
7{
8namespace dbus
9{
10namespace monitoring
11{
12
13/** @class Callback
14 * @brief Callback interface.
15 *
16 * Callbacks of any type can be run.
17 */
18class Callback
19{
20 public:
21 Callback() = default;
22 Callback(const Callback&) = delete;
23 Callback(Callback&&) = default;
24 Callback& operator=(const Callback&) = delete;
25 Callback& operator=(Callback&&) = default;
26 virtual ~Callback() = default;
27
Ratan Guptaa45e0862018-02-21 19:03:13 +053028 /** @brief Run the callback.
29 * @param[in] ctx - caller context
30 * Context could be Startup or Signal
31 * Startup: Callback is called as part of process startup.
32 * Signal: Callback is called as part of watch condition has been met.
33 *
34 */
35 virtual void operator()(Context ctx) = 0;
Brad Bishopc1283ae2017-05-20 21:42:38 -040036};
37
Brad Bishop4041d722017-05-21 10:06:07 -040038/** @class Conditional
39 * @brief Condition interface.
40 *
41 * Conditions of any type can be tested for true or false.
42 */
43class Conditional
44{
45 public:
46 Conditional() = default;
47 Conditional(const Conditional&) = delete;
48 Conditional(Conditional&&) = default;
49 Conditional& operator=(const Conditional&) = delete;
50 Conditional& operator=(Conditional&&) = default;
51 virtual ~Conditional() = default;
52
53 /** @brief Test the condition. */
54 virtual bool operator()() = 0;
55};
56
57/** @class IndexedConditional
58 * @brief Condition with an index.
59 */
60class IndexedConditional : public Conditional
61{
62 public:
63 IndexedConditional() = delete;
64 IndexedConditional(const IndexedConditional&) = delete;
65 IndexedConditional(IndexedConditional&&) = default;
66 IndexedConditional& operator=(const IndexedConditional&) = delete;
67 IndexedConditional& operator=(IndexedConditional&&) = default;
68 virtual ~IndexedConditional() = default;
69
70 explicit IndexedConditional(const PropertyIndex& conditionIndex)
71 : Conditional(), index(conditionIndex) {}
72
73 /** @brief Test the condition. */
74 virtual bool operator()() override = 0;
75
76 protected:
77
78 /** @brief Property names and their associated storage. */
79 const PropertyIndex& index;
80};
81
Brad Bishopc1283ae2017-05-20 21:42:38 -040082/** @class IndexedCallback
83 * @brief Callback with an index.
84 */
85class IndexedCallback : public Callback
86{
87 public:
88 IndexedCallback() = delete;
89 IndexedCallback(const IndexedCallback&) = delete;
90 IndexedCallback(IndexedCallback&&) = default;
91 IndexedCallback& operator=(const IndexedCallback&) = delete;
92 IndexedCallback& operator=(IndexedCallback&&) = default;
93 virtual ~IndexedCallback() = default;
94 explicit IndexedCallback(const PropertyIndex& callbackIndex)
95 : Callback(), index(callbackIndex) {}
96
97 /** @brief Run the callback. */
Ratan Guptaa45e0862018-02-21 19:03:13 +053098 virtual void operator()(Context ctx) override = 0;
Brad Bishopc1283ae2017-05-20 21:42:38 -040099
100 protected:
101
102 /** @brief Property names and their associated storage. */
103 const PropertyIndex& index;
104};
105
Brad Bishop49e66172017-05-23 19:16:21 -0400106/** @class GroupOfCallbacks
107 * @brief Invoke multiple callbacks.
108 *
Gunnar Mills78199b42017-10-25 16:30:18 -0500109 * A group of callbacks is implemented as a vector of array indices
Brad Bishop49e66172017-05-23 19:16:21 -0400110 * into an external array of callbacks. The group function call
Gunnar Mills78199b42017-10-25 16:30:18 -0500111 * operator traverses the vector of indices, invoking each
Brad Bishop49e66172017-05-23 19:16:21 -0400112 * callback.
113 *
114 * @tparam CallbackAccess - Access to the array of callbacks.
115 */
116template <typename CallbackAccess>
117class GroupOfCallbacks : public Callback
118{
119 public:
120 GroupOfCallbacks() = delete;
121 GroupOfCallbacks(const GroupOfCallbacks&) = delete;
122 GroupOfCallbacks(GroupOfCallbacks&&) = default;
123 GroupOfCallbacks& operator=(const GroupOfCallbacks&) = delete;
124 GroupOfCallbacks& operator=(GroupOfCallbacks&&) = default;
125 ~GroupOfCallbacks() = default;
126 explicit GroupOfCallbacks(
127 const std::vector<size_t>& graphEntry)
128 : graph(graphEntry) {}
129
130 /** @brief Run the callbacks. */
Ratan Guptaa45e0862018-02-21 19:03:13 +0530131 void operator()(Context ctx) override
Brad Bishop49e66172017-05-23 19:16:21 -0400132 {
133 for (auto e : graph)
134 {
Ratan Guptaa45e0862018-02-21 19:03:13 +0530135 (*CallbackAccess::get()[e])(ctx);
Brad Bishop49e66172017-05-23 19:16:21 -0400136 }
137 }
138
139 private:
140 /** @brief The offsets of the callbacks in the group. */
141 const std::vector<size_t>& graph;
142};
143
Brad Bishop4041d722017-05-21 10:06:07 -0400144/** @class ConditionalCallback
145 * @brief Callback adaptor that asssociates a condition with a callback.
146 */
147template <typename CallbackAccess>
148class ConditionalCallback: public Callback
149{
150 public:
151 ConditionalCallback() = delete;
152 ConditionalCallback(const ConditionalCallback&) = delete;
153 ConditionalCallback(ConditionalCallback&&) = default;
154 ConditionalCallback& operator=(const ConditionalCallback&) = delete;
155 ConditionalCallback& operator=(ConditionalCallback&&) = default;
Brad Bishop3539db62017-05-30 14:21:12 -0400156 virtual ~ConditionalCallback() = default;
Brad Bishop4041d722017-05-21 10:06:07 -0400157 ConditionalCallback(
158 const std::vector<size_t>& graphEntry,
159 Conditional& cond)
160 : graph(graphEntry), condition(cond) {}
161
162 /** @brief Run the callback if the condition is satisfied. */
Ratan Guptaa45e0862018-02-21 19:03:13 +0530163 virtual void operator()(Context ctx) override
Brad Bishop4041d722017-05-21 10:06:07 -0400164 {
165 if (condition())
166 {
Ratan Guptaa45e0862018-02-21 19:03:13 +0530167 (*CallbackAccess::get()[graph[0]])(ctx);
Brad Bishop4041d722017-05-21 10:06:07 -0400168 }
169 }
170
Brad Bishop3539db62017-05-30 14:21:12 -0400171 protected:
Brad Bishop4041d722017-05-21 10:06:07 -0400172 /** @brief The index of the callback to conditionally invoke. */
173 const std::vector<size_t>& graph;
174
175 /** @brief The condition to test. */
176 Conditional& condition;
177};
178
Brad Bishop3539db62017-05-30 14:21:12 -0400179/** @class DeferrableCallback
180 *
181 * Deferrable callbacks wait a configurable period before
182 * invoking their associated callback.
183 *
Gunnar Mills78199b42017-10-25 16:30:18 -0500184 * When the callback condition is initially met, start a timer. If the
Brad Bishop3539db62017-05-30 14:21:12 -0400185 * condition is tested again before the timer expires and it is not
186 * met cancel the timer. If the timer expires invoke the associated
187 * callback.
188 *
189 * @tparam CallbackAccess - Provide access to callback group instances.
190 * @tparam TimerType - Delegated timer access methods.
191 */
192template <typename CallbackAccess, typename TimerType>
193class DeferrableCallback : public ConditionalCallback<CallbackAccess>
194{
195 public:
196 DeferrableCallback() = delete;
197 DeferrableCallback(const DeferrableCallback&) = delete;
198 DeferrableCallback(DeferrableCallback&&) = default;
199 DeferrableCallback& operator=(const DeferrableCallback&) = delete;
200 DeferrableCallback& operator=(DeferrableCallback&&) = default;
201 ~DeferrableCallback() = default;
202
203 DeferrableCallback(
204 const std::vector<size_t>& graphEntry,
205 Conditional& cond,
206 const std::chrono::microseconds& delay)
207 : ConditionalCallback<CallbackAccess>(graphEntry, cond),
208 delayInterval(delay),
209 timer(nullptr) {}
210
Ratan Guptaa45e0862018-02-21 19:03:13 +0530211 void operator()(Context ctx) override
Brad Bishop3539db62017-05-30 14:21:12 -0400212 {
213 if (!timer)
214 {
215 timer = std::make_unique<TimerType>(
216// **INDENT-OFF**
Ratan Guptaa45e0862018-02-21 19:03:13 +0530217 [ctx, this](auto & source)
Brad Bishop3539db62017-05-30 14:21:12 -0400218 {
Ratan Guptaa45e0862018-02-21 19:03:13 +0530219 this->ConditionalCallback<CallbackAccess>::operator()(ctx);
Brad Bishop3539db62017-05-30 14:21:12 -0400220 });
221// **INDENT-ON**
222 timer->disable();
223 }
224
225 if (this->condition())
226 {
227 if (!timer->enabled())
228 {
229 // This is the first time the condition evaluated.
230 // Start the countdown.
231 timer->update(timer->now() + delayInterval);
232 timer->enable();
233 }
234 }
235 else
236 {
237 // The condition did not evaluate. Stop the countdown.
238 timer->disable();
239 }
240 }
241
242 private:
243 /** @brief The length to wait for the condition to stop evaluating. */
244 std::chrono::microseconds delayInterval;
245
246 /** @brief Delegated timer functions. */
247 std::unique_ptr<TimerType> timer;
248};
249
Brad Bishopc1283ae2017-05-20 21:42:38 -0400250} // namespace monitoring
251} // namespace dbus
252} // namespace phosphor