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