src/ex/detail/timer_service.cpp

100.0% Lines (55/55) 100.0% List of functions (6/6) 97.1% Branches (34/35)
f(x) Functions (6)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Michael Vandeberg
3 //
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)
6 //
7 // Official repository: https://github.com/cppalliance/capy
8 //
9
10 #include <boost/capy/ex/detail/timer_service.hpp>
11
12 namespace boost {
13 namespace capy {
14 namespace detail {
15
16 18x timer_service::
17 18x timer_service(execution_context& ctx)
18
1/1
✓ Branch 7 taken 18 times.
36x : thread_([this] { run(); })
19 {
20 (void)ctx;
21 18x }
22
23 timer_service::timer_id
24 125x timer_service::
25 schedule_at(
26 std::chrono::steady_clock::time_point deadline,
27 std::function<void()> cb)
28 {
29
1/1
✓ Branch 1 taken 125 times.
125x std::lock_guard lock(mutex_);
30 125x auto id = ++next_id_;
31
1/1
✓ Branch 1 taken 125 times.
125x active_ids_.insert(id);
32
1/1
✓ Branch 3 taken 125 times.
125x queue_.push(entry{deadline, id, std::move(cb)});
33 125x cv_.notify_one();
34 125x return id;
35 125x }
36
37 void
38 24x timer_service::
39 cancel(timer_id id)
40 {
41
1/1
✓ Branch 1 taken 24 times.
24x std::unique_lock lock(mutex_);
42
3/3
✓ Branch 1 taken 24 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 9 times.
24x if(!active_ids_.contains(id))
43 15x return;
44
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9x if(executing_id_ == id)
45 {
46 // Callback is running — wait for it to finish.
47 // run() erases from active_ids_ after execution.
48
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8x while(executing_id_ == id)
49
1/1
✓ Branch 1 taken 4 times.
4x cancel_cv_.wait(lock);
50 4x return;
51 }
52
1/1
✓ Branch 1 taken 5 times.
5x active_ids_.erase(id);
53 24x }
54
55 void
56 18x timer_service::
57 shutdown()
58 {
59 {
60
1/1
✓ Branch 1 taken 18 times.
18x std::lock_guard lock(mutex_);
61 18x stopped_ = true;
62 18x }
63 18x cv_.notify_one();
64
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18x if(thread_.joinable())
65 18x thread_.join();
66 18x }
67
68 void
69 18x timer_service::
70 run()
71 {
72
1/1
✓ Branch 1 taken 18 times.
18x std::unique_lock lock(mutex_);
73 for(;;)
74 {
75
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 159 times.
177x if(stopped_)
76 18x return;
77
78
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 143 times.
159x if(queue_.empty())
79 {
80
1/1
✓ Branch 1 taken 16 times.
16x cv_.wait(lock);
81 42x continue;
82 }
83
84 143x auto deadline = queue_.top().deadline;
85 143x auto now = std::chrono::steady_clock::now();
86
3/3
✓ Branch 1 taken 143 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 119 times.
143x if(deadline > now)
87 {
88
1/1
✓ Branch 1 taken 24 times.
24x cv_.wait_until(lock, deadline);
89 24x continue;
90 }
91
92 // Pop the entry (const_cast needed because priority_queue::top is const)
93 119x auto e = std::move(const_cast<entry&>(queue_.top()));
94
1/1
✓ Branch 1 taken 119 times.
119x queue_.pop();
95
96 // Skip if cancelled (no longer in active set)
97
3/3
✓ Branch 1 taken 119 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 117 times.
119x if(!active_ids_.contains(e.id))
98 2x continue;
99
100 117x executing_id_ = e.id;
101
1/1
✓ Branch 1 taken 117 times.
117x lock.unlock();
102
1/1
✓ Branch 1 taken 117 times.
117x e.callback();
103
1/1
✓ Branch 1 taken 117 times.
117x lock.lock();
104
1/1
✓ Branch 1 taken 117 times.
117x active_ids_.erase(e.id);
105 117x executing_id_ = 0;
106 117x cancel_cv_.notify_all();
107 278x }
108 18x }
109
110 } // detail
111 } // capy
112 } // boost
113