LCOV - code coverage report
Current view: top level - capy/ex - io_env.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 5 5
Test Date: 2026-03-06 20:40:21 Functions: 100.0 % 2 2

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
       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/capy
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_CAPY_IO_ENV_HPP
      11                 : #define BOOST_CAPY_IO_ENV_HPP
      12                 : 
      13                 : #include <boost/capy/detail/config.hpp>
      14                 : #include <boost/capy/ex/executor_ref.hpp>
      15                 : 
      16                 : #include <coroutine>
      17                 : #include <memory_resource>
      18                 : #include <stop_token>
      19                 : 
      20                 : namespace boost {
      21                 : namespace capy {
      22                 : 
      23                 : /** Callable that posts a coroutine handle to an executor.
      24                 : 
      25                 :     Use this as the callback type for `std::stop_callback` instead
      26                 :     of a raw `std::coroutine_handle<>`. Raw handles resume the
      27                 :     coroutine inline on whatever thread calls `request_stop()`,
      28                 :     which bypasses the executor and corrupts the thread-local
      29                 :     frame allocator.
      30                 : 
      31                 :     Prefer @ref io_env::post_resume and the @ref stop_resume_callback
      32                 :     alias to construct these—see examples there.
      33                 : 
      34                 :     @see io_env::post_resume, stop_resume_callback
      35                 : */
      36                 : struct resume_via_post
      37                 : {
      38                 :     executor_ref ex;
      39                 :     std::coroutine_handle<> h;
      40                 : 
      41                 :     // post() must not throw; stop_callback requires a
      42                 :     // non-throwing invocable.
      43 HIT         254 :     void operator()() const noexcept
      44                 :     {
      45             254 :         ex.post(h);
      46             254 :     }
      47                 : };
      48                 : 
      49                 : /** Execution environment for IoAwaitables.
      50                 : 
      51                 :     This struct bundles the execution context passed through
      52                 :     coroutine chains via the IoAwaitable protocol. It contains
      53                 :     the executor for resumption, a stop token for cancellation,
      54                 :     and an optional frame allocator for coroutine frame allocation.
      55                 : 
      56                 :     @par Lifetime
      57                 : 
      58                 :     Launch functions (@ref run_async, @ref run) own the `io_env` and
      59                 :     guarantee it outlives all tasks and awaitables in the launched
      60                 :     chain. Awaitables receive `io_env const*` in `await_suspend`
      61                 :     and should store it directly, never copy the pointed-to object.
      62                 : 
      63                 :     @par Stop Callback Contract
      64                 : 
      65                 :     Awaitables that register a `std::stop_callback` **must not**
      66                 :     resume the coroutine handle directly. The callback fires
      67                 :     synchronously on the thread that calls `request_stop()`, which
      68                 :     may not be an executor-managed thread. Resuming inline poisons
      69                 :     that thread's TLS frame allocator with the pool's allocator,
      70                 :     causing use-after-free on the next coroutine allocation.
      71                 : 
      72                 :     Use @ref io_env::post_resume and @ref stop_resume_callback:
      73                 :     @code
      74                 :     std::optional<stop_resume_callback> stop_cb_;
      75                 :     // In await_suspend:
      76                 :     stop_cb_.emplace(env->stop_token, env->post_resume(h));
      77                 :     @endcode
      78                 : 
      79                 :     @par Thread Safety
      80                 :     The referenced executor and allocator must remain valid
      81                 :     for the lifetime of any coroutine using this environment.
      82                 : 
      83                 :     @see IoAwaitable, IoRunnable, resume_via_post
      84                 : */
      85                 : struct io_env
      86                 : {
      87                 :     /** The executor for coroutine resumption. */
      88                 :     executor_ref executor;
      89                 : 
      90                 :     /** The stop token for cancellation propagation. */
      91                 :     std::stop_token stop_token;
      92                 : 
      93                 :     /** The frame allocator for coroutine frame allocation.
      94                 : 
      95                 :         When null, the default allocator is used.
      96                 :     */
      97                 :     std::pmr::memory_resource* frame_allocator = nullptr;
      98                 : 
      99                 :     /** Create a resume_via_post callable for this environment.
     100                 : 
     101                 :         Convenience method for registering @ref stop_resume_callback
     102                 :         instances. Equivalent to `resume_via_post{executor, h}`.
     103                 : 
     104                 :         @par Example
     105                 :         @code
     106                 :         stop_cb_.emplace(env->stop_token, env->post_resume(h));
     107                 :         @endcode
     108                 : 
     109                 :         @param h The coroutine handle to post on cancellation.
     110                 : 
     111                 :         @return A @ref resume_via_post callable that holds a
     112                 :         non-owning @ref executor_ref and the coroutine handle.
     113                 :         The callable must not outlive the executor it references.
     114                 : 
     115                 :         @see resume_via_post, stop_resume_callback
     116                 :     */
     117                 :     resume_via_post
     118             254 :     post_resume(std::coroutine_handle<> h) const noexcept
     119                 :     {
     120             254 :         return resume_via_post{executor, h};
     121                 :     }
     122                 : };
     123                 : 
     124                 : /** Type alias for a stop callback that posts through the executor.
     125                 : 
     126                 :     Use this to declare the stop callback member in your awaitable:
     127                 :     @code
     128                 :     std::optional<stop_resume_callback> stop_cb_;
     129                 :     @endcode
     130                 : 
     131                 :     @see resume_via_post, io_env::post_resume
     132                 : */
     133                 : using stop_resume_callback = std::stop_callback<resume_via_post>;
     134                 : 
     135                 : } // capy
     136                 : } // boost
     137                 : 
     138                 : #endif
        

Generated by: LCOV version 2.3