LCOV - code coverage report
Current view: top level - corosio/io - io_timer.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 96.9 % 32 31 1
Test Date: 2026-03-26 16:40:44 Functions: 100.0 % 10 10

           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_IO_IO_TIMER_HPP
      12                 : #define BOOST_COROSIO_IO_IO_TIMER_HPP
      13                 : 
      14                 : #include <boost/corosio/detail/config.hpp>
      15                 : #include <boost/corosio/detail/continuation_op.hpp>
      16                 : #include <boost/corosio/io/io_object.hpp>
      17                 : #include <boost/capy/io_result.hpp>
      18                 : #include <boost/capy/error.hpp>
      19                 : #include <boost/capy/ex/executor_ref.hpp>
      20                 : #include <boost/capy/ex/io_env.hpp>
      21                 : 
      22                 : #include <chrono>
      23                 : #include <coroutine>
      24                 : #include <cstddef>
      25                 : #include <limits>
      26                 : #include <stop_token>
      27                 : #include <system_error>
      28                 : 
      29                 : namespace boost::corosio {
      30                 : 
      31                 : /** Abstract base for asynchronous timers.
      32                 : 
      33                 :     Provides the common timer interface: `wait`, `cancel`, and
      34                 :     `expiry`. Concrete classes like @ref timer add the ability
      35                 :     to set expiry times and cancel individual waiters.
      36                 : 
      37                 :     @par Thread Safety
      38                 :     Distinct objects: Safe.
      39                 :     Shared objects: Unsafe.
      40                 : 
      41                 :     @see timer, io_object
      42                 : */
      43                 : class BOOST_COROSIO_DECL io_timer : public io_object
      44                 : {
      45                 :     struct wait_awaitable
      46                 :     {
      47                 :         io_timer& t_;
      48                 :         std::stop_token token_;
      49                 :         mutable std::error_code ec_;
      50                 :         detail::continuation_op cont_op_;
      51                 : 
      52 HIT        8622 :         explicit wait_awaitable(io_timer& t) noexcept : t_(t) {}
      53                 : 
      54            8598 :         bool await_ready() const noexcept
      55                 :         {
      56            8598 :             return token_.stop_requested();
      57                 :         }
      58                 : 
      59            8606 :         capy::io_result<> await_resume() const noexcept
      60                 :         {
      61            8606 :             if (token_.stop_requested())
      62 MIS           0 :                 return {capy::error::canceled};
      63 HIT        8606 :             return {ec_};
      64                 :         }
      65                 : 
      66            8622 :         auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
      67                 :             -> std::coroutine_handle<>
      68                 :         {
      69            8622 :             token_     = env->stop_token;
      70            8622 :             cont_op_.cont.h = h;
      71            8622 :             auto& impl = t_.get();
      72                 :             // Inline fast path: already expired and not in the heap
      73           17222 :             if (impl.heap_index_ == implementation::npos &&
      74           17196 :                 (impl.expiry_ == (time_point::min)() ||
      75           17218 :                  impl.expiry_ <= clock_type::now()))
      76                 :             {
      77             202 :                 ec_    = {};
      78             202 :                 token_ = {}; // match normal path so await_resume
      79                 :                              // returns ec_, not a stale stop check
      80             202 :                 auto d = env->executor;
      81             202 :                 d.post(cont_op_.cont);
      82             202 :                 return std::noop_coroutine();
      83                 :             }
      84            8420 :             return impl.wait(h, env->executor, std::move(token_), &ec_, &cont_op_.cont);
      85                 :         }
      86                 :     };
      87                 : 
      88                 : public:
      89                 :     /** Backend interface for timer wait operations.
      90                 : 
      91                 :         Holds per-timer state (expiry, heap position) and provides
      92                 :         the virtual `wait` entry point that concrete timer services
      93                 :         override.
      94                 :     */
      95                 :     struct implementation : io_object::implementation
      96                 :     {
      97                 :         /// Sentinel value indicating the timer is not in the heap.
      98                 :         static constexpr std::size_t npos =
      99                 :             (std::numeric_limits<std::size_t>::max)();
     100                 : 
     101                 :         /// The absolute expiry time point.
     102                 :         std::chrono::steady_clock::time_point expiry_{};
     103                 : 
     104                 :         /// Index in the timer service's min-heap, or `npos`.
     105                 :         std::size_t heap_index_ = npos;
     106                 : 
     107                 :         /// True if `wait()` has been called since last cancel.
     108                 :         bool might_have_pending_waits_ = false;
     109                 : 
     110                 :         /// Initiate an asynchronous wait for the timer to expire.
     111                 :         virtual std::coroutine_handle<> wait(
     112                 :             std::coroutine_handle<>,
     113                 :             capy::executor_ref,
     114                 :             std::stop_token,
     115                 :             std::error_code*,
     116                 :             capy::continuation*) = 0;
     117                 :     };
     118                 : 
     119                 :     /// The clock type used for time operations.
     120                 :     using clock_type = std::chrono::steady_clock;
     121                 : 
     122                 :     /// The time point type for absolute expiry times.
     123                 :     using time_point = clock_type::time_point;
     124                 : 
     125                 :     /// The duration type for relative expiry times.
     126                 :     using duration = clock_type::duration;
     127                 : 
     128                 :     /** Cancel all pending asynchronous wait operations.
     129                 : 
     130                 :         All outstanding operations complete with an error code that
     131                 :         compares equal to `capy::cond::canceled`.
     132                 : 
     133                 :         @return The number of operations that were cancelled.
     134                 :     */
     135              20 :     std::size_t cancel()
     136                 :     {
     137              20 :         if (!get().might_have_pending_waits_)
     138              12 :             return 0;
     139               8 :         return do_cancel();
     140                 :     }
     141                 : 
     142                 :     /** Return the timer's expiry time as an absolute time.
     143                 : 
     144                 :         @return The expiry time point. If no expiry has been set,
     145                 :             returns a default-constructed time_point.
     146                 :     */
     147              38 :     time_point expiry() const noexcept
     148                 :     {
     149              38 :         return get().expiry_;
     150                 :     }
     151                 : 
     152                 :     /** Wait for the timer to expire.
     153                 : 
     154                 :         Multiple coroutines may wait on the same timer concurrently.
     155                 :         When the timer expires, all waiters complete with success.
     156                 : 
     157                 :         The operation supports cancellation via `std::stop_token` through
     158                 :         the affine awaitable protocol. If the associated stop token is
     159                 :         triggered, only that waiter completes with an error that
     160                 :         compares equal to `capy::cond::canceled`; other waiters are
     161                 :         unaffected.
     162                 : 
     163                 :         This timer must outlive the returned awaitable.
     164                 : 
     165                 :         @return An awaitable that completes with `io_result<>`.
     166                 :     */
     167            8622 :     auto wait()
     168                 :     {
     169            8622 :         return wait_awaitable(*this);
     170                 :     }
     171                 : 
     172                 : protected:
     173                 :     /** Dispatch cancel to the concrete implementation.
     174                 : 
     175                 :         @return The number of operations that were cancelled.
     176                 :     */
     177                 :     virtual std::size_t do_cancel() = 0;
     178                 : 
     179            8625 :     explicit io_timer(handle h) noexcept : io_object(std::move(h)) {}
     180                 : 
     181                 :     /// Move construct.
     182               2 :     io_timer(io_timer&& other) noexcept : io_object(std::move(other)) {}
     183                 : 
     184                 :     /// Move assign.
     185                 :     io_timer& operator=(io_timer&& other) noexcept
     186                 :     {
     187                 :         if (this != &other)
     188                 :             h_ = std::move(other.h_);
     189                 :         return *this;
     190                 :     }
     191                 : 
     192                 :     io_timer(io_timer const&)            = delete;
     193                 :     io_timer& operator=(io_timer const&) = delete;
     194                 : 
     195                 :     /// Return the underlying implementation.
     196            8680 :     implementation& get() const noexcept
     197                 :     {
     198            8680 :         return *static_cast<implementation*>(h_.get());
     199                 :     }
     200                 : };
     201                 : 
     202                 : } // namespace boost::corosio
     203                 : 
     204                 : #endif
        

Generated by: LCOV version 2.3