TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Steve Gerbino
3 : // Copyright (c) 2026 Michael Vandeberg
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/corosio
9 : //
10 :
11 : #ifndef BOOST_COROSIO_TIMEOUT_HPP
12 : #define BOOST_COROSIO_TIMEOUT_HPP
13 :
14 : #include <boost/corosio/detail/config.hpp>
15 : #include <boost/corosio/detail/timeout_awaitable.hpp>
16 : #include <boost/capy/concept/io_awaitable.hpp>
17 :
18 : #include <chrono>
19 : #include <type_traits>
20 : #include <utility>
21 :
22 : namespace boost::corosio {
23 :
24 : /** Race an io_result-returning awaitable against a deadline.
25 :
26 : Starts the awaitable with an interposed stop token and arms a
27 : timer. If the awaitable finishes first, its result is returned
28 : as-is (success, error, or exception). If the deadline passes
29 : first, the awaitable is cancelled and an `io_result` whose
30 : `ec` compares equal to `capy::cond::timeout` (with a
31 : default-initialized payload) is produced.
32 :
33 : Exceptions from the inner awaitable always propagate to the caller.
34 :
35 : @pre The awaiting coroutine's executor must belong to an
36 : `io_context`. Any other execution context terminates with a
37 : diagnostic, because silently running without a timer would
38 : drop the requested timeout.
39 :
40 : @par Cancellation
41 : If the parent's stop token is activated, the inner awaitable
42 : is cancelled and its cancellation result is returned. Requesting
43 : stop from another thread requires a multi-threaded-capable
44 : `io_context`. A context running in `single_threaded` mode
45 : (auto-enabled at `concurrency_hint` == 1) does not permit
46 : cross-thread cancellation.
47 :
48 : @par Example
49 : @par !example timeout
50 :
51 : @param a The awaitable to race against the deadline.
52 : @param dur The maximum duration to wait, measured from
53 : suspension.
54 :
55 : @return An awaitable yielding `io_result` matching the inner
56 : awaitable's result type.
57 :
58 : @see delay
59 : */
60 : template<capy::IoAwaitable A, typename Rep, typename Period>
61 : requires detail::is_io_result_v<
62 : std::remove_cvref_t<capy::awaitable_result_t<A>>> &&
63 : std::is_default_constructible_v<
64 : std::remove_cvref_t<capy::awaitable_result_t<A>>>
65 : [[nodiscard]] auto
66 HIT 2055 : timeout(A a, std::chrono::duration<Rep, Period> dur)
67 : {
68 : using namespace std::chrono;
69 : // Narrow reps wrap if nanoseconds::max() is converted into them;
70 : // a double comparison clamps safely in both directions.
71 : using dsec = duration<double>;
72 2055 : auto ns = dsec(dur) >= dsec((nanoseconds::max)()) ? (nanoseconds::max)()
73 2053 : : dsec(dur) <= dsec((nanoseconds::min)())
74 2053 : ? (nanoseconds::min)()
75 2051 : : duration_cast<nanoseconds>(dur);
76 4110 : return detail::timeout_awaitable<A>(std::move(a), ns);
77 : }
78 :
79 : /** Race an io_result-returning awaitable against an absolute deadline.
80 :
81 : Behaves as the duration overload with the deadline fixed at
82 : `tp` instead of measured from suspension.
83 :
84 : @param a The awaitable to race against the deadline.
85 : @param tp The steady-clock time point at which the awaitable
86 : is cancelled.
87 :
88 : @return An awaitable yielding `io_result` matching the inner
89 : awaitable's result type.
90 :
91 : @see delay
92 : */
93 : template<capy::IoAwaitable A>
94 : requires detail::is_io_result_v<
95 : std::remove_cvref_t<capy::awaitable_result_t<A>>> &&
96 : std::is_default_constructible_v<
97 : std::remove_cvref_t<capy::awaitable_result_t<A>>>
98 : [[nodiscard]] auto
99 4 : timeout(A a, std::chrono::steady_clock::time_point tp)
100 : {
101 4 : return detail::timeout_awaitable<A>(std::move(a), tp);
102 : }
103 :
104 : } // namespace boost::corosio
105 :
106 : #endif
|