diff --git a/lib/include/srslte/common/timers.h b/lib/include/srslte/common/timers.h index 7f455c9de..4720d723b 100644 --- a/lib/include/srslte/common/timers.h +++ b/lib/include/srslte/common/timers.h @@ -142,7 +142,7 @@ public: class unique_timer { public: - unique_timer() : parent(nullptr), timer_id(std::numeric_limits::max()) {} + unique_timer() : timer_id(std::numeric_limits::max()) {} explicit unique_timer(timer_handler* parent_, uint32_t timer_id_) : parent(parent_), timer_id(timer_id_) {} unique_timer(const unique_timer&) = delete; @@ -154,7 +154,7 @@ public: ~unique_timer() { - if (parent) { + if (parent != nullptr) { // does not call callback impl()->clear(); } @@ -207,7 +207,7 @@ public: const timer_impl* impl() const { return &parent->timer_list[timer_id]; } - timer_handler* parent; + timer_handler* parent = nullptr; uint32_t timer_id; }; @@ -256,20 +256,7 @@ public: } } - unique_timer get_unique_timer() - { - uint32_t i = 0; - for (; i < timer_list.size(); ++i) { - if (not timer_list[i].active) { - break; - } - } - if (i == timer_list.size()) { - timer_list.emplace_back(this); - } - timer_list[i].active = true; - return unique_timer(this, i); - } + unique_timer get_unique_timer() { return unique_timer(this, alloc_timer()); } uint32_t get_cur_time() const { return cur_time; } @@ -283,6 +270,19 @@ public: return std::count_if(timer_list.begin(), timer_list.end(), [](const timer_impl& t) { return t.is_running(); }); } + template + void defer_callback(uint32_t duration, const F& func) + { + uint32_t id = alloc_timer(); + std::function c = [func, this, id](uint32_t tid) { + func(); + // auto-deletes timer + timer_list[id].clear(); + }; + timer_list[id].set(duration, std::move(c)); + timer_list[id].run(); + } + private: struct timer_run { uint32_t timer_id; @@ -300,6 +300,21 @@ private: } }; + uint32_t alloc_timer() + { + uint32_t i = 0; + for (; i < timer_list.size(); ++i) { + if (not timer_list[i].active) { + break; + } + } + if (i == timer_list.size()) { + timer_list.emplace_back(this); + } + timer_list[i].active = true; + return i; + } + std::vector timer_list; std::priority_queue running_timers; uint32_t cur_time = 0; diff --git a/lib/test/common/timer_test.cc b/lib/test/common/timer_test.cc index 7698a8d3a..6fde27052 100644 --- a/lib/test/common/timer_test.cc +++ b/lib/test/common/timer_test.cc @@ -35,7 +35,7 @@ using namespace srslte; -int timers2_test() +int timers_test1() { timer_handler timers; uint32_t dur = 5; @@ -130,7 +130,7 @@ int timers2_test() return SRSLTE_SUCCESS; } -int timers2_test2() +int timers_test2() { /** * Description: @@ -165,7 +165,7 @@ int timers2_test2() return SRSLTE_SUCCESS; } -int timers2_test3() +int timers_test3() { /** * Description: @@ -196,14 +196,14 @@ int timers2_test3() return SRSLTE_SUCCESS; } -struct timers2_test4_context { +struct timers_test4_ctxt { std::vector timers; srslte::tti_sync_cv tti_sync1; srslte::tti_sync_cv tti_sync2; const uint32_t duration = 1000; }; -static void timers2_test4_thread(timers2_test4_context* ctx) +static void timers2_test4_thread(timers_test4_ctxt* ctx) { std::mt19937 mt19937(4); std::uniform_real_distribution real_dist(0.0f, 1.0f); @@ -230,9 +230,9 @@ static void timers2_test4_thread(timers2_test4_context* ctx) } } -int timers2_test4() +int timers_test4() { - timers2_test4_context* ctx = new timers2_test4_context; + timers_test4_ctxt* ctx = new timers_test4_ctxt; timer_handler timers; uint32_t nof_timers = 32; std::mt19937 mt19937(4); @@ -305,12 +305,75 @@ int timers2_test4() return SRSLTE_SUCCESS; } +/** + * Description: Delaying a callback using the timer_handler + */ +int timers_test5() +{ + timer_handler timers; + TESTASSERT(timers.nof_timers() == 0); + TESTASSERT(timers.nof_running_timers() == 0); + + std::vector vals; + + // TTI 0: Add a unique_timer of duration=5 + timer_handler::unique_timer t = timers.get_unique_timer(); + TESTASSERT(timers.nof_timers() == 1); + t.set(5, [&vals](uint32_t tid) { vals.push_back(1); }); + t.run(); + TESTASSERT(timers.nof_running_timers() == 1); + timers.step_all(); + + // TTI 1: Add two delayed callbacks, with duration=2 and 6 + { + // ensure captures by value are ok + std::string string = "test string"; + timers.defer_callback(2, [&vals, string]() { + vals.push_back(2); + if (string != "test string") { + ERROR("string was not captured correctly\n"); + exit(-1); + } + }); + } + timers.defer_callback(6, [&vals]() { vals.push_back(3); }); + TESTASSERT(timers.nof_timers() == 3); + TESTASSERT(timers.nof_running_timers() == 3); + timers.step_all(); + timers.step_all(); + + // TTI 3: First callback should have been triggered by now + TESTASSERT(timers.nof_running_timers() == 2); + TESTASSERT(timers.nof_timers() == 2); + TESTASSERT(vals.size() == 1); + TESTASSERT(vals[0] == 2); + timers.step_all(); + timers.step_all(); + + // TTI 5: Unique timer should have been triggered by now + TESTASSERT(timers.nof_running_timers() == 1); + TESTASSERT(timers.nof_timers() == 2); + TESTASSERT(vals.size() == 2); + TESTASSERT(vals[1] == 1); + timers.step_all(); + timers.step_all(); + + // TTI 7: Second callback should have been triggered by now + TESTASSERT(timers.nof_running_timers() == 0); + TESTASSERT(timers.nof_timers() == 1); + TESTASSERT(vals.size() == 3); + TESTASSERT(vals[2] == 3); + + return SRSLTE_SUCCESS; +} + int main() { - TESTASSERT(timers2_test() == SRSLTE_SUCCESS); - TESTASSERT(timers2_test2() == SRSLTE_SUCCESS); - TESTASSERT(timers2_test3() == SRSLTE_SUCCESS); - TESTASSERT(timers2_test4() == SRSLTE_SUCCESS); + TESTASSERT(timers_test1() == SRSLTE_SUCCESS); + TESTASSERT(timers_test2() == SRSLTE_SUCCESS); + TESTASSERT(timers_test3() == SRSLTE_SUCCESS); + TESTASSERT(timers_test4() == SRSLTE_SUCCESS); + TESTASSERT(timers_test5() == SRSLTE_SUCCESS); printf("Success\n"); return 0; }