TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Steve Gerbino
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/corosio
8 : //
9 :
10 : #ifndef BOOST_COROSIO_NATIVE_NATIVE_TIMER_HPP
11 : #define BOOST_COROSIO_NATIVE_NATIVE_TIMER_HPP
12 :
13 : #include <boost/corosio/timer.hpp>
14 : #include <boost/corosio/backend.hpp>
15 : #include <boost/corosio/detail/timer_service.hpp>
16 :
17 : namespace boost::corosio {
18 :
19 : /** An asynchronous timer with devirtualized wait operations.
20 :
21 : This class template inherits from @ref timer and shadows the
22 : `wait` operation with a version that calls the backend
23 : implementation directly, allowing the compiler to inline
24 : through the entire call chain.
25 :
26 : Non-async operations (`cancel`, `expires_at`, `expires_after`)
27 : remain unchanged and dispatch through the compiled library.
28 :
29 : A `native_timer` IS-A `timer` and can be passed to any function
30 : expecting `timer&`.
31 :
32 : @tparam Backend A backend tag value (e.g., `epoll`).
33 : The timer implementation is backend-independent; the
34 : tag selects the concrete impl type for devirtualization.
35 :
36 : @par Thread Safety
37 : Same as @ref timer.
38 :
39 : @see timer, epoll_t, iocp_t
40 : */
41 : template<auto Backend>
42 : class native_timer : public timer
43 : {
44 : using impl_type = detail::timer_service::implementation;
45 :
46 HIT 10 : impl_type& get_impl() noexcept
47 : {
48 10 : return *static_cast<impl_type*>(h_.get());
49 : }
50 :
51 : struct native_wait_awaitable
52 : {
53 : native_timer& self_;
54 : std::stop_token token_;
55 : mutable std::error_code ec_;
56 : detail::continuation_op cont_op_;
57 :
58 10 : explicit native_wait_awaitable(native_timer& self) noexcept
59 10 : : self_(self)
60 : {
61 10 : }
62 :
63 10 : bool await_ready() const noexcept
64 : {
65 10 : return token_.stop_requested();
66 : }
67 :
68 10 : capy::io_result<> await_resume() const noexcept
69 : {
70 10 : if (token_.stop_requested())
71 MIS 0 : return {capy::error::canceled};
72 HIT 10 : return {ec_};
73 : }
74 :
75 10 : auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
76 : -> std::coroutine_handle<>
77 : {
78 10 : token_ = env->stop_token;
79 10 : cont_op_.cont.h = h;
80 10 : auto& impl = self_.get_impl();
81 : // Fast path: already expired and not in the heap
82 20 : if (impl.heap_index_ == timer::implementation::npos &&
83 20 : (impl.expiry_ == (time_point::min)() ||
84 20 : impl.expiry_ <= clock_type::now()))
85 : {
86 2 : ec_ = {};
87 2 : auto d = env->executor;
88 2 : d.post(cont_op_.cont);
89 2 : return std::noop_coroutine();
90 : }
91 8 : return impl.wait(h, env->executor, std::move(token_), &ec_, &cont_op_.cont);
92 : }
93 : };
94 :
95 : public:
96 : /** Construct a native timer from an execution context.
97 :
98 : @param ctx The execution context that will own this timer.
99 : */
100 16 : explicit native_timer(capy::execution_context& ctx) : timer(ctx) {}
101 :
102 : /** Construct a native timer with an initial absolute expiry.
103 :
104 : @param ctx The execution context that will own this timer.
105 : @param t The initial expiry time point.
106 : */
107 : native_timer(capy::execution_context& ctx, time_point t) : timer(ctx, t) {}
108 :
109 : /** Construct a native timer with an initial relative expiry.
110 :
111 : @param ctx The execution context that will own this timer.
112 : @param d The initial expiry duration relative to now.
113 : */
114 : template<class Rep, class Period>
115 4 : native_timer(
116 : capy::execution_context& ctx, std::chrono::duration<Rep, Period> d)
117 4 : : timer(ctx, d)
118 : {
119 4 : }
120 :
121 : /** Construct a native timer from an executor.
122 :
123 : The timer is associated with the executor's context, which must
124 : be a corosio io_context.
125 :
126 : @param ex The executor whose context will own this timer.
127 :
128 : @throws std::logic_error if the executor's context is not an
129 : io_context.
130 : */
131 : template<class Ex>
132 : requires(!std::same_as<std::remove_cvref_t<Ex>, native_timer>) &&
133 : capy::Executor<Ex>
134 2 : explicit native_timer(Ex const& ex) : native_timer(ex.context())
135 : {
136 2 : }
137 :
138 : /** Construct a native timer from an executor with an absolute expiry.
139 :
140 : @param ex The executor whose context will own this timer.
141 : @param t The initial expiry time point.
142 :
143 : @throws std::logic_error if the executor's context is not an
144 : io_context.
145 : */
146 : template<class Ex>
147 : requires capy::Executor<Ex>
148 : native_timer(Ex const& ex, time_point t) : native_timer(ex.context(), t)
149 : {
150 : }
151 :
152 : /** Construct a native timer from an executor with a relative expiry.
153 :
154 : @param ex The executor whose context will own this timer.
155 : @param d The initial expiry duration relative to now.
156 :
157 : @throws std::logic_error if the executor's context is not an
158 : io_context.
159 : */
160 : template<class Ex, class Rep, class Period>
161 : requires capy::Executor<Ex>
162 2 : native_timer(Ex const& ex, std::chrono::duration<Rep, Period> d)
163 2 : : native_timer(ex.context(), d)
164 : {
165 2 : }
166 :
167 : /** Move construct.
168 :
169 : @param other The timer to move from.
170 :
171 : @pre No awaitables returned by @p other's methods exist.
172 : @pre The execution context associated with @p other must
173 : outlive this timer.
174 : */
175 MIS 0 : native_timer(native_timer&&) noexcept = default;
176 :
177 : /** Move assign.
178 :
179 : @param other The timer to move from.
180 :
181 : @pre No awaitables returned by either `*this` or @p other's
182 : methods exist.
183 : @pre The execution context associated with @p other must
184 : outlive this timer.
185 : */
186 : native_timer& operator=(native_timer&&) noexcept = default;
187 :
188 : native_timer(native_timer const&) = delete;
189 : native_timer& operator=(native_timer const&) = delete;
190 :
191 : /** Wait for the timer to expire.
192 :
193 : Calls the backend implementation directly, bypassing virtual
194 : dispatch. Otherwise identical to @ref timer::wait.
195 :
196 : @return An awaitable yielding `io_result<>`.
197 :
198 : This timer must outlive the returned awaitable.
199 : */
200 HIT 10 : auto wait()
201 : {
202 10 : return native_wait_awaitable(*this);
203 : }
204 : };
205 :
206 : } // namespace boost::corosio
207 :
208 : #endif
|