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   14 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   2 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   2 : timer(ctx, d) 117   4 : timer(ctx, d)
118   { 118   {
HITCBC 119   2 } 119   4 }
120   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>
HITGNC   134 + 2 explicit native_timer(Ex const& ex) : native_timer(ex.context())
  135 + {
HITGNC   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>
HITGNC   162 + 2 native_timer(Ex const& ex, std::chrono::duration<Rep, Period> d)
HITGNC   163 + 2 : native_timer(ex.context(), d)
  164 + {
HITGNC   165 + 2 }
  166 +
121   /** Move construct. 167   /** Move construct.
122   168  
123   @param other The timer to move from. 169   @param other The timer to move from.
124   170  
125   @pre No awaitables returned by @p other's methods exist. 171   @pre No awaitables returned by @p other's methods exist.
126   @pre The execution context associated with @p other must 172   @pre The execution context associated with @p other must
127   outlive this timer. 173   outlive this timer.
128   */ 174   */
MISUBC 129   native_timer(native_timer&&) noexcept = default; 175   native_timer(native_timer&&) noexcept = default;
130   176  
131   /** Move assign. 177   /** Move assign.
132   178  
133   @param other The timer to move from. 179   @param other The timer to move from.
134   180  
135   @pre No awaitables returned by either `*this` or @p other's 181   @pre No awaitables returned by either `*this` or @p other's
136   methods exist. 182   methods exist.
137   @pre The execution context associated with @p other must 183   @pre The execution context associated with @p other must
138   outlive this timer. 184   outlive this timer.
139   */ 185   */
140   native_timer& operator=(native_timer&&) noexcept = default; 186   native_timer& operator=(native_timer&&) noexcept = default;
141   187  
142   native_timer(native_timer const&) = delete; 188   native_timer(native_timer const&) = delete;
143   native_timer& operator=(native_timer const&) = delete; 189   native_timer& operator=(native_timer const&) = delete;
144   190  
145   /** Wait for the timer to expire. 191   /** Wait for the timer to expire.
146   192  
147   Calls the backend implementation directly, bypassing virtual 193   Calls the backend implementation directly, bypassing virtual
148   dispatch. Otherwise identical to @ref timer::wait. 194   dispatch. Otherwise identical to @ref timer::wait.
149   195  
150   @return An awaitable yielding `io_result<>`. 196   @return An awaitable yielding `io_result<>`.
151   197  
152   This timer must outlive the returned awaitable. 198   This timer must outlive the returned awaitable.
153   */ 199   */
HITCBC 154   10 auto wait() 200   10 auto wait()
155   { 201   {
HITCBC 156   10 return native_wait_awaitable(*this); 202   10 return native_wait_awaitable(*this);
157   } 203   }
158   }; 204   };
159   205  
160   } // namespace boost::corosio 206   } // namespace boost::corosio
161   207  
162   #endif 208   #endif