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