include/boost/corosio/detail/scheduler_op.hpp

44.4% Lines (4/9) 60.0% List of functions (3/5) 0.0% Branches (0/2)
scheduler_op.hpp
f(x) Functions (5)
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco ([email protected])
3 // Copyright (c) 2026 Steve Gerbino
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/corosio
9 //
10
11 #ifndef BOOST_COROSIO_DETAIL_SCHEDULER_OP_HPP
12 #define BOOST_COROSIO_DETAIL_SCHEDULER_OP_HPP
13
14 #include <boost/corosio/detail/config.hpp>
15 #include <boost/corosio/detail/intrusive.hpp>
16
17 #include <cstdint>
18 #include <utility>
19
20 namespace boost::corosio::detail {
21
22 /** Base class for completion handlers using function pointer dispatch.
23
24 Handlers are continuations that execute after an asynchronous
25 operation completes. They can be queued for deferred invocation,
26 allowing callbacks and coroutine resumptions to be posted to an
27 executor.
28
29 This class uses a function pointer instead of virtual dispatch
30 to minimize overhead in the completion path. Each derived class
31 provides a static completion function that handles both normal
32 invocation and destruction.
33
34 @par Function Pointer Convention
35
36 The func_type signature is:
37 @code
38 void(*)(void* owner, scheduler_op* op, std::uint32_t bytes, std::uint32_t error);
39 @endcode
40
41 - When owner != nullptr: Normal completion. Process the operation.
42 - When owner == nullptr: Destroy mode. Clean up without invoking.
43
44 @par Ownership Contract
45
46 Callers must invoke exactly ONE of `complete()` or `destroy()`,
47 never both.
48
49 @see scheduler_op_queue
50 */
51 class scheduler_op : public intrusive_queue<scheduler_op>::node
52 {
53 public:
54 /** Function pointer type for completion handling.
55
56 @param owner Pointer to the scheduler (nullptr for destroy).
57 @param op The operation to complete or destroy.
58 @param bytes Bytes transferred (for I/O operations).
59 @param error Error code from the operation.
60 */
61 using func_type = void (*)(
62 void* owner,
63 scheduler_op* op,
64 std::uint32_t bytes,
65 std::uint32_t error);
66
67 /** Complete the operation via function pointer (IOCP path).
68
69 @param owner Pointer to the owning scheduler.
70 @param bytes Bytes transferred.
71 @param error Error code.
72 */
73 void complete(void* owner, std::uint32_t bytes, std::uint32_t error)
74 {
75 func_(owner, this, bytes, error);
76 }
77
78 /** Invoke the handler (epoll/select path).
79
80 Override in derived classes to handle operation completion.
81 Default implementation does nothing.
82 */
83 virtual void operator()() {}
84
85 /** Destroy without invoking the handler.
86
87 Called during shutdown or when discarding queued operations.
88 Override in derived classes if cleanup is needed.
89 Default implementation calls through func_ if set.
90 */
91 virtual void destroy()
92 {
93 if (func_)
94 func_(nullptr, this, 0, 0);
95 }
96
97 183177x virtual ~scheduler_op() = default;
98
99 protected:
100 /** Default constructor for derived classes using virtual dispatch.
101
102 Used by epoll/select backends that override operator() and destroy().
103 */
104 330422x scheduler_op() noexcept : func_(nullptr) {}
105
106 /** Construct with completion function for function pointer dispatch.
107
108 Used by IOCP backend for non-virtual completion.
109
110 @param func The static function to call for completion/destruction.
111 */
112 35944x explicit scheduler_op(func_type func) noexcept : func_(func) {}
113
114 func_type func_;
115
116 public:
117 // Tagged next-link for ready_queue (low bit selects node kind). Reuses
118 // the former 8-byte padding word, so size/alignment are unchanged. Used
119 // only while this op is in the ready queue; node.next_ is used while it
120 // is pending in an op_queue. An op is in one or the other, never both.
121 183183x std::uintptr_t q_next_ = 0;
122 };
123
124 using op_queue = intrusive_queue<scheduler_op>;
125
126 /** An intrusive FIFO queue of scheduler_ops.
127
128 This queue stores scheduler_ops using an intrusive linked list,
129 avoiding additional allocations for queue nodes. Scheduler_ops
130 are popped in the order they were pushed (first-in, first-out).
131
132 The destructor calls `destroy()` on any remaining scheduler_ops.
133
134 @note This is not thread-safe. External synchronization is
135 required for concurrent access.
136
137 @see scheduler_op
138 */
139 class scheduler_op_queue
140 {
141 op_queue q_;
142
143 public:
144 scheduler_op_queue() = default;
145
146 scheduler_op_queue(scheduler_op_queue&& other) noexcept
147 : q_(std::move(other.q_))
148 {
149 }
150
151 scheduler_op_queue(scheduler_op_queue const&) = delete;
152 scheduler_op_queue& operator=(scheduler_op_queue const&) = delete;
153 scheduler_op_queue& operator=(scheduler_op_queue&&) = delete;
154
155 ~scheduler_op_queue()
156 {
157 while (auto* h = q_.pop())
158 h->destroy();
159 }
160
161 bool empty() const noexcept
162 {
163 return q_.empty();
164 }
165 void push(scheduler_op* h) noexcept
166 {
167 q_.push(h);
168 }
169 void push(scheduler_op_queue& other) noexcept
170 {
171 q_.splice(other.q_);
172 }
173 scheduler_op* pop() noexcept
174 {
175 return q_.pop();
176 }
177 };
178
179 } // namespace boost::corosio::detail
180
181 #endif
182