100.00% Lines (62/62)
100.00% Functions (8/8)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | // | 1 | // | |||||
| 2 | // Copyright (c) 2026 Michael Vandeberg | 2 | // Copyright (c) 2026 Michael Vandeberg | |||||
| 3 | // | 3 | // | |||||
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |||||
| 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||||
| 6 | // | 6 | // | |||||
| 7 | // Official repository: https://github.com/cppalliance/capy | 7 | // Official repository: https://github.com/cppalliance/capy | |||||
| 8 | // | 8 | // | |||||
| 9 | 9 | |||||||
| 10 | #include <boost/capy/ex/detail/timer_service.hpp> | 10 | #include <boost/capy/ex/detail/timer_service.hpp> | |||||
| 11 | 11 | |||||||
| 12 | namespace boost { | 12 | namespace boost { | |||||
| 13 | namespace capy { | 13 | namespace capy { | |||||
| 14 | namespace detail { | 14 | namespace detail { | |||||
| 15 | 15 | |||||||
| HITCBC | 16 | 20 | timer_service:: | 16 | 20 | timer_service:: | ||
| HITCBC | 17 | 20 | timer_service(execution_context& ctx) | 17 | 20 | timer_service(execution_context& ctx) | ||
| HITCBC | 18 | 40 | : thread_([this] { run(); }) | 18 | 40 | : thread_([this] { run(); }) | ||
| 19 | { | 19 | { | |||||
| 20 | (void)ctx; | 20 | (void)ctx; | |||||
| HITCBC | 21 | 20 | } | 21 | 20 | } | ||
| 22 | 22 | |||||||
| HITCBC | 23 | 40 | timer_service:: | 23 | 40 | timer_service:: | ||
| HITCBC | 24 | 20 | ~timer_service() | 24 | 20 | ~timer_service() | ||
| 25 | { | 25 | { | |||||
| HITCBC | 26 | 20 | stop_and_join(); | 26 | 20 | stop_and_join(); | ||
| HITCBC | 27 | 40 | } | 27 | 40 | } | ||
| 28 | 28 | |||||||
| 29 | timer_service::timer_id | 29 | timer_service::timer_id | |||||
| HITCBC | 30 | 135 | timer_service:: | 30 | 135 | timer_service:: | ||
| 31 | schedule_at( | 31 | schedule_at( | |||||
| 32 | std::chrono::steady_clock::time_point deadline, | 32 | std::chrono::steady_clock::time_point deadline, | |||||
| 33 | std::function<void()> cb) | 33 | std::function<void()> cb) | |||||
| 34 | { | 34 | { | |||||
| HITCBC | 35 | 135 | std::lock_guard lock(mutex_); | 35 | 135 | std::lock_guard lock(mutex_); | ||
| HITCBC | 36 | 135 | auto id = ++next_id_; | 36 | 135 | auto id = ++next_id_; | ||
| HITCBC | 37 | 135 | active_ids_.insert(id); | 37 | 135 | active_ids_.insert(id); | ||
| HITCBC | 38 | 135 | queue_.push(entry{deadline, id, std::move(cb)}); | 38 | 135 | queue_.push(entry{deadline, id, std::move(cb)}); | ||
| HITCBC | 39 | 135 | cv_.notify_one(); | 39 | 135 | cv_.notify_one(); | ||
| HITCBC | 40 | 135 | return id; | 40 | 135 | return id; | ||
| HITCBC | 41 | 135 | } | 41 | 135 | } | ||
| 42 | 42 | |||||||
| 43 | void | 43 | void | |||||
| HITCBC | 44 | 43 | timer_service:: | 44 | 43 | timer_service:: | ||
| 45 | cancel(timer_id id) | 45 | cancel(timer_id id) | |||||
| 46 | { | 46 | { | |||||
| HITCBC | 47 | 43 | std::unique_lock lock(mutex_); | 47 | 43 | std::unique_lock lock(mutex_); | ||
| HITCBC | 48 | 43 | if(!active_ids_.contains(id)) | 48 | 43 | if(!active_ids_.contains(id)) | ||
| HITCBC | 49 | 34 | return; | 49 | 36 | return; | ||
| HITCBC | 50 | 9 | if(executing_id_ == id) | 50 | 7 | if(executing_id_ == id) | ||
| 51 | { | 51 | { | |||||
| 52 | // Callback is running — wait for it to finish. | 52 | // Callback is running — wait for it to finish. | |||||
| 53 | // run() erases from active_ids_ after execution. | 53 | // run() erases from active_ids_ after execution. | |||||
| HITCBC | 54 | 6 | while(executing_id_ == id) | 54 | 2 | while(executing_id_ == id) | ||
| HITCBC | 55 | 3 | cancel_cv_.wait(lock); | 55 | 1 | cancel_cv_.wait(lock); | ||
| HITCBC | 56 | 3 | return; | 56 | 1 | return; | ||
| 57 | } | 57 | } | |||||
| HITCBC | 58 | 6 | active_ids_.erase(id); | 58 | 6 | active_ids_.erase(id); | ||
| HITCBC | 59 | 43 | } | 59 | 43 | } | ||
| 60 | 60 | |||||||
| 61 | void | 61 | void | |||||
| HITCBC | 62 | 40 | timer_service:: | 62 | 40 | timer_service:: | ||
| 63 | stop_and_join() | 63 | stop_and_join() | |||||
| 64 | { | 64 | { | |||||
| 65 | { | 65 | { | |||||
| HITCBC | 66 | 40 | std::lock_guard lock(mutex_); | 66 | 40 | std::lock_guard lock(mutex_); | ||
| HITCBC | 67 | 40 | stopped_ = true; | 67 | 40 | stopped_ = true; | ||
| HITCBC | 68 | 40 | } | 68 | 40 | } | ||
| HITCBC | 69 | 40 | cv_.notify_one(); | 69 | 40 | cv_.notify_one(); | ||
| HITCBC | 70 | 40 | if(thread_.joinable()) | 70 | 40 | if(thread_.joinable()) | ||
| HITCBC | 71 | 20 | thread_.join(); | 71 | 20 | thread_.join(); | ||
| HITCBC | 72 | 40 | } | 72 | 40 | } | ||
| 73 | 73 | |||||||
| 74 | void | 74 | void | |||||
| HITCBC | 75 | 20 | timer_service:: | 75 | 20 | timer_service:: | ||
| 76 | shutdown() | 76 | shutdown() | |||||
| 77 | { | 77 | { | |||||
| HITCBC | 78 | 20 | stop_and_join(); | 78 | 20 | stop_and_join(); | ||
| HITCBC | 79 | 20 | } | 79 | 20 | } | ||
| 80 | 80 | |||||||
| 81 | void | 81 | void | |||||
| HITCBC | 82 | 20 | timer_service:: | 82 | 20 | timer_service:: | ||
| 83 | run() | 83 | run() | |||||
| 84 | { | 84 | { | |||||
| HITCBC | 85 | 20 | std::unique_lock lock(mutex_); | 85 | 20 | std::unique_lock lock(mutex_); | ||
| 86 | for(;;) | 86 | for(;;) | |||||
| 87 | { | 87 | { | |||||
| HITCBC | 88 | 199 | if(stopped_) | 88 | 202 | if(stopped_) | ||
| HITCBC | 89 | 20 | return; | 89 | 20 | return; | ||
| 90 | 90 | |||||||
| HITCBC | 91 | 179 | if(queue_.empty()) | 91 | 182 | if(queue_.empty()) | ||
| 92 | { | 92 | { | |||||
| HITCBC | 93 | 19 | cv_.wait(lock); | 93 | 18 | cv_.wait(lock); | ||
| HITCBC | 94 | 53 | continue; | 94 | 56 | continue; | ||
| 95 | } | 95 | } | |||||
| 96 | 96 | |||||||
| HITCBC | 97 | 160 | auto deadline = queue_.top().deadline; | 97 | 164 | auto deadline = queue_.top().deadline; | ||
| HITCBC | 98 | 160 | auto now = std::chrono::steady_clock::now(); | 98 | 164 | auto now = std::chrono::steady_clock::now(); | ||
| HITCBC | 99 | 160 | if(deadline > now) | 99 | 164 | if(deadline > now) | ||
| 100 | { | 100 | { | |||||
| HITCBC | 101 | 32 | cv_.wait_until(lock, deadline); | 101 | 36 | cv_.wait_until(lock, deadline); | ||
| HITCBC | 102 | 32 | continue; | 102 | 36 | continue; | ||
| 103 | } | 103 | } | |||||
| 104 | 104 | |||||||
| 105 | // Pop the entry (const_cast needed because priority_queue::top is const) | 105 | // Pop the entry (const_cast needed because priority_queue::top is const) | |||||
| HITCBC | 106 | 128 | auto e = std::move(const_cast<entry&>(queue_.top())); | 106 | 128 | auto e = std::move(const_cast<entry&>(queue_.top())); | ||
| HITCBC | 107 | 128 | queue_.pop(); | 107 | 128 | queue_.pop(); | ||
| 108 | 108 | |||||||
| 109 | // Skip if cancelled (no longer in active set) | 109 | // Skip if cancelled (no longer in active set) | |||||
| HITCBC | 110 | 128 | if(!active_ids_.contains(e.id)) | 110 | 128 | if(!active_ids_.contains(e.id)) | ||
| HITCBC | 111 | 2 | continue; | 111 | 2 | continue; | ||
| 112 | 112 | |||||||
| HITCBC | 113 | 126 | executing_id_ = e.id; | 113 | 126 | executing_id_ = e.id; | ||
| HITCBC | 114 | 126 | lock.unlock(); | 114 | 126 | lock.unlock(); | ||
| HITCBC | 115 | 126 | e.callback(); | 115 | 126 | e.callback(); | ||
| HITCBC | 116 | 126 | lock.lock(); | 116 | 126 | lock.lock(); | ||
| HITCBC | 117 | 126 | active_ids_.erase(e.id); | 117 | 126 | active_ids_.erase(e.id); | ||
| HITCBC | 118 | 126 | executing_id_ = 0; | 118 | 126 | executing_id_ = 0; | ||
| HITCBC | 119 | 126 | cancel_cv_.notify_all(); | 119 | 126 | cancel_cv_.notify_all(); | ||
| HITCBC | 120 | 307 | } | 120 | 310 | } | ||
| HITCBC | 121 | 20 | } | 121 | 20 | } | ||
| 122 | 122 | |||||||
| 123 | } // detail | 123 | } // detail | |||||
| 124 | } // capy | 124 | } // capy | |||||
| 125 | } // boost | 125 | } // boost | |||||