From 3539db640767e6dafa652864fc5a5445db4ee697 Mon Sep 17 00:00:00 2001 From: Brad Bishop Date: Tue, 30 May 2017 14:21:12 -0400 Subject: Add deferrable callbacks Deferrable callbacks delay callback invocation until a pre configured length of time has elapsed. One example scenario where deferrable callbacks help is to avoid oscillation when testing a condition and making callbacks frequently. Signed-off-by: Brad Bishop Change-Id: I180c99b57ec1c9bde4da76d947a026f809341c8a --- src/callback.hpp | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 3 deletions(-) (limited to 'src/callback.hpp') diff --git a/src/callback.hpp b/src/callback.hpp index f7886cb..06df910 100644 --- a/src/callback.hpp +++ b/src/callback.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include "data_types.hpp" namespace phosphor @@ -146,14 +147,14 @@ class ConditionalCallback: public Callback ConditionalCallback(ConditionalCallback&&) = default; ConditionalCallback& operator=(const ConditionalCallback&) = delete; ConditionalCallback& operator=(ConditionalCallback&&) = default; - ~ConditionalCallback() = default; + virtual ~ConditionalCallback() = default; ConditionalCallback( const std::vector& graphEntry, Conditional& cond) : graph(graphEntry), condition(cond) {} /** @brief Run the callback if the condition is satisfied. */ - void operator()() override + virtual void operator()() override { if (condition()) { @@ -161,7 +162,7 @@ class ConditionalCallback: public Callback } } - private: + protected: /** @brief The index of the callback to conditionally invoke. */ const std::vector& graph; @@ -169,6 +170,77 @@ class ConditionalCallback: public Callback Conditional& condition; }; +/** @class DeferrableCallback + * + * Deferrable callbacks wait a configurable period before + * invoking their associated callback. + * + * When the callback condition is initally 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 +class DeferrableCallback : public ConditionalCallback +{ + 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& graphEntry, + Conditional& cond, + const std::chrono::microseconds& delay) + : ConditionalCallback(graphEntry, cond), + delayInterval(delay), + timer(nullptr) {} + + void operator()() override + { + if (!timer) + { + timer = std::make_unique( +// **INDENT-OFF** + [this](auto & source) + { + this->ConditionalCallback::operator()(); + }); +// **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 timer; +}; + } // namespace monitoring } // namespace dbus } // namespace phosphor -- cgit v1.2.1