Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 65 additions & 6 deletions include/boost/corosio/timer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <chrono>
#include <coroutine>
#include <cstddef>
#include <limits>
#include <stop_token>

namespace boost::corosio {
Expand Down Expand Up @@ -79,13 +80,32 @@ class BOOST_COROSIO_DECL timer : public io_object
capy::io_env const* env) -> std::coroutine_handle<>
{
token_ = env->stop_token;
return t_.get().wait(h, env->executor, token_, &ec_);
auto& impl = t_.get();
// Inline fast path: already expired and not in the heap
if (impl.heap_index_ == timer_impl::npos &&
(impl.expiry_ == (time_point::min)() ||
impl.expiry_ <= clock_type::now()))
{
ec_ = {};
auto d = env->executor;
d.post(h);
return std::noop_coroutine();
}
return impl.wait(
h, env->executor, std::move(token_), &ec_);
}
};

public:
struct timer_impl : io_object_impl
{
static constexpr std::size_t npos =
(std::numeric_limits<std::size_t>::max)();

std::chrono::steady_clock::time_point expiry_{};
std::size_t heap_index_ = npos;
bool might_have_pending_waits_ = false;

virtual std::coroutine_handle<> wait(
std::coroutine_handle<>,
capy::executor_ref,
Expand Down Expand Up @@ -167,7 +187,12 @@ class BOOST_COROSIO_DECL timer : public io_object
@return The number of operations that were cancelled.
*/
std::size_t cancel();
std::size_t cancel()
{
if (!get().might_have_pending_waits_)
return 0;
return do_cancel();
}

/** Cancel one pending asynchronous wait operation.
Expand All @@ -177,14 +202,22 @@ class BOOST_COROSIO_DECL timer : public io_object
@return The number of operations that were cancelled (0 or 1).
*/
std::size_t cancel_one();
std::size_t cancel_one()
{
if (!get().might_have_pending_waits_)
return 0;
return do_cancel_one();
}

/** Return the timer's expiry time as an absolute time.
@return The expiry time point. If no expiry has been set,
returns a default-constructed time_point.
*/
time_point expiry() const;
time_point expiry() const noexcept
{
return get().expiry_;
}

/** Set the timer's expiry time as an absolute time.
Expand All @@ -194,7 +227,15 @@ class BOOST_COROSIO_DECL timer : public io_object
@return The number of pending operations that were cancelled.
*/
std::size_t expires_at(time_point t);
std::size_t expires_at(time_point t)
{
auto& impl = get();
impl.expiry_ = t;
if (impl.heap_index_ == timer_impl::npos &&
!impl.might_have_pending_waits_)
return 0;
return do_update_expiry();
}

/** Set the timer's expiry time relative to now.
Expand All @@ -204,7 +245,18 @@ class BOOST_COROSIO_DECL timer : public io_object
@return The number of pending operations that were cancelled.
*/
std::size_t expires_after(duration d);
std::size_t expires_after(duration d)
{
auto& impl = get();
if (d <= duration::zero())
impl.expiry_ = (time_point::min)();
else
impl.expiry_ = clock_type::now() + d;
if (impl.heap_index_ == timer_impl::npos &&
!impl.might_have_pending_waits_)
return 0;
return do_update_expiry();
}

/** Set the timer's expiry time relative to now.
Expand Down Expand Up @@ -266,6 +318,13 @@ class BOOST_COROSIO_DECL timer : public io_object
}

private:
// Out-of-line cancel/expiry when inline fast-path
// conditions (no waiters, not in heap) are not met.
std::size_t do_cancel();
std::size_t do_cancel_one();
std::size_t do_update_expiry();

/// Return the underlying implementation.
timer_impl& get() const noexcept
{
return *static_cast<timer_impl*>(impl_);
Expand Down
24 changes: 3 additions & 21 deletions src/corosio/src/detail/timer_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,6 @@ struct timer_impl
using duration = clock_type::duration;

timer_service_impl* svc_ = nullptr;
time_point expiry_;
std::size_t heap_index_ = (std::numeric_limits<std::size_t>::max)();
// Lets cancel_timer() skip the lock when no wait() was ever issued
bool might_have_pending_waits_ = false;
intrusive_list<waiter_node> waiters_;

// Free list linkage (reused when impl is on free_list)
Expand Down Expand Up @@ -702,7 +698,8 @@ wait(
// scheduler, allowing other queued work to run.
if (heap_index_ == (std::numeric_limits<std::size_t>::max)())
{
if (expiry_ <= clock_type::now())
if (expiry_ == (time_point::min)() ||
expiry_ <= clock_type::now())
{
if (ec)
*ec = {};
Expand Down Expand Up @@ -832,25 +829,10 @@ timer_service_destroy(timer::timer_impl& base) noexcept
static_cast<timer_impl&>(base).release();
}

timer::time_point
timer_service_expiry(timer::timer_impl& base) noexcept
{
return static_cast<timer_impl&>(base).expiry_;
}

std::size_t
timer_service_expires_at(timer::timer_impl& base, timer::time_point t)
{
auto& impl = static_cast<timer_impl&>(base);
impl.expiry_ = t;
return impl.svc_->update_timer(impl, t);
}

std::size_t
timer_service_expires_after(timer::timer_impl& base, timer::duration d)
timer_service_update_expiry(timer::timer_impl& base)
{
auto& impl = static_cast<timer_impl&>(base);
impl.expiry_ = timer::clock_type::now() + d;
return impl.svc_->update_timer(impl, impl.expiry_);
}

Expand Down
26 changes: 5 additions & 21 deletions src/corosio/src/timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ namespace detail {
// Defined in timer_service.cpp
extern timer::timer_impl* timer_service_create(capy::execution_context&);
extern void timer_service_destroy(timer::timer_impl&) noexcept;
extern timer::time_point timer_service_expiry(timer::timer_impl&) noexcept;
extern std::size_t timer_service_expires_at(timer::timer_impl&, timer::time_point);
extern std::size_t timer_service_expires_after(timer::timer_impl&, timer::duration);
extern std::size_t timer_service_update_expiry(timer::timer_impl&);
extern std::size_t timer_service_cancel(timer::timer_impl&) noexcept;
extern std::size_t timer_service_cancel_one(timer::timer_impl&) noexcept;

Expand Down Expand Up @@ -75,37 +73,23 @@ operator=(timer&& other)

std::size_t
timer::
cancel()
do_cancel()
{
return detail::timer_service_cancel(get());
}

std::size_t
timer::
cancel_one()
do_cancel_one()
{
return detail::timer_service_cancel_one(get());
}

timer::time_point
timer::
expiry() const
{
return detail::timer_service_expiry(get());
}

std::size_t
timer::
expires_at(time_point t)
{
return detail::timer_service_expires_at(get(), t);
}

std::size_t
timer::
expires_after(duration d)
do_update_expiry()
{
return detail::timer_service_expires_after(get(), d);
return detail::timer_service_update_expiry(get());
}

} // namespace boost::corosio
Loading