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 // Calls shutdown() to join the background thread.
51 // Handles the discard path in use_service_impl where
52 // a duplicate service is deleted without shutdown().
53 ~timer_service();
54
55 /** Schedule a callback to fire after a duration.
56
57 The callback is invoked on the timer service's background
58 thread. It must not block for extended periods.
59
60 @return An id that can be passed to cancel().
61 */
62 template<typename Rep, typename Period>
63 134x timer_id schedule_after(
64 std::chrono::duration<Rep, Period> dur,
65 std::function<void()> cb)
66 {
67
1/1
✓ Branch 2 taken 19 times.
134x auto deadline = std::chrono::steady_clock::now() + dur;
68
1/1
✓ Branch 3 taken 19 times.
134x return schedule_at(deadline, std::move(cb));
69 }
70
71 /** Cancel a pending timer.
72
73 After this function returns, the callback is guaranteed
74 not to be running and will never be invoked. If the
75 callback is currently executing on the timer thread,
76 this call blocks until it completes.
77
78 Safe to call with any id, including ids that have
79 already fired, been cancelled, or were never issued.
80 */
81 void cancel(timer_id id);
82
83 protected:
84 void shutdown() override;
85
86 private:
87 void stop_and_join();
88 struct entry
89 {
90 std::chrono::steady_clock::time_point deadline;
91 timer_id id;
92 std::function<void()> callback;
93
94 664x bool operator>(entry const& o) const noexcept
95 {
96 664x return deadline > o.deadline;
97 }
98 };
99
100 timer_id schedule_at(
101 std::chrono::steady_clock::time_point deadline,
102 std::function<void()> cb);
103
104 void run();
105
106 // warning C4251: std types need to have dll-interface
107 BOOST_CAPY_MSVC_WARNING_PUSH
108 BOOST_CAPY_MSVC_WARNING_DISABLE(4251)
109 std::mutex mutex_;
110 std::condition_variable cv_;
111 std::condition_variable cancel_cv_;
112 std::priority_queue<
113 entry,
114 std::vector<entry>,
115 std::greater<>> queue_;
116 std::unordered_set<timer_id> active_ids_;
117 timer_id next_id_ = 0;
118 timer_id executing_id_ = 0;
119 bool stopped_ = false;
120 std::thread thread_;
121 BOOST_CAPY_MSVC_WARNING_POP
122 };
123
124 } // detail
125 } // capy
126 } // boost
127
128 #endif
129