| @@ -19,7 +19,8 @@ namespace timer { | |||||
| 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) | ||||
| : _timeout(clock::now() + p_duration) | |||||
| : _timeout (clock::now() + p_duration) | |||||
| , _registration (*this) | |||||
| { } | { } | ||||
| inline delay::~delay() | inline delay::~delay() | ||||
| @@ -3,6 +3,8 @@ | |||||
| #include <set> | #include <set> | ||||
| #include <memory> | #include <memory> | ||||
| #include <cppcore/synchronization/locked.h> | |||||
| #include "misc.h" | #include "misc.h" | ||||
| namespace asyncpp { | namespace asyncpp { | ||||
| @@ -48,7 +50,13 @@ namespace timer { | |||||
| using inner_set = std::set<inner_ptr_s, inner_less_compare>; | using inner_set = std::set<inner_ptr_s, inner_less_compare>; | ||||
| private: | private: | ||||
| inner_set _registrations; | |||||
| cppcore::locked<inner_set> _registrations; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| inline ~timer(); | |||||
| public: | public: | ||||
| /** | /** | ||||
| @@ -35,8 +35,15 @@ namespace timer { | |||||
| /* timer */ | /* timer */ | ||||
| timer::~timer() | |||||
| { | |||||
| auto& s = local_storage(); | |||||
| if (s.current == this) | |||||
| s.current = nullptr; | |||||
| } | |||||
| size_t timer::resource_count() const | size_t timer::resource_count() const | ||||
| { return _registrations.size(); } | |||||
| { return _registrations.lock()->size(); } | |||||
| void timer::make_current() | void timer::make_current() | ||||
| { | { | ||||
| @@ -83,13 +90,13 @@ namespace timer { | |||||
| auto s = p_value.ptr.lock(); | auto s = p_value.ptr.lock(); | ||||
| p_value.ptr.reset(); | p_value.ptr.reset(); | ||||
| if (s) | if (s) | ||||
| s->owner._registrations.erase(s); | |||||
| s->owner._registrations.lock()->erase(s); | |||||
| } | } | ||||
| inline timer::inner_ptr_s timer::make_inner(registration& p_value) | inline timer::inner_ptr_s timer::make_inner(registration& p_value) | ||||
| { | { | ||||
| auto s = std::make_shared<registration::inner>(*this, p_value.owner.timeout()); | auto s = std::make_shared<registration::inner>(*this, p_value.owner.timeout()); | ||||
| _registrations.insert(s); | |||||
| _registrations.lock()->insert(s); | |||||
| return s; | return s; | ||||
| } | } | ||||
| @@ -4,6 +4,8 @@ Include ( cotire OPTIONAL RESULT_VARIABLE HAS | |||||
| Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | ||||
| Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) | Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) | ||||
| Find_Package ( cppcore REQUIRED ) | |||||
| # Interface Library ############################################################################### | # Interface Library ############################################################################### | ||||
| Set ( ASYNCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | Set ( ASYNCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | ||||
| @@ -12,6 +14,9 @@ Target_Include_Directories ( asyncpp | |||||
| INTERFACE | INTERFACE | ||||
| $<BUILD_INTERFACE:${ASYNCPP_INCLUDE_DIR}> | $<BUILD_INTERFACE:${ASYNCPP_INCLUDE_DIR}> | ||||
| $<INSTALL_INTERFACE:${ASYNCPP_INSTALL_DIR_INCLUDE}> ) | $<INSTALL_INTERFACE:${ASYNCPP_INSTALL_DIR_INCLUDE}> ) | ||||
| Target_Link_Libraries ( asyncpp | |||||
| INTERFACE | |||||
| cppcore::cppcore ) | |||||
| # Install ######################################################################################### | # Install ######################################################################################### | ||||
| @@ -0,0 +1,78 @@ | |||||
| #include <gtest/gtest.h> | |||||
| #include "../../helper/now_mock.h" | |||||
| #include <asyncpp.h> | |||||
| #include <asyncpp/timer.h> | |||||
| using namespace ::testing; | |||||
| using namespace ::asyncpp; | |||||
| TEST(timer_tests, current) | |||||
| { | |||||
| { | |||||
| timer::timer t; | |||||
| EXPECT_EQ(nullptr, timer::timer::current()); | |||||
| t.make_current(); | |||||
| EXPECT_EQ(&t, timer::timer::current()); | |||||
| t.clear_current(); | |||||
| EXPECT_EQ(nullptr, timer::timer::current()); | |||||
| t.make_current(); | |||||
| EXPECT_EQ(&t, timer::timer::current()); | |||||
| } | |||||
| EXPECT_EQ(nullptr, timer::timer::current()); | |||||
| } | |||||
| TEST(timer_tests, resource_registration) | |||||
| { | |||||
| StrictMock<now_mock> m; | |||||
| EXPECT_CALL(m, now) | |||||
| .WillRepeatedly(Return(timer::time_point(std::chrono::seconds(0)))); | |||||
| using delay_future_type = decltype(as_future(timer::delay(std::chrono::seconds(10)))); | |||||
| timer::timer t; | |||||
| t.make_current(); | |||||
| auto f1 = std::make_unique<delay_future_type>(timer::delay(std::chrono::seconds(10))); | |||||
| auto f2 = std::make_unique<delay_future_type>(timer::delay(std::chrono::seconds(20))); | |||||
| auto f3 = std::make_unique<delay_future_type>(timer::delay(std::chrono::seconds(30))); | |||||
| EXPECT_EQ(0, t.resource_count()); | |||||
| f1->poll(); // simple add | |||||
| EXPECT_EQ(1, t.resource_count()); | |||||
| f2->poll(); // simple add | |||||
| EXPECT_EQ(2, t.resource_count()); | |||||
| f1.reset(); // remove first | |||||
| EXPECT_EQ(1, t.resource_count()); | |||||
| f3->poll(); // simple add | |||||
| EXPECT_EQ(2, t.resource_count()); | |||||
| f3->poll(); // calling twice should not add | |||||
| EXPECT_EQ(2, t.resource_count()); | |||||
| f3.reset(); // remove last | |||||
| EXPECT_EQ(1, t.resource_count()); | |||||
| f2.reset(); // remove remaining | |||||
| EXPECT_EQ(0, t.resource_count()); | |||||
| } | |||||