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