include/boost/corosio/timer.hpp

100.0% Lines (35/35) 100.0% List of functions (13/13)
timer.hpp
f(x) Functions (13)
Function Calls Lines Blocks
boost::corosio::timer::timer<long, std::ratio<1l, 1000l> >(boost::capy::execution_context&, std::chrono::duration<long, std::ratio<1l, 1000l> >) :93 8x 100.0% 80.0% boost::corosio::timer::timer<boost::capy::thread_pool::executor_type>(boost::capy::thread_pool::executor_type const&) :112 2x 50.0% 100.0% boost::corosio::timer::timer<boost::corosio::io_context::executor_type>(boost::corosio::io_context::executor_type const&) :112 2x 100.0% 100.0% boost::corosio::timer::timer<boost::corosio::io_context::executor_type>(boost::corosio::io_context::executor_type const&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >) :126 2x 100.0% 100.0% boost::corosio::timer::timer<boost::corosio::io_context::executor_type, long, std::ratio<1l, 1000l> >(boost::corosio::io_context::executor_type const&, std::chrono::duration<long, std::ratio<1l, 1000l> >) :140 2x 100.0% 100.0% boost::corosio::timer::cancel_one() :183 4x 100.0% 100.0% boost::corosio::timer::expires_at(std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >) :198 54x 100.0% 100.0% boost::corosio::timer::expires_after(std::chrono::duration<long, std::ratio<1l, 1000000000l> >) :216 8700x 100.0% 94.0% unsigned long boost::corosio::timer::expires_after<long, std::ratio<1l, 1000000l> >(std::chrono::duration<long, std::ratio<1l, 1000000l> >) :240 7972x 100.0% 100.0% unsigned long boost::corosio::timer::expires_after<long, std::ratio<1l, 1000l> >(std::chrono::duration<long, std::ratio<1l, 1000l> >) :240 644x 100.0% 100.0% unsigned long boost::corosio::timer::expires_after<long, std::ratio<1l, 1l> >(std::chrono::duration<long, std::ratio<1l, 1l> >) :240 68x 100.0% 100.0% unsigned long boost::corosio::timer::expires_after<long, std::ratio<3600l, 1l> >(std::chrono::duration<long, std::ratio<3600l, 1l> >) :240 16x 100.0% 100.0% boost::corosio::timer::get() const :254 8776x 100.0% 100.0%
Line TLA Hits 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 <concepts>
21 #include <cstddef>
22 #include <type_traits>
23
24 namespace boost::corosio {
25
26 /** An asynchronous timer for coroutine I/O.
27
28 This class provides asynchronous timer operations that return
29 awaitable types. The timer can be used to schedule operations
30 to occur after a specified duration or at a specific time point.
31
32 Multiple coroutines may wait concurrently on the same timer.
33 When the timer expires, all waiters complete with success. When
34 the timer is cancelled, all waiters complete with an error that
35 compares equal to `capy::cond::canceled`.
36
37 Each timer operation participates in the affine awaitable protocol,
38 ensuring coroutines resume on the correct executor.
39
40 @par Thread Safety
41 Distinct objects: Safe.@n
42 Shared objects: Unsafe.
43
44 @par Semantics
45 Timers are not backed by per-timer kernel objects. The io_context's
46 timer service keeps a process-side min-heap of pending expirations;
47 the nearest expiry drives the reactor's poll timeout, and expirations
48 are processed in the run loop.
49 */
50 class BOOST_COROSIO_DECL timer : public io_timer
51 {
52 public:
53 /// Alias for backward compatibility.
54 using implementation = io_timer::implementation;
55
56 /** Destructor.
57
58 Cancels any pending operations and releases timer resources.
59 */
60 ~timer() override;
61
62 /** Construct a timer from an execution context.
63
64 @param ctx The execution context that will own this timer. It
65 must be a corosio io_context; otherwise the constructor
66 throws (a timer service is required).
67
68 @throws std::logic_error if @p ctx is not an io_context.
69 */
70 explicit timer(capy::execution_context& ctx);
71
72 /** Construct a timer with an initial absolute expiry time.
73
74 @param ctx The execution context that will own this timer. It
75 must be a corosio io_context; otherwise the constructor
76 throws (a timer service is required).
77 @param t The initial expiry time point.
78
79 @throws std::logic_error if @p ctx is not an io_context.
80 */
81 timer(capy::execution_context& ctx, time_point t);
82
83 /** Construct a timer with an initial relative expiry time.
84
85 @param ctx The execution context that will own this timer. It
86 must be a corosio io_context; otherwise the constructor
87 throws (a timer service is required).
88 @param d The initial expiry duration relative to now.
89
90 @throws std::logic_error if @p ctx is not an io_context.
91 */
92 template<class Rep, class Period>
93 8x timer(capy::execution_context& ctx, std::chrono::duration<Rep, Period> d)
94 8x : timer(ctx)
95 {
96 8x expires_after(d);
97 8x }
98
99 /** Construct a timer from an executor.
100
101 The timer is associated with the executor's context, which must
102 be a corosio io_context.
103
104 @param ex The executor whose context will own this timer.
105
106 @throws std::logic_error if the executor's context is not an
107 io_context.
108 */
109 template<class Ex>
110 requires(!std::same_as<std::remove_cvref_t<Ex>, timer>) &&
111 capy::Executor<Ex>
112 4x explicit timer(Ex const& ex) : timer(ex.context())
113 {
114 2x }
115
116 /** Construct a timer from an executor with an absolute expiry time.
117
118 @param ex The executor whose context will own this timer.
119 @param t The initial expiry time point.
120
121 @throws std::logic_error if the executor's context is not an
122 io_context.
123 */
124 template<class Ex>
125 requires capy::Executor<Ex>
126 2x timer(Ex const& ex, time_point t) : timer(ex.context(), t)
127 {
128 2x }
129
130 /** Construct a timer from an executor with a relative expiry time.
131
132 @param ex The executor whose context will own this timer.
133 @param d The initial expiry duration relative to now.
134
135 @throws std::logic_error if the executor's context is not an
136 io_context.
137 */
138 template<class Ex, class Rep, class Period>
139 requires capy::Executor<Ex>
140 2x timer(Ex const& ex, std::chrono::duration<Rep, Period> d)
141 2x : timer(ex.context(), d)
142 {
143 2x }
144
145 /** Move constructor.
146
147 Transfers ownership of the timer resources.
148
149 @param other The timer to move from.
150
151 @pre No awaitables returned by @p other's methods exist.
152 @pre The execution context associated with @p other must
153 outlive this timer.
154 */
155 timer(timer&& other) noexcept;
156
157 /** Move assignment operator.
158
159 Closes any existing timer and transfers ownership.
160
161 @param other The timer to move from.
162
163 @pre No awaitables returned by either `*this` or @p other's
164 methods exist.
165 @pre The execution context associated with @p other must
166 outlive this timer.
167
168 @return Reference to this timer.
169 */
170 timer& operator=(timer&& other) noexcept;
171
172 timer(timer const&) = delete;
173 timer& operator=(timer const&) = delete;
174
175 /** Cancel one pending asynchronous wait operation.
176
177 The oldest pending wait is cancelled (FIFO order). It
178 completes with an error code that compares equal to
179 `capy::cond::canceled`.
180
181 @return The number of operations that were cancelled (0 or 1).
182 */
183 4x std::size_t cancel_one()
184 {
185 4x if (!get().might_have_pending_waits_)
186 2x return 0;
187 2x return do_cancel_one();
188 }
189
190 /** Set the timer's expiry time as an absolute time.
191
192 Any pending asynchronous wait operations will be cancelled.
193
194 @param t The expiry time to be used for the timer.
195
196 @return The number of pending operations that were cancelled.
197 */
198 54x std::size_t expires_at(time_point t)
199 {
200 54x auto& impl = get();
201 54x impl.expiry_ = t;
202 54x if (impl.heap_index_ == implementation::npos &&
203 50x !impl.might_have_pending_waits_)
204 50x return 0;
205 4x return do_update_expiry();
206 }
207
208 /** Set the timer's expiry time relative to now.
209
210 Any pending asynchronous wait operations will be cancelled.
211
212 @param d The expiry time relative to now.
213
214 @return The number of pending operations that were cancelled.
215 */
216 8700x std::size_t expires_after(duration d)
217 {
218 8700x auto& impl = get();
219 8700x if (d <= duration::zero())
220 6x impl.expiry_ = (time_point::min)();
221 else
222 8694x impl.expiry_ = clock_type::now() + d;
223 8700x if (impl.heap_index_ == implementation::npos &&
224 8696x !impl.might_have_pending_waits_)
225 8696x return 0;
226 4x return do_update_expiry();
227 }
228
229 /** Set the timer's expiry time relative to now.
230
231 This is a convenience overload that accepts any duration type
232 and converts it to the timer's native duration type. Any
233 pending asynchronous wait operations will be cancelled.
234
235 @param d The expiry time relative to now.
236
237 @return The number of pending operations that were cancelled.
238 */
239 template<class Rep, class Period>
240 8700x std::size_t expires_after(std::chrono::duration<Rep, Period> d)
241 {
242 8700x return expires_after(std::chrono::duration_cast<duration>(d));
243 }
244
245 protected:
246 explicit timer(handle h) noexcept : io_timer(std::move(h)) {}
247
248 private:
249 std::size_t do_cancel() override;
250 std::size_t do_cancel_one();
251 std::size_t do_update_expiry();
252
253 /// Return the underlying implementation.
254 8776x implementation& get() const noexcept
255 {
256 8776x return *static_cast<implementation*>(h_.get());
257 }
258 };
259
260 } // namespace boost::corosio
261
262 #endif
263