include/boost/corosio/detail/continuation_op.hpp

69.6% Lines (16/23) 80.0% List of functions (4/5)
continuation_op.hpp
f(x) Functions (5)
Line TLA Hits 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 163510x 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 8960x void operator()() override
50 {
51 // ThreadSanitizer cannot instrument standalone fences; this acquire
52 // fence pairs with the scheduler's release and is intentional.
53 BOOST_COROSIO_GCC_WARNING_PUSH
54 BOOST_COROSIO_GCC_WARNING_DISABLE("-Wtsan")
55 std::atomic_thread_fence(std::memory_order_acquire);
56 BOOST_COROSIO_GCC_WARNING_POP
57 8960x cont.h.resume();
58 8960x }
59
60 4x void destroy() override
61 {
62 4x if (cont.h)
63 4x cont.h.destroy();
64 4x }
65
66 private:
67 // IOCP completion entry point. owner == nullptr means destroy.
68 static void do_complete(
69 void* owner,
70 scheduler_op* base,
71 std::uint32_t,
72 std::uint32_t)
73 {
74 auto* self = static_cast<continuation_op*>(base);
75 if (!owner)
76 {
77 if (self->cont.h)
78 self->cont.h.destroy();
79 return;
80 }
81 BOOST_COROSIO_GCC_WARNING_PUSH
82 BOOST_COROSIO_GCC_WARNING_DISABLE("-Wtsan")
83 std::atomic_thread_fence(std::memory_order_acquire);
84 BOOST_COROSIO_GCC_WARNING_POP
85 self->cont.h.resume();
86 }
87
88 public:
89
90 // Recover the enclosing continuation_op from its cont member.
91 // Returns nullptr if the continuation is not tagged (bare
92 // capy::continuation from capy internals like run_async).
93 10443x static continuation_op* try_from_continuation(
94 capy::continuation& c) noexcept
95 {
96 // offsetof on non-standard-layout is conditionally-supported;
97 // suppress the warning — all targeted compilers handle this
98 // correctly and the self-relative arithmetic is move-safe.
99 #if defined(__GNUC__) || defined(__clang__)
100 #pragma GCC diagnostic push
101 #pragma GCC diagnostic ignored "-Winvalid-offsetof"
102 #endif
103 10443x constexpr auto cont_off = offsetof(continuation_op, cont);
104 10443x constexpr auto tag_off = offsetof(continuation_op, tag_);
105 #if defined(__GNUC__) || defined(__clang__)
106 #pragma GCC diagnostic pop
107 #endif
108 // Read the tag through memcpy from a char*, not through a
109 // continuation_op*. This avoids UBSan's vptr check when
110 // the continuation is not actually inside a continuation_op.
111 10443x auto* base = reinterpret_cast<char*>(&c) - cont_off;
112 std::uint32_t tag;
113 10443x std::memcpy(&tag, base + tag_off, sizeof(tag));
114 10443x if (tag != magic_)
115 1479x return nullptr;
116 8964x return reinterpret_cast<continuation_op*>(base);
117 }
118 };
119
120 } // namespace boost::corosio::detail
121
122 #endif
123