1 #pragma once
2 
3 #include <chrono>
4 #include "data_types.hpp"
5 
6 namespace phosphor
7 {
8 namespace dbus
9 {
10 namespace monitoring
11 {
12 
13 /** @class Callback
14  *  @brief Callback interface.
15  *
16  *  Callbacks of any type can be run.
17  */
18 class 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 
28     /** @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;
36 };
37 
38 /** @class Conditional
39  *  @brief Condition interface.
40  *
41  *  Conditions of any type can be tested for true or false.
42  */
43 class 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  */
60 class 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     }
74 
75     /** @brief Test the condition. */
76     virtual bool operator()() override = 0;
77 
78   protected:
79     /** @brief Property names and their associated storage. */
80     const PropertyIndex& index;
81 };
82 
83 /** @class IndexedCallback
84  *  @brief Callback with an index.
85  */
86 class IndexedCallback : public Callback
87 {
88   public:
89     IndexedCallback() = delete;
90     IndexedCallback(const IndexedCallback&) = delete;
91     IndexedCallback(IndexedCallback&&) = default;
92     IndexedCallback& operator=(const IndexedCallback&) = delete;
93     IndexedCallback& operator=(IndexedCallback&&) = default;
94     virtual ~IndexedCallback() = default;
95     explicit IndexedCallback(const PropertyIndex& callbackIndex) :
96         Callback(), index(callbackIndex)
97     {
98     }
99 
100     /** @brief Run the callback. */
101     virtual void operator()(Context ctx) override = 0;
102 
103   protected:
104     /** @brief Property names and their associated storage. */
105     const PropertyIndex& index;
106 };
107 
108 /** @class GroupOfCallbacks
109  *  @brief Invoke multiple callbacks.
110  *
111  *  A group of callbacks is implemented as a vector of array indices
112  *  into an external array  of callbacks.  The group function call
113  *  operator traverses the vector of indices, invoking each
114  *  callback.
115  *
116  *  @tparam CallbackAccess - Access to the array of callbacks.
117  */
118 template <typename CallbackAccess> class GroupOfCallbacks : public Callback
119 {
120   public:
121     GroupOfCallbacks() = delete;
122     GroupOfCallbacks(const GroupOfCallbacks&) = delete;
123     GroupOfCallbacks(GroupOfCallbacks&&) = default;
124     GroupOfCallbacks& operator=(const GroupOfCallbacks&) = delete;
125     GroupOfCallbacks& operator=(GroupOfCallbacks&&) = default;
126     ~GroupOfCallbacks() = default;
127     explicit GroupOfCallbacks(const std::vector<size_t>& graphEntry) :
128         graph(graphEntry)
129     {
130     }
131 
132     /** @brief Run the callbacks. */
133     void operator()(Context ctx) override
134     {
135         for (auto e : graph)
136         {
137             (*CallbackAccess::get()[e])(ctx);
138         }
139     }
140 
141   private:
142     /** @brief The offsets of the callbacks in the group. */
143     const std::vector<size_t>& graph;
144 };
145 
146 /** @class ConditionalCallback
147  *  @brief Callback adaptor that asssociates a condition with a callback.
148  */
149 template <typename CallbackAccess> class ConditionalCallback : public Callback
150 {
151   public:
152     ConditionalCallback() = delete;
153     ConditionalCallback(const ConditionalCallback&) = delete;
154     ConditionalCallback(ConditionalCallback&&) = default;
155     ConditionalCallback& operator=(const ConditionalCallback&) = delete;
156     ConditionalCallback& operator=(ConditionalCallback&&) = default;
157     virtual ~ConditionalCallback() = default;
158     ConditionalCallback(const std::vector<size_t>& graphEntry,
159                         Conditional& cond) :
160         graph(graphEntry),
161         condition(cond)
162     {
163     }
164 
165     /** @brief Run the callback if the condition is satisfied. */
166     virtual void operator()(Context ctx) override
167     {
168         if (condition())
169         {
170             (*CallbackAccess::get()[graph[0]])(ctx);
171         }
172     }
173 
174   protected:
175     /** @brief The index of the callback to conditionally invoke. */
176     const std::vector<size_t>& graph;
177 
178     /** @brief The condition to test. */
179     Conditional& condition;
180 };
181 
182 /** @class DeferrableCallback
183  *
184  *  Deferrable callbacks wait a configurable period before
185  *  invoking their associated callback.
186  *
187  *  When the callback condition is initially met, start a timer.  If the
188  *  condition is tested again before the timer expires and it is not
189  *  met cancel the timer.  If the timer expires invoke the associated
190  *  callback.
191  *
192  *  @tparam CallbackAccess - Provide access to callback group instances.
193  *  @tparam TimerType - Delegated timer access methods.
194  */
195 template <typename CallbackAccess, typename TimerType>
196 class DeferrableCallback : public ConditionalCallback<CallbackAccess>
197 {
198   public:
199     DeferrableCallback() = delete;
200     DeferrableCallback(const DeferrableCallback&) = delete;
201     DeferrableCallback(DeferrableCallback&&) = default;
202     DeferrableCallback& operator=(const DeferrableCallback&) = delete;
203     DeferrableCallback& operator=(DeferrableCallback&&) = default;
204     ~DeferrableCallback() = default;
205 
206     DeferrableCallback(const std::vector<size_t>& graphEntry, Conditional& cond,
207                        const std::chrono::microseconds& delay) :
208         ConditionalCallback<CallbackAccess>(graphEntry, cond),
209         delayInterval(delay), timer(nullptr)
210     {
211     }
212 
213     void operator()(Context ctx) override
214     {
215         if (!timer)
216         {
217             timer = std::make_unique<TimerType>(
218                 // **INDENT-OFF**
219                 [ctx, this](auto& source) {
220                     this->ConditionalCallback<CallbackAccess>::operator()(ctx);
221                 });
222             // **INDENT-ON**
223             timer->disable();
224         }
225 
226         if (this->condition())
227         {
228             if (!timer->enabled())
229             {
230                 // This is the first time the condition evaluated.
231                 // Start the countdown.
232                 timer->update(timer->now() + delayInterval);
233                 timer->enable();
234             }
235         }
236         else
237         {
238             // The condition did not evaluate.  Stop the countdown.
239             timer->disable();
240         }
241     }
242 
243   private:
244     /** @brief The length to wait for the condition to stop evaluating. */
245     std::chrono::microseconds delayInterval;
246 
247     /** @brief Delegated timer functions. */
248     std::unique_ptr<TimerType> timer;
249 };
250 
251 } // namespace monitoring
252 } // namespace dbus
253 } // namespace phosphor
254