LCOV - code coverage report
Current view: top level - corosio/detail - continuation_op.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 52.2 % 23 12 11
Test Date: 2026-03-26 16:40:44 Functions: 60.0 % 5 3 2

           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_DETAIL_CONTINUATION_OP_HPP
      11                 : #define BOOST_COROSIO_DETAIL_CONTINUATION_OP_HPP
      12                 : 
      13                 : #include <boost/corosio/detail/scheduler_op.hpp>
      14                 : #include <boost/capy/continuation.hpp>
      15                 : 
      16                 : #include <atomic>
      17                 : #include <cstdint>
      18                 : #include <cstring>
      19                 : 
      20                 : namespace boost::corosio::detail {
      21                 : 
      22                 : /* Scheduler operation that resumes a capy::continuation.
      23                 : 
      24                 :    Embeds a continuation alongside a scheduler_op so the
      25                 :    scheduler can queue it in the same FIFO as I/O completions
      26                 :    without a heap allocation. The continuation lives in the
      27                 :    caller's coroutine frame (awaitable or op struct); this
      28                 :    wrapper gives it a scheduler_op identity.
      29                 : 
      30                 :    io_context::executor_type::post(continuation&) uses
      31                 :    try_from_continuation() to recover the enclosing
      32                 :    continuation_op via a magic tag. The tag is read through
      33                 :    memcpy (not through a continuation_op*) so that UBSan
      34                 :    does not flag the speculative pointer arithmetic when the
      35                 :    continuation is not actually inside a continuation_op.
      36                 : */
      37                 : struct continuation_op final : scheduler_op
      38                 : {
      39                 :     static constexpr std::uint32_t magic_ = 0xC0710Au;
      40                 : 
      41                 :     std::uint32_t tag_ = magic_;
      42                 :     capy::continuation cont;
      43                 : 
      44 HIT       80883 :     continuation_op() noexcept : scheduler_op(&do_complete) {}
      45                 : 
      46                 :     // Reactor backends (epoll, select, kqueue) dispatch through
      47                 :     // virtual operator()(). IOCP dispatches through func_ which
      48                 :     // routes to do_complete below.
      49            8632 :     void operator()() override
      50                 :     {
      51                 :         std::atomic_thread_fence(std::memory_order_acquire);
      52            8632 :         cont.h.resume();
      53            8632 :     }
      54                 : 
      55 MIS           0 :     void destroy() override
      56                 :     {
      57               0 :         if (cont.h)
      58               0 :             cont.h.destroy();
      59               0 :     }
      60                 : 
      61                 : private:
      62                 :     // IOCP completion entry point. owner == nullptr means destroy.
      63               0 :     static void do_complete(
      64                 :         void* owner,
      65                 :         scheduler_op* base,
      66                 :         std::uint32_t,
      67                 :         std::uint32_t)
      68                 :     {
      69               0 :         auto* self = static_cast<continuation_op*>(base);
      70               0 :         if (!owner)
      71                 :         {
      72               0 :             if (self->cont.h)
      73               0 :                 self->cont.h.destroy();
      74               0 :             return;
      75                 :         }
      76                 :         std::atomic_thread_fence(std::memory_order_acquire);
      77               0 :         self->cont.h.resume();
      78                 :     }
      79                 : 
      80                 : public:
      81                 : 
      82                 :     // Recover the enclosing continuation_op from its cont member.
      83                 :     // Returns nullptr if the continuation is not tagged (bare
      84                 :     // capy::continuation from capy internals like run_async).
      85 HIT        9323 :     static continuation_op* try_from_continuation(
      86                 :         capy::continuation& c) noexcept
      87                 :     {
      88                 :         // offsetof on non-standard-layout is conditionally-supported;
      89                 :         // suppress the warning — all targeted compilers handle this
      90                 :         // correctly and the self-relative arithmetic is move-safe.
      91                 : #if defined(__GNUC__) || defined(__clang__)
      92                 : #pragma GCC diagnostic push
      93                 : #pragma GCC diagnostic ignored "-Winvalid-offsetof"
      94                 : #endif
      95            9323 :         constexpr auto cont_off = offsetof(continuation_op, cont);
      96            9323 :         constexpr auto tag_off  = offsetof(continuation_op, tag_);
      97                 : #if defined(__GNUC__) || defined(__clang__)
      98                 : #pragma GCC diagnostic pop
      99                 : #endif
     100                 :         // Read the tag through memcpy from a char*, not through a
     101                 :         // continuation_op*. This avoids UBSan's vptr check when
     102                 :         // the continuation is not actually inside a continuation_op.
     103            9323 :         auto* base = reinterpret_cast<char*>(&c) - cont_off;
     104                 :         std::uint32_t tag;
     105            9323 :         std::memcpy(&tag, base + tag_off, sizeof(tag));
     106            9323 :         if (tag != magic_)
     107             691 :             return nullptr;
     108            8632 :         return reinterpret_cast<continuation_op*>(base);
     109                 :     }
     110                 : };
     111                 : 
     112                 : } // namespace boost::corosio::detail
     113                 : 
     114                 : #endif
        

Generated by: LCOV version 2.3