100.00% Lines (5/5) 100.00% Functions (2/2)
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_SIGNAL_SET_HPP 10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_SIGNAL_SET_HPP
11   #define BOOST_COROSIO_NATIVE_NATIVE_SIGNAL_SET_HPP 11   #define BOOST_COROSIO_NATIVE_NATIVE_SIGNAL_SET_HPP
12   12  
13   #include <boost/corosio/signal_set.hpp> 13   #include <boost/corosio/signal_set.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 || BOOST_COROSIO_HAS_SELECT || \ 17   #if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_SELECT || \
18   BOOST_COROSIO_HAS_KQUEUE 18   BOOST_COROSIO_HAS_KQUEUE
19   #include <boost/corosio/native/detail/posix/posix_signal_service.hpp> 19   #include <boost/corosio/native/detail/posix/posix_signal_service.hpp>
20   #endif 20   #endif
21   21  
22   #if BOOST_COROSIO_HAS_IOCP 22   #if BOOST_COROSIO_HAS_IOCP
23   #include <boost/corosio/native/detail/iocp/win_signals.hpp> 23   #include <boost/corosio/native/detail/iocp/win_signals.hpp>
24   #endif 24   #endif
25   #endif // !BOOST_COROSIO_MRDOCS 25   #endif // !BOOST_COROSIO_MRDOCS
26   26  
27   namespace boost::corosio { 27   namespace boost::corosio {
28   28  
29   /** An asynchronous signal set with devirtualized wait operations. 29   /** An asynchronous signal set with devirtualized wait operations.
30   30  
31   This class template inherits from @ref signal_set and shadows 31   This class template inherits from @ref signal_set and shadows
32   the `wait` operation with a version that calls the backend 32   the `wait` operation with a version that calls the backend
33   implementation directly, allowing the compiler to inline 33   implementation directly, allowing the compiler to inline
34   through the entire call chain. 34   through the entire call chain.
35   35  
36   Non-async operations (`add`, `remove`, `clear`, `cancel`) 36   Non-async operations (`add`, `remove`, `clear`, `cancel`)
37   remain unchanged and dispatch through the compiled library. 37   remain unchanged and dispatch through the compiled library.
38   38  
39   A `native_signal_set` IS-A `signal_set` and can be passed to 39   A `native_signal_set` IS-A `signal_set` and can be passed to
40   any function expecting `signal_set&`. 40   any function expecting `signal_set&`.
41   41  
42   @tparam Backend A backend tag value (e.g., `epoll`). 42   @tparam Backend A backend tag value (e.g., `epoll`).
43   43  
44   @par Thread Safety 44   @par Thread Safety
45   Same as @ref signal_set. 45   Same as @ref signal_set.
46   46  
47   @see signal_set, epoll_t, iocp_t 47   @see signal_set, epoll_t, iocp_t
48   */ 48   */
49   template<auto Backend> 49   template<auto Backend>
50   class native_signal_set : public signal_set 50   class native_signal_set : public signal_set
51   { 51   {
52   using backend_type = decltype(Backend); 52   using backend_type = decltype(Backend);
53   using impl_type = typename backend_type::signal_type; 53   using impl_type = typename backend_type::signal_type;
54   54  
55   impl_type& get_impl() noexcept 55   impl_type& get_impl() noexcept
56   { 56   {
57   return *static_cast<impl_type*>(h_.get()); 57   return *static_cast<impl_type*>(h_.get());
58   } 58   }
59   59  
60   struct native_wait_awaitable 60   struct native_wait_awaitable
61   { 61   {
62   native_signal_set& self_; 62   native_signal_set& self_;
63   std::stop_token token_; 63   std::stop_token token_;
64   mutable std::error_code ec_; 64   mutable std::error_code ec_;
65   mutable int signal_number_ = 0; 65   mutable int signal_number_ = 0;
66   66  
67   explicit native_wait_awaitable(native_signal_set& self) noexcept 67   explicit native_wait_awaitable(native_signal_set& self) noexcept
68   : self_(self) 68   : self_(self)
69   { 69   {
70   } 70   }
71   71  
72   bool await_ready() const noexcept 72   bool await_ready() const noexcept
73   { 73   {
74   return token_.stop_requested(); 74   return token_.stop_requested();
75   } 75   }
76   76  
77   capy::io_result<int> await_resume() const noexcept 77   capy::io_result<int> await_resume() const noexcept
78   { 78   {
79   if (token_.stop_requested()) 79   if (token_.stop_requested())
80   return {capy::error::canceled, 0}; 80   return {capy::error::canceled, 0};
81   return {ec_, signal_number_}; 81   return {ec_, signal_number_};
82   } 82   }
83   83  
84   auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 84   auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
85   -> std::coroutine_handle<> 85   -> std::coroutine_handle<>
86   { 86   {
87   token_ = env->stop_token; 87   token_ = env->stop_token;
88   return self_.get_impl().wait( 88   return self_.get_impl().wait(
89   h, env->executor, token_, &ec_, &signal_number_); 89   h, env->executor, token_, &ec_, &signal_number_);
90   } 90   }
91   }; 91   };
92   92  
93   public: 93   public:
94   /** Construct a native signal set from an execution context. 94   /** Construct a native signal set from an execution context.
95   95  
96   @param ctx The execution context that will own this signal set. 96   @param ctx The execution context that will own this signal set.
97   */ 97   */
HITGIC 98   explicit native_signal_set(capy::execution_context& ctx) : signal_set(ctx) 98   2 explicit native_signal_set(capy::execution_context& ctx) : signal_set(ctx)
99   { 99   {
HITGIC 100   } 100   2 }
101   101  
102   /** Construct a native signal set with initial signals. 102   /** Construct a native signal set with initial signals.
103   103  
104   @param ctx The execution context that will own this signal set. 104   @param ctx The execution context that will own this signal set.
105   @param signal First signal number to add. 105   @param signal First signal number to add.
106   @param signals Additional signal numbers to add. 106   @param signals Additional signal numbers to add.
107   107  
108   @throws std::system_error on failure. 108   @throws std::system_error on failure.
109   */ 109   */
110   template<std::convertible_to<int>... Signals> 110   template<std::convertible_to<int>... Signals>
HITGIC 111   native_signal_set( 111   4 native_signal_set(
112   capy::execution_context& ctx, int signal, Signals... signals) 112   capy::execution_context& ctx, int signal, Signals... signals)
HITGIC 113   : signal_set(ctx, signal, signals...) 113   4 : signal_set(ctx, signal, signals...)
114   { 114   {
HITGIC 115   } 115   4 }
116   116  
117   /** Move construct. 117   /** Move construct.
118   118  
119   @param other The signal set to move from. 119   @param other The signal set to move from.
120   120  
121   @pre No awaitables returned by @p other's methods exist. 121   @pre No awaitables returned by @p other's methods exist.
122   @pre The execution context associated with @p other must 122   @pre The execution context associated with @p other must
123   outlive this signal set. 123   outlive this signal set.
124   */ 124   */
125   native_signal_set(native_signal_set&&) noexcept = default; 125   native_signal_set(native_signal_set&&) noexcept = default;
126   126  
127   /** Move assign. 127   /** Move assign.
128   128  
129   @param other The signal set to move from. 129   @param other The signal set to move from.
130   130  
131   @pre No awaitables returned by either `*this` or @p other's 131   @pre No awaitables returned by either `*this` or @p other's
132   methods exist. 132   methods exist.
133   @pre The execution context associated with @p other must 133   @pre The execution context associated with @p other must
134   outlive this signal set. 134   outlive this signal set.
135   */ 135   */
136   native_signal_set& operator=(native_signal_set&&) noexcept = default; 136   native_signal_set& operator=(native_signal_set&&) noexcept = default;
137   137  
138   native_signal_set(native_signal_set const&) = delete; 138   native_signal_set(native_signal_set const&) = delete;
139   native_signal_set& operator=(native_signal_set const&) = delete; 139   native_signal_set& operator=(native_signal_set const&) = delete;
140   140  
141   /** Wait for a signal to be delivered. 141   /** Wait for a signal to be delivered.
142   142  
143   Calls the backend implementation directly, bypassing virtual 143   Calls the backend implementation directly, bypassing virtual
144   dispatch. Otherwise identical to @ref signal_set::wait. 144   dispatch. Otherwise identical to @ref signal_set::wait.
145   145  
146   @return An awaitable yielding `io_result<int>`. 146   @return An awaitable yielding `io_result<int>`.
147   147  
148   This signal set must outlive the returned awaitable. 148   This signal set must outlive the returned awaitable.
149   */ 149   */
150   auto wait() 150   auto wait()
151   { 151   {
152   return native_wait_awaitable(*this); 152   return native_wait_awaitable(*this);
153   } 153   }
154   }; 154   };
155   155  
156   } // namespace boost::corosio 156   } // namespace boost::corosio
157   157  
158   #endif 158   #endif