TLA Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2026 Steve Gerbino
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_TIMER_HPP
12 : #define BOOST_COROSIO_TIMER_HPP
13 :
14 : #include <boost/corosio/detail/config.hpp>
15 : #include <boost/corosio/io/io_timer.hpp>
16 : #include <boost/capy/ex/execution_context.hpp>
17 : #include <boost/capy/concept/executor.hpp>
18 :
19 : #include <chrono>
20 : #include <cstddef>
21 :
22 : namespace boost::corosio {
23 :
24 : /** An asynchronous timer for coroutine I/O.
25 :
26 : This class provides asynchronous timer operations that return
27 : awaitable types. The timer can be used to schedule operations
28 : to occur after a specified duration or at a specific time point.
29 :
30 : Multiple coroutines may wait concurrently on the same timer.
31 : When the timer expires, all waiters complete with success. When
32 : the timer is cancelled, all waiters complete with an error that
33 : compares equal to `capy::cond::canceled`.
34 :
35 : Each timer operation participates in the affine awaitable protocol,
36 : ensuring coroutines resume on the correct executor.
37 :
38 : @par Thread Safety
39 : Distinct objects: Safe.@n
40 : Shared objects: Unsafe.
41 :
42 : @par Semantics
43 : Wraps platform timer facilities via the io_context reactor.
44 : Operations dispatch to OS timer APIs (timerfd, IOCP timers,
45 : kqueue EVFILT_TIMER).
46 : */
47 : class BOOST_COROSIO_DECL timer : public io_timer
48 : {
49 : public:
50 : /// Alias for backward compatibility.
51 : using implementation = io_timer::implementation;
52 :
53 : /** Destructor.
54 :
55 : Cancels any pending operations and releases timer resources.
56 : */
57 : ~timer() override;
58 :
59 : /** Construct a timer from an execution context.
60 :
61 : @param ctx The execution context that will own this timer.
62 : */
63 : explicit timer(capy::execution_context& ctx);
64 :
65 : /** Construct a timer with an initial absolute expiry time.
66 :
67 : @param ctx The execution context that will own this timer.
68 : @param t The initial expiry time point.
69 : */
70 : timer(capy::execution_context& ctx, time_point t);
71 :
72 : /** Construct a timer with an initial relative expiry time.
73 :
74 : @param ctx The execution context that will own this timer.
75 : @param d The initial expiry duration relative to now.
76 : */
77 : template<class Rep, class Period>
78 HIT 2 : timer(capy::execution_context& ctx, std::chrono::duration<Rep, Period> d)
79 2 : : timer(ctx)
80 : {
81 2 : expires_after(d);
82 2 : }
83 :
84 : /** Move constructor.
85 :
86 : Transfers ownership of the timer resources.
87 :
88 : @param other The timer to move from.
89 : */
90 : timer(timer&& other) noexcept;
91 :
92 : /** Move assignment operator.
93 :
94 : Closes any existing timer and transfers ownership.
95 :
96 : @param other The timer to move from.
97 :
98 : @return Reference to this timer.
99 : */
100 : timer& operator=(timer&& other) noexcept;
101 :
102 : timer(timer const&) = delete;
103 : timer& operator=(timer const&) = delete;
104 :
105 : /** Cancel one pending asynchronous wait operation.
106 :
107 : The oldest pending wait is cancelled (FIFO order). It
108 : completes with an error code that compares equal to
109 : `capy::cond::canceled`.
110 :
111 : @return The number of operations that were cancelled (0 or 1).
112 : */
113 4 : std::size_t cancel_one()
114 : {
115 4 : if (!get().might_have_pending_waits_)
116 2 : return 0;
117 2 : return do_cancel_one();
118 : }
119 :
120 : /** Set the timer's expiry time as an absolute time.
121 :
122 : Any pending asynchronous wait operations will be cancelled.
123 :
124 : @param t The expiry time to be used for the timer.
125 :
126 : @return The number of pending operations that were cancelled.
127 : */
128 18 : std::size_t expires_at(time_point t)
129 : {
130 18 : auto& impl = get();
131 18 : impl.expiry_ = t;
132 18 : if (impl.heap_index_ == implementation::npos &&
133 16 : !impl.might_have_pending_waits_)
134 16 : return 0;
135 2 : return do_update_expiry();
136 : }
137 :
138 : /** Set the timer's expiry time relative to now.
139 :
140 : Any pending asynchronous wait operations will be cancelled.
141 :
142 : @param d The expiry time relative to now.
143 :
144 : @return The number of pending operations that were cancelled.
145 : */
146 8636 : std::size_t expires_after(duration d)
147 : {
148 8636 : auto& impl = get();
149 8636 : if (d <= duration::zero())
150 6 : impl.expiry_ = (time_point::min)();
151 : else
152 8630 : impl.expiry_ = clock_type::now() + d;
153 8636 : if (impl.heap_index_ == implementation::npos &&
154 8632 : !impl.might_have_pending_waits_)
155 8632 : return 0;
156 4 : return do_update_expiry();
157 : }
158 :
159 : /** Set the timer's expiry time relative to now.
160 :
161 : This is a convenience overload that accepts any duration type
162 : and converts it to the timer's native duration type. Any
163 : pending asynchronous wait operations will be cancelled.
164 :
165 : @param d The expiry time relative to now.
166 :
167 : @return The number of pending operations that were cancelled.
168 : */
169 : template<class Rep, class Period>
170 8636 : std::size_t expires_after(std::chrono::duration<Rep, Period> d)
171 : {
172 8636 : return expires_after(std::chrono::duration_cast<duration>(d));
173 : }
174 :
175 : protected:
176 : explicit timer(handle h) noexcept : io_timer(std::move(h)) {}
177 :
178 : private:
179 : std::size_t do_cancel() override;
180 : std::size_t do_cancel_one();
181 : std::size_t do_update_expiry();
182 :
183 : /// Return the underlying implementation.
184 8674 : implementation& get() const noexcept
185 : {
186 8674 : return *static_cast<implementation*>(h_.get());
187 : }
188 : };
189 :
190 : } // namespace boost::corosio
191 :
192 : #endif
|