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