include/boost/capy/ex/detail/timer_service.hpp

100.0% Lines (8/8) 100.0% List of functions (2/3) 100.0% Branches (2/2)
f(x) Functions (3)
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 #ifndef BOOST_CAPY_EX_TIMER_SERVICE_HPP
11 #define BOOST_CAPY_EX_TIMER_SERVICE_HPP
12
13 #include <boost/capy/detail/config.hpp>
14 #include <boost/capy/ex/execution_context.hpp>
15
16 #include <chrono>
17 #include <cstdint>
18 #include <functional>
19 #include <mutex>
20 #include <condition_variable>
21 #include <queue>
22 #include <thread>
23 #include <unordered_set>
24 #include <vector>
25
26 namespace boost {
27 namespace capy {
28 namespace detail {
29
30 /* Shared timer thread for an execution_context.
31
32 One background std::thread per execution_context. All timeouts
33 scheduled through this context share the same thread, which sleeps
34 on a condition variable until the next deadline.
35
36 The timer thread never touches coroutine frames or executors
37 directly — callbacks are responsible for posting work through
38 the appropriate executor.
39 */
40
41 class BOOST_CAPY_DECL
42 timer_service
43 : public execution_context::service
44 {
45 public:
46 using timer_id = std::uint64_t;
47
48 explicit timer_service(execution_context& ctx);
49
50 /** Schedule a callback to fire after a duration.
51
52 The callback is invoked on the timer service's background
53 thread. It must not block for extended periods.
54
55 @return An id that can be passed to cancel().
56 */
57 template<typename Rep, typename Period>
58 125x timer_id schedule_after(
59 std::chrono::duration<Rep, Period> dur,
60 std::function<void()> cb)
61 {
62
1/1
✓ Branch 2 taken 10 times.
125x auto deadline = std::chrono::steady_clock::now() + dur;
63
1/1
✓ Branch 3 taken 10 times.
125x return schedule_at(deadline, std::move(cb));
64 }
65
66 /** Cancel a pending timer.
67
68 After this function returns, the callback is guaranteed
69 not to be running and will never be invoked. If the
70 callback is currently executing on the timer thread,
71 this call blocks until it completes.
72
73 Safe to call with any id, including ids that have
74 already fired, been cancelled, or were never issued.
75 */
76 void cancel(timer_id id);
77
78 protected:
79 void shutdown() override;
80
81 private:
82 struct entry
83 {
84 std::chrono::steady_clock::time_point deadline;
85 timer_id id;
86 std::function<void()> callback;
87
88 639x bool operator>(entry const& o) const noexcept
89 {
90 639x return deadline > o.deadline;
91 }
92 };
93
94 timer_id schedule_at(
95 std::chrono::steady_clock::time_point deadline,
96 std::function<void()> cb);
97
98 void run();
99
100 // warning C4251: std types need to have dll-interface
101 #ifdef _MSC_VER
102 # pragma warning(push)
103 # pragma warning(disable: 4251)
104 #endif
105 std::mutex mutex_;
106 std::condition_variable cv_;
107 std::condition_variable cancel_cv_;
108 std::priority_queue<
109 entry,
110 std::vector<entry>,
111 std::greater<>> queue_;
112 std::unordered_set<timer_id> active_ids_;
113 timer_id next_id_ = 0;
114 timer_id executing_id_ = 0;
115 bool stopped_ = false;
116 std::thread thread_;
117 #ifdef _MSC_VER
118 # pragma warning(pop)
119 #endif
120 };
121
122 } // detail
123 } // capy
124 } // boost
125
126 #endif
127