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 /** @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 82 /** @class IndexedCallback 83 * @brief Callback with an index. 84 */ 85 class 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. */ 98 virtual void operator()(Context ctx) override = 0; 99 100 protected: 101 102 /** @brief Property names and their associated storage. */ 103 const PropertyIndex& index; 104 }; 105 106 /** @class GroupOfCallbacks 107 * @brief Invoke multiple callbacks. 108 * 109 * A group of callbacks is implemented as a vector of array indices 110 * into an external array of callbacks. The group function call 111 * operator traverses the vector of indices, invoking each 112 * callback. 113 * 114 * @tparam CallbackAccess - Access to the array of callbacks. 115 */ 116 template <typename CallbackAccess> 117 class 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. */ 131 void operator()(Context ctx) override 132 { 133 for (auto e : graph) 134 { 135 (*CallbackAccess::get()[e])(ctx); 136 } 137 } 138 139 private: 140 /** @brief The offsets of the callbacks in the group. */ 141 const std::vector<size_t>& graph; 142 }; 143 144 /** @class ConditionalCallback 145 * @brief Callback adaptor that asssociates a condition with a callback. 146 */ 147 template <typename CallbackAccess> 148 class 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; 156 virtual ~ConditionalCallback() = default; 157 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. */ 163 virtual void operator()(Context ctx) override 164 { 165 if (condition()) 166 { 167 (*CallbackAccess::get()[graph[0]])(ctx); 168 } 169 } 170 171 protected: 172 /** @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 179 /** @class DeferrableCallback 180 * 181 * Deferrable callbacks wait a configurable period before 182 * invoking their associated callback. 183 * 184 * When the callback condition is initially met, start a timer. If the 185 * 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 */ 192 template <typename CallbackAccess, typename TimerType> 193 class 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 211 void operator()(Context ctx) override 212 { 213 if (!timer) 214 { 215 timer = std::make_unique<TimerType>( 216 // **INDENT-OFF** 217 [ctx, this](auto & source) 218 { 219 this->ConditionalCallback<CallbackAccess>::operator()(ctx); 220 }); 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 250 } // namespace monitoring 251 } // namespace dbus 252 } // namespace phosphor 253