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