LCOV - code coverage report
Current view: top level - include/boost/corosio - basic_io_context.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 95.5 % 67 64
Test Date: 2026-02-12 21:00:53 Functions: 100.0 % 21 21

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2026 Steve Gerbino
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/cppalliance/corosio
       8              : //
       9              : 
      10              : #ifndef BOOST_COROSIO_BASIC_IO_CONTEXT_HPP
      11              : #define BOOST_COROSIO_BASIC_IO_CONTEXT_HPP
      12              : 
      13              : #include <boost/corosio/detail/config.hpp>
      14              : #include <boost/corosio/detail/scheduler.hpp>
      15              : #include <boost/capy/ex/execution_context.hpp>
      16              : 
      17              : #include <chrono>
      18              : #include <coroutine>
      19              : #include <cstddef>
      20              : #include <limits>
      21              : 
      22              : namespace boost::corosio {
      23              : 
      24              : namespace detail {
      25              : struct timer_service_access;
      26              : } // namespace detail
      27              : 
      28              : /** Base class for I/O context implementations.
      29              : 
      30              :     This class provides the common API for all I/O context types.
      31              :     Concrete context implementations (epoll_context, iocp_context, etc.)
      32              :     inherit from this class to gain the standard io_context interface.
      33              : 
      34              :     @par Thread Safety
      35              :     Distinct objects: Safe.@n
      36              :     Shared objects: Safe, if using a concurrency hint greater than 1.
      37              : */
      38              : class BOOST_COROSIO_DECL basic_io_context : public capy::execution_context
      39              : {
      40              :     friend struct detail::timer_service_access;
      41              : 
      42              : public:
      43              :     /** The executor type for this context. */
      44              :     class executor_type;
      45              : 
      46              :     /** Return an executor for this context.
      47              : 
      48              :         The returned executor can be used to dispatch coroutines
      49              :         and post work items to this context.
      50              : 
      51              :         @return An executor associated with this context.
      52              :     */
      53              :     executor_type
      54              :     get_executor() const noexcept;
      55              : 
      56              :     /** Signal the context to stop processing.
      57              : 
      58              :         This causes `run()` to return as soon as possible. Any pending
      59              :         work items remain queued.
      60              :     */
      61              :     void
      62            1 :     stop()
      63              :     {
      64            1 :         sched_->stop();
      65            1 :     }
      66              : 
      67              :     /** Return whether the context has been stopped.
      68              : 
      69              :         @return `true` if `stop()` has been called and `restart()`
      70              :             has not been called since.
      71              :     */
      72              :     bool
      73           21 :     stopped() const noexcept
      74              :     {
      75           21 :         return sched_->stopped();
      76              :     }
      77              : 
      78              :     /** Restart the context after being stopped.
      79              : 
      80              :         This function must be called before `run()` can be called
      81              :         again after `stop()` has been called.
      82              :     */
      83              :     void
      84           83 :     restart()
      85              :     {
      86           83 :         sched_->restart();
      87           83 :     }
      88              : 
      89              :     /** Process all pending work items.
      90              : 
      91              :         This function blocks until all pending work items have been
      92              :         executed or `stop()` is called. The context is stopped
      93              :         when there is no more outstanding work.
      94              : 
      95              :         @note The context must be restarted with `restart()` before
      96              :             calling this function again after it returns.
      97              : 
      98              :         @return The number of handlers executed.
      99              :     */
     100              :     std::size_t
     101          279 :     run()
     102              :     {
     103          279 :         return sched_->run();
     104              :     }
     105              : 
     106              :     /** Process at most one pending work item.
     107              : 
     108              :         This function blocks until one work item has been executed
     109              :         or `stop()` is called. The context is stopped when there
     110              :         is no more outstanding work.
     111              : 
     112              :         @note The context must be restarted with `restart()` before
     113              :             calling this function again after it returns.
     114              : 
     115              :         @return The number of handlers executed (0 or 1).
     116              :     */
     117              :     std::size_t
     118            2 :     run_one()
     119              :     {
     120            2 :         return sched_->run_one();
     121              :     }
     122              : 
     123              :     /** Process work items for the specified duration.
     124              : 
     125              :         This function blocks until work items have been executed for
     126              :         the specified duration, or `stop()` is called. The context
     127              :         is stopped when there is no more outstanding work.
     128              : 
     129              :         @note The context must be restarted with `restart()` before
     130              :             calling this function again after it returns.
     131              : 
     132              :         @param rel_time The duration for which to process work.
     133              : 
     134              :         @return The number of handlers executed.
     135              :     */
     136              :     template<class Rep, class Period>
     137              :     std::size_t
     138            8 :     run_for(std::chrono::duration<Rep, Period> const& rel_time)
     139              :     {
     140            8 :         return run_until(std::chrono::steady_clock::now() + rel_time);
     141              :     }
     142              : 
     143              :     /** Process work items until the specified time.
     144              : 
     145              :         This function blocks until the specified time is reached
     146              :         or `stop()` is called. The context is stopped when there
     147              :         is no more outstanding work.
     148              : 
     149              :         @note The context must be restarted with `restart()` before
     150              :             calling this function again after it returns.
     151              : 
     152              :         @param abs_time The time point until which to process work.
     153              : 
     154              :         @return The number of handlers executed.
     155              :     */
     156              :     template<class Clock, class Duration>
     157              :     std::size_t
     158            8 :     run_until(std::chrono::time_point<Clock, Duration> const& abs_time)
     159              :     {
     160            8 :         std::size_t n = 0;
     161           57 :         while (run_one_until(abs_time))
     162           49 :             if (n != (std::numeric_limits<std::size_t>::max)())
     163           49 :                 ++n;
     164            8 :         return n;
     165              :     }
     166              : 
     167              :     /** Process at most one work item for the specified duration.
     168              : 
     169              :         This function blocks until one work item has been executed,
     170              :         the specified duration has elapsed, or `stop()` is called.
     171              :         The context is stopped when there is no more outstanding work.
     172              : 
     173              :         @note The context must be restarted with `restart()` before
     174              :             calling this function again after it returns.
     175              : 
     176              :         @param rel_time The duration for which the call may block.
     177              : 
     178              :         @return The number of handlers executed (0 or 1).
     179              :     */
     180              :     template<class Rep, class Period>
     181              :     std::size_t
     182            2 :     run_one_for(std::chrono::duration<Rep, Period> const& rel_time)
     183              :     {
     184            2 :         return run_one_until(std::chrono::steady_clock::now() + rel_time);
     185              :     }
     186              : 
     187              :     /** Process at most one work item until the specified time.
     188              : 
     189              :         This function blocks until one work item has been executed,
     190              :         the specified time is reached, or `stop()` is called.
     191              :         The context is stopped when there is no more outstanding work.
     192              : 
     193              :         @note The context must be restarted with `restart()` before
     194              :             calling this function again after it returns.
     195              : 
     196              :         @param abs_time The time point until which the call may block.
     197              : 
     198              :         @return The number of handlers executed (0 or 1).
     199              :     */
     200              :     template<class Clock, class Duration>
     201              :     std::size_t
     202           61 :     run_one_until(std::chrono::time_point<Clock, Duration> const& abs_time)
     203              :     {
     204           61 :         typename Clock::time_point now = Clock::now();
     205           61 :         while (now < abs_time)
     206              :         {
     207           61 :             auto rel_time = abs_time - now;
     208           61 :             if (rel_time > std::chrono::seconds(1))
     209            0 :                 rel_time = std::chrono::seconds(1);
     210              : 
     211           61 :             std::size_t s = sched_->wait_one(
     212              :                 static_cast<long>(std::chrono::duration_cast<
     213           61 :                     std::chrono::microseconds>(rel_time).count()));
     214              : 
     215           61 :             if (s || stopped())
     216           61 :                 return s;
     217              : 
     218            0 :             now = Clock::now();
     219              :         }
     220            0 :         return 0;
     221              :     }
     222              : 
     223              :     /** Process all ready work items without blocking.
     224              : 
     225              :         This function executes all work items that are ready to run
     226              :         without blocking for more work. The context is stopped
     227              :         when there is no more outstanding work.
     228              : 
     229              :         @note The context must be restarted with `restart()` before
     230              :             calling this function again after it returns.
     231              : 
     232              :         @return The number of handlers executed.
     233              :     */
     234              :     std::size_t
     235            2 :     poll()
     236              :     {
     237            2 :         return sched_->poll();
     238              :     }
     239              : 
     240              :     /** Process at most one ready work item without blocking.
     241              : 
     242              :         This function executes at most one work item that is ready
     243              :         to run without blocking for more work. The context is
     244              :         stopped when there is no more outstanding work.
     245              : 
     246              :         @note The context must be restarted with `restart()` before
     247              :             calling this function again after it returns.
     248              : 
     249              :         @return The number of handlers executed (0 or 1).
     250              :     */
     251              :     std::size_t
     252            4 :     poll_one()
     253              :     {
     254            4 :         return sched_->poll_one();
     255              :     }
     256              : 
     257              : protected:
     258              :     /** Default constructor.
     259              : 
     260              :         Derived classes must set sched_ in their constructor body.
     261              :     */
     262          336 :     basic_io_context()
     263          336 :         : capy::execution_context(this)
     264          336 :         , sched_(nullptr)
     265              :     {
     266          336 :     }
     267              : 
     268              :     detail::scheduler* sched_;
     269              : };
     270              : 
     271              : /** An executor for dispatching work to an I/O context.
     272              : 
     273              :     The executor provides the interface for posting work items and
     274              :     dispatching coroutines to the associated context. It satisfies
     275              :     the `capy::Executor` concept.
     276              : 
     277              :     Executors are lightweight handles that can be copied and compared
     278              :     for equality. Two executors compare equal if they refer to the
     279              :     same context.
     280              : 
     281              :     @par Thread Safety
     282              :     Distinct objects: Safe.@n
     283              :     Shared objects: Safe.
     284              : */
     285              : class basic_io_context::executor_type
     286              : {
     287              :     basic_io_context* ctx_ = nullptr;
     288              : 
     289              : public:
     290              :     /** Default constructor.
     291              : 
     292              :         Constructs an executor not associated with any context.
     293              :     */
     294              :     executor_type() = default;
     295              : 
     296              :     /** Construct an executor from a context.
     297              : 
     298              :         @param ctx The context to associate with this executor.
     299              :     */
     300              :     explicit
     301          356 :     executor_type(basic_io_context& ctx) noexcept
     302          356 :         : ctx_(&ctx)
     303              :     {
     304          356 :     }
     305              : 
     306              :     /** Return a reference to the associated execution context.
     307              : 
     308              :         @return Reference to the context.
     309              :     */
     310              :     basic_io_context&
     311         1218 :     context() const noexcept
     312              :     {
     313         1218 :         return *ctx_;
     314              :     }
     315              : 
     316              :     /** Check if the current thread is running this executor's context.
     317              : 
     318              :         @return `true` if `run()` is being called on this thread.
     319              :     */
     320              :     bool
     321       157873 :     running_in_this_thread() const noexcept
     322              :     {
     323       157873 :         return ctx_->sched_->running_in_this_thread();
     324              :     }
     325              : 
     326              :     /** Informs the executor that work is beginning.
     327              : 
     328              :         Must be paired with `on_work_finished()`.
     329              :     */
     330              :     void
     331         1243 :     on_work_started() const noexcept
     332              :     {
     333         1243 :         ctx_->sched_->on_work_started();
     334         1243 :     }
     335              : 
     336              :     /** Informs the executor that work has completed.
     337              : 
     338              :         @par Preconditions
     339              :         A preceding call to `on_work_started()` on an equal executor.
     340              :     */
     341              :     void
     342         1217 :     on_work_finished() const noexcept
     343              :     {
     344         1217 :         ctx_->sched_->on_work_finished();
     345         1217 :     }
     346              : 
     347              :     /** Dispatch a coroutine handle.
     348              : 
     349              :         Returns a handle for symmetric transfer. If called from
     350              :         within `run()`, returns `h`. Otherwise posts the coroutine
     351              :         for later execution and returns `std::noop_coroutine()`.
     352              : 
     353              :         @param h The coroutine handle to dispatch.
     354              : 
     355              :         @return A handle for symmetric transfer or `std::noop_coroutine()`.
     356              :     */
     357              :     std::coroutine_handle<>
     358       157871 :     dispatch(std::coroutine_handle<> h) const
     359              :     {
     360       157871 :         if (running_in_this_thread())
     361       157448 :             return h;
     362          423 :         ctx_->sched_->post(h);
     363          423 :         return std::noop_coroutine();
     364              :     }
     365              : 
     366              :     /** Post a coroutine for deferred execution.
     367              : 
     368              :         The coroutine will be resumed during a subsequent call to
     369              :         `run()`.
     370              : 
     371              :         @param h The coroutine handle to post.
     372              :     */
     373              :     void
     374        10215 :     post(std::coroutine_handle<> h) const
     375              :     {
     376        10215 :         ctx_->sched_->post(h);
     377        10215 :     }
     378              : 
     379              :     /** Compare two executors for equality.
     380              : 
     381              :         @return `true` if both executors refer to the same context.
     382              :     */
     383              :     bool
     384            1 :     operator==(executor_type const& other) const noexcept
     385              :     {
     386            1 :         return ctx_ == other.ctx_;
     387              :     }
     388              : 
     389              :     /** Compare two executors for inequality.
     390              : 
     391              :         @return `true` if the executors refer to different contexts.
     392              :     */
     393              :     bool
     394              :     operator!=(executor_type const& other) const noexcept
     395              :     {
     396              :         return ctx_ != other.ctx_;
     397              :     }
     398              : };
     399              : 
     400              : inline
     401              : basic_io_context::executor_type
     402          356 : basic_io_context::
     403              : get_executor() const noexcept
     404              : {
     405          356 :     return executor_type(const_cast<basic_io_context&>(*this));
     406              : }
     407              : 
     408              : } // namespace boost::corosio
     409              : 
     410              : #endif // BOOST_COROSIO_BASIC_IO_CONTEXT_HPP
        

Generated by: LCOV version 2.3