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

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