LCOV - code coverage report
Current view: top level - corosio - timer.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 35 35
Test Date: 2026-06-21 01:30:34 Functions: 100.0 % 13 13

           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_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 HIT           8 :     timer(capy::execution_context& ctx, std::chrono::duration<Rep, Period> d)
      94               8 :         : timer(ctx)
      95                 :     {
      96               8 :         expires_after(d);
      97               8 :     }
      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               4 :     explicit timer(Ex const& ex) : timer(ex.context())
     113                 :     {
     114               2 :     }
     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               2 :     timer(Ex const& ex, time_point t) : timer(ex.context(), t)
     127                 :     {
     128               2 :     }
     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               2 :     timer(Ex const& ex, std::chrono::duration<Rep, Period> d)
     141               2 :         : timer(ex.context(), d)
     142                 :     {
     143               2 :     }
     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               4 :     std::size_t cancel_one()
     184                 :     {
     185               4 :         if (!get().might_have_pending_waits_)
     186               2 :             return 0;
     187               2 :         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              54 :     std::size_t expires_at(time_point t)
     199                 :     {
     200              54 :         auto& impl   = get();
     201              54 :         impl.expiry_ = t;
     202              54 :         if (impl.heap_index_ == implementation::npos &&
     203              50 :             !impl.might_have_pending_waits_)
     204              50 :             return 0;
     205               4 :         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            8700 :     std::size_t expires_after(duration d)
     217                 :     {
     218            8700 :         auto& impl = get();
     219            8700 :         if (d <= duration::zero())
     220               6 :             impl.expiry_ = (time_point::min)();
     221                 :         else
     222            8694 :             impl.expiry_ = clock_type::now() + d;
     223            8700 :         if (impl.heap_index_ == implementation::npos &&
     224            8696 :             !impl.might_have_pending_waits_)
     225            8696 :             return 0;
     226               4 :         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            8700 :     std::size_t expires_after(std::chrono::duration<Rep, Period> d)
     241                 :     {
     242            8700 :         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            8776 :     implementation& get() const noexcept
     255                 :     {
     256            8776 :         return *static_cast<implementation*>(h_.get());
     257                 :     }
     258                 : };
     259                 : 
     260                 : } // namespace boost::corosio
     261                 : 
     262                 : #endif
        

Generated by: LCOV version 2.3