93.33% Lines (28/30) 88.89% Functions (8/9)
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  
HITGIC 46   impl_type& get_impl() noexcept 46   10 impl_type& get_impl() noexcept
47   { 47   {
HITGIC 48   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  
HITGIC 58   explicit native_wait_awaitable(native_timer& self) noexcept 58   10 explicit native_wait_awaitable(native_timer& self) noexcept
HITGIC 59   : self_(self) 59   10 : self_(self)
60   { 60   {
HITGIC 61   } 61   10 }
62   62  
HITGIC 63   bool await_ready() const noexcept 63   10 bool await_ready() const noexcept
64   { 64   {
HITGIC 65   return token_.stop_requested(); 65   10 return token_.stop_requested();
66   } 66   }
67   67  
HITGIC 68   capy::io_result<> await_resume() const noexcept 68   10 capy::io_result<> await_resume() const noexcept
69   { 69   {
HITGIC 70   if (token_.stop_requested()) 70   10 if (token_.stop_requested())
MISUIC 71   return {capy::error::canceled}; 71   return {capy::error::canceled};
HITGIC 72   return {ec_}; 72   10 return {ec_};
73   } 73   }
74   74  
HITGIC 75   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   {
HITGIC 78   token_ = env->stop_token; 78   10 token_ = env->stop_token;
HITGIC 79   cont_op_.cont.h = h; 79   10 cont_op_.cont.h = h;
HITGIC 80   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
HITGIC 82   if (impl.heap_index_ == timer::implementation::npos && 82   20 if (impl.heap_index_ == timer::implementation::npos &&
HITGIC 83   (impl.expiry_ == (time_point::min)() || 83   20 (impl.expiry_ == (time_point::min)() ||
HITGIC 84   impl.expiry_ <= clock_type::now())) 84   20 impl.expiry_ <= clock_type::now()))
85   { 85   {
HITGIC 86   ec_ = {}; 86   2 ec_ = {};
HITGIC 87   auto d = env->executor; 87   2 auto d = env->executor;
HITGIC 88   d.post(cont_op_.cont); 88   2 d.post(cont_op_.cont);
HITGIC 89   return std::noop_coroutine(); 89   2 return std::noop_coroutine();
90   } 90   }
HITGIC 91   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   */
HITGIC 100   explicit native_timer(capy::execution_context& ctx) : timer(ctx) {} 100   14 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>
HITGIC 115   native_timer( 115   2 native_timer(
116   capy::execution_context& ctx, std::chrono::duration<Rep, Period> d) 116   capy::execution_context& ctx, std::chrono::duration<Rep, Period> d)
HITGIC 117   : timer(ctx, d) 117   2 : timer(ctx, d)
118   { 118   {
HITGIC 119   } 119   2 }
120   120  
121   /** Move construct. 121   /** Move construct.
122   122  
123   @param other The timer to move from. 123   @param other The timer to move from.
124   124  
125   @pre No awaitables returned by @p other's methods exist. 125   @pre No awaitables returned by @p other's methods exist.
126   @pre The execution context associated with @p other must 126   @pre The execution context associated with @p other must
127   outlive this timer. 127   outlive this timer.
128   */ 128   */
MISUIC 129   native_timer(native_timer&&) noexcept = default; 129   native_timer(native_timer&&) noexcept = default;
130   130  
131   /** Move assign. 131   /** Move assign.
132   132  
133   @param other The timer to move from. 133   @param other The timer to move from.
134   134  
135   @pre No awaitables returned by either `*this` or @p other's 135   @pre No awaitables returned by either `*this` or @p other's
136   methods exist. 136   methods exist.
137   @pre The execution context associated with @p other must 137   @pre The execution context associated with @p other must
138   outlive this timer. 138   outlive this timer.
139   */ 139   */
140   native_timer& operator=(native_timer&&) noexcept = default; 140   native_timer& operator=(native_timer&&) noexcept = default;
141   141  
142   native_timer(native_timer const&) = delete; 142   native_timer(native_timer const&) = delete;
143   native_timer& operator=(native_timer const&) = delete; 143   native_timer& operator=(native_timer const&) = delete;
144   144  
145   /** Wait for the timer to expire. 145   /** Wait for the timer to expire.
146   146  
147   Calls the backend implementation directly, bypassing virtual 147   Calls the backend implementation directly, bypassing virtual
148   dispatch. Otherwise identical to @ref timer::wait. 148   dispatch. Otherwise identical to @ref timer::wait.
149   149  
150   @return An awaitable yielding `io_result<>`. 150   @return An awaitable yielding `io_result<>`.
151   151  
152   This timer must outlive the returned awaitable. 152   This timer must outlive the returned awaitable.
153   */ 153   */
HITGIC 154   auto wait() 154   10 auto wait()
155   { 155   {
HITGIC 156   return native_wait_awaitable(*this); 156   10 return native_wait_awaitable(*this);
157   } 157   }
158   }; 158   };
159   159  
160   } // namespace boost::corosio 160   } // namespace boost::corosio
161   161  
162   #endif 162   #endif