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