include/boost/corosio/native/detail/io_uring/io_uring_op.hpp

100.0% Lines (14/14) 100.0% List of functions (4/4)
io_uring_op.hpp
f(x) Functions (4)
Line TLA Hits 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_NATIVE_DETAIL_IO_URING_IO_URING_OP_HPP
11 #define BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_OP_HPP
12
13 #include <boost/corosio/detail/platform.hpp>
14
15 #if BOOST_COROSIO_HAS_IO_URING
16
17 #include <boost/corosio/detail/continuation_op.hpp>
18 #include <boost/corosio/detail/scheduler_op.hpp>
19 #include <boost/capy/ex/executor_ref.hpp>
20
21 // Forward declare to avoid circular include with io_uring_scheduler.hpp.
22 namespace boost::corosio::detail { class io_uring_scheduler; }
23
24 #include <atomic>
25 #include <coroutine>
26 #include <cstddef>
27 #include <memory>
28 #include <optional>
29 #include <stop_token>
30
31 #include <liburing.h>
32
33 namespace boost::corosio::detail {
34
35 /** Base class for io_uring operations.
36
37 Holds per-operation state common to every uring op: coroutine
38 handle, executor for handler dispatch, output pointers, the
39 stop_token wiring for cancellation, and a function pointer
40 used by the scheduler to dispatch a CQE arrival.
41
42 Concrete op types (uring_read_op, uring_write_op, etc.) set
43 `cqe_func` at construction so the run loop's completion path
44 has zero virtual indirection.
45 */
46 struct io_uring_op : scheduler_op
47 {
48 /// CQE-side dispatcher type. Called once per completion event.
49 /// Pushes self into `local` rather than dispatching inline so
50 /// process_completions can splice the batch into completed_ops_
51 /// atomically and do_one dispatches one handler at a time.
52 using cqe_func_type =
53 void (*)(io_uring_op*, int res, unsigned flags, op_queue& local) noexcept;
54
55 /// SQE-preparation dispatcher type. Called by the leader during
56 /// its drain step to fill an SQE for this op. Concrete op types
57 /// set this at construction so the new submit path is purely
58 /// data-driven (no template instantiation, no allocation).
59 using prep_func_type =
60 void (*)(io_uring_op*, ::io_uring_sqe*) noexcept;
61
62 /// Stop-callback handler: requests cancellation of this op.
63 struct canceller
64 {
65 io_uring_op* op;
66 101x void operator()() const noexcept { op->request_cancel(); }
67 };
68
69 52431x explicit io_uring_op(
70 func_type post_func,
71 cqe_func_type cqe_fn,
72 prep_func_type prep_fn = nullptr) noexcept
73 52431x : scheduler_op(post_func)
74 52431x , cqe_func(cqe_fn)
75 52431x , prep_func(prep_fn)
76 52431x {}
77
78 std::coroutine_handle<> h;
79 detail::continuation_op cont_op;
80 capy::executor_ref ex;
81 std::error_code* ec_out = nullptr;
82 std::size_t* bytes_out = nullptr;
83
84 int res = 0;
85 unsigned cqe_flags = 0;
86 bool is_read = false;
87 bool empty_buffer = false;
88
89 std::atomic<bool> cancelled{false};
90 /// True after `io_uring_sqe_set_data` has linked an SQE to this op.
91 /// Until then, request_cancel() has nothing for the kernel to find.
92 std::atomic<bool> sqe_set{false};
93 std::optional<std::stop_callback<canceller>> stop_cb;
94 cqe_func_type cqe_func;
95 /// SQE-preparation dispatcher. nullptr for ops still using the
96 /// old `io_uring_submit_op<PrepFn>(prep)` template path
97 /// (UDP/local/file/dgram during plan 5a). Set non-null by ops
98 /// migrated to the queue-based submit path.
99 prep_func_type prep_func;
100
101 /// Keeps the owning impl alive while the op is in flight (kernel
102 /// owns user buffers until completion).
103 std::shared_ptr<void> impl_ptr;
104
105 /// Scheduler reference for submitting cancel SQEs on stop_token.
106 io_uring_scheduler* sched_ = nullptr;
107
108 void request_cancel() noexcept;
109
110
111 /// Bridge virtual dispatch to func-pointer dispatch. Lets the run
112 /// loop dispatch any scheduler_op via `(*op)()` — both reactor-style
113 /// services posted into the queue and proactor-style io_uring ops.
114 /// `owner` is non-null per scheduler_op's completion-vs-destroy
115 /// convention (see scheduler_op.hpp).
116 41899x void operator()() override { complete(this, 0, 0); }
117
118 /// Arm the stop-token callback. Must be called before the SQE submits.
119 37943x void start(std::stop_token const& token)
120 {
121 37943x cancelled.store(false, std::memory_order_relaxed);
122 37943x sqe_set.store(false, std::memory_order_relaxed);
123 37943x stop_cb.reset();
124 37943x if (token.stop_possible())
125 101x stop_cb.emplace(token, canceller{this});
126 37943x }
127 };
128
129 } // namespace boost::corosio::detail
130
131 #endif // BOOST_COROSIO_HAS_IO_URING
132
133 #endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_OP_HPP
134