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 : @pre No awaitables returned by @p other's methods exist.
91 : @pre The execution context associated with @p other must
92 : outlive this timer.
93 : */
94 : timer(timer&& other) noexcept;
95 :
96 : /** Move assignment operator.
97 :
98 : Closes any existing timer and transfers ownership.
99 :
100 : @param other The timer to move from.
101 :
102 : @pre No awaitables returned by either `*this` or @p other's
103 : methods exist.
104 : @pre The execution context associated with @p other must
105 : outlive this timer.
106 :
107 : @return Reference to this timer.
108 : */
109 : timer& operator=(timer&& other) noexcept;
110 :
111 : timer(timer const&) = delete;
112 : timer& operator=(timer const&) = delete;
113 :
114 : /** Cancel one pending asynchronous wait operation.
115 :
116 : The oldest pending wait is cancelled (FIFO order). It
117 : completes with an error code that compares equal to
118 : `capy::cond::canceled`.
119 :
120 : @return The number of operations that were cancelled (0 or 1).
121 : */
122 4 : std::size_t cancel_one()
123 : {
124 4 : if (!get().might_have_pending_waits_)
125 2 : return 0;
126 2 : return do_cancel_one();
127 : }
128 :
129 : /** Set the timer's expiry time as an absolute time.
130 :
131 : Any pending asynchronous wait operations will be cancelled.
132 :
133 : @param t The expiry time to be used for the timer.
134 :
135 : @return The number of pending operations that were cancelled.
136 : */
137 18 : std::size_t expires_at(time_point t)
138 : {
139 18 : auto& impl = get();
140 18 : impl.expiry_ = t;
141 18 : if (impl.heap_index_ == implementation::npos &&
142 16 : !impl.might_have_pending_waits_)
143 16 : return 0;
144 2 : return do_update_expiry();
145 : }
146 :
147 : /** Set the timer's expiry time relative to now.
148 :
149 : Any pending asynchronous wait operations will be cancelled.
150 :
151 : @param d The expiry time relative to now.
152 :
153 : @return The number of pending operations that were cancelled.
154 : */
155 7975 : std::size_t expires_after(duration d)
156 : {
157 7975 : auto& impl = get();
158 7975 : if (d <= duration::zero())
159 6 : impl.expiry_ = (time_point::min)();
160 : else
161 7969 : impl.expiry_ = clock_type::now() + d;
162 7975 : if (impl.heap_index_ == implementation::npos &&
163 7971 : !impl.might_have_pending_waits_)
164 7971 : return 0;
165 4 : return do_update_expiry();
166 : }
167 :
168 : /** Set the timer's expiry time relative to now.
169 :
170 : This is a convenience overload that accepts any duration type
171 : and converts it to the timer's native duration type. Any
172 : pending asynchronous wait operations will be cancelled.
173 :
174 : @param d The expiry time relative to now.
175 :
176 : @return The number of pending operations that were cancelled.
177 : */
178 : template<class Rep, class Period>
179 7975 : std::size_t expires_after(std::chrono::duration<Rep, Period> d)
180 : {
181 7975 : return expires_after(std::chrono::duration_cast<duration>(d));
182 : }
183 :
184 : protected:
185 : explicit timer(handle h) noexcept : io_timer(std::move(h)) {}
186 :
187 : private:
188 : std::size_t do_cancel() override;
189 : std::size_t do_cancel_one();
190 : std::size_t do_update_expiry();
191 :
192 : /// Return the underlying implementation.
193 8013 : implementation& get() const noexcept
194 : {
195 8013 : return *static_cast<implementation*>(h_.get());
196 : }
197 : };
198 :
199 : } // namespace boost::corosio
200 :
201 : #endif
|