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 */, 51 sdbusplus::message::message& /* msg */){}; 52 }; 53 54 /** @class Conditional 55 * @brief Condition interface. 56 * 57 * Conditions of any type can be tested for true or false. 58 */ 59 class Conditional 60 { 61 public: 62 Conditional() = default; 63 Conditional(const Conditional&) = delete; 64 Conditional(Conditional&&) = default; 65 Conditional& operator=(const Conditional&) = delete; 66 Conditional& operator=(Conditional&&) = default; 67 virtual ~Conditional() = default; 68 69 /** @brief Test the condition. */ 70 virtual bool operator()() = 0; 71 }; 72 73 /** @class IndexedConditional 74 * @brief Condition with an index. 75 */ 76 class IndexedConditional : public Conditional 77 { 78 public: 79 IndexedConditional() = delete; 80 IndexedConditional(const IndexedConditional&) = delete; 81 IndexedConditional(IndexedConditional&&) = default; 82 IndexedConditional& operator=(const IndexedConditional&) = delete; 83 IndexedConditional& operator=(IndexedConditional&&) = default; 84 virtual ~IndexedConditional() = default; 85 86 explicit IndexedConditional(const PropertyIndex& conditionIndex) : 87 Conditional(), index(conditionIndex) 88 {} 89 90 /** @brief Test the condition. */ 91 virtual bool operator()() override = 0; 92 93 protected: 94 /** @brief Property names and their associated storage. */ 95 const PropertyIndex& index; 96 }; 97 98 /** @class IndexedCallback 99 * @brief Callback with an index. 100 */ 101 class IndexedCallback : public Callback 102 { 103 public: 104 IndexedCallback() = delete; 105 IndexedCallback(const IndexedCallback&) = delete; 106 IndexedCallback(IndexedCallback&&) = default; 107 IndexedCallback& operator=(const IndexedCallback&) = delete; 108 IndexedCallback& operator=(IndexedCallback&&) = default; 109 virtual ~IndexedCallback() = default; 110 explicit IndexedCallback(const PropertyIndex& callbackIndex) : 111 Callback(), index(callbackIndex) 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 /** @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 /** @brief Run the callback if the condition is satisfied. */ 180 virtual void operator()(Context ctx) override 181 { 182 if (condition()) 183 { 184 (*CallbackAccess::get()[graph[0]])(ctx); 185 } 186 } 187 188 protected: 189 /** @brief The index of the callback to conditionally invoke. */ 190 const std::vector<size_t>& graph; 191 192 /** @brief The condition to test. */ 193 Conditional& condition; 194 }; 195 196 /** @class DeferrableCallback 197 * 198 * Deferrable callbacks wait a configurable period before 199 * invoking their associated callback. 200 * 201 * When the callback condition is initially met, start a timer. If the 202 * condition is tested again before the timer expires and it is not 203 * met cancel the timer. If the timer expires invoke the associated 204 * callback. 205 * 206 * @tparam CallbackAccess - Provide access to callback group instances. 207 */ 208 template <typename CallbackAccess> 209 class DeferrableCallback : public ConditionalCallback<CallbackAccess> 210 { 211 public: 212 using TimerType = 213 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>; 214 215 DeferrableCallback() = delete; 216 DeferrableCallback(const DeferrableCallback&) = delete; 217 DeferrableCallback(DeferrableCallback&&) = delete; 218 DeferrableCallback& operator=(const DeferrableCallback&) = delete; 219 DeferrableCallback& operator=(DeferrableCallback&&) = delete; 220 ~DeferrableCallback() = default; 221 222 DeferrableCallback(const std::vector<size_t>& graphEntry, Conditional& cond, 223 const std::chrono::microseconds& delay) : 224 ConditionalCallback<CallbackAccess>(graphEntry, cond), 225 delayInterval(delay), timer(nullptr) 226 {} 227 228 /** @brief Start internal timer if the condition is satisfied. 229 * 230 * When the timer expires, it calls operator() for the 231 * ConditionalCallback with the context saved in 232 * DeferrableCallback instance. 233 */ 234 void operator()(Context ctx) override 235 { 236 if (!timer) 237 { 238 timer = std::make_unique<TimerType>( 239 sdeventplus::Event::get_default(), 240 // **INDENT-OFF** 241 [this](auto& /* source */) { 242 // The timer uses the context saved on timer enable 243 this->ConditionalCallback<CallbackAccess>::operator()( 244 this->ctx); 245 }); 246 // **INDENT-ON** 247 } 248 249 if (this->condition()) 250 { 251 if (!timer->isEnabled()) 252 { 253 // This is the first time the condition evaluated. 254 // Save current context for timer use. 255 this->ctx = ctx; 256 // Start the countdown. 257 timer->restartOnce(delayInterval); 258 } 259 } 260 else 261 { 262 // The condition did not evaluate. Stop the countdown. 263 timer->setEnabled(false); 264 } 265 } 266 267 private: 268 /** @brief The length to wait for the condition to stop evaluating. */ 269 std::chrono::microseconds delayInterval; 270 271 /** @brief Delegated timer functions. */ 272 std::unique_ptr<TimerType> timer; 273 274 /** @brief Current context for timer. */ 275 Context ctx; 276 }; 277 278 } // namespace monitoring 279 } // namespace dbus 280 } // namespace phosphor 281