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 : co_return;
53 : @endcode
54 :
55 : @param a The awaitable to race against the deadline.
56 : @param dur The maximum duration to wait, measured from
57 : suspension.
58 :
59 : @return An awaitable yielding `io_result` matching the inner
60 : awaitable's result type.
61 :
62 : @see delay
63 : */
64 : template<capy::IoAwaitable A, typename Rep, typename Period>
65 : requires detail::is_io_result_v<
66 : std::remove_cvref_t<capy::awaitable_result_t<A>>> &&
67 : std::is_default_constructible_v<
68 : std::remove_cvref_t<capy::awaitable_result_t<A>>>
69 HIT 2055 : [[nodiscard]] auto timeout(A a, std::chrono::duration<Rep, Period> dur)
70 : {
71 : using namespace std::chrono;
72 : // Narrow reps wrap if nanoseconds::max() is converted into them;
73 : // a double comparison clamps safely in both directions.
74 : using dsec = duration<double>;
75 4082 : auto ns = dsec(dur) >= dsec((nanoseconds::max)())
76 4082 : ? (nanoseconds::max)()
77 2053 : : dsec(dur) <= dsec((nanoseconds::min)())
78 2053 : ? (nanoseconds::min)()
79 2051 : : duration_cast<nanoseconds>(dur);
80 4110 : return detail::timeout_awaitable<A>(std::move(a), ns);
81 : }
82 :
83 : /** Race an io_result-returning awaitable against an absolute deadline.
84 :
85 : Behaves as the duration overload with the deadline fixed at
86 : `tp` instead of measured from suspension.
87 :
88 : @param a The awaitable to race against the deadline.
89 : @param tp The steady-clock time point at which the awaitable
90 : is cancelled.
91 :
92 : @return An awaitable yielding `io_result` matching the inner
93 : awaitable's result type.
94 :
95 : @see delay
96 : */
97 : template<capy::IoAwaitable A>
98 : requires detail::is_io_result_v<
99 : std::remove_cvref_t<capy::awaitable_result_t<A>>> &&
100 : std::is_default_constructible_v<
101 : std::remove_cvref_t<capy::awaitable_result_t<A>>>
102 4 : [[nodiscard]] auto timeout(A a, std::chrono::steady_clock::time_point tp)
103 : {
104 4 : return detail::timeout_awaitable<A>(std::move(a), tp);
105 : }
106 :
107 : } // namespace boost::corosio
108 :
109 : #endif
|