100.00% Lines (42/42) 100.00% Functions (12/12)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Steve Gerbino 2   // Copyright (c) 2026 Steve Gerbino
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/corosio 7   // Official repository: https://github.com/cppalliance/corosio
8   // 8   //
9   9  
10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP 10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
11   #define BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP 11   #define BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
12   12  
13   #include <boost/corosio/io_context.hpp> 13   #include <boost/corosio/io_context.hpp>
14   #include <boost/corosio/backend.hpp> 14   #include <boost/corosio/backend.hpp>
15   15  
16   #ifndef BOOST_COROSIO_MRDOCS 16   #ifndef BOOST_COROSIO_MRDOCS
17   #if BOOST_COROSIO_HAS_EPOLL 17   #if BOOST_COROSIO_HAS_EPOLL
18   #include <boost/corosio/native/detail/epoll/epoll_scheduler.hpp> 18   #include <boost/corosio/native/detail/epoll/epoll_scheduler.hpp>
19   #endif 19   #endif
20   20  
21   #if BOOST_COROSIO_HAS_SELECT 21   #if BOOST_COROSIO_HAS_SELECT
22   #include <boost/corosio/native/detail/select/select_scheduler.hpp> 22   #include <boost/corosio/native/detail/select/select_scheduler.hpp>
23   #endif 23   #endif
24   24  
25   #if BOOST_COROSIO_HAS_KQUEUE 25   #if BOOST_COROSIO_HAS_KQUEUE
26   #include <boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp> 26   #include <boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp>
27   #endif 27   #endif
28   28  
29   #if BOOST_COROSIO_HAS_IOCP 29   #if BOOST_COROSIO_HAS_IOCP
30   #include <boost/corosio/native/detail/iocp/win_scheduler.hpp> 30   #include <boost/corosio/native/detail/iocp/win_scheduler.hpp>
31   #endif 31   #endif
32   #endif // !BOOST_COROSIO_MRDOCS 32   #endif // !BOOST_COROSIO_MRDOCS
33   33  
34   namespace boost::corosio { 34   namespace boost::corosio {
35   35  
36   /** An I/O context with devirtualized event loop methods. 36   /** An I/O context with devirtualized event loop methods.
37   37  
38   This class template inherits from @ref io_context and shadows 38   This class template inherits from @ref io_context and shadows
39   all public methods with versions that call the concrete 39   all public methods with versions that call the concrete
40   scheduler directly, bypassing virtual dispatch. No new state 40   scheduler directly, bypassing virtual dispatch. No new state
41   is added. 41   is added.
42   42  
43   A `native_io_context` IS-A `io_context` and can be passed 43   A `native_io_context` IS-A `io_context` and can be passed
44   anywhere an `io_context&` is accepted, in which case virtual 44   anywhere an `io_context&` is accepted, in which case virtual
45   dispatch is used transparently. 45   dispatch is used transparently.
46   46  
47   @tparam Backend A backend tag value (e.g., `epoll`, 47   @tparam Backend A backend tag value (e.g., `epoll`,
48   `iocp`) whose type provides `scheduler_type`. 48   `iocp`) whose type provides `scheduler_type`.
49   49  
50   @par Thread Safety 50   @par Thread Safety
51   Same as the underlying context type. 51   Same as the underlying context type.
52   52  
53   @par Example 53   @par Example
54   @code 54   @code
55   #include <boost/corosio/native/native_io_context.hpp> 55   #include <boost/corosio/native/native_io_context.hpp>
56   56  
57   native_io_context<epoll> ctx; 57   native_io_context<epoll> ctx;
58   ctx.poll(); // devirtualized call 58   ctx.poll(); // devirtualized call
59   @endcode 59   @endcode
60   60  
61   @see io_context, epoll_t, iocp_t 61   @see io_context, epoll_t, 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  
HITGIC 69   scheduler_type& sched() noexcept 69   36 scheduler_type& sched() noexcept
70   { 70   {
HITGIC 71   return *static_cast<scheduler_type*>(this->sched_); 71   36 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. */
HITGIC 76   native_io_context() : io_context(Backend) {} 76   16 native_io_context() : io_context(Backend) {}
77   77  
78   /** Construct with a concurrency hint. 78   /** Construct with a concurrency hint.
79   79  
80   @param concurrency_hint Hint for the number of threads that 80   @param concurrency_hint Hint for the number of threads that
81   will call `run()`. 81   will call `run()`.
82   */ 82   */
HITGIC 83   explicit native_io_context(unsigned concurrency_hint) 83   2 explicit native_io_context(unsigned concurrency_hint)
HITGIC 84   : io_context(Backend, concurrency_hint) 84   2 : io_context(Backend, concurrency_hint)
85   { 85   {
HITGIC 86   } 86   2 }
87   87  
88   /** Construct with runtime tuning options. 88   /** Construct with runtime tuning options.
89   89  
90   @param opts Runtime options controlling scheduler and 90   @param opts Runtime options controlling scheduler and
91   service behavior. 91   service behavior.
92   @param concurrency_hint Hint for the number of threads that 92   @param concurrency_hint Hint for the number of threads that
93   will call `run()`. 93   will call `run()`.
94   */ 94   */
HITGIC 95   explicit native_io_context( 95   2 explicit native_io_context(
96   io_context_options const& opts, 96   io_context_options const& opts,
97   unsigned concurrency_hint = std::thread::hardware_concurrency()) 97   unsigned concurrency_hint = std::thread::hardware_concurrency())
HITGIC 98   : io_context(Backend, opts, concurrency_hint) 98   2 : io_context(Backend, opts, concurrency_hint)
99   { 99   {
HITGIC 100   } 100   2 }
101   101  
102   // Non-copyable, non-movable 102   // Non-copyable, non-movable
103   native_io_context(native_io_context const&) = delete; 103   native_io_context(native_io_context const&) = delete;
104   native_io_context& operator=(native_io_context const&) = delete; 104   native_io_context& operator=(native_io_context const&) = delete;
105   105  
106   /// Signal the context to stop processing. 106   /// Signal the context to stop processing.
HITGIC 107   void stop() 107   2 void stop()
108   { 108   {
HITGIC 109   sched().stop(); 109   2 sched().stop();
HITGIC 110   } 110   2 }
111   111  
112   /// Return whether the context has been stopped. 112   /// Return whether the context has been stopped.
HITGIC 113   bool stopped() const noexcept 113   18 bool stopped() const noexcept
114   { 114   {
HITGIC 115   return const_cast<native_io_context*>(this)->sched().stopped(); 115   18 return const_cast<native_io_context*>(this)->sched().stopped();
116   } 116   }
117   117  
118   /// Restart the context after being stopped. 118   /// Restart the context after being stopped.
HITGIC 119   void restart() 119   2 void restart()
120   { 120   {
HITGIC 121   sched().restart(); 121   2 sched().restart();
HITGIC 122   } 122   2 }
123   123  
124   /** Process all pending work items. 124   /** Process all pending work items.
125   125  
126   @return The number of handlers executed. 126   @return The number of handlers executed.
127   */ 127   */
HITGIC 128   std::size_t run() 128   2 std::size_t run()
129   { 129   {
HITGIC 130   return sched().run(); 130   2 return sched().run();
131   } 131   }
132   132  
133   /** Process at most one pending work item. 133   /** Process at most one pending work item.
134   134  
135   @return The number of handlers executed (0 or 1). 135   @return The number of handlers executed (0 or 1).
136   */ 136   */
137   std::size_t run_one() 137   std::size_t run_one()
138   { 138   {
139   return sched().run_one(); 139   return sched().run_one();
140   } 140   }
141   141  
142   /** Process work items for the specified duration. 142   /** Process work items for the specified duration.
143   143  
144   @param rel_time The duration for which to process work. 144   @param rel_time The duration for which to process work.
145   145  
146   @return The number of handlers executed. 146   @return The number of handlers executed.
147   */ 147   */
148   template<class Rep, class Period> 148   template<class Rep, class Period>
HITGIC 149   std::size_t run_for(std::chrono::duration<Rep, Period> const& rel_time) 149   4 std::size_t run_for(std::chrono::duration<Rep, Period> const& rel_time)
150   { 150   {
HITGIC 151   return run_until(std::chrono::steady_clock::now() + rel_time); 151   4 return run_until(std::chrono::steady_clock::now() + rel_time);
152   } 152   }
153   153  
154   /** Process work items until the specified time. 154   /** Process work items until the specified time.
155   155  
156   @param abs_time The time point until which to process work. 156   @param abs_time The time point until which to process work.
157   157  
158   @return The number of handlers executed. 158   @return The number of handlers executed.
159   */ 159   */
160   template<class Clock, class Duration> 160   template<class Clock, class Duration>
161   std::size_t 161   std::size_t
HITGIC 162   run_until(std::chrono::time_point<Clock, Duration> const& abs_time) 162   4 run_until(std::chrono::time_point<Clock, Duration> const& abs_time)
163   { 163   {
HITGIC 164   std::size_t n = 0; 164   4 std::size_t n = 0;
HITGIC 165   while (run_one_until(abs_time)) 165   6 while (run_one_until(abs_time))
HITGIC 166   if (n != (std::numeric_limits<std::size_t>::max)()) 166   2 if (n != (std::numeric_limits<std::size_t>::max)())
HITGIC 167   ++n; 167   2 ++n;
HITGIC 168   return n; 168   4 return n;
169   } 169   }
170   170  
171   /** Process at most one work item for the specified duration. 171   /** Process at most one work item for the specified duration.
172   172  
173   @param rel_time The duration for which the call may block. 173   @param rel_time The duration for which the call may block.
174   174  
175   @return The number of handlers executed (0 or 1). 175   @return The number of handlers executed (0 or 1).
176   */ 176   */
177   template<class Rep, class Period> 177   template<class Rep, class Period>
178   std::size_t run_one_for(std::chrono::duration<Rep, Period> const& rel_time) 178   std::size_t run_one_for(std::chrono::duration<Rep, Period> const& rel_time)
179   { 179   {
180   return run_one_until(std::chrono::steady_clock::now() + rel_time); 180   return run_one_until(std::chrono::steady_clock::now() + rel_time);
181   } 181   }
182   182  
183   /** Process at most one work item until the specified time. 183   /** Process at most one work item until the specified time.
184   184  
185   @param abs_time The time point until which the call may block. 185   @param abs_time The time point until which the call may block.
186   186  
187   @return The number of handlers executed (0 or 1). 187   @return The number of handlers executed (0 or 1).
188   */ 188   */
189   template<class Clock, class Duration> 189   template<class Clock, class Duration>
190   std::size_t 190   std::size_t
HITGIC 191   run_one_until(std::chrono::time_point<Clock, Duration> const& abs_time) 191   8 run_one_until(std::chrono::time_point<Clock, Duration> const& abs_time)
192   { 192   {
HITGIC 193   typename Clock::time_point now = Clock::now(); 193   8 typename Clock::time_point now = Clock::now();
HITGIC 194   while (now < abs_time) 194   12 while (now < abs_time)
195   { 195   {
HITGIC 196   auto rel_time = abs_time - now; 196   10 auto rel_time = abs_time - now;
HITGIC 197   if (rel_time > std::chrono::seconds(1)) 197   10 if (rel_time > std::chrono::seconds(1))
HITGIC 198   rel_time = std::chrono::seconds(1); 198   2 rel_time = std::chrono::seconds(1);
199   199  
HITGIC 200   std::size_t s = sched().wait_one( 200   20 std::size_t s = sched().wait_one(
201   static_cast<long>( 201   static_cast<long>(
HITGIC 202   std::chrono::duration_cast<std::chrono::microseconds>( 202   10 std::chrono::duration_cast<std::chrono::microseconds>(
203   rel_time) 203   rel_time)
HITGIC 204   .count())); 204   10 .count()));
205   205  
HITGIC 206   if (s || stopped()) 206   10 if (s || stopped())
HITGIC 207   return s; 207   6 return s;
208   208  
HITGIC 209   now = Clock::now(); 209   4 now = Clock::now();
210   } 210   }
HITGIC 211   return 0; 211   2 return 0;
212   } 212   }
213   213  
214   /** Process all ready work items without blocking. 214   /** Process all ready work items without blocking.
215   215  
216   @return The number of handlers executed. 216   @return The number of handlers executed.
217   */ 217   */
HITGIC 218   std::size_t poll() 218   2 std::size_t poll()
219   { 219   {
HITGIC 220   return sched().poll(); 220   2 return sched().poll();
221   } 221   }
222   222  
223   /** Process at most one ready work item without blocking. 223   /** Process at most one ready work item without blocking.
224   224  
225   @return The number of handlers executed (0 or 1). 225   @return The number of handlers executed (0 or 1).
226   */ 226   */
227   std::size_t poll_one() 227   std::size_t poll_one()
228   { 228   {
229   return sched().poll_one(); 229   return sched().poll_one();
230   } 230   }
231   }; 231   };
232   232  
233   } // namespace boost::corosio 233   } // namespace boost::corosio
234   234  
235   #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP 235   #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP