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