LCOV - code coverage report
Current view: top level - corosio/native/detail - coro_op.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 16 16
Test Date: 2026-10-08 18:13:32 Functions: 100.0 % 5 5

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2026 Michael Vandeberg
       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_NATIVE_DETAIL_CORO_OP_HPP
      11                 : #define BOOST_COROSIO_NATIVE_DETAIL_CORO_OP_HPP
      12                 : 
      13                 : #include <boost/corosio/detail/config.hpp>
      14                 : #include <boost/capy/continuation.hpp>
      15                 : #include <boost/corosio/detail/object_ref.hpp>
      16                 : #include <boost/corosio/detail/scheduler_op.hpp>
      17                 : #include <boost/capy/ex/executor_ref.hpp>
      18                 : 
      19                 : #include <atomic>
      20                 : #include <coroutine>
      21                 : #include <cstddef>
      22                 : #include <memory>
      23                 : #include <optional>
      24                 : #include <stop_token>
      25                 : #include <system_error>
      26                 : 
      27                 : /*
      28                 :     Shared, non-template op envelope for every native backend — the readiness
      29                 :     reactors (epoll/kqueue/select), io_uring, and IOCP. It captures the part of
      30                 :     an async operation that is identical regardless of how completion is
      31                 :     reported: the coroutine to resume, the executor it dispatches on, the
      32                 :     output pointers, the stop_token wiring, the cancelled flag, and the
      33                 :     keepalive that holds the owning impl alive while the op is in flight.
      34                 : 
      35                 :     What is deliberately NOT here (it differs by backend and stays in the
      36                 :     derived op layer):
      37                 :       - the result model: the reactors re-run the syscall and record
      38                 :         `errn`/`bytes_transferred` (reactor_op_base); io_uring stores the raw
      39                 :         `res`/`cqe_flags`; IOCP stores `dwError`/`bytes_transferred`. Each
      40                 :         decodes its own result.
      41                 :       - the submission + the kernel cancel action. Cancellation is unified only
      42                 :         at the call site via the virtual `on_cancel()` hook: the stop_callback
      43                 :         always targets `coro_op`, and each backend overrides `on_cancel()` —
      44                 :         the reactors route to the owning impl's cancel(), io_uring submits an
      45                 :         ASYNC_CANCEL SQE, IOCP calls the stored cancel_func_/CancelIoEx.
      46                 : 
      47                 :     See tasks/proactor-dedup-decisions.md and coro-op-unification-scope.md.
      48                 : */
      49                 : 
      50                 : namespace boost::corosio::detail {
      51                 : 
      52                 : /** Non-template op envelope shared by every native backend's operations.
      53                 : 
      54                 :     `reactor_op_base`, `uring_op`, and `overlapped_op` all derive from this.
      55                 :     Derives from scheduler_op so ops queue intrusively and dispatch through the
      56                 :     function-pointer (io_uring/IOCP) or virtual (reactors) completion path —
      57                 :     hence both a default and a func_type constructor.
      58                 : 
      59                 :     @note For IOCP, the concrete op multiply-inherits `OVERLAPPED` as its
      60                 :     first base (so `static_cast<OVERLAPPED*>` round-trips); `coro_op`
      61                 :     follows it.
      62                 : */
      63                 : struct coro_op : scheduler_op
      64                 : {
      65                 :     /** Stop-callback handler: routes a stop_token firing to `on_cancel()`.
      66                 : 
      67                 :         A single canceller type for both backends keeps `stop_cb` (and thus
      68                 :         `start()`) in this shared base; the backend-specific action lives
      69                 :         behind the `on_cancel()` virtual.
      70                 :     */
      71                 :     struct canceller
      72                 :     {
      73                 :         coro_op* op;
      74 HIT         525 :         void operator()() const noexcept
      75                 :         {
      76             525 :             op->on_cancel();
      77             525 :         }
      78                 :     };
      79                 : 
      80                 :     std::coroutine_handle<> h;
      81                 :     capy::continuation cont;
      82                 :     capy::executor_ref ex;
      83                 :     std::error_code* ec_out = nullptr;
      84                 :     std::size_t* bytes_out  = nullptr;
      85                 : 
      86                 :     /// True for receive/read ops (drives the zero-byte == EOF decision).
      87                 :     bool is_read = false;
      88                 :     /// True when the submitted buffer was zero-length (suppresses EOF).
      89                 :     bool empty_buffer = false;
      90                 : 
      91                 :     std::atomic<bool> cancelled{false};
      92                 :     std::optional<std::stop_callback<canceller>> stop_cb;
      93                 : 
      94                 :     /// Keeps the owning impl alive while the op is in flight (the kernel
      95                 :     /// owns user buffers until completion). Dropped in the handler's resume
      96                 :     /// tail (see coro_op_complete.hpp).
      97                 :     detail::object_ref object_ref_;
      98                 : 
      99                 :     /// Default-construct for virtual-dispatch backends (the reactors, which
     100                 :     /// override operator()/destroy() and leave func_ null).
     101           24384 :     coro_op() noexcept = default;
     102                 : 
     103                 :     /// Construct with the completion function for func-pointer dispatch
     104                 :     /// (io_uring / IOCP completion handlers).
     105                 :     explicit coro_op(func_type func) noexcept : scheduler_op(func) {}
     106                 : 
     107                 :     /** Arm the stop-token callback. Call before the op is submitted.
     108                 : 
     109                 :         Resets the cancellation flag and (re)arms `stop_cb` against @a token.
     110                 :         Derived ops that carry extra pre-submit state (e.g. io_uring's
     111                 :         `sqe_set`) extend this.
     112                 :     */
     113          103661 :     void start(std::stop_token const& token)
     114                 :     {
     115          103661 :         cancelled.store(false, std::memory_order_relaxed);
     116          103661 :         stop_cb.reset();
     117          103661 :         if (token.stop_possible())
     118             727 :             stop_cb.emplace(token, canceller{this});
     119          103661 :     }
     120                 : 
     121                 :     /// Mark this op cancellation-requested. Shared by every backend.
     122          316719 :     void request_cancel() noexcept
     123                 :     {
     124          316719 :         cancelled.store(true, std::memory_order_release);
     125          316719 :     }
     126                 : 
     127                 :     /** Backend cancellation hook, invoked when the stop_token fires.
     128                 : 
     129                 :         The default just records the request. Backends override to also
     130                 :         drive the kernel: io_uring submits an ASYNC_CANCEL SQE; IOCP calls
     131                 :         its stored cancel_func_ (CancelIoEx / wait-reactor deregister).
     132                 :     */
     133             200 :     virtual void on_cancel() noexcept
     134                 :     {
     135             200 :         request_cancel();
     136             200 :     }
     137                 : };
     138                 : 
     139                 : } // namespace boost::corosio::detail
     140                 : 
     141                 : #endif
        

Generated by: LCOV version 2.3