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