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