100.00% Lines (8/8) 100.00% Functions (4/4)
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_CANCEL_HPP 10   #ifndef BOOST_COROSIO_CANCEL_HPP
11   #define BOOST_COROSIO_CANCEL_HPP 11   #define BOOST_COROSIO_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/timer.hpp> 14   #include <boost/corosio/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   Races @p op against the given timer. If the deadline is reached 24   Races @p op against the given timer. If the deadline is reached
25   first, the inner operation is cancelled via its stop token and 25   first, the inner operation is cancelled via its stop token and
26   completes with an error comparing equal to `capy::cond::canceled`. 26   completes with an error comparing equal to `capy::cond::canceled`.
27   If the inner operation completes first, the timer is cancelled. 27   If the inner operation completes first, the timer is cancelled.
28   28  
29   Parent cancellation (from the caller's stop token) is forwarded 29   Parent cancellation (from the caller's stop token) is forwarded
30   to both the inner operation and the timeout timer. 30   to both the inner operation and the timeout timer.
31   31  
32   The timer's expiry is overwritten by this call. The timer must 32   The timer's expiry is overwritten by this call. The timer must
33   outlive the returned awaitable. Do not issue overlapping waits 33   outlive the returned awaitable. Do not issue overlapping waits
34   on the same timer. 34   on the same timer.
35   35  
36   @par Completion Conditions 36   @par Completion Conditions
37   The returned awaitable resumes when either: 37   The returned awaitable resumes when either:
38   @li The inner operation completes (successfully or with error). 38   @li The inner operation completes (successfully or with error).
39   @li The deadline expires and the inner operation is cancelled. 39   @li The deadline expires and the inner operation is cancelled.
40   @li The caller's stop token is triggered, cancelling both. 40   @li The caller's stop token is triggered, cancelling both.
41   41  
42   @par Error Conditions 42   @par Error Conditions
43   @li On timeout or parent cancellation, the inner operation 43   @li On timeout or parent cancellation, the inner operation
44   completes with an error equal to `capy::cond::canceled`. 44   completes with an error equal to `capy::cond::canceled`.
45   @li All other errors are propagated from the inner operation. 45   @li All other errors are propagated from the inner operation.
46   46  
47   @par Example 47   @par Example
48   @code 48   @code
49   timer timeout_timer( ioc ); 49   timer timeout_timer( ioc );
50   auto [ec, n] = co_await cancel_at( 50   auto [ec, n] = co_await cancel_at(
51   sock.read_some( buf ), timeout_timer, 51   sock.read_some( buf ), timeout_timer,
52   clock::now() + 5s ); 52   clock::now() + 5s );
53   if (ec == capy::cond::canceled) 53   if (ec == capy::cond::canceled)
54   // timed out or parent cancelled 54   // timed out or parent cancelled
55   @endcode 55   @endcode
56   56  
57   @param op The inner I/O awaitable to wrap. 57   @param op The inner I/O awaitable to wrap.
58   @param t The timer to use for the deadline. Must outlive 58   @param t The timer to use for the deadline. Must outlive
59   the returned awaitable. 59   the returned awaitable.
60   @param deadline The absolute time point at which to cancel. 60   @param deadline The absolute time point at which to cancel.
61   61  
62   @return An awaitable whose result matches @p op's result type. 62   @return An awaitable whose result matches @p op's result type.
63   63  
64   @see cancel_after 64   @see cancel_after
65   */ 65   */
66   auto 66   auto
HITCBC 67   18 cancel_at(capy::IoAwaitable auto&& op, timer& t, timer::time_point deadline) 67   18 cancel_at(capy::IoAwaitable auto&& op, timer& t, timer::time_point deadline)
68   { 68   {
69   return detail::cancel_at_awaitable<std::decay_t<decltype(op)>, timer>( 69   return detail::cancel_at_awaitable<std::decay_t<decltype(op)>, timer>(
HITCBC 70   18 std::forward<decltype(op)>(op), t, deadline); 70   18 std::forward<decltype(op)>(op), t, deadline);
71   } 71   }
72   72  
73   /** Cancel an operation if it does not complete within a duration. 73   /** Cancel an operation if it does not complete within a duration.
74   74  
75   Equivalent to `cancel_at( op, t, clock::now() + timeout )`. 75   Equivalent to `cancel_at( op, t, clock::now() + timeout )`.
76   76  
77   The timer's expiry is overwritten by this call. The timer must 77   The timer's expiry is overwritten by this call. The timer must
78   outlive the returned awaitable. Do not issue overlapping waits 78   outlive the returned awaitable. Do not issue overlapping waits
79   on the same timer. 79   on the same timer.
80   80  
81   @par Completion Conditions 81   @par Completion Conditions
82   The returned awaitable resumes when either: 82   The returned awaitable resumes when either:
83   @li The inner operation completes (successfully or with error). 83   @li The inner operation completes (successfully or with error).
84   @li The timeout elapses and the inner operation is cancelled. 84   @li The timeout elapses and the inner operation is cancelled.
85   @li The caller's stop token is triggered, cancelling both. 85   @li The caller's stop token is triggered, cancelling both.
86   86  
87   @par Error Conditions 87   @par Error Conditions
88   @li On timeout or parent cancellation, the inner operation 88   @li On timeout or parent cancellation, the inner operation
89   completes with an error equal to `capy::cond::canceled`. 89   completes with an error equal to `capy::cond::canceled`.
90   @li All other errors are propagated from the inner operation. 90   @li All other errors are propagated from the inner operation.
91   91  
92   @par Example 92   @par Example
93   @code 93   @code
94   timer timeout_timer( ioc ); 94   timer timeout_timer( ioc );
95   auto [ec, n] = co_await cancel_after( 95   auto [ec, n] = co_await cancel_after(
96   sock.read_some( buf ), timeout_timer, 5s ); 96   sock.read_some( buf ), timeout_timer, 5s );
97   if (ec == capy::cond::canceled) 97   if (ec == capy::cond::canceled)
98   // timed out 98   // timed out
99   @endcode 99   @endcode
100   100  
101   @param op The inner I/O awaitable to wrap. 101   @param op The inner I/O awaitable to wrap.
102   @param t The timer to use for the timeout. Must outlive 102   @param t The timer to use for the timeout. Must outlive
103   the returned awaitable. 103   the returned awaitable.
104   @param timeout The relative duration after which to cancel. 104   @param timeout The relative duration after which to cancel.
105   105  
106   @return An awaitable whose result matches @p op's result type. 106   @return An awaitable whose result matches @p op's result type.
107   107  
108   @see cancel_at 108   @see cancel_at
109   */ 109   */
110   auto 110   auto
HITCBC 111   14 cancel_after(capy::IoAwaitable auto&& op, timer& t, timer::duration timeout) 111   14 cancel_after(capy::IoAwaitable auto&& op, timer& t, timer::duration timeout)
112   { 112   {
113   return cancel_at( 113   return cancel_at(
HITCBC 114   14 std::forward<decltype(op)>(op), t, timer::clock_type::now() + timeout); 114   14 std::forward<decltype(op)>(op), t, timer::clock_type::now() + timeout);
115   } 115   }
116   116  
117   /** Cancel an operation if it does not complete by a deadline. 117   /** Cancel an operation if it does not complete by a deadline.
118   118  
119   Convenience overload that creates a @ref timer internally. 119   Convenience overload that creates a @ref timer internally.
120   Otherwise identical to the explicit-timer overload. 120   Otherwise identical to the explicit-timer overload.
121   121  
122   @par Completion Conditions 122   @par Completion Conditions
123   The returned awaitable resumes when either: 123   The returned awaitable resumes when either:
124   @li The inner operation completes (successfully or with error). 124   @li The inner operation completes (successfully or with error).
125   @li The deadline expires and the inner operation is cancelled. 125   @li The deadline expires and the inner operation is cancelled.
126   @li The caller's stop token is triggered, cancelling both. 126   @li The caller's stop token is triggered, cancelling both.
127   127  
128   @par Error Conditions 128   @par Error Conditions
129   @li On timeout or parent cancellation, the inner operation 129   @li On timeout or parent cancellation, the inner operation
130   completes with an error equal to `capy::cond::canceled`. 130   completes with an error equal to `capy::cond::canceled`.
131   @li All other errors are propagated from the inner operation. 131   @li All other errors are propagated from the inner operation.
132   132  
133   @note Creates a timer per call. Use the explicit-timer overload 133   @note Creates a timer per call. Use the explicit-timer overload
134   to amortize allocation across multiple timeouts. 134   to amortize allocation across multiple timeouts.
135   135  
136   @par Example 136   @par Example
137   @code 137   @code
138   auto [ec, n] = co_await cancel_at( 138   auto [ec, n] = co_await cancel_at(
139   sock.read_some( buf ), 139   sock.read_some( buf ),
140   clock::now() + 5s ); 140   clock::now() + 5s );
141   if (ec == capy::cond::canceled) 141   if (ec == capy::cond::canceled)
142   // timed out or parent cancelled 142   // timed out or parent cancelled
143   @endcode 143   @endcode
144   144  
145   @param op The inner I/O awaitable to wrap. 145   @param op The inner I/O awaitable to wrap.
146   @param deadline The absolute time point at which to cancel. 146   @param deadline The absolute time point at which to cancel.
147   147  
148   @return An awaitable whose result matches @p op's result type. 148   @return An awaitable whose result matches @p op's result type.
149   149  
150   @see cancel_after 150   @see cancel_after
151   */ 151   */
152   auto 152   auto
HITCBC 153   6 cancel_at(capy::IoAwaitable auto&& op, timer::time_point deadline) 153   6 cancel_at(capy::IoAwaitable auto&& op, timer::time_point deadline)
154   { 154   {
155   return detail::cancel_at_awaitable<std::decay_t<decltype(op)>, timer, true>( 155   return detail::cancel_at_awaitable<std::decay_t<decltype(op)>, timer, true>(
HITCBC 156   6 std::forward<decltype(op)>(op), deadline); 156   6 std::forward<decltype(op)>(op), deadline);
157   } 157   }
158   158  
159   /** Cancel an operation if it does not complete within a duration. 159   /** Cancel an operation if it does not complete within a duration.
160   160  
161   Convenience overload that creates a @ref timer internally. 161   Convenience overload that creates a @ref timer internally.
162   Equivalent to `cancel_at( op, clock::now() + timeout )`. 162   Equivalent to `cancel_at( op, clock::now() + timeout )`.
163   163  
164   @par Completion Conditions 164   @par Completion Conditions
165   The returned awaitable resumes when either: 165   The returned awaitable resumes when either:
166   @li The inner operation completes (successfully or with error). 166   @li The inner operation completes (successfully or with error).
167   @li The timeout elapses and the inner operation is cancelled. 167   @li The timeout elapses and the inner operation is cancelled.
168   @li The caller's stop token is triggered, cancelling both. 168   @li The caller's stop token is triggered, cancelling both.
169   169  
170   @par Error Conditions 170   @par Error Conditions
171   @li On timeout or parent cancellation, the inner operation 171   @li On timeout or parent cancellation, the inner operation
172   completes with an error equal to `capy::cond::canceled`. 172   completes with an error equal to `capy::cond::canceled`.
173   @li All other errors are propagated from the inner operation. 173   @li All other errors are propagated from the inner operation.
174   174  
175   @note Creates a timer per call. Use the explicit-timer overload 175   @note Creates a timer per call. Use the explicit-timer overload
176   to amortize allocation across multiple timeouts. 176   to amortize allocation across multiple timeouts.
177   177  
178   @par Example 178   @par Example
179   @code 179   @code
180   auto [ec, n] = co_await cancel_after( 180   auto [ec, n] = co_await cancel_after(
181   sock.read_some( buf ), 5s ); 181   sock.read_some( buf ), 5s );
182   if (ec == capy::cond::canceled) 182   if (ec == capy::cond::canceled)
183   // timed out 183   // timed out
184   @endcode 184   @endcode
185   185  
186   @param op The inner I/O awaitable to wrap. 186   @param op The inner I/O awaitable to wrap.
187   @param timeout The relative duration after which to cancel. 187   @param timeout The relative duration after which to cancel.
188   188  
189   @return An awaitable whose result matches @p op's result type. 189   @return An awaitable whose result matches @p op's result type.
190   190  
191   @see cancel_at 191   @see cancel_at
192   */ 192   */
193   auto 193   auto
HITCBC 194   4 cancel_after(capy::IoAwaitable auto&& op, timer::duration timeout) 194   4 cancel_after(capy::IoAwaitable auto&& op, timer::duration timeout)
195   { 195   {
196   return cancel_at( 196   return cancel_at(
HITCBC 197   4 std::forward<decltype(op)>(op), timer::clock_type::now() + timeout); 197   4 std::forward<decltype(op)>(op), timer::clock_type::now() + timeout);
198   } 198   }
199   199  
200   } // namespace boost::corosio 200   } // namespace boost::corosio
201   201  
202   #endif 202   #endif