| #pragma once |
| |
| #include <chrono> |
| #include "data_types.hpp" |
| |
| namespace phosphor |
| { |
| namespace dbus |
| { |
| namespace monitoring |
| { |
| |
| /** @class Callback |
| * @brief Callback interface. |
| * |
| * Callbacks of any type can be run. |
| */ |
| class Callback |
| { |
| public: |
| Callback() = default; |
| Callback(const Callback&) = delete; |
| Callback(Callback&&) = default; |
| Callback& operator=(const Callback&) = delete; |
| Callback& operator=(Callback&&) = default; |
| virtual ~Callback() = default; |
| |
| /** @brief Run the callback. |
| * @param[in] ctx - caller context |
| * Context could be Startup or Signal |
| * Startup: Callback is called as part of process startup. |
| * Signal: Callback is called as part of watch condition has been met. |
| * |
| */ |
| virtual void operator()(Context ctx) = 0; |
| |
| /** @brief Run the callback. |
| * @param[in] ctx - caller context |
| * Context could be Startup or Signal |
| * Startup: Callback is called as part of process startup. |
| * Signal: Callback is called as part of watch condition has been met. |
| * @param[in] msg - The sdbusplus signal message |
| */ |
| virtual void operator()(Context ctx, sdbusplus::message::message& msg){}; |
| }; |
| |
| /** @class Conditional |
| * @brief Condition interface. |
| * |
| * Conditions of any type can be tested for true or false. |
| */ |
| class Conditional |
| { |
| public: |
| Conditional() = default; |
| Conditional(const Conditional&) = delete; |
| Conditional(Conditional&&) = default; |
| Conditional& operator=(const Conditional&) = delete; |
| Conditional& operator=(Conditional&&) = default; |
| virtual ~Conditional() = default; |
| |
| /** @brief Test the condition. */ |
| virtual bool operator()() = 0; |
| }; |
| |
| /** @class IndexedConditional |
| * @brief Condition with an index. |
| */ |
| class IndexedConditional : public Conditional |
| { |
| public: |
| IndexedConditional() = delete; |
| IndexedConditional(const IndexedConditional&) = delete; |
| IndexedConditional(IndexedConditional&&) = default; |
| IndexedConditional& operator=(const IndexedConditional&) = delete; |
| IndexedConditional& operator=(IndexedConditional&&) = default; |
| virtual ~IndexedConditional() = default; |
| |
| explicit IndexedConditional(const PropertyIndex& conditionIndex) : |
| Conditional(), index(conditionIndex) |
| { |
| } |
| |
| /** @brief Test the condition. */ |
| virtual bool operator()() override = 0; |
| |
| protected: |
| /** @brief Property names and their associated storage. */ |
| const PropertyIndex& index; |
| }; |
| |
| /** @class IndexedCallback |
| * @brief Callback with an index. |
| */ |
| class IndexedCallback : public Callback |
| { |
| public: |
| IndexedCallback() = delete; |
| IndexedCallback(const IndexedCallback&) = delete; |
| IndexedCallback(IndexedCallback&&) = default; |
| IndexedCallback& operator=(const IndexedCallback&) = delete; |
| IndexedCallback& operator=(IndexedCallback&&) = default; |
| virtual ~IndexedCallback() = default; |
| explicit IndexedCallback(const PropertyIndex& callbackIndex) : |
| Callback(), index(callbackIndex) |
| { |
| } |
| |
| /** @brief Run the callback. */ |
| virtual void operator()(Context ctx) override = 0; |
| |
| protected: |
| /** @brief Property names and their associated storage. */ |
| const PropertyIndex& index; |
| }; |
| |
| /** @class GroupOfCallbacks |
| * @brief Invoke multiple callbacks. |
| * |
| * A group of callbacks is implemented as a vector of array indices |
| * into an external array of callbacks. The group function call |
| * operator traverses the vector of indices, invoking each |
| * callback. |
| * |
| * @tparam CallbackAccess - Access to the array of callbacks. |
| */ |
| template <typename CallbackAccess> class GroupOfCallbacks : public Callback |
| { |
| public: |
| GroupOfCallbacks() = delete; |
| GroupOfCallbacks(const GroupOfCallbacks&) = delete; |
| GroupOfCallbacks(GroupOfCallbacks&&) = default; |
| GroupOfCallbacks& operator=(const GroupOfCallbacks&) = delete; |
| GroupOfCallbacks& operator=(GroupOfCallbacks&&) = default; |
| ~GroupOfCallbacks() = default; |
| explicit GroupOfCallbacks(const std::vector<size_t>& graphEntry) : |
| graph(graphEntry) |
| { |
| } |
| |
| /** @brief Run the callbacks. */ |
| void operator()(Context ctx) override |
| { |
| for (auto e : graph) |
| { |
| (*CallbackAccess::get()[e])(ctx); |
| } |
| } |
| |
| private: |
| /** @brief The offsets of the callbacks in the group. */ |
| const std::vector<size_t>& graph; |
| }; |
| |
| /** @class ConditionalCallback |
| * @brief Callback adaptor that asssociates a condition with a callback. |
| */ |
| template <typename CallbackAccess> class ConditionalCallback : public Callback |
| { |
| public: |
| ConditionalCallback() = delete; |
| ConditionalCallback(const ConditionalCallback&) = delete; |
| ConditionalCallback(ConditionalCallback&&) = default; |
| ConditionalCallback& operator=(const ConditionalCallback&) = delete; |
| ConditionalCallback& operator=(ConditionalCallback&&) = default; |
| virtual ~ConditionalCallback() = default; |
| ConditionalCallback(const std::vector<size_t>& graphEntry, |
| Conditional& cond) : |
| graph(graphEntry), |
| condition(cond) |
| { |
| } |
| |
| /** @brief Run the callback if the condition is satisfied. */ |
| virtual void operator()(Context ctx) override |
| { |
| if (condition()) |
| { |
| (*CallbackAccess::get()[graph[0]])(ctx); |
| } |
| } |
| |
| protected: |
| /** @brief The index of the callback to conditionally invoke. */ |
| const std::vector<size_t>& graph; |
| |
| /** @brief The condition to test. */ |
| Conditional& condition; |
| }; |
| |
| /** @class DeferrableCallback |
| * |
| * Deferrable callbacks wait a configurable period before |
| * invoking their associated callback. |
| * |
| * When the callback condition is initially met, start a timer. If the |
| * condition is tested again before the timer expires and it is not |
| * met cancel the timer. If the timer expires invoke the associated |
| * callback. |
| * |
| * @tparam CallbackAccess - Provide access to callback group instances. |
| * @tparam TimerType - Delegated timer access methods. |
| */ |
| template <typename CallbackAccess, typename TimerType> |
| class DeferrableCallback : public ConditionalCallback<CallbackAccess> |
| { |
| public: |
| DeferrableCallback() = delete; |
| DeferrableCallback(const DeferrableCallback&) = delete; |
| DeferrableCallback(DeferrableCallback&&) = default; |
| DeferrableCallback& operator=(const DeferrableCallback&) = delete; |
| DeferrableCallback& operator=(DeferrableCallback&&) = default; |
| ~DeferrableCallback() = default; |
| |
| DeferrableCallback(const std::vector<size_t>& graphEntry, Conditional& cond, |
| const std::chrono::microseconds& delay) : |
| ConditionalCallback<CallbackAccess>(graphEntry, cond), |
| delayInterval(delay), timer(nullptr) |
| { |
| } |
| |
| void operator()(Context ctx) override |
| { |
| if (!timer) |
| { |
| timer = std::make_unique<TimerType>( |
| // **INDENT-OFF** |
| [ctx, this](auto& source) { |
| this->ConditionalCallback<CallbackAccess>::operator()(ctx); |
| }); |
| // **INDENT-ON** |
| timer->disable(); |
| } |
| |
| if (this->condition()) |
| { |
| if (!timer->enabled()) |
| { |
| // This is the first time the condition evaluated. |
| // Start the countdown. |
| timer->update(timer->now() + delayInterval); |
| timer->enable(); |
| } |
| } |
| else |
| { |
| // The condition did not evaluate. Stop the countdown. |
| timer->disable(); |
| } |
| } |
| |
| private: |
| /** @brief The length to wait for the condition to stop evaluating. */ |
| std::chrono::microseconds delayInterval; |
| |
| /** @brief Delegated timer functions. */ |
| std::unique_ptr<TimerType> timer; |
| }; |
| |
| } // namespace monitoring |
| } // namespace dbus |
| } // namespace phosphor |