LCOV - code coverage report
Current view: top level - /jenkins/workspace/boost-root/boost/corosio - basic_io_context.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 90.9 % 66 60
Test Date: 2026-02-04 14:16:13 Functions: 95.2 % 21 20

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

Generated by: LCOV version 2.3