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