src/ex/detail/timer_service.cpp

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