include/boost/corosio/native/detail/uring/uring_op.hpp

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