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 HIT 18 : auto cancel_at(
67 : capy::IoAwaitable auto&& op,
68 : timer& t,
69 : timer::time_point deadline)
70 : {
71 : return detail::cancel_at_awaitable<
72 : std::decay_t<decltype(op)>, timer>(
73 18 : std::forward<decltype(op)>(op), t, deadline);
74 : }
75 :
76 : /** Cancel an operation if it does not complete within a duration.
77 :
78 : Equivalent to `cancel_at( op, t, clock::now() + timeout )`.
79 :
80 : The timer's expiry is overwritten by this call. The timer must
81 : outlive the returned awaitable. Do not issue overlapping waits
82 : on the same timer.
83 :
84 : @par Completion Conditions
85 : The returned awaitable resumes when either:
86 : @li The inner operation completes (successfully or with error).
87 : @li The timeout elapses and the inner operation is cancelled.
88 : @li The caller's stop token is triggered, cancelling both.
89 :
90 : @par Error Conditions
91 : @li On timeout or parent cancellation, the inner operation
92 : completes with an error equal to `capy::cond::canceled`.
93 : @li All other errors are propagated from the inner operation.
94 :
95 : @par Example
96 : @code
97 : timer timeout_timer( ioc );
98 : auto [ec, n] = co_await cancel_after(
99 : sock.read_some( buf ), timeout_timer, 5s );
100 : if (ec == capy::cond::canceled)
101 : // timed out
102 : @endcode
103 :
104 : @param op The inner I/O awaitable to wrap.
105 : @param t The timer to use for the timeout. Must outlive
106 : the returned awaitable.
107 : @param timeout The relative duration after which to cancel.
108 :
109 : @return An awaitable whose result matches @p op's result type.
110 :
111 : @see cancel_at
112 : */
113 14 : auto cancel_after(
114 : capy::IoAwaitable auto&& op,
115 : timer& t,
116 : timer::duration timeout)
117 : {
118 : return cancel_at(
119 : std::forward<decltype(op)>(op), t,
120 14 : timer::clock_type::now() + timeout);
121 : }
122 :
123 : /** Cancel an operation if it does not complete by a deadline.
124 :
125 : Convenience overload that creates a @ref timer internally.
126 : Otherwise identical to the explicit-timer overload.
127 :
128 : @par Completion Conditions
129 : The returned awaitable resumes when either:
130 : @li The inner operation completes (successfully or with error).
131 : @li The deadline expires and the inner operation is cancelled.
132 : @li The caller's stop token is triggered, cancelling both.
133 :
134 : @par Error Conditions
135 : @li On timeout or parent cancellation, the inner operation
136 : completes with an error equal to `capy::cond::canceled`.
137 : @li All other errors are propagated from the inner operation.
138 :
139 : @note Creates a timer per call. Use the explicit-timer overload
140 : to amortize allocation across multiple timeouts.
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 6 : auto cancel_at(
159 : capy::IoAwaitable auto&& op,
160 : timer::time_point deadline)
161 : {
162 : return detail::cancel_at_awaitable<
163 : std::decay_t<decltype(op)>, timer, true>(
164 6 : std::forward<decltype(op)>(op), deadline);
165 : }
166 :
167 : /** Cancel an operation if it does not complete within a duration.
168 :
169 : Convenience overload that creates a @ref timer internally.
170 : Equivalent to `cancel_at( op, clock::now() + timeout )`.
171 :
172 : @par Completion Conditions
173 : The returned awaitable resumes when either:
174 : @li The inner operation completes (successfully or with error).
175 : @li The timeout elapses and the inner operation is cancelled.
176 : @li The caller's stop token is triggered, cancelling both.
177 :
178 : @par Error Conditions
179 : @li On timeout or parent cancellation, the inner operation
180 : completes with an error equal to `capy::cond::canceled`.
181 : @li All other errors are propagated from the inner operation.
182 :
183 : @note Creates a timer per call. Use the explicit-timer overload
184 : to amortize allocation across multiple timeouts.
185 :
186 : @par Example
187 : @code
188 : auto [ec, n] = co_await cancel_after(
189 : sock.read_some( buf ), 5s );
190 : if (ec == capy::cond::canceled)
191 : // timed out
192 : @endcode
193 :
194 : @param op The inner I/O awaitable to wrap.
195 : @param timeout The relative duration after which to cancel.
196 :
197 : @return An awaitable whose result matches @p op's result type.
198 :
199 : @see cancel_at
200 : */
201 4 : auto cancel_after(
202 : capy::IoAwaitable auto&& op,
203 : timer::duration timeout)
204 : {
205 : return cancel_at(
206 : std::forward<decltype(op)>(op),
207 4 : timer::clock_type::now() + timeout);
208 : }
209 :
210 : } // namespace boost::corosio
211 :
212 : #endif
|