include/boost/corosio/timer.hpp

100.0% Lines (28/28) 100.0% Functions (9/9)
include/boost/corosio/timer.hpp
Line 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 <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 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
202