src/corosio/src/timer.cpp

53.8% Lines (21/39) 33.3% List of functions (3/9)
timer.cpp
f(x) Functions (9)
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 #include <boost/corosio/detail/timer.hpp>
12 #include <boost/corosio/detail/timer_service.hpp>
13
14 namespace boost::corosio::detail {
15
16 8457x timer::~timer() = default;
17
18 8461x timer::timer(capy::execution_context& ctx)
19 8461x : io_object(create_handle<detail::timer_service>(ctx))
20 {
21 8457x }
22
23 timer::timer(capy::execution_context& ctx, time_point t) : timer(ctx)
24 {
25 expires_at(t);
26 }
27
28 timer::timer(timer&& other) noexcept : io_object(std::move(other)) {}
29
30 timer&
31 timer::operator=(timer&& other) noexcept
32 {
33 if (this != &other)
34 h_ = std::move(other.h_);
35 return *this;
36 }
37
38 std::size_t
39 timer::do_cancel()
40 {
41 return detail::timer_service_cancel(get());
42 }
43
44 std::size_t
45 timer::do_cancel_one()
46 {
47 return detail::timer_service_cancel_one(get());
48 }
49
50 std::size_t
51 timer::do_update_expiry()
52 {
53 return detail::timer_service_update_expiry(get());
54 }
55
56 // Not inline: wait_awaitable::await_suspend (defined in timer.hpp) calls
57 // this from translation units that may never include timer_service.hpp,
58 // so this must be the one strong definition the linker can always find
59 // wherever a detail::timer is used (every such user also needs timer's
60 // constructors, defined in this same translation unit).
61 std::coroutine_handle<>
62 7601x timer::implementation::wait(
63 std::coroutine_handle<> h,
64 capy::executor_ref d,
65 std::stop_token token,
66 std::error_code* ec,
67 capy::continuation* cont)
68 {
69 // Already-expired fast path — no waiter_node, no mutex.
70 // Post instead of dispatch so the coroutine yields to the
71 // scheduler, allowing other queued work to run.
72 15202x if (heap_index_.load(std::memory_order_relaxed) == npos)
73 {
74 7601x if (expiry_ == (time_point::min)() || expiry_ <= clock_type::now())
75 {
76 if (ec)
77 *ec = {};
78 d.post(*cont);
79 return std::noop_coroutine();
80 }
81 }
82
83 // Publication-last invariant: fully initialize the waiter, count
84 // its work, and arm cancellation BEFORE insert_waiter() publishes
85 // it into the heap/list where a concurrent run() thread can fire
86 // it. impl_ stays null until insert_waiter() sets it under the
87 // mutex, so a stop callback that fires early (cancel_waiter) sees a
88 // null impl_ and is a safe no-op. To avoid losing such an early
89 // cancel, insert_waiter() re-checks stop_requested() under the lock
90 // and completes as canceled if it fires in this window.
91 7601x auto* w = svc_->create_waiter();
92 7601x w->impl_ = nullptr;
93 7601x w->svc_ = svc_;
94 7601x w->h_ = h;
95 7601x w->cont_ = cont;
96 7601x w->d_ = d;
97 7601x w->token_ = std::move(token);
98 7601x w->ec_out_ = ec;
99
100 7601x might_have_pending_waits_.store(true, std::memory_order_relaxed);
101 7601x svc_->get_scheduler().work_started();
102
103 7601x if (w->token_.stop_possible())
104 1419x w->stop_cb_.emplace(w->token_, waiter_node::canceller{w});
105
106 7601x svc_->insert_waiter(*this, w);
107
108 7601x return std::noop_coroutine();
109 }
110
111 } // namespace boost::corosio::detail
112