libs/corosio/src/corosio/src/detail/scheduler_op.hpp

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