100.00% Lines (4/4) 100.00% Functions (2/2)
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_CANCEL_HPP 10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_CANCEL_HPP
11   #define BOOST_COROSIO_NATIVE_NATIVE_CANCEL_HPP 11   #define BOOST_COROSIO_NATIVE_NATIVE_CANCEL_HPP
12   12  
13   #include <boost/corosio/detail/cancel_at_awaitable.hpp> 13   #include <boost/corosio/detail/cancel_at_awaitable.hpp>
14   #include <boost/corosio/native/native_timer.hpp> 14   #include <boost/corosio/native/native_timer.hpp>
15   #include <boost/capy/concept/io_awaitable.hpp> 15   #include <boost/capy/concept/io_awaitable.hpp>
16   16  
17   #include <type_traits> 17   #include <type_traits>
18   #include <utility> 18   #include <utility>
19   19  
20   namespace boost::corosio { 20   namespace boost::corosio {
21   21  
22   /** Cancel an operation if it does not complete by a deadline. 22   /** Cancel an operation if it does not complete by a deadline.
23   23  
24   Overload for @ref native_timer that devirtualizes the internal 24   Overload for @ref native_timer that devirtualizes the internal
25   timer wait, allowing the compiler to inline the timer path. 25   timer wait, allowing the compiler to inline the timer path.
26   Otherwise identical to the @ref timer overload. 26   Otherwise identical to the @ref timer overload.
27   27  
28   If the deadline is reached first, the inner operation completes 28   If the deadline is reached first, the inner operation completes
29   with an error comparing equal to `capy::cond::canceled`. If the 29   with an error comparing equal to `capy::cond::canceled`. If the
30   inner operation completes first, the timer is cancelled. Parent 30   inner operation completes first, the timer is cancelled. Parent
31   cancellation is forwarded to both. 31   cancellation is forwarded to both.
32   32  
33   The timer's expiry is overwritten by this call. The timer must 33   The timer's expiry is overwritten by this call. The timer must
34   outlive the returned awaitable. Do not issue overlapping waits 34   outlive the returned awaitable. Do not issue overlapping waits
35   on the same timer. 35   on the same timer.
36   36  
37   @par Completion Conditions 37   @par Completion Conditions
38   The returned awaitable resumes when either: 38   The returned awaitable resumes when either:
39   @li The inner operation completes (successfully or with error). 39   @li The inner operation completes (successfully or with error).
40   @li The deadline expires and the inner operation is cancelled. 40   @li The deadline expires and the inner operation is cancelled.
41   @li The caller's stop token is triggered, cancelling both. 41   @li The caller's stop token is triggered, cancelling both.
42   42  
43   @par Error Conditions 43   @par Error Conditions
44   @li On timeout or parent cancellation, the inner operation 44   @li On timeout or parent cancellation, the inner operation
45   completes with an error equal to `capy::cond::canceled`. 45   completes with an error equal to `capy::cond::canceled`.
46   @li All other errors are propagated from the inner operation. 46   @li All other errors are propagated from the inner operation.
47   47  
48   @par Example 48   @par Example
49   @code 49   @code
50   native_timer<epoll> t( ioc ); 50   native_timer<epoll> t( ioc );
51   auto [ec, n] = co_await cancel_at( 51   auto [ec, n] = co_await cancel_at(
52   sock.read_some( buf ), t, 52   sock.read_some( buf ), t,
53   clock::now() + 5s ); 53   clock::now() + 5s );
54   if (ec == capy::cond::canceled) 54   if (ec == capy::cond::canceled)
55   // timed out or parent cancelled 55   // timed out or parent cancelled
56   @endcode 56   @endcode
57   57  
58   @tparam Backend A backend tag value (e.g., `epoll`). 58   @tparam Backend A backend tag value (e.g., `epoll`).
59   59  
60   @param op The inner I/O awaitable to wrap. 60   @param op The inner I/O awaitable to wrap.
61   @param t The native timer to use for the deadline. Must outlive 61   @param t The native timer to use for the deadline. Must outlive
62   the returned awaitable. 62   the returned awaitable.
63   @param deadline The absolute time point at which to cancel. 63   @param deadline The absolute time point at which to cancel.
64   64  
65   @return An awaitable whose result matches @p op's result type. 65   @return An awaitable whose result matches @p op's result type.
66   66  
67   @see cancel_after, native_timer 67   @see cancel_after, native_timer
68   */ 68   */
69   template<auto Backend> 69   template<auto Backend>
70   auto 70   auto
71   cancel_at( 71   cancel_at(
72   capy::IoAwaitable auto&& op, 72   capy::IoAwaitable auto&& op,
73   native_timer<Backend>& t, 73   native_timer<Backend>& t,
74   timer::time_point deadline) 74   timer::time_point deadline)
75   { 75   {
76   return detail::cancel_at_awaitable< 76   return detail::cancel_at_awaitable<
77   std::decay_t<decltype(op)>, native_timer<Backend>>( 77   std::decay_t<decltype(op)>, native_timer<Backend>>(
78   std::forward<decltype(op)>(op), t, deadline); 78   std::forward<decltype(op)>(op), t, deadline);
79   } 79   }
80   80  
81   /** Cancel an operation if it does not complete within a duration. 81   /** Cancel an operation if it does not complete within a duration.
82   82  
83   Overload for @ref native_timer. Equivalent to 83   Overload for @ref native_timer. Equivalent to
84   `cancel_at( op, t, clock::now() + timeout )`. 84   `cancel_at( op, t, clock::now() + timeout )`.
85   85  
86   The timer's expiry is overwritten by this call. The timer must 86   The timer's expiry is overwritten by this call. The timer must
87   outlive the returned awaitable. Do not issue overlapping waits 87   outlive the returned awaitable. Do not issue overlapping waits
88   on the same timer. 88   on the same timer.
89   89  
90   @par Completion Conditions 90   @par Completion Conditions
91   The returned awaitable resumes when either: 91   The returned awaitable resumes when either:
92   @li The inner operation completes (successfully or with error). 92   @li The inner operation completes (successfully or with error).
93   @li The timeout elapses and the inner operation is cancelled. 93   @li The timeout elapses and the inner operation is cancelled.
94   @li The caller's stop token is triggered, cancelling both. 94   @li The caller's stop token is triggered, cancelling both.
95   95  
96   @par Error Conditions 96   @par Error Conditions
97   @li On timeout or parent cancellation, the inner operation 97   @li On timeout or parent cancellation, the inner operation
98   completes with an error equal to `capy::cond::canceled`. 98   completes with an error equal to `capy::cond::canceled`.
99   @li All other errors are propagated from the inner operation. 99   @li All other errors are propagated from the inner operation.
100   100  
101   @par Example 101   @par Example
102   @code 102   @code
103   native_timer<epoll> t( ioc ); 103   native_timer<epoll> t( ioc );
104   auto [ec, n] = co_await cancel_after( 104   auto [ec, n] = co_await cancel_after(
105   sock.read_some( buf ), t, 5s ); 105   sock.read_some( buf ), t, 5s );
106   if (ec == capy::cond::canceled) 106   if (ec == capy::cond::canceled)
107   // timed out 107   // timed out
108   @endcode 108   @endcode
109   109  
110   @tparam Backend A backend tag value (e.g., `epoll`). 110   @tparam Backend A backend tag value (e.g., `epoll`).
111   111  
112   @param op The inner I/O awaitable to wrap. 112   @param op The inner I/O awaitable to wrap.
113   @param t The native timer to use for the timeout. Must outlive 113   @param t The native timer to use for the timeout. Must outlive
114   the returned awaitable. 114   the returned awaitable.
115   @param timeout The relative duration after which to cancel. 115   @param timeout The relative duration after which to cancel.
116   116  
117   @return An awaitable whose result matches @p op's result type. 117   @return An awaitable whose result matches @p op's result type.
118   118  
119   @see cancel_at, native_timer 119   @see cancel_at, native_timer
120   */ 120   */
121   template<auto Backend> 121   template<auto Backend>
122   auto 122   auto
123   cancel_after( 123   cancel_after(
124   capy::IoAwaitable auto&& op, 124   capy::IoAwaitable auto&& op,
125   native_timer<Backend>& t, 125   native_timer<Backend>& t,
126   timer::duration timeout) 126   timer::duration timeout)
127   { 127   {
128   return cancel_at( 128   return cancel_at(
129   std::forward<decltype(op)>(op), t, timer::clock_type::now() + timeout); 129   std::forward<decltype(op)>(op), t, timer::clock_type::now() + timeout);
130   } 130   }
131   131  
132   /** Cancel an operation if it does not complete by a deadline. 132   /** Cancel an operation if it does not complete by a deadline.
133   133  
134   Convenience overload that creates a @ref native_timer internally, 134   Convenience overload that creates a @ref native_timer internally,
135   devirtualizing the timer wait. Otherwise identical to the 135   devirtualizing the timer wait. Otherwise identical to the
136   explicit-timer overload. 136   explicit-timer overload.
137   137  
138   @par Completion Conditions 138   @par Completion Conditions
139   The returned awaitable resumes when either: 139   The returned awaitable resumes when either:
140   @li The inner operation completes (successfully or with error). 140   @li The inner operation completes (successfully or with error).
141   @li The deadline expires and the inner operation is cancelled. 141   @li The deadline expires and the inner operation is cancelled.
142   @li The caller's stop token is triggered, cancelling both. 142   @li The caller's stop token is triggered, cancelling both.
143   143  
144   @par Error Conditions 144   @par Error Conditions
145   @li On timeout or parent cancellation, the inner operation 145   @li On timeout or parent cancellation, the inner operation
146   completes with an error equal to `capy::cond::canceled`. 146   completes with an error equal to `capy::cond::canceled`.
147   @li All other errors are propagated from the inner operation. 147   @li All other errors are propagated from the inner operation.
148   148  
149   @note Creates a timer per call. Use the explicit-timer overload 149   @note Creates a timer per call. Use the explicit-timer overload
150   to amortize allocation across multiple timeouts. 150   to amortize allocation across multiple timeouts.
151   151  
152   @note The awaiting coroutine's executor must be backed by an 152   @note The awaiting coroutine's executor must be backed by an
153   io_context (the deadline timer is built from it). Awaiting this 153   io_context (the deadline timer is built from it). Awaiting this
154   on a non-io_context executor is a precondition violation and 154   on a non-io_context executor is a precondition violation and
155   aborts; use the explicit-timer overload to construct the timer 155   aborts; use the explicit-timer overload to construct the timer
156   yourself if you need a catchable error. 156   yourself if you need a catchable error.
157   157  
158   @par Example 158   @par Example
159   @code 159   @code
160   auto [ec, n] = co_await cancel_at<epoll>( 160   auto [ec, n] = co_await cancel_at<epoll>(
161   sock.read_some( buf ), 161   sock.read_some( buf ),
162   clock::now() + 5s ); 162   clock::now() + 5s );
163   if (ec == capy::cond::canceled) 163   if (ec == capy::cond::canceled)
164   // timed out or parent cancelled 164   // timed out or parent cancelled
165   @endcode 165   @endcode
166   166  
167   @tparam Backend A backend tag value (e.g., `epoll`). 167   @tparam Backend A backend tag value (e.g., `epoll`).
168   168  
169   @param op The inner I/O awaitable to wrap. 169   @param op The inner I/O awaitable to wrap.
170   @param deadline The absolute time point at which to cancel. 170   @param deadline The absolute time point at which to cancel.
171   171  
172   @return An awaitable whose result matches @p op's result type. 172   @return An awaitable whose result matches @p op's result type.
173   173  
174   @see cancel_after, native_timer 174   @see cancel_after, native_timer
175   */ 175   */
176   template<auto Backend> 176   template<auto Backend>
177   auto 177   auto
HITCBC 178   6 cancel_at(capy::IoAwaitable auto&& op, timer::time_point deadline) 178   6 cancel_at(capy::IoAwaitable auto&& op, timer::time_point deadline)
179   { 179   {
180   return detail::cancel_at_awaitable< 180   return detail::cancel_at_awaitable<
181   std::decay_t<decltype(op)>, native_timer<Backend>, true>( 181   std::decay_t<decltype(op)>, native_timer<Backend>, true>(
HITCBC 182   6 std::forward<decltype(op)>(op), deadline); 182   6 std::forward<decltype(op)>(op), deadline);
183   } 183   }
184   184  
185   /** Cancel an operation if it does not complete within a duration. 185   /** Cancel an operation if it does not complete within a duration.
186   186  
187   Convenience overload that creates a @ref native_timer internally. 187   Convenience overload that creates a @ref native_timer internally.
188   Equivalent to `cancel_at<Backend>( op, clock::now() + timeout )`. 188   Equivalent to `cancel_at<Backend>( op, clock::now() + timeout )`.
189   189  
190   @par Completion Conditions 190   @par Completion Conditions
191   The returned awaitable resumes when either: 191   The returned awaitable resumes when either:
192   @li The inner operation completes (successfully or with error). 192   @li The inner operation completes (successfully or with error).
193   @li The timeout elapses and the inner operation is cancelled. 193   @li The timeout elapses and the inner operation is cancelled.
194   @li The caller's stop token is triggered, cancelling both. 194   @li The caller's stop token is triggered, cancelling both.
195   195  
196   @par Error Conditions 196   @par Error Conditions
197   @li On timeout or parent cancellation, the inner operation 197   @li On timeout or parent cancellation, the inner operation
198   completes with an error equal to `capy::cond::canceled`. 198   completes with an error equal to `capy::cond::canceled`.
199   @li All other errors are propagated from the inner operation. 199   @li All other errors are propagated from the inner operation.
200   200  
201   @note Creates a timer per call. Use the explicit-timer overload 201   @note Creates a timer per call. Use the explicit-timer overload
202   to amortize allocation across multiple timeouts. 202   to amortize allocation across multiple timeouts.
203   203  
204   @note The awaiting coroutine's executor must be backed by an 204   @note The awaiting coroutine's executor must be backed by an
205   io_context (the deadline timer is built from it). Awaiting this 205   io_context (the deadline timer is built from it). Awaiting this
206   on a non-io_context executor is a precondition violation and 206   on a non-io_context executor is a precondition violation and
207   aborts; use the explicit-timer overload to construct the timer 207   aborts; use the explicit-timer overload to construct the timer
208   yourself if you need a catchable error. 208   yourself if you need a catchable error.
209   209  
210   @par Example 210   @par Example
211   @code 211   @code
212   auto [ec, n] = co_await cancel_after<epoll>( 212   auto [ec, n] = co_await cancel_after<epoll>(
213   sock.read_some( buf ), 5s ); 213   sock.read_some( buf ), 5s );
214   if (ec == capy::cond::canceled) 214   if (ec == capy::cond::canceled)
215   // timed out 215   // timed out
216   @endcode 216   @endcode
217   217  
218   @tparam Backend A backend tag value (e.g., `epoll`). 218   @tparam Backend A backend tag value (e.g., `epoll`).
219   219  
220   @param op The inner I/O awaitable to wrap. 220   @param op The inner I/O awaitable to wrap.
221   @param timeout The relative duration after which to cancel. 221   @param timeout The relative duration after which to cancel.
222   222  
223   @return An awaitable whose result matches @p op's result type. 223   @return An awaitable whose result matches @p op's result type.
224   224  
225   @see cancel_at, native_timer 225   @see cancel_at, native_timer
226   */ 226   */
227   template<auto Backend> 227   template<auto Backend>
228   auto 228   auto
HITCBC 229   4 cancel_after(capy::IoAwaitable auto&& op, timer::duration timeout) 229   4 cancel_after(capy::IoAwaitable auto&& op, timer::duration timeout)
230   { 230   {
231   return cancel_at<Backend>( 231   return cancel_at<Backend>(
HITCBC 232   4 std::forward<decltype(op)>(op), timer::clock_type::now() + timeout); 232   4 std::forward<decltype(op)>(op), timer::clock_type::now() + timeout);
233   } 233   }
234   234  
235   } // namespace boost::corosio 235   } // namespace boost::corosio
236   236  
237   #endif 237   #endif