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-17 18:48:50 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                 :     Wraps platform timer facilities via the io_context reactor.
      46                 :     Operations dispatch to OS timer APIs (timerfd, IOCP timers,
      47                 :     kqueue EVFILT_TIMER).
      48                 : */
      49                 : class BOOST_COROSIO_DECL timer : public io_timer
      50                 : {
      51                 : public:
      52                 :     /// Alias for backward compatibility.
      53                 :     using implementation = io_timer::implementation;
      54                 : 
      55                 :     /** Destructor.
      56                 : 
      57                 :         Cancels any pending operations and releases timer resources.
      58                 :     */
      59                 :     ~timer() override;
      60                 : 
      61                 :     /** Construct a timer from an execution context.
      62                 : 
      63                 :         @param ctx The execution context that will own this timer. It
      64                 :             must be a corosio io_context; otherwise the constructor
      65                 :             throws (a timer service is required).
      66                 : 
      67                 :         @throws std::logic_error if @p ctx is not an io_context.
      68                 :     */
      69                 :     explicit timer(capy::execution_context& ctx);
      70                 : 
      71                 :     /** Construct a timer with an initial absolute expiry time.
      72                 : 
      73                 :         @param ctx The execution context that will own this timer. It
      74                 :             must be a corosio io_context; otherwise the constructor
      75                 :             throws (a timer service is required).
      76                 :         @param t The initial expiry time point.
      77                 : 
      78                 :         @throws std::logic_error if @p ctx is not an io_context.
      79                 :     */
      80                 :     timer(capy::execution_context& ctx, time_point t);
      81                 : 
      82                 :     /** Construct a timer with an initial relative expiry time.
      83                 : 
      84                 :         @param ctx The execution context that will own this timer. It
      85                 :             must be a corosio io_context; otherwise the constructor
      86                 :             throws (a timer service is required).
      87                 :         @param d The initial expiry duration relative to now.
      88                 : 
      89                 :         @throws std::logic_error if @p ctx is not an io_context.
      90                 :     */
      91                 :     template<class Rep, class Period>
      92 HIT           8 :     timer(capy::execution_context& ctx, std::chrono::duration<Rep, Period> d)
      93               8 :         : timer(ctx)
      94                 :     {
      95               8 :         expires_after(d);
      96               8 :     }
      97                 : 
      98                 :     /** Construct a timer from an executor.
      99                 : 
     100                 :         The timer is associated with the executor's context, which must
     101                 :         be a corosio io_context.
     102                 : 
     103                 :         @param ex The executor whose context will own this timer.
     104                 : 
     105                 :         @throws std::logic_error if the executor's context is not an
     106                 :             io_context.
     107                 :     */
     108                 :     template<class Ex>
     109                 :         requires(!std::same_as<std::remove_cvref_t<Ex>, timer>) &&
     110                 :         capy::Executor<Ex>
     111               4 :     explicit timer(Ex const& ex) : timer(ex.context())
     112                 :     {
     113               2 :     }
     114                 : 
     115                 :     /** Construct a timer from an executor with an absolute expiry time.
     116                 : 
     117                 :         @param ex The executor whose context will own this timer.
     118                 :         @param t The initial expiry time point.
     119                 : 
     120                 :         @throws std::logic_error if the executor's context is not an
     121                 :             io_context.
     122                 :     */
     123                 :     template<class Ex>
     124                 :         requires capy::Executor<Ex>
     125               2 :     timer(Ex const& ex, time_point t) : timer(ex.context(), t)
     126                 :     {
     127               2 :     }
     128                 : 
     129                 :     /** Construct a timer from an executor with a relative expiry time.
     130                 : 
     131                 :         @param ex The executor whose context will own this timer.
     132                 :         @param d The initial expiry duration relative to now.
     133                 : 
     134                 :         @throws std::logic_error if the executor's context is not an
     135                 :             io_context.
     136                 :     */
     137                 :     template<class Ex, class Rep, class Period>
     138                 :         requires capy::Executor<Ex>
     139               2 :     timer(Ex const& ex, std::chrono::duration<Rep, Period> d)
     140               2 :         : timer(ex.context(), d)
     141                 :     {
     142               2 :     }
     143                 : 
     144                 :     /** Move constructor.
     145                 : 
     146                 :         Transfers ownership of the timer resources.
     147                 : 
     148                 :         @param other The timer to move from.
     149                 : 
     150                 :         @pre No awaitables returned by @p other's methods exist.
     151                 :         @pre The execution context associated with @p other must
     152                 :             outlive this timer.
     153                 :     */
     154                 :     timer(timer&& other) noexcept;
     155                 : 
     156                 :     /** Move assignment operator.
     157                 : 
     158                 :         Closes any existing timer and transfers ownership.
     159                 : 
     160                 :         @param other The timer to move from.
     161                 : 
     162                 :         @pre No awaitables returned by either `*this` or @p other's
     163                 :             methods exist.
     164                 :         @pre The execution context associated with @p other must
     165                 :             outlive this timer.
     166                 : 
     167                 :         @return Reference to this timer.
     168                 :     */
     169                 :     timer& operator=(timer&& other) noexcept;
     170                 : 
     171                 :     timer(timer const&)            = delete;
     172                 :     timer& operator=(timer const&) = delete;
     173                 : 
     174                 :     /** Cancel one pending asynchronous wait operation.
     175                 : 
     176                 :         The oldest pending wait is cancelled (FIFO order). It
     177                 :         completes with an error code that compares equal to
     178                 :         `capy::cond::canceled`.
     179                 : 
     180                 :         @return The number of operations that were cancelled (0 or 1).
     181                 :     */
     182               4 :     std::size_t cancel_one()
     183                 :     {
     184               4 :         if (!get().might_have_pending_waits_)
     185               2 :             return 0;
     186               2 :         return do_cancel_one();
     187                 :     }
     188                 : 
     189                 :     /** Set the timer's expiry time as an absolute time.
     190                 : 
     191                 :         Any pending asynchronous wait operations will be cancelled.
     192                 : 
     193                 :         @param t The expiry time to be used for the timer.
     194                 : 
     195                 :         @return The number of pending operations that were cancelled.
     196                 :     */
     197              54 :     std::size_t expires_at(time_point t)
     198                 :     {
     199              54 :         auto& impl   = get();
     200              54 :         impl.expiry_ = t;
     201              54 :         if (impl.heap_index_ == implementation::npos &&
     202              50 :             !impl.might_have_pending_waits_)
     203              50 :             return 0;
     204               4 :         return do_update_expiry();
     205                 :     }
     206                 : 
     207                 :     /** Set the timer's expiry time relative to now.
     208                 : 
     209                 :         Any pending asynchronous wait operations will be cancelled.
     210                 : 
     211                 :         @param d The expiry time relative to now.
     212                 : 
     213                 :         @return The number of pending operations that were cancelled.
     214                 :     */
     215            9077 :     std::size_t expires_after(duration d)
     216                 :     {
     217            9077 :         auto& impl = get();
     218            9077 :         if (d <= duration::zero())
     219               6 :             impl.expiry_ = (time_point::min)();
     220                 :         else
     221            9071 :             impl.expiry_ = clock_type::now() + d;
     222            9077 :         if (impl.heap_index_ == implementation::npos &&
     223            9073 :             !impl.might_have_pending_waits_)
     224            9073 :             return 0;
     225               4 :         return do_update_expiry();
     226                 :     }
     227                 : 
     228                 :     /** Set the timer's expiry time relative to now.
     229                 : 
     230                 :         This is a convenience overload that accepts any duration type
     231                 :         and converts it to the timer's native duration type. Any
     232                 :         pending asynchronous wait operations will be cancelled.
     233                 : 
     234                 :         @param d The expiry time relative to now.
     235                 : 
     236                 :         @return The number of pending operations that were cancelled.
     237                 :     */
     238                 :     template<class Rep, class Period>
     239            9077 :     std::size_t expires_after(std::chrono::duration<Rep, Period> d)
     240                 :     {
     241            9077 :         return expires_after(std::chrono::duration_cast<duration>(d));
     242                 :     }
     243                 : 
     244                 : protected:
     245                 :     explicit timer(handle h) noexcept : io_timer(std::move(h)) {}
     246                 : 
     247                 : private:
     248                 :     std::size_t do_cancel() override;
     249                 :     std::size_t do_cancel_one();
     250                 :     std::size_t do_update_expiry();
     251                 : 
     252                 :     /// Return the underlying implementation.
     253            9153 :     implementation& get() const noexcept
     254                 :     {
     255            9153 :         return *static_cast<implementation*>(h_.get());
     256                 :     }
     257                 : };
     258                 : 
     259                 : } // namespace boost::corosio
     260                 : 
     261                 : #endif
        

Generated by: LCOV version 2.3