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; they are
34 : never swallowed by the timer.
35 :
36 : @par Preconditions
37 : The awaiting coroutine's executor must belong to an
38 : `io_context`; any other execution context terminates with a
39 : diagnostic.
40 :
41 : @par Cancellation
42 : If the parent's stop token is activated, the inner awaitable
43 : is cancelled and its cancellation result is returned. Requesting
44 : stop from another thread requires a multi-threaded-capable
45 : io_context; a context running in single_threaded mode
46 : (auto-enabled at concurrency_hint == 1) does not permit
47 : cross-thread cancellation.
48 :
49 : @par Example
50 : @par !example timeout
51 :
52 : @param a The awaitable to race against the deadline.
53 : @param dur The maximum duration to wait, measured from
54 : suspension.
55 :
56 : @return An awaitable yielding `io_result` matching the inner
57 : awaitable's result type.
58 :
59 : @see delay
60 : */
61 : template<capy::IoAwaitable A, typename Rep, typename Period>
62 : requires detail::is_io_result_v<
63 : std::remove_cvref_t<capy::awaitable_result_t<A>>> &&
64 : std::is_default_constructible_v<
65 : std::remove_cvref_t<capy::awaitable_result_t<A>>>
66 : [[nodiscard]] auto
67 HIT 2055 : timeout(A a, std::chrono::duration<Rep, Period> dur)
68 : {
69 : using namespace std::chrono;
70 : // Narrow reps wrap if nanoseconds::max() is converted into them;
71 : // a double comparison clamps safely in both directions.
72 : using dsec = duration<double>;
73 2055 : auto ns = dsec(dur) >= dsec((nanoseconds::max)()) ? (nanoseconds::max)()
74 2053 : : dsec(dur) <= dsec((nanoseconds::min)())
75 2053 : ? (nanoseconds::min)()
76 2051 : : duration_cast<nanoseconds>(dur);
77 4110 : return detail::timeout_awaitable<A>(std::move(a), ns);
78 : }
79 :
80 : /** Race an io_result-returning awaitable against an absolute deadline.
81 :
82 : Behaves as the duration overload with the deadline fixed at
83 : `tp` instead of measured from suspension.
84 :
85 : @param a The awaitable to race against the deadline.
86 : @param tp The steady-clock time point at which the awaitable
87 : is cancelled.
88 :
89 : @return An awaitable yielding `io_result` matching the inner
90 : awaitable's result type.
91 :
92 : @see delay
93 : */
94 : template<capy::IoAwaitable A>
95 : requires detail::is_io_result_v<
96 : std::remove_cvref_t<capy::awaitable_result_t<A>>> &&
97 : std::is_default_constructible_v<
98 : std::remove_cvref_t<capy::awaitable_result_t<A>>>
99 : [[nodiscard]] auto
100 4 : timeout(A a, std::chrono::steady_clock::time_point tp)
101 : {
102 4 : return detail::timeout_awaitable<A>(std::move(a), tp);
103 : }
104 :
105 : } // namespace boost::corosio
106 :
107 : #endif
|