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

100.0% Lines (10/0/10) 100.0% List of functions (3/0/3)
io_uring_op.hpp
f(x) Functions (3)
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/native/detail/coro_op.hpp>
18 #include <boost/corosio/detail/ready_queue.hpp>
19
20 // Forward declare to avoid circular include with io_uring_scheduler.hpp.
21 namespace boost::corosio::detail { class io_uring_scheduler; }
22
23 #include <atomic>
24
25 #include <liburing.h>
26
27 namespace boost::corosio::detail {
28
29 /** io_uring operation: the shared proactor op envelope plus the
30 io_uring-specific completion plumbing.
31
32 `coro_op` supplies the fields common to both proactor backends
33 (coroutine handle, executor, output pointers, stop_token wiring,
34 impl_ptr keepalive). This type adds the CQE result (`res`/`cqe_flags`),
35 the ring-cancel visibility flag (`sqe_set`), and the two function
36 pointers the run loop uses to prep an SQE and dispatch a CQE without
37 template instantiation.
38 */
39 struct io_uring_op : coro_op
40 {
41 /// CQE-side dispatcher type. Called once per completion event.
42 /// Pushes self into `local` rather than dispatching inline so
43 /// process_completions can splice the batch into completed_ops_
44 /// atomically and do_one dispatches one handler at a time.
45 using cqe_func_type =
46 void (*)(io_uring_op*, int res, unsigned flags, ready_queue& local) noexcept;
47
48 /// SQE-preparation dispatcher type. Called by the leader during
49 /// its drain step to fill an SQE for this op. Concrete op types
50 /// set this at construction so the new submit path is purely
51 /// data-driven (no template instantiation, no allocation).
52 using prep_func_type =
53 void (*)(io_uring_op*, ::io_uring_sqe*) noexcept;
54
55 /// Retired-CQE dispatcher type. Called in place of `cqe_func` once
56 /// the op is retired, so the op type can release whatever `res`
57 /// owns (an accepted descriptor, a registered buffer) that no
58 /// handler will now take delivery of.
59 using retire_func_type =
60 void (*)(io_uring_op*, int res, unsigned flags) noexcept;
61
62 30817x explicit io_uring_op(
63 func_type post_func,
64 cqe_func_type cqe_fn,
65 prep_func_type prep_fn = nullptr) noexcept
66 30817x : coro_op(post_func)
67 30817x , cqe_func(cqe_fn)
68 30817x , prep_func(prep_fn)
69 30817x {}
70
71 int res = 0;
72 unsigned cqe_flags = 0;
73 /// True after `io_uring_sqe_set_data` has linked an SQE to this op.
74 /// Until then, on_cancel() has nothing for the kernel to find.
75 std::atomic<bool> sqe_set{false};
76 cqe_func_type cqe_func;
77 /// SQE-preparation dispatcher. nullptr for ops still using the
78 /// old `io_uring_submit_op<PrepFn>(prep)` template path
79 /// (UDP/local/file/dgram during plan 5a). Set non-null by ops
80 /// migrated to the queue-based submit path.
81 prep_func_type prep_func;
82
83 /// Scheduler reference for submitting cancel SQEs on stop_token.
84 io_uring_scheduler* sched_ = nullptr;
85
86 /// Set when the op's owner went away while the kernel still held
87 /// its user_data (see `io_uring_scheduler::retire_op`). A retired
88 /// op belongs to the scheduler: the run loop routes its CQEs to
89 /// `retire_func` instead of `cqe_func` and frees the op on the
90 /// terminal CQE.
91 bool retired = false;
92
93 /// Disposal hook used while `retired` is set. May be null when the
94 /// op's result owns nothing.
95 retire_func_type retire_func = nullptr;
96
97 /// Bridge virtual dispatch to func-pointer dispatch. Lets the run
98 /// loop dispatch any scheduler_op via `(*op)()` — both reactor-style
99 /// services posted into the queue and proactor-style io_uring ops.
100 /// `owner` is non-null per scheduler_op's completion-vs-destroy
101 /// convention (see scheduler_op.hpp).
102 21034x void operator()() override { complete(this, 0, 0); }
103
104 /// Arm the stop-token callback. Must be called before the SQE submits.
105 /// Extends coro_op::start to also clear the ring-cancel flag.
106 18799x void start(std::stop_token const& token)
107 {
108 18799x sqe_set.store(false, std::memory_order_relaxed);
109 18799x coro_op::start(token);
110 18799x }
111
112 /// io_uring cancellation: record the request and, if an SQE was already
113 /// linked, ask the kernel to cancel it by user_data.
114 void on_cancel() noexcept override;
115 };
116
117 } // namespace boost::corosio::detail
118
119 #endif // BOOST_COROSIO_HAS_IO_URING
120
121 #endif // BOOST_COROSIO_NATIVE_DETAIL_IO_URING_IO_URING_OP_HPP
122