| @@ -9,3 +9,6 @@ Option ( ASYNCPP_INSTALL_PACKAGE | |||||
| Option ( ASYNCPP_USE_GIT_VERSION | Option ( ASYNCPP_USE_GIT_VERSION | ||||
| "Read the git tags to get the version of asyncpp" | "Read the git tags to get the version of asyncpp" | ||||
| ON ) | ON ) | ||||
| Option ( ASYNCPP_FEATURE_TIMING_ENABLED | |||||
| "Enable the timing features of asyncpp" | |||||
| ON ) | |||||
| @@ -0,0 +1,3 @@ | |||||
| #pragma once | |||||
| #cmakedefine ASYNCPP_FEATURE_TIMING_ENABLED | |||||
| @@ -1,3 +1,9 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <asyncpp/config.h> | |||||
| #include <asyncpp/core.h> | #include <asyncpp/core.h> | ||||
| #ifdef ASYNCPP_FEATURE_TIMING_ENABLED | |||||
| #include <asyncpp/timing.h> | |||||
| #endif | |||||
| @@ -6,6 +6,6 @@ | |||||
| #include "future/lazy.inl" | #include "future/lazy.inl" | ||||
| #include "future/and_then.inl" | #include "future/and_then.inl" | ||||
| #ifdef asyncpp_timing | |||||
| #ifdef ASYNCPP_FEATURE_TIMING_ENABLED | |||||
| #include "future/timeout.inl" | #include "future/timeout.inl" | ||||
| #endif | #endif | ||||
| @@ -57,7 +57,7 @@ namespace asyncpp | |||||
| typename X_lambda> | typename X_lambda> | ||||
| inline auto and_then(X_lambda&& p_lambda) &&; | inline auto and_then(X_lambda&& p_lambda) &&; | ||||
| #ifdef asyncpp_timing | |||||
| #ifdef ASYNCPP_FEATURE_TIMING_ENABLED | |||||
| public: | public: | ||||
| /** | /** | ||||
| * @brief Throw an execption if the timeout has passed. | * @brief Throw an execption if the timeout has passed. | ||||
| @@ -1,5 +1,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <asyncpp/timing/timeout/timeout_future.h> | |||||
| #include "future.h" | #include "future.h" | ||||
| namespace asyncpp { | namespace asyncpp { | ||||
| @@ -22,11 +24,11 @@ namespace __future { | |||||
| derived_type const &, | derived_type const &, | ||||
| derived_type &>; | derived_type &>; | ||||
| using derived_forward_type = forward_type_t<X_mode, derived_ref_type>; | using derived_forward_type = forward_type_t<X_mode, derived_ref_type>; | ||||
| using timeout_type = asyncpp::timing::timeout<derived_storage_type>; | |||||
| using timeout_future_type = asyncpp::timing::timeout_future<derived_storage_type>; | |||||
| auto& self = static_cast<derived_ref_type>(p_self); | auto& self = static_cast<derived_ref_type>(p_self); | ||||
| return timeout_type( | |||||
| return timeout_future_type( | |||||
| std::forward<derived_forward_type>(self), | std::forward<derived_forward_type>(self), | ||||
| p_timeout); | p_timeout); | ||||
| } | } | ||||
| @@ -6,6 +6,6 @@ | |||||
| #include "stream/flatten.inl" | #include "stream/flatten.inl" | ||||
| #include "stream/for_each.inl" | #include "stream/for_each.inl" | ||||
| #ifdef asyncpp_timing | |||||
| #ifdef ASYNCPP_FEATURE_TIMING_ENABLED | |||||
| #include "stream/timeout.inl" | #include "stream/timeout.inl" | ||||
| #endif | #endif | ||||
| @@ -75,7 +75,7 @@ namespace asyncpp | |||||
| chaining_mode X_mode = move> | chaining_mode X_mode = move> | ||||
| inline auto flatten() &&; | inline auto flatten() &&; | ||||
| #ifdef asyncpp_timing | |||||
| #ifdef ASYNCPP_FEATURE_TIMING_ENABLED | |||||
| public: | public: | ||||
| /** | /** | ||||
| * @brief Throw an execption if the timeout has passed. | * @brief Throw an execption if the timeout has passed. | ||||
| @@ -1,5 +1,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <asyncpp/timing/timeout/timeout_stream.h> | |||||
| #include "stream.h" | #include "stream.h" | ||||
| namespace asyncpp { | namespace asyncpp { | ||||
| @@ -22,11 +24,11 @@ namespace __stream { | |||||
| derived_type const &, | derived_type const &, | ||||
| derived_type &>; | derived_type &>; | ||||
| using derived_forward_type = forward_type_t<X_mode, derived_ref_type>; | using derived_forward_type = forward_type_t<X_mode, derived_ref_type>; | ||||
| using timeout_type = timing::timeout<derived_storage_type>; | |||||
| using timeout_stream_type = timing::timeout_stream<derived_storage_type>; | |||||
| auto& self = static_cast<derived_ref_type>(p_self); | auto& self = static_cast<derived_ref_type>(p_self); | ||||
| return timeout_type( | |||||
| return timeout_stream_type( | |||||
| std::forward<derived_forward_type>(self), | std::forward<derived_forward_type>(self), | ||||
| p_timeout); | p_timeout); | ||||
| } | } | ||||
| @@ -59,6 +59,9 @@ namespace asyncpp | |||||
| */ | */ | ||||
| inline lock(task::handle_ptr_s p_handle); | inline lock(task::handle_ptr_s p_handle); | ||||
| inline lock(lock &&) = delete; | |||||
| inline lock(lock const &) = delete; | |||||
| /** | /** | ||||
| * @brief Destructor. | * @brief Destructor. | ||||
| */ | */ | ||||
| @@ -1,5 +1,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cppcore/misc/exception.h> | |||||
| #include "task.h" | #include "task.h" | ||||
| namespace asyncpp | namespace asyncpp | ||||
| @@ -8,7 +10,12 @@ namespace asyncpp | |||||
| /* task::lock */ | /* task::lock */ | ||||
| task::lock::lock(task::handle_ptr_s p_handle) | task::lock::lock(task::handle_ptr_s p_handle) | ||||
| { local_storage().current = p_handle; } | |||||
| { | |||||
| auto& current = local_storage().current; | |||||
| if (!current.expired()) | |||||
| throw cppcore::invalid_operation_exception("Current task is already assigned!"); | |||||
| current = p_handle; | |||||
| } | |||||
| task::lock::~lock() | task::lock::~lock() | ||||
| { local_storage().current.reset(); } | { local_storage().current.reset(); } | ||||
| @@ -1,5 +1,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cppcore/misc/exception.h> | |||||
| #include "executor.h" | #include "executor.h" | ||||
| #include "task_handle.inl" | #include "task_handle.inl" | ||||
| @@ -33,7 +35,12 @@ namespace executor { | |||||
| /* lock */ | /* lock */ | ||||
| executor::lock::lock(executor& p_current) | executor::lock::lock(executor& p_current) | ||||
| { executor::local_storage().current = &p_current; } | |||||
| { | |||||
| auto& current = executor::local_storage().current; | |||||
| if (current) | |||||
| throw cppcore::invalid_operation_exception("Current executor is already assigned!"); | |||||
| current = &p_current; | |||||
| } | |||||
| executor::lock::~lock() | executor::lock::~lock() | ||||
| { executor::local_storage().current = nullptr; } | { executor::local_storage().current = nullptr; } | ||||
| @@ -1,13 +1,8 @@ | |||||
| #pragma once | #pragma once | ||||
| #define asyncpp_timing | |||||
| #define ASYNCPP_FEATURE_TIMING_ENABLED | |||||
| #include "timing/delay.h" | #include "timing/delay.h" | ||||
| #include "timing/interval.h" | #include "timing/interval.h" | ||||
| #include "timing/timeout.h" | #include "timing/timeout.h" | ||||
| #include "timing/timer.h" | #include "timing/timer.h" | ||||
| #include "timing/delay.inl" | |||||
| #include "timing/interval.inl" | |||||
| #include "timing/timeout.inl" | |||||
| #include "timing/timer.inl" | |||||
| @@ -1,64 +1,5 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <asyncpp/core/misc.h> | |||||
| #include <asyncpp/core/future/future.h> | |||||
| #include "delay/delay.h" | |||||
| #include "timer.h" | |||||
| #include "delay.pre.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| struct delay final | |||||
| : public base_future<void, delay> | |||||
| { | |||||
| public: | |||||
| using value_type = void; | |||||
| using base_future_type = base_future<void, delay>; | |||||
| using result_type = typename base_future_type::result_type; | |||||
| private: | |||||
| time_point _deadline; | |||||
| __impl::registration_ptr_w _registration; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. Create a delay at the given deadline. | |||||
| */ | |||||
| inline delay(const time_point& p_deadline); | |||||
| /** | |||||
| * @brief Constructor. Create a delay with the given duration. | |||||
| */ | |||||
| template<typename T_base, typename T_ratio> | |||||
| inline delay(const duration<T_base, T_ratio>& p_duration); | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| inline ~delay(); | |||||
| /** | |||||
| * @brief Get the current deadline of the delay. | |||||
| */ | |||||
| inline time_point deadline() const; | |||||
| /** | |||||
| * @brief Reset the delay to a new time point. | |||||
| */ | |||||
| inline void reset(const time_point& p_deadline); | |||||
| /** | |||||
| * @brief Reset the delay to the given duration. | |||||
| */ | |||||
| template<typename T_base, typename T_ratio> | |||||
| inline void reset(const duration<T_base, T_ratio>& p_duration); | |||||
| public: /* future */ | |||||
| /** | |||||
| * @brief Poll the result from the future. | |||||
| */ | |||||
| inline result_type poll(); | |||||
| }; | |||||
| } } | |||||
| #include "delay/delay.inl" | |||||
| @@ -0,0 +1,65 @@ | |||||
| #pragma once | |||||
| #include <asyncpp/core/misc.h> | |||||
| #include <asyncpp/core/future/future.h> | |||||
| #include "delay.pre.h" | |||||
| #include "../timer/timer.h" | |||||
| #include "../timer/resource.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| struct delay final | |||||
| : public base_future<void, delay> | |||||
| { | |||||
| public: | |||||
| using value_type = void; | |||||
| using base_future_type = base_future<void, delay>; | |||||
| using result_type = typename base_future_type::result_type; | |||||
| private: | |||||
| time_point _deadline; | |||||
| __impl::resource_ptr_w _resource; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. Create a delay at the given deadline. | |||||
| */ | |||||
| inline delay(const time_point& p_deadline); | |||||
| /** | |||||
| * @brief Constructor. Create a delay with the given duration. | |||||
| */ | |||||
| template<typename T_base, typename T_ratio> | |||||
| inline delay(const duration<T_base, T_ratio>& p_duration); | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| inline ~delay(); | |||||
| /** | |||||
| * @brief Get the current deadline of the delay. | |||||
| */ | |||||
| inline time_point deadline() const; | |||||
| /** | |||||
| * @brief Reset the delay to a new time point. | |||||
| */ | |||||
| inline void reset(const time_point& p_deadline); | |||||
| /** | |||||
| * @brief Reset the delay to the given duration. | |||||
| */ | |||||
| template<typename T_base, typename T_ratio> | |||||
| inline void reset(const duration<T_base, T_ratio>& p_duration); | |||||
| public: /* future */ | |||||
| /** | |||||
| * @brief Poll the result from the future. | |||||
| */ | |||||
| inline result_type poll(); | |||||
| }; | |||||
| } } | |||||
| @@ -5,7 +5,7 @@ | |||||
| #include "delay.h" | #include "delay.h" | ||||
| #include "timer.inl" | |||||
| #include "../timer/timer_base.inl" | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace timing { | namespace timing { | ||||
| @@ -13,32 +13,32 @@ namespace timing { | |||||
| /* delay */ | /* delay */ | ||||
| delay::delay(const time_point& p_deadline) | delay::delay(const time_point& p_deadline) | ||||
| : _deadline (p_deadline) | |||||
| , _registration () | |||||
| : _deadline (p_deadline) | |||||
| , _resource () | |||||
| { } | { } | ||||
| template<typename T_base, typename T_ratio> | template<typename T_base, typename T_ratio> | ||||
| delay::delay(const duration<T_base, T_ratio>& p_duration) | delay::delay(const duration<T_base, T_ratio>& p_duration) | ||||
| : _deadline (asyncpp::now() + p_duration) | |||||
| , _registration () | |||||
| : _deadline (asyncpp::now() + p_duration) | |||||
| , _resource () | |||||
| { } | { } | ||||
| inline delay::~delay() | inline delay::~delay() | ||||
| { __impl::timer_base::unregister_resource(_registration); } | |||||
| { __impl::timer_base::unregister_resource(_resource); } | |||||
| time_point delay::deadline() const | time_point delay::deadline() const | ||||
| { return _deadline; } | { return _deadline; } | ||||
| void delay::reset(const time_point& p_deadline) | void delay::reset(const time_point& p_deadline) | ||||
| { | { | ||||
| __impl::timer_base::unregister_resource(_registration); | |||||
| __impl::timer_base::unregister_resource(_resource); | |||||
| _deadline = p_deadline; | _deadline = p_deadline; | ||||
| } | } | ||||
| template<typename T_base, typename T_ratio> | template<typename T_base, typename T_ratio> | ||||
| void delay::reset(const duration<T_base, T_ratio>& p_duration) | void delay::reset(const duration<T_base, T_ratio>& p_duration) | ||||
| { | { | ||||
| __impl::timer_base::unregister_resource(_registration); | |||||
| __impl::timer_base::unregister_resource(_resource); | |||||
| _deadline = asyncpp::now() + p_duration; | _deadline = asyncpp::now() + p_duration; | ||||
| } | } | ||||
| @@ -51,8 +51,8 @@ namespace timing { | |||||
| if (_deadline <= now) | if (_deadline <= now) | ||||
| return result_type::ready(); | return result_type::ready(); | ||||
| if (_registration.expired()) | |||||
| _registration = timing::__impl::timer_base::register_resource(_deadline); | |||||
| if (_resource.expired()) | |||||
| _resource = timing::__impl::timer_base::register_resource(_deadline); | |||||
| return result_type::not_ready(); | return result_type::not_ready(); | ||||
| } | } | ||||
| @@ -1,88 +0,0 @@ | |||||
| #pragma once | |||||
| #include <set> | |||||
| #include <memory> | |||||
| #include <cppcore/synchronization/locked.h> | |||||
| #include <asyncpp/core/misc.h> | |||||
| #include "timer_base.pre.h" | |||||
| #include "registration.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| namespace __impl { | |||||
| struct timer_base | |||||
| { | |||||
| private: | |||||
| struct registration_less_compare | |||||
| { | |||||
| constexpr bool operator()( | |||||
| const registration_ptr_s& lhs, | |||||
| const registration_ptr_s& rhs) const; | |||||
| }; | |||||
| using registration_set = std::set<registration_ptr_s, registration_less_compare>; | |||||
| protected: | |||||
| cppcore::locked<registration_set> _registrations; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline ~timer_base(); | |||||
| public: | |||||
| /** | |||||
| * @brief Get the number of resources assigned to this timer_base. | |||||
| */ | |||||
| inline size_t resource_count() const; | |||||
| /** | |||||
| * @brief Set the thread local current timer_base. | |||||
| */ | |||||
| inline void make_current(); | |||||
| /** | |||||
| * @brief Set the thread local current timer_base. | |||||
| */ | |||||
| inline void clear_current(); | |||||
| public: | |||||
| /** | |||||
| * @brief Get the thread local timer_base instance. | |||||
| */ | |||||
| static inline timer_base* current(); | |||||
| /** | |||||
| * @brief Register a new resource within this timer_base. | |||||
| */ | |||||
| static inline registration_ptr_w register_resource(const time_point& p_deadline); | |||||
| /** | |||||
| * @brief Register a new resource within this timer_base. | |||||
| */ | |||||
| static inline void unregister_resource(registration_ptr_w& p_value); | |||||
| private: | |||||
| /** | |||||
| * @brief Create registration for a new resource. | |||||
| */ | |||||
| registration_ptr_w create_registration(const time_point& p_deadline); | |||||
| protected: | |||||
| struct storage | |||||
| { | |||||
| timer_base* current { nullptr }; | |||||
| }; | |||||
| /** | |||||
| * @brief Get the thread local storage. | |||||
| */ | |||||
| static inline storage& local_storage(); | |||||
| }; | |||||
| } } } | |||||
| @@ -1,91 +0,0 @@ | |||||
| #pragma once | |||||
| #include "timer_base.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| namespace __impl { | |||||
| /* timer_base::inner_less_compare */ | |||||
| constexpr bool timer_base::registration_less_compare::operator()( | |||||
| const registration_ptr_s& lhs, | |||||
| const registration_ptr_s& rhs) const | |||||
| { | |||||
| return (lhs->deadline < rhs->deadline) | |||||
| ? true | |||||
| : | |||||
| (lhs->deadline == rhs->deadline) | |||||
| && (lhs.get() < rhs.get()) | |||||
| ? true | |||||
| : false; | |||||
| } | |||||
| /* timer_base */ | |||||
| timer_base::~timer_base() | |||||
| { | |||||
| auto& s = local_storage(); | |||||
| if (s.current == this) | |||||
| s.current = nullptr; | |||||
| } | |||||
| size_t timer_base::resource_count() const | |||||
| { return _registrations.lock()->size(); } | |||||
| void timer_base::make_current() | |||||
| { | |||||
| auto& s = local_storage(); | |||||
| if (s.current) | |||||
| throw std::runtime_error("Thread local timer_base instance is already assigned!"); | |||||
| s.current = this; | |||||
| } | |||||
| void timer_base::clear_current() | |||||
| { | |||||
| auto& s = local_storage(); | |||||
| if (s.current && s.current != this) | |||||
| throw std::runtime_error("Thread local timer_base instance is not assigned to this instance!"); | |||||
| s.current = nullptr; | |||||
| } | |||||
| timer_base* timer_base::current() | |||||
| { return local_storage().current; } | |||||
| registration_ptr_w timer_base::register_resource(const time_point& p_deadline) | |||||
| { | |||||
| auto t = current(); | |||||
| if (!t) | |||||
| throw std::runtime_error("Thread local timer_base instance is not assigned!"); | |||||
| return t->create_registration(p_deadline); | |||||
| } | |||||
| registration_ptr_w timer_base::create_registration(const time_point& p_deadline) | |||||
| { | |||||
| auto r = std::make_shared<registration>( | |||||
| *this, | |||||
| p_deadline, | |||||
| task::current()); | |||||
| _registrations.lock()->insert(r); | |||||
| return r; | |||||
| } | |||||
| void timer_base::unregister_resource(registration_ptr_w& p_value) | |||||
| { | |||||
| auto s = p_value.lock(); | |||||
| p_value.reset(); | |||||
| if (s) | |||||
| s->owner._registrations.lock()->erase(s); | |||||
| } | |||||
| timer_base::storage& timer_base::local_storage() | |||||
| { | |||||
| thread_local storage value; | |||||
| return value; | |||||
| } | |||||
| } } } | |||||
| @@ -1,80 +0,0 @@ | |||||
| #pragma once | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| template<typename T_inner = void> | |||||
| struct timer; | |||||
| namespace __impl | |||||
| { | |||||
| /* timer_impl - default */ | |||||
| template<typename T_inner> | |||||
| struct timer_impl | |||||
| { | |||||
| public: | |||||
| using inner_type = T_inner; | |||||
| using owner_type = timer<inner_type>; | |||||
| using inner_thread_lock_type = decltype(std::declval<inner_type>().init_thread()); | |||||
| struct thread_lock | |||||
| { | |||||
| inner_thread_lock_type inner_lock; | |||||
| template<typename... X_args> | |||||
| inline thread_lock(X_args&&... p_args); | |||||
| inline ~thread_lock(); | |||||
| }; | |||||
| using thread_lock_ptr_u = std::unique_ptr<thread_lock>; | |||||
| public: | |||||
| owner_type& owner; | |||||
| inner_type inner; | |||||
| public: | |||||
| template<typename... X_args> | |||||
| inline timer_impl( | |||||
| owner_type& p_owner, | |||||
| X_args&&... p_args); | |||||
| inline void idle( | |||||
| const time_point * p_deadline); | |||||
| inline thread_lock_ptr_u init_thread(); | |||||
| }; | |||||
| /* timer_impl<void> */ | |||||
| template<> | |||||
| struct timer_impl<void> | |||||
| { | |||||
| public: | |||||
| using owner_type = timer<void>; | |||||
| struct thread_lock | |||||
| { | |||||
| inline ~thread_lock(); | |||||
| }; | |||||
| using thread_lock_ptr_u = std::unique_ptr<thread_lock>; | |||||
| public: | |||||
| owner_type& owner; | |||||
| public: | |||||
| inline timer_impl( | |||||
| owner_type& p_owner); | |||||
| inline void idle( | |||||
| const time_point * p_deadline); | |||||
| inline thread_lock_ptr_u init_thread(); | |||||
| }; | |||||
| } | |||||
| } } | |||||
| @@ -1,73 +0,0 @@ | |||||
| #pragma once | |||||
| #include "timer_impl.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| namespace __impl { | |||||
| /* timer_impl::thread_lock - default */ | |||||
| template<typename T_inner> | |||||
| template<typename... X_args> | |||||
| timer_impl<T_inner>::thread_lock::thread_lock(X_args&&... p_args) | |||||
| : inner_lock(std::forward<X_args>(p_args)...) | |||||
| { } | |||||
| template<typename T_inner> | |||||
| timer_impl<T_inner>::thread_lock::~thread_lock() | |||||
| { owner_type::local_storage().current = nullptr; } | |||||
| /* timer_impl - default */ | |||||
| template<typename T_inner> | |||||
| template<typename... X_args> | |||||
| timer_impl<T_inner>::timer_impl( | |||||
| owner_type& p_owner, | |||||
| X_args&&... p_args) | |||||
| : owner(p_owner) | |||||
| , inner(std::forward<X_args>(p_args)...) | |||||
| { } | |||||
| template<typename T_inner> | |||||
| void timer_impl<T_inner>::idle(const time_point * p_deadline) | |||||
| { | |||||
| { | |||||
| auto r = owner._registrations.lock(); | |||||
| if (!r->empty()) | |||||
| { | |||||
| p_deadline = merge_deadlines(p_deadline, &(*r->begin())->deadline); | |||||
| } | |||||
| } | |||||
| inner.idle(p_deadline); | |||||
| } | |||||
| template<typename T_inner> | |||||
| typename timer_impl<T_inner>::thread_lock_ptr_u | |||||
| timer_impl<T_inner>::init_thread() | |||||
| { return std::make_unique<thread_lock>(inner.init_thread()); } | |||||
| /* timer_impl<void>::thread_lock - default */ | |||||
| timer_impl<void>::thread_lock::~thread_lock() | |||||
| { owner_type::local_storage().current = nullptr; } | |||||
| /* timer_impl<void> */ | |||||
| timer_impl<void>::timer_impl( | |||||
| owner_type& p_owner) | |||||
| : owner(p_owner) | |||||
| { } | |||||
| void timer_impl<void>::idle( | |||||
| const time_point * p_deadline) | |||||
| { } | |||||
| timer_impl<void>::thread_lock_ptr_u | |||||
| timer_impl<void>::init_thread() | |||||
| { return std::unique_ptr<thread_lock>(); } | |||||
| } } } | |||||
| @@ -1,55 +1,5 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <asyncpp/core/misc.h> | |||||
| #include <asyncpp/core/future/future.h> | |||||
| #include <asyncpp/core/stream/stream.h> | |||||
| #include "interval/interval.h" | |||||
| #include "delay.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| struct interval final | |||||
| : public base_stream<void, interval> | |||||
| { | |||||
| public: | |||||
| using value_type = void; | |||||
| using base_stream_type = base_stream<void, delay>; | |||||
| using result_type = typename base_stream_type::result_type; | |||||
| private: | |||||
| delay _delay; //!< Delay future | |||||
| clock::duration _duration; //!< Interval duration. | |||||
| time_point _deadline; //!< Deadline after the interval should end. | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| template<typename T_base, typename T_ratio> | |||||
| inline interval( | |||||
| const duration<T_base, T_ratio>& p_duration, | |||||
| time_point p_deadline = time_point()); | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| template<typename T_base, typename T_ratio> | |||||
| inline interval( | |||||
| const time_point& p_at, | |||||
| const duration<T_base, T_ratio>& p_duration, | |||||
| time_point p_deadline = time_point()); | |||||
| /** | |||||
| * @brief Get the duration of the interval. | |||||
| */ | |||||
| inline const clock::duration& duration() const; | |||||
| public: /* stream */ | |||||
| /** | |||||
| * @brief Poll the result from the stream. | |||||
| */ | |||||
| inline result_type poll(); | |||||
| }; | |||||
| } } | |||||
| #include "interval/interval.inl" | |||||
| @@ -0,0 +1,55 @@ | |||||
| #pragma once | |||||
| #include <asyncpp/core/misc.h> | |||||
| #include <asyncpp/core/future/future.h> | |||||
| #include <asyncpp/core/stream/stream.h> | |||||
| #include "../delay/delay.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| struct interval final | |||||
| : public base_stream<void, interval> | |||||
| { | |||||
| public: | |||||
| using value_type = void; | |||||
| using base_stream_type = base_stream<void, delay>; | |||||
| using result_type = typename base_stream_type::result_type; | |||||
| private: | |||||
| delay _delay; //!< Delay future | |||||
| clock::duration _duration; //!< Interval duration. | |||||
| time_point _deadline; //!< Deadline after the interval should end. | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| template<typename T_base, typename T_ratio> | |||||
| inline interval( | |||||
| const duration<T_base, T_ratio>& p_duration, | |||||
| time_point p_deadline = time_point()); | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| template<typename T_base, typename T_ratio> | |||||
| inline interval( | |||||
| const time_point& p_at, | |||||
| const duration<T_base, T_ratio>& p_duration, | |||||
| time_point p_deadline = time_point()); | |||||
| /** | |||||
| * @brief Get the duration of the interval. | |||||
| */ | |||||
| inline const clock::duration& duration() const; | |||||
| public: /* stream */ | |||||
| /** | |||||
| * @brief Poll the result from the stream. | |||||
| */ | |||||
| inline result_type poll(); | |||||
| }; | |||||
| } } | |||||
| @@ -2,7 +2,7 @@ | |||||
| #include "interval.h" | #include "interval.h" | ||||
| #include "delay.inl" | |||||
| #include "../delay/delay.inl" | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace timing { | namespace timing { | ||||
| @@ -1,103 +1,9 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cppcore/misc/exception.h> | |||||
| #include "timeout/misc.h" | |||||
| #include "timeout/timeout_future.h" | |||||
| #include "timeout/timeout_stream.h" | |||||
| #include <asyncpp/core/misc.h> | |||||
| #include <asyncpp/core/future/future.h> | |||||
| #include <asyncpp/core/stream/stream.h> | |||||
| #include "delay.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| struct timeout_exception | |||||
| : public cppcore::exception | |||||
| { | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline timeout_exception(); | |||||
| }; | |||||
| template<typename T_inner> | |||||
| struct timeout; | |||||
| namespace __impl | |||||
| { | |||||
| template< | |||||
| typename T_derived, | |||||
| typename = void> | |||||
| struct timeout_impl; | |||||
| template< | |||||
| typename T_inner> | |||||
| struct timeout_impl< | |||||
| timeout<T_inner>, | |||||
| std::enable_if_t<is_future_v<std::decay_t<T_inner>>>> | |||||
| : public base_future< | |||||
| typename std::decay_t<T_inner>::value_type, | |||||
| timeout<T_inner>> | |||||
| { | |||||
| private: | |||||
| using derived_type = timeout<T_inner>; | |||||
| public: | |||||
| auto poll(); | |||||
| }; | |||||
| template< | |||||
| typename T_inner> | |||||
| struct timeout_impl< | |||||
| timeout<T_inner>, | |||||
| std::enable_if_t<is_stream_v<std::decay_t<T_inner>>>> | |||||
| : public base_stream< | |||||
| typename std::decay_t<T_inner>::value_type, | |||||
| timeout<T_inner>> | |||||
| { | |||||
| private: | |||||
| using derived_type = timeout<T_inner>; | |||||
| public: | |||||
| auto poll(); | |||||
| }; | |||||
| } | |||||
| template<typename T_inner> | |||||
| struct timeout final | |||||
| : public __impl::timeout_impl<timeout<T_inner>> | |||||
| { | |||||
| public: | |||||
| using inner_type = T_inner; | |||||
| using value_type = typename std::decay_t<inner_type>::value_type; | |||||
| using this_type = timeout<inner_type>; | |||||
| using impl_type = __impl::timeout_impl<this_type>; | |||||
| friend impl_type; | |||||
| private: | |||||
| inner_type _inner; //!< Inner future / stream. | |||||
| clock::duration _timeout; //!< Timeout. | |||||
| delay _delay; //!< Delay future. | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| template<typename X_inner, typename X_base, typename X_ratio> | |||||
| inline timeout( | |||||
| X_inner&& p_inner, | |||||
| const duration<X_base, X_ratio>& p_timeout); | |||||
| /** | |||||
| * @brief Reset the deadline. | |||||
| */ | |||||
| template<typename X_base, typename X_ratio> | |||||
| inline void reset( | |||||
| const duration<X_base, X_ratio>& p_timeout); | |||||
| }; | |||||
| } } | |||||
| #include "timeout/misc.inl" | |||||
| #include "timeout/timeout_future.inl" | |||||
| #include "timeout/timeout_stream.inl" | |||||
| @@ -1,96 +0,0 @@ | |||||
| #pragma once | |||||
| #include "timeout.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| namespace __impl | |||||
| { | |||||
| template< | |||||
| typename T_inner> | |||||
| auto timeout_impl< | |||||
| timeout<T_inner>, | |||||
| std::enable_if_t<is_future_v<std::decay_t<T_inner>>>> | |||||
| ::poll() | |||||
| { | |||||
| auto& self = static_cast<derived_type&>(*this); | |||||
| auto r = self._inner.poll(); | |||||
| if ( r.is_not_ready() | |||||
| && self._delay.poll()) | |||||
| { | |||||
| auto new_deadline = self._delay.deadline() + self._timeout; | |||||
| self._delay.reset(new_deadline); | |||||
| throw timing::timeout_exception(); | |||||
| } | |||||
| return r; | |||||
| } | |||||
| template< | |||||
| typename T_inner> | |||||
| auto timeout_impl< | |||||
| timeout<T_inner>, | |||||
| std::enable_if_t<is_stream_v<std::decay_t<T_inner>>>> | |||||
| ::poll() | |||||
| { | |||||
| auto& self = static_cast<derived_type&>(*this); | |||||
| auto r = self._inner.poll(); | |||||
| if (r.is_not_ready()) | |||||
| { | |||||
| if (self._delay.poll()) | |||||
| { | |||||
| self._delay.reset(self._timeout); | |||||
| throw timing::timeout_exception(); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| self._delay.reset(self._timeout); | |||||
| } | |||||
| return r; | |||||
| } | |||||
| } | |||||
| /* timeout_exception */ | |||||
| timeout_exception::timeout_exception() | |||||
| : cppcore::exception::exception("timeout") | |||||
| { } | |||||
| /* timer */ | |||||
| template< | |||||
| typename T_inner> | |||||
| template< | |||||
| typename X_inner, | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| timeout<T_inner> | |||||
| ::timeout( | |||||
| X_inner&& p_inner, | |||||
| const duration<X_base, X_ratio>& p_duration) | |||||
| : _inner (std::forward<X_inner>(p_inner)) | |||||
| , _timeout (p_duration) | |||||
| , _delay (asyncpp::now() + p_duration) | |||||
| { } | |||||
| template< | |||||
| typename T_inner> | |||||
| template< | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| void timeout<T_inner> | |||||
| ::reset(const duration<X_base, X_ratio>& p_duration) | |||||
| { | |||||
| _timeout = p_duration; | |||||
| _delay.reset(asyncpp::now() + p_duration); | |||||
| } | |||||
| } } | |||||
| @@ -0,0 +1,18 @@ | |||||
| #pragma once | |||||
| #include <cppcore/misc/exception.h> | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| struct timeout_exception | |||||
| : public cppcore::exception | |||||
| { | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline timeout_exception(); | |||||
| }; | |||||
| } } | |||||
| @@ -0,0 +1,14 @@ | |||||
| #pragma once | |||||
| #include "misc.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| /* timeout_exception */ | |||||
| timeout_exception::timeout_exception() | |||||
| : cppcore::exception::exception("timeout") | |||||
| { } | |||||
| } } | |||||
| @@ -0,0 +1,50 @@ | |||||
| #pragma once | |||||
| #include <asyncpp/core/future/future.h> | |||||
| #include "../delay/delay.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| template<typename T_inner> | |||||
| struct timeout_future final | |||||
| : public base_future< | |||||
| typename std::decay_t<T_inner>::value_type, | |||||
| timeout_future<T_inner>> | |||||
| { | |||||
| public: | |||||
| using inner_type = T_inner; | |||||
| using value_type = typename std::decay_t<inner_type>::value_type; | |||||
| using this_type = timeout_future<inner_type>; | |||||
| using base_future_type = base_future<value_type, this_type>; | |||||
| using result_type = typename base_future_type::result_type; | |||||
| private: | |||||
| inner_type _inner; //!< Inner future. | |||||
| clock::duration _timeout; //!< Timeout. | |||||
| delay _delay; //!< Delay future. | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| template<typename X_inner, typename X_base, typename X_ratio> | |||||
| inline timeout_future( | |||||
| X_inner&& p_inner, | |||||
| const duration<X_base, X_ratio>& p_timeout); | |||||
| /** | |||||
| * @brief Reset the deadline. | |||||
| */ | |||||
| template<typename X_base, typename X_ratio> | |||||
| inline void reset( | |||||
| const duration<X_base, X_ratio>& p_timeout); | |||||
| /** | |||||
| * @brief Poll the result from the future. | |||||
| */ | |||||
| inline result_type poll(); | |||||
| }; | |||||
| } } | |||||
| @@ -0,0 +1,55 @@ | |||||
| #pragma once | |||||
| #include "timeout_future.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| /* timeout_future */ | |||||
| template< | |||||
| typename T_inner> | |||||
| template< | |||||
| typename X_inner, | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| timeout_future<T_inner>::timeout_future( | |||||
| X_inner&& p_inner, | |||||
| const duration<X_base, X_ratio>& p_timeout) | |||||
| : _inner (std::forward<X_inner>(p_inner)) | |||||
| , _timeout (p_timeout) | |||||
| , _delay (asyncpp::now() + p_timeout) | |||||
| { } | |||||
| template< | |||||
| typename T_inner> | |||||
| template< | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| void timeout_future<T_inner> | |||||
| ::reset(const duration<X_base, X_ratio>& p_timeout) | |||||
| { | |||||
| _timeout = p_timeout; | |||||
| _delay.reset(_timeout); | |||||
| } | |||||
| template< | |||||
| typename T_inner> | |||||
| typename timeout_future<T_inner>::result_type | |||||
| timeout_future<T_inner> | |||||
| ::poll() | |||||
| { | |||||
| auto r = _inner.poll(); | |||||
| if ( r.is_not_ready() | |||||
| && _delay.poll()) | |||||
| { | |||||
| auto new_deadline = _delay.deadline() + _timeout; | |||||
| _delay.reset(new_deadline); | |||||
| throw timing::timeout_exception(); | |||||
| } | |||||
| return r; | |||||
| } | |||||
| } } | |||||
| @@ -0,0 +1,50 @@ | |||||
| #pragma once | |||||
| #include <asyncpp/core/stream/stream.h> | |||||
| #include "../delay/delay.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| template<typename T_inner> | |||||
| struct timeout_stream final | |||||
| : public base_stream< | |||||
| typename std::decay_t<T_inner>::value_type, | |||||
| timeout_stream<T_inner>> | |||||
| { | |||||
| public: | |||||
| using inner_type = T_inner; | |||||
| using value_type = typename std::decay_t<inner_type>::value_type; | |||||
| using this_type = timeout_stream<inner_type>; | |||||
| using base_stream_type = base_stream<value_type, this_type>; | |||||
| using result_type = typename base_stream_type::result_type; | |||||
| private: | |||||
| inner_type _inner; //!< Inner stream. | |||||
| clock::duration _timeout; //!< Timeout. | |||||
| delay _delay; //!< Delay stream. | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| template<typename X_inner, typename X_base, typename X_ratio> | |||||
| inline timeout_stream( | |||||
| X_inner&& p_inner, | |||||
| const duration<X_base, X_ratio>& p_timeout); | |||||
| /** | |||||
| * @brief Reset the deadline. | |||||
| */ | |||||
| template<typename X_base, typename X_ratio> | |||||
| inline void reset( | |||||
| const duration<X_base, X_ratio>& p_timeout); | |||||
| /** | |||||
| * @brief Poll the result from the future. | |||||
| */ | |||||
| inline result_type poll(); | |||||
| }; | |||||
| } } | |||||
| @@ -0,0 +1,60 @@ | |||||
| #pragma once | |||||
| #include "timeout_stream.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| /* timeout_stream */ | |||||
| template< | |||||
| typename T_inner> | |||||
| template< | |||||
| typename X_inner, | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| timeout_stream<T_inner>::timeout_stream( | |||||
| X_inner&& p_inner, | |||||
| const duration<X_base, X_ratio>& p_timeout) | |||||
| : _inner (std::forward<X_inner>(p_inner)) | |||||
| , _timeout (p_timeout) | |||||
| , _delay (asyncpp::now() + p_timeout) | |||||
| { } | |||||
| template< | |||||
| typename T_inner> | |||||
| template< | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| void timeout_stream<T_inner> | |||||
| ::reset(const duration<X_base, X_ratio>& p_timeout) | |||||
| { | |||||
| _timeout = p_timeout; | |||||
| _delay.reset(_timeout); | |||||
| } | |||||
| template< | |||||
| typename T_inner> | |||||
| typename timeout_stream<T_inner>::result_type | |||||
| timeout_stream<T_inner> | |||||
| ::poll() | |||||
| { | |||||
| auto r = _inner.poll(); | |||||
| if (r.is_not_ready()) | |||||
| { | |||||
| if (_delay.poll()) | |||||
| { | |||||
| _delay.reset(_timeout); | |||||
| throw timing::timeout_exception(); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| _delay.reset(_timeout); | |||||
| } | |||||
| return r; | |||||
| } | |||||
| } } | |||||
| @@ -1,50 +1,11 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <set> | |||||
| #include <memory> | |||||
| #include <cppcore/synchronization/locked.h> | |||||
| #include "impl/timer_base.h" | |||||
| #include "impl/timer_impl.h" | |||||
| #include "impl/registration.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| template<typename T_inner> | |||||
| struct timer | |||||
| : public __impl::timer_base | |||||
| { | |||||
| public: | |||||
| template<typename X> | |||||
| friend struct __impl::timer_impl; | |||||
| using inner_type = T_inner; | |||||
| using timer_impl_type = __impl::timer_impl<inner_type>; | |||||
| private: | |||||
| timer_impl_type _impl; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| template<typename... X_args> | |||||
| inline timer(X_args&&... p_args); | |||||
| /** | |||||
| * @brief Handle idle of the runtime. | |||||
| * | |||||
| * This method is called as soon as the runtime has nothing to do. | |||||
| * The passed deadline is the timepoint the method should return (or null if not set). | |||||
| */ | |||||
| inline void idle(const time_point * p_deadline); | |||||
| /** | |||||
| * @brief This method is calld by the executor when a new thread needs to be initialized. | |||||
| */ | |||||
| inline decltype(auto) init_thread(); | |||||
| }; | |||||
| } } | |||||
| #include "timer/timer.h" | |||||
| #include "timer/timer_base.h" | |||||
| #include "timer/timer_impl.h" | |||||
| #include "timer/resource.h" | |||||
| #include "timer/timer.inl" | |||||
| #include "timer/timer_base.inl" | |||||
| #include "timer/timer_impl.inl" | |||||
| #include "timer/resource.inl" | |||||
| @@ -11,7 +11,7 @@ namespace asyncpp { | |||||
| namespace timing { | namespace timing { | ||||
| namespace __impl { | namespace __impl { | ||||
| struct registration | |||||
| struct resource | |||||
| { | { | ||||
| public: | public: | ||||
| timer_base& owner; | timer_base& owner; | ||||
| @@ -21,13 +21,13 @@ namespace __impl { | |||||
| /** | /** | ||||
| * @brief Constructor. | * @brief Constructor. | ||||
| */ | */ | ||||
| inline registration( | |||||
| inline resource( | |||||
| timer_base& p_owner, | timer_base& p_owner, | ||||
| const time_point& p_deadline, | const time_point& p_deadline, | ||||
| const asyncpp::task& p_task); | const asyncpp::task& p_task); | ||||
| }; | }; | ||||
| using registration_ptr_w = std::weak_ptr<registration>; | |||||
| using registration_ptr_s = std::shared_ptr<registration>; | |||||
| using resource_ptr_w = std::weak_ptr<resource>; | |||||
| using resource_ptr_s = std::shared_ptr<resource>; | |||||
| } } } | } } } | ||||
| @@ -1,14 +1,14 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "registration.h" | |||||
| #include "resource.h" | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace timing { | namespace timing { | ||||
| namespace __impl { | namespace __impl { | ||||
| /* registration */ | |||||
| /* resource */ | |||||
| registration::registration( | |||||
| resource::resource( | |||||
| timer_base& p_owner, | timer_base& p_owner, | ||||
| const time_point& p_deadline, | const time_point& p_deadline, | ||||
| const asyncpp::task& p_task) | const asyncpp::task& p_task) | ||||
| @@ -0,0 +1,44 @@ | |||||
| #pragma once | |||||
| #include <set> | |||||
| #include <memory> | |||||
| #include <cppcore/synchronization/locked.h> | |||||
| #include "timer_impl.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| template<typename T_inner = void> | |||||
| struct timer | |||||
| : public __impl::timer_impl<T_inner> | |||||
| { | |||||
| public: | |||||
| using base_type = __impl::timer_impl<T_inner>; | |||||
| using inner_type = T_inner; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| template<typename... X_args> | |||||
| inline timer(X_args&&... p_args); | |||||
| /** | |||||
| * @brief Handle idle of the runtime. | |||||
| * | |||||
| * This method is called as soon as the runtime has nothing to do. | |||||
| * The passed deadline is the timepoint the method should return (or null if not set). | |||||
| */ | |||||
| inline void idle(const time_point * p_deadline); | |||||
| /** | |||||
| * @brief This method is calld by the executor when a new thread needs to be initialized. | |||||
| * | |||||
| * @return Object to hold as long as the thread is active on this timer. | |||||
| */ | |||||
| inline auto init_thread(); | |||||
| }; | |||||
| } } | |||||
| @@ -1,11 +1,8 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "timer.h" | #include "timer.h" | ||||
| #include "delay.inl" | |||||
| #include "impl/timer_base.inl" | |||||
| #include "impl/timer_impl.inl" | |||||
| #include "impl/registration.inl" | |||||
| #include "timer_impl.inl" | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace timing { | namespace timing { | ||||
| @@ -15,7 +12,7 @@ namespace timing { | |||||
| template<typename T_inner> | template<typename T_inner> | ||||
| template<typename... X_args> | template<typename... X_args> | ||||
| timer<T_inner>::timer(X_args&&... p_args) | timer<T_inner>::timer(X_args&&... p_args) | ||||
| : _impl(*this, std::forward<X_args>(p_args)...) | |||||
| : base_type(std::forward<X_args>(p_args)...) | |||||
| { } | { } | ||||
| template<typename T_inner> | template<typename T_inner> | ||||
| @@ -24,7 +21,7 @@ namespace timing { | |||||
| auto now = asyncpp::now(); | auto now = asyncpp::now(); | ||||
| { | { | ||||
| auto r = _registrations.lock(); | |||||
| auto r = this->_resources.lock(); | |||||
| auto it = r->begin(); | auto it = r->begin(); | ||||
| while (it != r->end() && now >= (**it).deadline) | while (it != r->end() && now >= (**it).deadline) | ||||
| { | { | ||||
| @@ -33,14 +30,11 @@ namespace timing { | |||||
| } | } | ||||
| } | } | ||||
| _impl.idle(p_deadline); | |||||
| base_type::idle_impl(p_deadline); | |||||
| } | } | ||||
| template<typename T_inner> | template<typename T_inner> | ||||
| decltype(auto) timer<T_inner>::init_thread() | |||||
| { | |||||
| local_storage().current = this; | |||||
| return _impl.init_thread(); | |||||
| } | |||||
| auto timer<T_inner>::init_thread() | |||||
| { return base_type::init_thread_impl(); } | |||||
| } } | } } | ||||
| @@ -0,0 +1,87 @@ | |||||
| #pragma once | |||||
| #include <set> | |||||
| #include <memory> | |||||
| #include <cppcore/synchronization/locked.h> | |||||
| #include <asyncpp/core/misc.h> | |||||
| #include "timer_base.pre.h" | |||||
| #include "resource.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| namespace __impl { | |||||
| struct timer_base | |||||
| { | |||||
| private: | |||||
| struct resource_less_compare | |||||
| { | |||||
| constexpr bool operator()( | |||||
| const resource_ptr_s& lhs, | |||||
| const resource_ptr_s& rhs) const; | |||||
| }; | |||||
| using resource_set = std::set<resource_ptr_s, resource_less_compare>; | |||||
| protected: | |||||
| cppcore::locked<resource_set> _resources; | |||||
| public: | |||||
| /** | |||||
| * @brief Get the number of registered timing resources. | |||||
| */ | |||||
| inline size_t resource_count(); | |||||
| public: | |||||
| /** | |||||
| * @brief Get the thread local timer_base instance. | |||||
| */ | |||||
| static inline timer_base* current(); | |||||
| /** | |||||
| * @brief Register a new resource within this timer_base. | |||||
| */ | |||||
| static inline resource_ptr_w register_resource(const time_point& p_deadline); | |||||
| /** | |||||
| * @brief Register a new resource within this timer_base. | |||||
| */ | |||||
| static inline void unregister_resource(resource_ptr_w& p_value); | |||||
| private: | |||||
| /** | |||||
| * @brief Create resource for a new resource. | |||||
| */ | |||||
| resource_ptr_w create_resource(const time_point& p_deadline); | |||||
| public: | |||||
| struct lock | |||||
| { | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline lock(timer_base& p_timer); | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| inline ~lock(); | |||||
| }; | |||||
| private: | |||||
| struct storage | |||||
| { | |||||
| timer_base* current { nullptr }; | |||||
| }; | |||||
| /** | |||||
| * @brief Get the thread local storage. | |||||
| */ | |||||
| static inline storage& local_storage(); | |||||
| }; | |||||
| } } } | |||||
| @@ -0,0 +1,83 @@ | |||||
| #pragma once | |||||
| #include <cppcore/misc/exception.h> | |||||
| #include "timer_base.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| namespace __impl { | |||||
| /* timer_base::inner_less_compare */ | |||||
| constexpr bool timer_base::resource_less_compare::operator()( | |||||
| const resource_ptr_s& lhs, | |||||
| const resource_ptr_s& rhs) const | |||||
| { | |||||
| return (lhs->deadline < rhs->deadline) | |||||
| ? true | |||||
| : | |||||
| (lhs->deadline == rhs->deadline) | |||||
| && (lhs.get() < rhs.get()) | |||||
| ? true | |||||
| : false; | |||||
| } | |||||
| /* timer_base::lock */ | |||||
| timer_base::lock::lock(timer_base& p_timer) | |||||
| { | |||||
| auto& current = timer_base::local_storage().current; | |||||
| if (current) | |||||
| throw cppcore::invalid_operation_exception("Current timer is already assigned!"); | |||||
| current = &p_timer; | |||||
| } | |||||
| timer_base::lock::~lock() | |||||
| { timer_base::local_storage().current = nullptr; } | |||||
| /* timer_base */ | |||||
| size_t timer_base::resource_count() | |||||
| { return _resources.lock()->size(); } | |||||
| timer_base* timer_base::current() | |||||
| { return local_storage().current; } | |||||
| resource_ptr_w timer_base::register_resource(const time_point& p_deadline) | |||||
| { | |||||
| auto t = current(); | |||||
| if (!t) | |||||
| throw cppcore::invalid_operation_exception("Thread local timer_base instance is not assigned!"); | |||||
| return t->create_resource(p_deadline); | |||||
| } | |||||
| void timer_base::unregister_resource(resource_ptr_w& p_value) | |||||
| { | |||||
| auto s = p_value.lock(); | |||||
| p_value.reset(); | |||||
| if (s) | |||||
| s->owner._resources.lock()->erase(s); | |||||
| } | |||||
| resource_ptr_w timer_base::create_resource(const time_point& p_deadline) | |||||
| { | |||||
| auto r = std::make_shared<resource>( | |||||
| *this, | |||||
| p_deadline, | |||||
| task::current()); | |||||
| _resources.lock()->insert(r); | |||||
| return r; | |||||
| } | |||||
| timer_base::storage& timer_base::local_storage() | |||||
| { | |||||
| thread_local storage value; | |||||
| return value; | |||||
| } | |||||
| } } } | |||||
| @@ -0,0 +1,10 @@ | |||||
| #pragma once | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| namespace __impl { | |||||
| template<typename T_inner> | |||||
| struct timer_impl; | |||||
| } } } | |||||
| @@ -0,0 +1,76 @@ | |||||
| #pragma once | |||||
| #include "timer_impl.h" | |||||
| #include "timer_base.h" | |||||
| namespace asyncpp { | |||||
| namespace timing { | |||||
| namespace __impl { | |||||
| /* timer_impl - default */ | |||||
| template<typename T_inner> | |||||
| struct timer_impl | |||||
| : public timer_base | |||||
| { | |||||
| public: | |||||
| using inner_type = T_inner; | |||||
| using inner_thread_lock_type = decltype(std::declval<inner_type>().init_thread()); | |||||
| struct thread_lock | |||||
| { | |||||
| timer_base::lock timer_lock; | |||||
| inner_thread_lock_type inner_lock; | |||||
| template<typename... X_args> | |||||
| inline thread_lock(timer_base& p_timer, X_args&&... p_args) | |||||
| : timer_lock(p_timer) | |||||
| , inner_lock(std::forward<X_args>(p_args)...) | |||||
| { } | |||||
| inline thread_lock(thread_lock &&) = delete; | |||||
| inline thread_lock(thread_lock const &) = delete; | |||||
| }; | |||||
| private: | |||||
| inner_type _inner; | |||||
| public: | |||||
| template<typename X_inner> | |||||
| inline timer_impl(X_inner&& p_inner) | |||||
| : _inner(std::forward<X_inner>(p_inner)) | |||||
| { } | |||||
| protected: | |||||
| inline void idle_impl(const time_point * p_deadline) | |||||
| { | |||||
| { | |||||
| auto r = _resources.lock(); | |||||
| if (!r->empty()) | |||||
| { | |||||
| p_deadline = merge_deadlines(p_deadline, &(*r->begin())->deadline); | |||||
| } | |||||
| } | |||||
| _inner.idle(p_deadline); | |||||
| } | |||||
| inline auto init_thread_impl() | |||||
| { return thread_lock(*this, _inner.init_thread()); } | |||||
| }; | |||||
| /* timer_impl - void */ | |||||
| template<> | |||||
| struct timer_impl<void> | |||||
| : public timer_base | |||||
| { | |||||
| protected: | |||||
| inline void idle_impl(const time_point * p_deadline) | |||||
| { } | |||||
| inline auto init_thread_impl() | |||||
| { return timer_base::lock(*this); } | |||||
| }; | |||||
| } } } | |||||
| @@ -9,11 +9,15 @@ Find_Package ( cppcore REQUIRED ) | |||||
| # Interface Library ############################################################################### | # Interface Library ############################################################################### | ||||
| Set ( ASYNCPP_GENERATED_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated ) | |||||
| Configure_File ( ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/config.h.in | |||||
| ${ASYNCPP_GENERATED_INCLUDE_DIR}/asyncpp/config.h ) | |||||
| Set ( ASYNCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | Set ( ASYNCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | ||||
| Add_Library ( asyncpp INTERFACE ) | Add_Library ( asyncpp INTERFACE ) | ||||
| Target_Include_Directories ( asyncpp | Target_Include_Directories ( asyncpp | ||||
| INTERFACE | INTERFACE | ||||
| $<BUILD_INTERFACE:${ASYNCPP_INCLUDE_DIR}> | $<BUILD_INTERFACE:${ASYNCPP_INCLUDE_DIR}> | ||||
| $<BUILD_INTERFACE:${ASYNCPP_GENERATED_INCLUDE_DIR}> | |||||
| $<INSTALL_INTERFACE:${ASYNCPP_INSTALL_DIR_INCLUDE}> ) | $<INSTALL_INTERFACE:${ASYNCPP_INSTALL_DIR_INCLUDE}> ) | ||||
| Target_Link_Libraries ( asyncpp | Target_Link_Libraries ( asyncpp | ||||
| INTERFACE | INTERFACE | ||||
| @@ -31,6 +35,8 @@ If ( ASYNCPP_INSTALL_HEADER ) | |||||
| DESTINATION ${ASYNCPP_INSTALL_DIR_INCLUDE} ) | DESTINATION ${ASYNCPP_INSTALL_DIR_INCLUDE} ) | ||||
| Install ( DIRECTORY ${ASYNCPP_INCLUDE_DIR}/asyncpp | Install ( DIRECTORY ${ASYNCPP_INCLUDE_DIR}/asyncpp | ||||
| DESTINATION ${ASYNCPP_INSTALL_DIR_INCLUDE} ) | DESTINATION ${ASYNCPP_INSTALL_DIR_INCLUDE} ) | ||||
| Install ( DIRECTORY ${ASYNCPP_GENERATED_INCLUDE_DIR}/cppcore | |||||
| DESTINATION ${ASYNCPP_INSTALL_DIR_INCLUDE} ) | |||||
| Install ( TARGETS asyncpp | Install ( TARGETS asyncpp | ||||
| EXPORT asyncpp | EXPORT asyncpp | ||||
| DESTINATION ${ASYNCPP_INSTALL_DIR_INCLUDE} ) | DESTINATION ${ASYNCPP_INSTALL_DIR_INCLUDE} ) | ||||
| @@ -3,9 +3,8 @@ | |||||
| #include "../../helper/now_mock.h" | #include "../../helper/now_mock.h" | ||||
| #include "../../helper/runtime_mock.h" | #include "../../helper/runtime_mock.h" | ||||
| #include <asyncpp/timing.h> | |||||
| #include <asyncpp/executor/current_thread.h> | |||||
| #include <asyncpp.h> | #include <asyncpp.h> | ||||
| #include <asyncpp/executor/current_thread.h> | |||||
| using namespace ::testing; | using namespace ::testing; | ||||
| using namespace ::asyncpp; | using namespace ::asyncpp; | ||||
| @@ -3,7 +3,6 @@ | |||||
| #include "../../helper/now_mock.h" | #include "../../helper/now_mock.h" | ||||
| #include <asyncpp.h> | #include <asyncpp.h> | ||||
| #include <asyncpp/timing.h> | |||||
| using namespace ::testing; | using namespace ::testing; | ||||
| using namespace ::asyncpp; | using namespace ::asyncpp; | ||||
| @@ -19,7 +18,7 @@ TEST(delay_tests, poll) | |||||
| .WillOnce(Return(time_point(std::chrono::seconds(1000)))); | .WillOnce(Return(time_point(std::chrono::seconds(1000)))); | ||||
| asyncpp::timing::timer t; | asyncpp::timing::timer t; | ||||
| t.make_current(); | |||||
| timing::__impl::timer_base::lock l(t); | |||||
| { | { | ||||
| delay f(time_point(std::chrono::seconds(1000))); | delay f(time_point(std::chrono::seconds(1000))); | ||||
| @@ -3,7 +3,6 @@ | |||||
| #include "../../helper/now_mock.h" | #include "../../helper/now_mock.h" | ||||
| #include <asyncpp.h> | #include <asyncpp.h> | ||||
| #include <asyncpp/timing.h> | |||||
| using namespace ::testing; | using namespace ::testing; | ||||
| using namespace ::asyncpp; | using namespace ::asyncpp; | ||||
| @@ -23,7 +22,7 @@ TEST(interval_tests, poll) | |||||
| // 20 / 5 = 4 | // 20 / 5 = 4 | ||||
| // 4 x Ready | // 4 x Ready | ||||
| t.make_current(); | |||||
| timing::__impl::timer_base::lock l(t); | |||||
| EXPECT_CALL(m, now) | EXPECT_CALL(m, now) | ||||
| .WillOnce(Return(time_point(std::chrono::seconds(0)))); | .WillOnce(Return(time_point(std::chrono::seconds(0)))); | ||||
| @@ -2,7 +2,6 @@ | |||||
| #include "../../helper/now_mock.h" | #include "../../helper/now_mock.h" | ||||
| #include <asyncpp/timing.h> | |||||
| #include <asyncpp.h> | #include <asyncpp.h> | ||||
| using namespace ::testing; | using namespace ::testing; | ||||
| @@ -68,8 +67,8 @@ TEST(timeout_tests, poll_future_no_timeout) | |||||
| InSequence seq; | InSequence seq; | ||||
| StrictMock<now_mock> m; | StrictMock<now_mock> m; | ||||
| asyncpp::timing::timer tmr; | |||||
| tmr.make_current(); | |||||
| timing::timer tmr; | |||||
| timing::__impl::timer_base::lock l(tmr); | |||||
| EXPECT_CALL(m, now()) | EXPECT_CALL(m, now()) | ||||
| .WillOnce(Return(time_point(std::chrono::seconds(0)))); | .WillOnce(Return(time_point(std::chrono::seconds(0)))); | ||||
| @@ -101,8 +100,8 @@ TEST(timeout_tests, poll_future_timeout) | |||||
| InSequence seq; | InSequence seq; | ||||
| StrictMock<now_mock> m; | StrictMock<now_mock> m; | ||||
| asyncpp::timing::timer tmr; | |||||
| tmr.make_current(); | |||||
| timing::timer tmr; | |||||
| timing::__impl::timer_base::lock l(tmr); | |||||
| EXPECT_CALL(m, now()) | EXPECT_CALL(m, now()) | ||||
| .WillOnce(Return(time_point(std::chrono::seconds(0)))); | .WillOnce(Return(time_point(std::chrono::seconds(0)))); | ||||
| @@ -133,8 +132,8 @@ TEST(timeout_tests, poll_stream_no_timeout) | |||||
| InSequence seq; | InSequence seq; | ||||
| StrictMock<now_mock> m; | StrictMock<now_mock> m; | ||||
| asyncpp::timing::timer tmr; | |||||
| tmr.make_current(); | |||||
| timing::timer tmr; | |||||
| timing::__impl::timer_base::lock l(tmr); | |||||
| EXPECT_CALL(m, now()) | EXPECT_CALL(m, now()) | ||||
| .WillOnce(Return(time_point(std::chrono::seconds(0)))); | .WillOnce(Return(time_point(std::chrono::seconds(0)))); | ||||
| @@ -183,8 +182,8 @@ TEST(timeout_tests, poll_stream_timeout) | |||||
| InSequence seq; | InSequence seq; | ||||
| StrictMock<now_mock> m; | StrictMock<now_mock> m; | ||||
| asyncpp::timing::timer tmr; | |||||
| tmr.make_current(); | |||||
| timing::timer tmr; | |||||
| timing::__impl::timer_base::lock l(tmr); | |||||
| EXPECT_CALL(m, now()) | EXPECT_CALL(m, now()) | ||||
| .WillOnce(Return(time_point(std::chrono::seconds(0)))); | .WillOnce(Return(time_point(std::chrono::seconds(0)))); | ||||
| @@ -4,27 +4,18 @@ | |||||
| #include "../../helper/runtime_mock.h" | #include "../../helper/runtime_mock.h" | ||||
| #include <asyncpp.h> | #include <asyncpp.h> | ||||
| #include <asyncpp/timing.h> | |||||
| using namespace ::testing; | using namespace ::testing; | ||||
| using namespace ::asyncpp; | using namespace ::asyncpp; | ||||
| TEST(timer_tests, current) | |||||
| TEST(timer_tests, lock) | |||||
| { | { | ||||
| { | |||||
| timing::timer t; | timing::timer t; | ||||
| EXPECT_EQ(nullptr, timing::__impl::timer_base::current()); | EXPECT_EQ(nullptr, timing::__impl::timer_base::current()); | ||||
| t.make_current(); | |||||
| EXPECT_EQ(&t, timing::__impl::timer_base::current()); | |||||
| t.clear_current(); | |||||
| EXPECT_EQ(nullptr, timing::__impl::timer_base::current()); | |||||
| t.make_current(); | |||||
| { | |||||
| timing::__impl::timer_base::lock l(t); | |||||
| EXPECT_EQ(&t, timing::__impl::timer_base::current()); | EXPECT_EQ(&t, timing::__impl::timer_base::current()); | ||||
| } | } | ||||
| @@ -39,7 +30,7 @@ TEST(timer_tests, resource_registration) | |||||
| .WillRepeatedly(Return(time_point(std::chrono::seconds(0)))); | .WillRepeatedly(Return(time_point(std::chrono::seconds(0)))); | ||||
| timing::timer t; | timing::timer t; | ||||
| t.make_current(); | |||||
| timing::__impl::timer_base::lock l(t); | |||||
| auto f1 = std::make_unique<timing::delay>(std::chrono::seconds(10)); | auto f1 = std::make_unique<timing::delay>(std::chrono::seconds(10)); | ||||
| auto f2 = std::make_unique<timing::delay>(std::chrono::seconds(20)); | auto f2 = std::make_unique<timing::delay>(std::chrono::seconds(20)); | ||||
| @@ -83,7 +74,7 @@ TEST(timer_tests, idle) | |||||
| StrictMock<now_mock> nm; | StrictMock<now_mock> nm; | ||||
| StrictMock<runtime_mock> rm; | StrictMock<runtime_mock> rm; | ||||
| timing::timer<StrictMock<runtime_mock>&> t(rm); | timing::timer<StrictMock<runtime_mock>&> t(rm); | ||||
| t.make_current(); | |||||
| timing::__impl::timer_base::lock l(t); | |||||
| EXPECT_CALL(nm, now); | EXPECT_CALL(nm, now); | ||||
| EXPECT_CALL(rm, idle(nullptr)); | EXPECT_CALL(rm, idle(nullptr)); | ||||