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 : #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 HIT 125 : timer_id schedule_after(
59 : std::chrono::duration<Rep, Period> dur,
60 : std::function<void()> cb)
61 : {
62 125 : auto deadline = std::chrono::steady_clock::now() + dur;
63 125 : 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 639 : bool operator>(entry const& o) const noexcept
89 : {
90 639 : 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
|