100.00% Lines (59/59) 100.00% Functions (14/14)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Steve Gerbino 2   // Copyright (c) 2026 Steve Gerbino
3   // Copyright (c) 2026 Michael Vandeberg 3   // Copyright (c) 2026 Michael Vandeberg
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_NATIVE_NATIVE_IO_CONTEXT_HPP 11   #ifndef BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
12   #define BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP 12   #define BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
13   13  
14   #include <boost/corosio/io_context.hpp> 14   #include <boost/corosio/io_context.hpp>
15   #include <boost/corosio/backend.hpp> 15   #include <boost/corosio/backend.hpp>
16   16  
17   #ifndef BOOST_COROSIO_MRDOCS 17   #ifndef BOOST_COROSIO_MRDOCS
18   #if BOOST_COROSIO_HAS_EPOLL 18   #if BOOST_COROSIO_HAS_EPOLL
19   #include <boost/corosio/native/detail/epoll/epoll_scheduler.hpp> 19   #include <boost/corosio/native/detail/epoll/epoll_scheduler.hpp>
20   #endif 20   #endif
21   21  
22   #if BOOST_COROSIO_HAS_SELECT 22   #if BOOST_COROSIO_HAS_SELECT
23   #include <boost/corosio/native/detail/select/select_scheduler.hpp> 23   #include <boost/corosio/native/detail/select/select_scheduler.hpp>
24   #endif 24   #endif
25   25  
26   #if BOOST_COROSIO_HAS_KQUEUE 26   #if BOOST_COROSIO_HAS_KQUEUE
27   #include <boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp> 27   #include <boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp>
28   #endif 28   #endif
29   29  
30   #if BOOST_COROSIO_HAS_IOCP 30   #if BOOST_COROSIO_HAS_IOCP
31   #include <boost/corosio/native/detail/iocp/win_scheduler.hpp> 31   #include <boost/corosio/native/detail/iocp/win_scheduler.hpp>
32   #endif 32   #endif
33   33  
34   #if BOOST_COROSIO_HAS_URING 34   #if BOOST_COROSIO_HAS_URING
35   #include <boost/corosio/native/detail/uring/uring_scheduler.hpp> 35   #include <boost/corosio/native/detail/uring/uring_scheduler.hpp>
36   #endif 36   #endif
37   #endif // !BOOST_COROSIO_MRDOCS 37   #endif // !BOOST_COROSIO_MRDOCS
38   38  
39   namespace boost::corosio { 39   namespace boost::corosio {
40   40  
41   /** Runs asynchronous operations, calling the backend event loop directly. 41   /** Runs asynchronous operations, calling the backend event loop directly.
42   42  
43   This class template inherits from @ref io_context and shadows 43   This class template inherits from @ref io_context and shadows
44   all public methods with versions that call the concrete 44   all public methods with versions that call the concrete
45   scheduler directly, bypassing virtual dispatch. No new state 45   scheduler directly, bypassing virtual dispatch. No new state
46   is added. 46   is added.
47   47  
48   A `native_io_context` IS-A `io_context` and can be passed 48   A `native_io_context` IS-A `io_context` and can be passed
49   anywhere an `io_context&` is accepted. In that case, virtual 49   anywhere an `io_context&` is accepted. In that case, virtual
50   dispatch is used transparently. 50   dispatch is used transparently.
51   51  
52   @tparam Backend A backend tag value (e.g., `epoll`, 52   @tparam Backend A backend tag value (e.g., `epoll`,
53   `iocp`) whose type provides `scheduler_type`. 53   `iocp`) whose type provides `scheduler_type`.
54   54  
55   @par Thread Safety 55   @par Thread Safety
56   Same as the underlying context type. 56   Same as the underlying context type.
57   57  
58   @par Example 58   @par Example
59   @par !example poll 59   @par !example poll
60   60  
61   @see @ref io_context, @ref epoll_t, @ref iocp_t 61   @see @ref io_context, @ref epoll_t, @ref iocp_t
62   */ 62   */
63   template<auto Backend> 63   template<auto Backend>
64   class native_io_context : public io_context 64   class native_io_context : public io_context
65   { 65   {
66   using backend_type = decltype(Backend); 66   using backend_type = decltype(Backend);
67   using scheduler_type = typename backend_type::scheduler_type; 67   using scheduler_type = typename backend_type::scheduler_type;
68   68  
HITCBC 69   219 scheduler_type& sched() noexcept 69   219 scheduler_type& sched() noexcept
70   { 70   {
HITCBC 71   219 return *static_cast<scheduler_type*>(this->sched_); 71   219 return *static_cast<scheduler_type*>(this->sched_);
72   } 72   }
73   73  
74   public: 74   public:
75   /** Construct with default concurrency. 75   /** Construct with default concurrency.
76   76  
77   @throws std::system_error If the backend's infrastructure 77   @throws std::system_error If the backend's infrastructure
78   could not be created. 78   could not be created.
79   */ 79   */
HITCBC 80   224 native_io_context() : io_context(Backend) {} 80   224 native_io_context() : io_context(Backend) {}
81   81  
82   /** Construct with a concurrency hint. 82   /** Construct with a concurrency hint.
83   83  
84   @throws std::system_error If the backend's infrastructure 84   @throws std::system_error If the backend's infrastructure
85   could not be created. 85   could not be created.
86   86  
87   @param concurrency_hint Hint for the number of threads that 87   @param concurrency_hint Hint for the number of threads that
88   call `run()`. 88   call `run()`.
89   */ 89   */
HITCBC 90   2 explicit native_io_context(unsigned concurrency_hint) 90   2 explicit native_io_context(unsigned concurrency_hint)
HITCBC 91   2 : io_context(Backend, concurrency_hint) 91   2 : io_context(Backend, concurrency_hint)
92   { 92   {
HITCBC 93   2 } 93   2 }
94   94  
95   /** Construct with runtime tuning options. 95   /** Construct with runtime tuning options.
96   96  
97   @throws std::invalid_argument If `opts.thread_pool_size` is 97   @throws std::invalid_argument If `opts.thread_pool_size` is
98   less than 1 (POSIX), `opts.max_events_per_poll` is outside 98   less than 1 (POSIX), `opts.max_events_per_poll` is outside
99   the range its member documents, or `opts.inline_budget_max` 99   the range its member documents, or `opts.inline_budget_max`
100   exceeds `INT_MAX` (platforms with a reactor backend). 100   exceeds `INT_MAX` (platforms with a reactor backend).
101   101  
102   @throws std::system_error If the backend's infrastructure 102   @throws std::system_error If the backend's infrastructure
103   could not be created. 103   could not be created.
104   104  
105   @param opts Runtime options controlling scheduler and 105   @param opts Runtime options controlling scheduler and
106   service behavior. 106   service behavior.
107   @param concurrency_hint Hint for the number of threads that 107   @param concurrency_hint Hint for the number of threads that
108   call `run()`. 108   call `run()`.
109   */ 109   */
HITCBC 110   7 explicit native_io_context( 110   7 explicit native_io_context(
111   io_context_options const& opts, 111   io_context_options const& opts,
112   unsigned concurrency_hint = std::thread::hardware_concurrency()) 112   unsigned concurrency_hint = std::thread::hardware_concurrency())
HITCBC 113   7 : io_context(Backend, opts, concurrency_hint) 113   7 : io_context(Backend, opts, concurrency_hint)
114   { 114   {
HITCBC 115   7 } 115   7 }
116   116  
117   // Non-copyable, non-movable 117   // Non-copyable, non-movable
118   /// Copy construction is disabled; the context owns its services. 118   /// Copy construction is disabled; the context owns its services.
119   native_io_context(native_io_context const&) = delete; 119   native_io_context(native_io_context const&) = delete;
120   /// Copy assignment is disabled; the context owns its services. 120   /// Copy assignment is disabled; the context owns its services.
121   native_io_context& operator=(native_io_context const&) = delete; 121   native_io_context& operator=(native_io_context const&) = delete;
122   122  
123   /** Signal the context to stop processing. 123   /** Signal the context to stop processing.
124   124  
125   @throws std::system_error on Windows if the wakeup cannot be 125   @throws std::system_error on Windows if the wakeup cannot be
126   queued, which leaves blocked `run()` callers unable to wake 126   queued, which leaves blocked `run()` callers unable to wake
127   until a later call succeeds. 127   until a later call succeeds.
128   */ 128   */
HITCBC 129   2 void stop() 129   2 void stop()
130   { 130   {
HITCBC 131   2 sched().stop(); 131   2 sched().stop();
HITCBC 132   2 } 132   2 }
133   133  
134   /** Return whether the context stopped. 134   /** Return whether the context stopped.
135   135  
136   @return `true` if the context has stopped. 136   @return `true` if the context has stopped.
137   */ 137   */
HITCBC 138   26 bool stopped() const noexcept 138   26 bool stopped() const noexcept
139   { 139   {
HITCBC 140   26 return const_cast<native_io_context*>(this)->sched().stopped(); 140   26 return const_cast<native_io_context*>(this)->sched().stopped();
141   } 141   }
142   142  
143   /// Restart the context after being stopped. 143   /// Restart the context after being stopped.
HITCBC 144   16 void restart() 144   16 void restart()
145   { 145   {
HITCBC 146   16 sched().restart(); 146   16 sched().restart();
HITCBC 147   16 } 147   16 }
148   148  
149   /** Process all pending work items. 149   /** Process all pending work items.
150   150  
151   @throws std::system_error if waiting on the operating system's 151   @throws std::system_error if waiting on the operating system's
152   event demultiplexer fails other than by interruption or 152   event demultiplexer fails other than by interruption or
153   another transient condition; the context can no longer 153   another transient condition; the context can no longer
154   dispatch work. On Windows, also if a wakeup needed to 154   dispatch work. On Windows, also if a wakeup needed to
155   stop the context cannot be queued. 155   stop the context cannot be queued.
156   156  
157   @return The number of handlers executed. 157   @return The number of handlers executed.
158   */ 158   */
HITCBC 159   141 std::size_t run() 159   141 std::size_t run()
160   { 160   {
HITCBC 161   141 frame_allocator_restore restore; 161   141 frame_allocator_restore restore;
HITCBC 162   282 return sched().run(); 162   282 return sched().run();
HITCBC 163   141 } 163   141 }
164   164  
165   /** Process at most one pending work item. 165   /** Process at most one pending work item.
166   166  
167   @throws std::system_error if waiting on the operating system's 167   @throws std::system_error if waiting on the operating system's
168   event demultiplexer fails other than by interruption or 168   event demultiplexer fails other than by interruption or
169   another transient condition; the context can no longer 169   another transient condition; the context can no longer
170   dispatch work. On Windows, also if a wakeup needed to 170   dispatch work. On Windows, also if a wakeup needed to
171   stop the context cannot be queued. 171   stop the context cannot be queued.
172   172  
173   @return The number of handlers executed (0 or 1). 173   @return The number of handlers executed (0 or 1).
174   */ 174   */
HITCBC 175   2 std::size_t run_one() 175   2 std::size_t run_one()
176   { 176   {
HITCBC 177   2 frame_allocator_restore restore; 177   2 frame_allocator_restore restore;
HITCBC 178   4 return sched().run_one(); 178   4 return sched().run_one();
HITCBC 179   2 } 179   2 }
180   180  
181   /** Process work items for the specified duration. 181   /** Process work items for the specified duration.
182   182  
183   @throws std::system_error if waiting on the operating system's 183   @throws std::system_error if waiting on the operating system's
184   event demultiplexer fails other than by interruption or 184   event demultiplexer fails other than by interruption or
185   another transient condition; the context can no longer 185   another transient condition; the context can no longer
186   dispatch work. On Windows, also if a wakeup needed to 186   dispatch work. On Windows, also if a wakeup needed to
187   stop the context cannot be queued. 187   stop the context cannot be queued.
188   188  
189   @param rel_time The duration for which to process work. 189   @param rel_time The duration for which to process work.
190   190  
191   @return The number of handlers executed. 191   @return The number of handlers executed.
192   */ 192   */
193   template<class Rep, class Period> 193   template<class Rep, class Period>
HITCBC 194   6 std::size_t run_for(std::chrono::duration<Rep, Period> const& rel_time) 194   6 std::size_t run_for(std::chrono::duration<Rep, Period> const& rel_time)
195   { 195   {
HITCBC 196   6 return run_until(std::chrono::steady_clock::now() + rel_time); 196   6 return run_until(std::chrono::steady_clock::now() + rel_time);
197   } 197   }
198   198  
199   /** Process work items until the specified time. 199   /** Process work items until the specified time.
200   200  
201   @throws std::system_error if waiting on the operating system's 201   @throws std::system_error if waiting on the operating system's
202   event demultiplexer fails other than by interruption or 202   event demultiplexer fails other than by interruption or
203   another transient condition; the context can no longer 203   another transient condition; the context can no longer
204   dispatch work. On Windows, also if a wakeup needed to 204   dispatch work. On Windows, also if a wakeup needed to
205   stop the context cannot be queued. 205   stop the context cannot be queued.
206   206  
207   @param abs_time The time point until which to process work. 207   @param abs_time The time point until which to process work.
208   208  
209   @return The number of handlers executed. 209   @return The number of handlers executed.
210   */ 210   */
211   template<class Clock, class Duration> 211   template<class Clock, class Duration>
212   std::size_t 212   std::size_t
HITCBC 213   6 run_until(std::chrono::time_point<Clock, Duration> const& abs_time) 213   6 run_until(std::chrono::time_point<Clock, Duration> const& abs_time)
214   { 214   {
HITCBC 215   6 std::size_t n = 0; 215   6 std::size_t n = 0;
HITCBC 216   10 while (run_one_until(abs_time)) 216   10 while (run_one_until(abs_time))
HITCBC 217   4 if (n != (std::numeric_limits<std::size_t>::max)()) 217   4 if (n != (std::numeric_limits<std::size_t>::max)())
HITCBC 218   4 ++n; 218   4 ++n;
HITCBC 219   6 return n; 219   6 return n;
220   } 220   }
221   221  
222   /** Process at most one work item for the specified duration. 222   /** Process at most one work item for the specified duration.
223   223  
224   @throws std::system_error if waiting on the operating system's 224   @throws std::system_error if waiting on the operating system's
225   event demultiplexer fails other than by interruption or 225   event demultiplexer fails other than by interruption or
226   another transient condition; the context can no longer 226   another transient condition; the context can no longer
227   dispatch work. On Windows, also if a wakeup needed to 227   dispatch work. On Windows, also if a wakeup needed to
228   stop the context cannot be queued. 228   stop the context cannot be queued.
229   229  
230   @param rel_time The duration for which the call may block. 230   @param rel_time The duration for which the call may block.
231   231  
232   @return The number of handlers executed (0 or 1). 232   @return The number of handlers executed (0 or 1).
233   */ 233   */
234   template<class Rep, class Period> 234   template<class Rep, class Period>
235   std::size_t run_one_for(std::chrono::duration<Rep, Period> const& rel_time) 235   std::size_t run_one_for(std::chrono::duration<Rep, Period> const& rel_time)
236   { 236   {
237   return run_one_until(std::chrono::steady_clock::now() + rel_time); 237   return run_one_until(std::chrono::steady_clock::now() + rel_time);
238   } 238   }
239   239  
240   /** Process at most one work item until the specified time. 240   /** Process at most one work item until the specified time.
241   241  
242   @throws std::system_error if waiting on the operating system's 242   @throws std::system_error if waiting on the operating system's
243   event demultiplexer fails other than by interruption or 243   event demultiplexer fails other than by interruption or
244   another transient condition; the context can no longer 244   another transient condition; the context can no longer
245   dispatch work. On Windows, also if a wakeup needed to 245   dispatch work. On Windows, also if a wakeup needed to
246   stop the context cannot be queued. 246   stop the context cannot be queued.
247   247  
248   @param abs_time The time point until which the call may block. 248   @param abs_time The time point until which the call may block.
249   249  
250   @return The number of handlers executed (0 or 1). 250   @return The number of handlers executed (0 or 1).
251   */ 251   */
252   template<class Clock, class Duration> 252   template<class Clock, class Duration>
253   std::size_t 253   std::size_t
HITCBC 254   14 run_one_until(std::chrono::time_point<Clock, Duration> const& abs_time) 254   14 run_one_until(std::chrono::time_point<Clock, Duration> const& abs_time)
255   { 255   {
HITCBC 256   14 frame_allocator_restore restore; 256   14 frame_allocator_restore restore;
HITCBC 257   14 typename Clock::time_point now = Clock::now(); 257   14 typename Clock::time_point now = Clock::now();
HITCBC 258   4 for (;;) 258   4 for (;;)
259   { 259   {
HITCBC 260   18 auto rel_time = abs_time - now; 260   18 auto rel_time = abs_time - now;
261   using rel_type = decltype(rel_time); 261   using rel_type = decltype(rel_time);
HITCBC 262   18 if (rel_time < rel_type::zero()) 262   18 if (rel_time < rel_type::zero())
HITCBC 263   2 rel_time = rel_type::zero(); 263   2 rel_time = rel_type::zero();
HITCBC 264   16 else if (rel_time > std::chrono::seconds(1)) 264   16 else if (rel_time > std::chrono::seconds(1))
HITCBC 265   8 rel_time = std::chrono::seconds(1); 265   8 rel_time = std::chrono::seconds(1);
266   266  
HITCBC 267   36 std::size_t s = sched().wait_one( 267   36 std::size_t s = sched().wait_one(
268   static_cast<long>( 268   static_cast<long>(
HITCBC 269   18 std::chrono::duration_cast<std::chrono::microseconds>( 269   18 std::chrono::duration_cast<std::chrono::microseconds>(
270   rel_time) 270   rel_time)
HITCBC 271   18 .count())); 271   18 .count()));
272   272  
HITCBC 273   18 if (s || stopped()) 273   18 if (s || stopped())
HITCBC 274   12 return s; 274   12 return s;
275   275  
HITCBC 276   6 now = Clock::now(); 276   6 now = Clock::now();
HITCBC 277   6 if (now >= abs_time) 277   6 if (now >= abs_time)
HITCBC 278   2 return 0; 278   2 return 0;
279   } 279   }
HITCBC 280   14 } 280   14 }
281   281  
282   /** Process all ready work items without blocking. 282   /** Process all ready work items without blocking.
283   283  
284   @throws std::system_error if waiting on the operating system's 284   @throws std::system_error if waiting on the operating system's
285   event demultiplexer fails other than by interruption or 285   event demultiplexer fails other than by interruption or
286   another transient condition; the context can no longer 286   another transient condition; the context can no longer
287   dispatch work. On Windows, also if a wakeup needed to 287   dispatch work. On Windows, also if a wakeup needed to
288   stop the context cannot be queued. 288   stop the context cannot be queued.
289   289  
290   @return The number of handlers executed. 290   @return The number of handlers executed.
291   */ 291   */
HITCBC 292   12 std::size_t poll() 292   12 std::size_t poll()
293   { 293   {
HITCBC 294   12 frame_allocator_restore restore; 294   12 frame_allocator_restore restore;
HITCBC 295   24 return sched().poll(); 295   24 return sched().poll();
HITCBC 296   12 } 296   12 }
297   297  
298   /** Process at most one ready work item without blocking. 298   /** Process at most one ready work item without blocking.
299   299  
300   @throws std::system_error if waiting on the operating system's 300   @throws std::system_error if waiting on the operating system's
301   event demultiplexer fails other than by interruption or 301   event demultiplexer fails other than by interruption or
302   another transient condition; the context can no longer 302   another transient condition; the context can no longer
303   dispatch work. On Windows, also if a wakeup needed to 303   dispatch work. On Windows, also if a wakeup needed to
304   stop the context cannot be queued. 304   stop the context cannot be queued.
305   305  
306   @return The number of handlers executed (0 or 1). 306   @return The number of handlers executed (0 or 1).
307   */ 307   */
HITCBC 308   2 std::size_t poll_one() 308   2 std::size_t poll_one()
309   { 309   {
HITCBC 310   2 frame_allocator_restore restore; 310   2 frame_allocator_restore restore;
HITCBC 311   4 return sched().poll_one(); 311   4 return sched().poll_one();
HITCBC 312   2 } 312   2 }
313   }; 313   };
314   314  
315   } // namespace boost::corosio 315   } // namespace boost::corosio
316   316  
317   #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP 317   #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP