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   199 scheduler_type& sched() noexcept 69   219 scheduler_type& sched() noexcept
70   { 70   {
HITCBC 71   199 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 +
  77 + @throws std::system_error If the backend's infrastructure
  78 + could not be created.
  79 + */
HITCBC 76   200 native_io_context() : io_context(Backend) {} 80   224 native_io_context() : io_context(Backend) {}
77   81  
78   /** Construct with a concurrency hint. 82   /** Construct with a concurrency hint.
79   83  
  84 + @throws std::system_error If the backend's infrastructure
  85 + could not be created.
  86 +
80   @param concurrency_hint Hint for the number of threads that 87   @param concurrency_hint Hint for the number of threads that
81   call `run()`. 88   call `run()`.
82   */ 89   */
HITCBC 83   2 explicit native_io_context(unsigned concurrency_hint) 90   2 explicit native_io_context(unsigned concurrency_hint)
HITCBC 84   2 : io_context(Backend, concurrency_hint) 91   2 : io_context(Backend, concurrency_hint)
85   { 92   {
HITCBC 86   2 } 93   2 }
87   94  
88   /** Construct with runtime tuning options. 95   /** Construct with runtime tuning options.
89   96  
  97 + @throws std::invalid_argument If `opts.thread_pool_size` is
  98 + less than 1 (POSIX), `opts.max_events_per_poll` is outside
  99 + the range its member documents, or `opts.inline_budget_max`
  100 + exceeds `INT_MAX` (platforms with a reactor backend).
  101 +
  102 + @throws std::system_error If the backend's infrastructure
  103 + could not be created.
  104 +
90   @param opts Runtime options controlling scheduler and 105   @param opts Runtime options controlling scheduler and
91   service behavior. 106   service behavior.
92   @param concurrency_hint Hint for the number of threads that 107   @param concurrency_hint Hint for the number of threads that
93   call `run()`. 108   call `run()`.
94   */ 109   */
HITCBC 95   7 explicit native_io_context( 110   7 explicit native_io_context(
96   io_context_options const& opts, 111   io_context_options const& opts,
97   unsigned concurrency_hint = std::thread::hardware_concurrency()) 112   unsigned concurrency_hint = std::thread::hardware_concurrency())
HITCBC 98   7 : io_context(Backend, opts, concurrency_hint) 113   7 : io_context(Backend, opts, concurrency_hint)
99   { 114   {
HITCBC 100   7 } 115   7 }
101   116  
102   // Non-copyable, non-movable 117   // Non-copyable, non-movable
103   /// Copy construction is disabled; the context owns its services. 118   /// Copy construction is disabled; the context owns its services.
104   native_io_context(native_io_context const&) = delete; 119   native_io_context(native_io_context const&) = delete;
105   /// Copy assignment is disabled; the context owns its services. 120   /// Copy assignment is disabled; the context owns its services.
106   native_io_context& operator=(native_io_context const&) = delete; 121   native_io_context& operator=(native_io_context const&) = delete;
107   122  
108 - /// Signal the context to stop processing. 123 + /** Signal the context to stop processing.
  124 +
  125 + @throws std::system_error on Windows if the wakeup cannot be
  126 + queued, which leaves blocked `run()` callers unable to wake
  127 + until a later call succeeds.
  128 + */
HITCBC 109   2 void stop() 129   2 void stop()
110   { 130   {
HITCBC 111   2 sched().stop(); 131   2 sched().stop();
HITCBC 112   2 } 132   2 }
113   133  
114   /** Return whether the context stopped. 134   /** Return whether the context stopped.
115   135  
116   @return `true` if the context has stopped. 136   @return `true` if the context has stopped.
117   */ 137   */
HITCBC 118   26 bool stopped() const noexcept 138   26 bool stopped() const noexcept
119   { 139   {
HITCBC 120   26 return const_cast<native_io_context*>(this)->sched().stopped(); 140   26 return const_cast<native_io_context*>(this)->sched().stopped();
121   } 141   }
122   142  
123   /// Restart the context after being stopped. 143   /// Restart the context after being stopped.
HITCBC 124   16 void restart() 144   16 void restart()
125   { 145   {
HITCBC 126   16 sched().restart(); 146   16 sched().restart();
HITCBC 127   16 } 147   16 }
128   148  
129   /** Process all pending work items. 149   /** Process all pending work items.
130   150  
  151 + @throws std::system_error if waiting on the operating system's
  152 + event demultiplexer fails other than by interruption or
  153 + another transient condition; the context can no longer
  154 + dispatch work. On Windows, also if a wakeup needed to
  155 + stop the context cannot be queued.
  156 +
131   @return The number of handlers executed. 157   @return The number of handlers executed.
132   */ 158   */
HITCBC 133   129 std::size_t run() 159   141 std::size_t run()
134   { 160   {
HITCBC 135   129 frame_allocator_restore restore; 161   141 frame_allocator_restore restore;
HITCBC 136   258 return sched().run(); 162   282 return sched().run();
HITCBC 137   129 } 163   141 }
138   164  
139   /** Process at most one pending work item. 165   /** Process at most one pending work item.
140   166  
  167 + @throws std::system_error if waiting on the operating system's
  168 + event demultiplexer fails other than by interruption or
  169 + another transient condition; the context can no longer
  170 + dispatch work. On Windows, also if a wakeup needed to
  171 + stop the context cannot be queued.
  172 +
141   @return The number of handlers executed (0 or 1). 173   @return The number of handlers executed (0 or 1).
142   */ 174   */
HITCBC 143   2 std::size_t run_one() 175   2 std::size_t run_one()
144   { 176   {
HITCBC 145   2 frame_allocator_restore restore; 177   2 frame_allocator_restore restore;
HITCBC 146   4 return sched().run_one(); 178   4 return sched().run_one();
HITCBC 147   2 } 179   2 }
148   180  
149   /** Process work items for the specified duration. 181   /** Process work items for the specified duration.
150   182  
  183 + @throws std::system_error if waiting on the operating system's
  184 + event demultiplexer fails other than by interruption or
  185 + another transient condition; the context can no longer
  186 + dispatch work. On Windows, also if a wakeup needed to
  187 + stop the context cannot be queued.
  188 +
151   @param rel_time The duration for which to process work. 189   @param rel_time The duration for which to process work.
152   190  
153   @return The number of handlers executed. 191   @return The number of handlers executed.
154   */ 192   */
155   template<class Rep, class Period> 193   template<class Rep, class Period>
HITCBC 156   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)
157   { 195   {
HITCBC 158   6 return run_until(std::chrono::steady_clock::now() + rel_time); 196   6 return run_until(std::chrono::steady_clock::now() + rel_time);
159   } 197   }
160   198  
161   /** Process work items until the specified time. 199   /** Process work items until the specified time.
162   200  
  201 + @throws std::system_error if waiting on the operating system's
  202 + event demultiplexer fails other than by interruption or
  203 + another transient condition; the context can no longer
  204 + dispatch work. On Windows, also if a wakeup needed to
  205 + stop the context cannot be queued.
  206 +
163   @param abs_time The time point until which to process work. 207   @param abs_time The time point until which to process work.
164   208  
165   @return The number of handlers executed. 209   @return The number of handlers executed.
166   */ 210   */
167   template<class Clock, class Duration> 211   template<class Clock, class Duration>
168   std::size_t 212   std::size_t
HITCBC 169   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)
170   { 214   {
HITCBC 171   6 std::size_t n = 0; 215   6 std::size_t n = 0;
HITCBC 172   10 while (run_one_until(abs_time)) 216   10 while (run_one_until(abs_time))
HITCBC 173   4 if (n != (std::numeric_limits<std::size_t>::max)()) 217   4 if (n != (std::numeric_limits<std::size_t>::max)())
HITCBC 174   4 ++n; 218   4 ++n;
HITCBC 175   6 return n; 219   6 return n;
176   } 220   }
177   221  
178   /** Process at most one work item for the specified duration. 222   /** Process at most one work item for the specified duration.
179   223  
  224 + @throws std::system_error if waiting on the operating system's
  225 + event demultiplexer fails other than by interruption or
  226 + another transient condition; the context can no longer
  227 + dispatch work. On Windows, also if a wakeup needed to
  228 + stop the context cannot be queued.
  229 +
180   @param rel_time The duration for which the call may block. 230   @param rel_time The duration for which the call may block.
181   231  
182   @return The number of handlers executed (0 or 1). 232   @return The number of handlers executed (0 or 1).
183   */ 233   */
184   template<class Rep, class Period> 234   template<class Rep, class Period>
185   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)
186   { 236   {
187   return run_one_until(std::chrono::steady_clock::now() + rel_time); 237   return run_one_until(std::chrono::steady_clock::now() + rel_time);
188   } 238   }
189   239  
190   /** Process at most one work item until the specified time. 240   /** Process at most one work item until the specified time.
191   241  
  242 + @throws std::system_error if waiting on the operating system's
  243 + event demultiplexer fails other than by interruption or
  244 + another transient condition; the context can no longer
  245 + dispatch work. On Windows, also if a wakeup needed to
  246 + stop the context cannot be queued.
  247 +
192   @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.
193   249  
194   @return The number of handlers executed (0 or 1). 250   @return The number of handlers executed (0 or 1).
195   */ 251   */
196   template<class Clock, class Duration> 252   template<class Clock, class Duration>
197   std::size_t 253   std::size_t
HITCBC 198   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)
199   { 255   {
HITCBC 200   14 frame_allocator_restore restore; 256   14 frame_allocator_restore restore;
HITCBC 201   14 typename Clock::time_point now = Clock::now(); 257   14 typename Clock::time_point now = Clock::now();
HITCBC 202   4 for (;;) 258   4 for (;;)
203   { 259   {
HITCBC 204   18 auto rel_time = abs_time - now; 260   18 auto rel_time = abs_time - now;
205   using rel_type = decltype(rel_time); 261   using rel_type = decltype(rel_time);
HITCBC 206   18 if (rel_time < rel_type::zero()) 262   18 if (rel_time < rel_type::zero())
HITCBC 207   2 rel_time = rel_type::zero(); 263   2 rel_time = rel_type::zero();
HITCBC 208   16 else if (rel_time > std::chrono::seconds(1)) 264   16 else if (rel_time > std::chrono::seconds(1))
HITCBC 209   8 rel_time = std::chrono::seconds(1); 265   8 rel_time = std::chrono::seconds(1);
210   266  
HITCBC 211   36 std::size_t s = sched().wait_one( 267   36 std::size_t s = sched().wait_one(
212   static_cast<long>( 268   static_cast<long>(
HITCBC 213   18 std::chrono::duration_cast<std::chrono::microseconds>( 269   18 std::chrono::duration_cast<std::chrono::microseconds>(
214   rel_time) 270   rel_time)
HITCBC 215   18 .count())); 271   18 .count()));
216   272  
HITCBC 217   18 if (s || stopped()) 273   18 if (s || stopped())
HITCBC 218   12 return s; 274   12 return s;
219   275  
HITCBC 220   6 now = Clock::now(); 276   6 now = Clock::now();
HITCBC 221   6 if (now >= abs_time) 277   6 if (now >= abs_time)
HITCBC 222   2 return 0; 278   2 return 0;
223   } 279   }
HITCBC 224   14 } 280   14 }
225   281  
226   /** Process all ready work items without blocking. 282   /** Process all ready work items without blocking.
227   283  
  284 + @throws std::system_error if waiting on the operating system's
  285 + event demultiplexer fails other than by interruption or
  286 + another transient condition; the context can no longer
  287 + dispatch work. On Windows, also if a wakeup needed to
  288 + stop the context cannot be queued.
  289 +
228   @return The number of handlers executed. 290   @return The number of handlers executed.
229   */ 291   */
HITCBC 230   4 std::size_t poll() 292   12 std::size_t poll()
231   { 293   {
HITCBC 232   4 frame_allocator_restore restore; 294   12 frame_allocator_restore restore;
HITCBC 233   8 return sched().poll(); 295   24 return sched().poll();
HITCBC 234   4 } 296   12 }
235   297  
236   /** Process at most one ready work item without blocking. 298   /** Process at most one ready work item without blocking.
  299 +
  300 + @throws std::system_error if waiting on the operating system's
  301 + event demultiplexer fails other than by interruption or
  302 + another transient condition; the context can no longer
  303 + dispatch work. On Windows, also if a wakeup needed to
  304 + stop the context cannot be queued.
237   305  
238   @return The number of handlers executed (0 or 1). 306   @return The number of handlers executed (0 or 1).
239   */ 307   */
HITCBC 240   2 std::size_t poll_one() 308   2 std::size_t poll_one()
241   { 309   {
HITCBC 242   2 frame_allocator_restore restore; 310   2 frame_allocator_restore restore;
HITCBC 243   4 return sched().poll_one(); 311   4 return sched().poll_one();
HITCBC 244   2 } 312   2 }
245   }; 313   };
246   314  
247   } // namespace boost::corosio 315   } // namespace boost::corosio
248   316  
249   #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP 317   #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP