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