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_TIMEOUT_HPP
11 : #define BOOST_COROSIO_TIMEOUT_HPP
12 :
13 : #include <boost/corosio/detail/config.hpp>
14 : #include <boost/corosio/detail/timeout_awaitable.hpp>
15 : #include <boost/capy/concept/io_awaitable.hpp>
16 :
17 : #include <chrono>
18 : #include <type_traits>
19 : #include <utility>
20 :
21 : namespace boost::corosio {
22 :
23 : /** Race an io_result-returning awaitable against a deadline.
24 :
25 : Starts the awaitable with an interposed stop token and arms a
26 : timer. If the awaitable finishes first, its result is returned
27 : as-is (success, error, or exception). If the deadline passes
28 : first, the awaitable is cancelled and an `io_result` whose
29 : `ec` compares equal to `capy::cond::timeout` (with a
30 : default-initialized payload) is produced.
31 :
32 : Exceptions from the inner awaitable always propagate; they are
33 : never swallowed by the timer.
34 :
35 : @par Preconditions
36 : The awaiting coroutine's executor must belong to an
37 : `io_context`; any other execution context terminates with a
38 : diagnostic.
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 : @code
50 : auto [ec, n] = co_await timeout(sock.read_some(buf), 50ms);
51 : if (ec == capy::cond::timeout) {
52 : // handle timeout
53 : }
54 : @endcode
55 :
56 : @param a The awaitable to race against the deadline.
57 : @param dur The maximum duration to wait, measured from
58 : suspension.
59 :
60 : @return An awaitable yielding `io_result` matching the inner
61 : awaitable's result type.
62 :
63 : @see delay
64 : */
65 : template<capy::IoAwaitable A, typename Rep, typename Period>
66 : requires detail::is_io_result_v<
67 : std::remove_cvref_t<capy::awaitable_result_t<A>>> &&
68 : std::is_default_constructible_v<
69 : std::remove_cvref_t<capy::awaitable_result_t<A>>>
70 HIT 2038 : [[nodiscard]] auto timeout(A a, std::chrono::duration<Rep, Period> dur)
71 : {
72 : using namespace std::chrono;
73 : // Narrow reps wrap if nanoseconds::max() is converted into them;
74 : // a double comparison clamps safely in both directions.
75 : using dsec = duration<double>;
76 4062 : auto ns = dsec(dur) >= dsec((nanoseconds::max)())
77 4062 : ? (nanoseconds::max)()
78 2036 : : dsec(dur) <= dsec((nanoseconds::min)())
79 2036 : ? (nanoseconds::min)()
80 2034 : : duration_cast<nanoseconds>(dur);
81 4076 : return detail::timeout_awaitable<A>(std::move(a), ns);
82 : }
83 :
84 : /** Race an io_result-returning awaitable against an absolute deadline.
85 :
86 : Behaves as the duration overload with the deadline fixed at
87 : `tp` instead of measured from suspension.
88 :
89 : @param a The awaitable to race against the deadline.
90 : @param tp The steady-clock time point at which the awaitable
91 : is cancelled.
92 :
93 : @return An awaitable yielding `io_result` matching the inner
94 : awaitable's result type.
95 :
96 : @see delay
97 : */
98 : template<capy::IoAwaitable A>
99 : requires detail::is_io_result_v<
100 : std::remove_cvref_t<capy::awaitable_result_t<A>>> &&
101 : std::is_default_constructible_v<
102 : std::remove_cvref_t<capy::awaitable_result_t<A>>>
103 4 : [[nodiscard]] auto timeout(A a, std::chrono::steady_clock::time_point tp)
104 : {
105 4 : return detail::timeout_awaitable<A>(std::move(a), tp);
106 : }
107 :
108 : } // namespace boost::corosio
109 :
110 : #endif
|