100.00% Lines (10/10) 100.00% Functions (4/4)
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_SIGNAL_SET_HPP 11   #ifndef BOOST_COROSIO_NATIVE_NATIVE_SIGNAL_SET_HPP
12   #define BOOST_COROSIO_NATIVE_NATIVE_SIGNAL_SET_HPP 12   #define BOOST_COROSIO_NATIVE_NATIVE_SIGNAL_SET_HPP
13   13  
14   #include <boost/corosio/signal_set.hpp> 14   #include <boost/corosio/signal_set.hpp>
15   #include <boost/corosio/backend.hpp> 15   #include <boost/corosio/backend.hpp>
16   #include <boost/corosio/detail/op_base.hpp> 16   #include <boost/corosio/detail/op_base.hpp>
17   17  
18   #ifndef BOOST_COROSIO_MRDOCS 18   #ifndef BOOST_COROSIO_MRDOCS
19   #if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_SELECT || \ 19   #if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_SELECT || \
20   BOOST_COROSIO_HAS_KQUEUE 20   BOOST_COROSIO_HAS_KQUEUE
21   #include <boost/corosio/native/detail/posix/posix_signal_service.hpp> 21   #include <boost/corosio/native/detail/posix/posix_signal_service.hpp>
22   #endif 22   #endif
23   23  
24   #if BOOST_COROSIO_HAS_IOCP 24   #if BOOST_COROSIO_HAS_IOCP
25   #include <boost/corosio/native/detail/iocp/win_signals.hpp> 25   #include <boost/corosio/native/detail/iocp/win_signals.hpp>
26   #endif 26   #endif
27   #endif // !BOOST_COROSIO_MRDOCS 27   #endif // !BOOST_COROSIO_MRDOCS
28   28  
29   namespace boost::corosio { 29   namespace boost::corosio {
30   30  
31   /** Waits for a registered signal, calling the backend directly. 31   /** Waits for a registered signal, calling the backend directly.
32   32  
33   This class template inherits from @ref signal_set. It shadows the 33   This class template inherits from @ref signal_set. It shadows the
34   `wait` operation with a version that calls the backend 34   `wait` operation with a version that calls the backend
35   implementation directly. The compiler can then inline through the 35   implementation directly. The compiler can then inline through the
36   entire call chain. 36   entire call chain.
37   37  
38   Non-async operations (`add`, `remove`, `clear`, `cancel`) 38   Non-async operations (`add`, `remove`, `clear`, `cancel`)
39   remain unchanged and dispatch through the compiled library. 39   remain unchanged and dispatch through the compiled library.
40   40  
41   A `native_signal_set` IS-A `signal_set` and can be passed to 41   A `native_signal_set` IS-A `signal_set` and can be passed to
42   any function expecting `signal_set&`. 42   any function expecting `signal_set&`.
43   43  
44   @tparam Backend A backend tag value (e.g., `epoll`). 44   @tparam Backend A backend tag value (e.g., `epoll`).
45   45  
46   @par Thread Safety 46   @par Thread Safety
47   Same as @ref signal_set. 47   Same as @ref signal_set.
48   48  
49   @see @ref signal_set, @ref epoll_t, @ref iocp_t 49   @see @ref signal_set, @ref epoll_t, @ref iocp_t
50   */ 50   */
51   template<auto Backend> 51   template<auto Backend>
52   class native_signal_set : public signal_set 52   class native_signal_set : public signal_set
53   { 53   {
54   using backend_type = decltype(Backend); 54   using backend_type = decltype(Backend);
55   using impl_type = typename backend_type::signal_type; 55   using impl_type = typename backend_type::signal_type;
56   56  
57   impl_type& get_impl() noexcept 57   impl_type& get_impl() noexcept
58   { 58   {
59   return *static_cast<impl_type*>(h_.get()); 59   return *static_cast<impl_type*>(h_.get());
60   } 60   }
61   61  
62   struct native_wait_awaitable 62   struct native_wait_awaitable
63   : detail::value_op_base<native_wait_awaitable, int> 63   : detail::value_op_base<native_wait_awaitable, int>
64   { 64   {
65   native_signal_set& self_; 65   native_signal_set& self_;
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   std::coroutine_handle<> 72   std::coroutine_handle<>
73   dispatch(capy::continuation& cont, capy::executor_ref ex) const 73   dispatch(capy::continuation& cont, capy::executor_ref ex) const
74   { 74   {
75   return self_.get_impl().wait( 75   return self_.get_impl().wait(
76   cont, ex, this->token_, &this->ec_, &this->value_); 76   cont, ex, this->token_, &this->ec_, &this->value_);
77   } 77   }
78   }; 78   };
79   79  
80   public: 80   public:
81   /** Construct a native signal set from an execution context. 81   /** Construct a native signal set from an execution context.
82   82  
83   @param ctx The execution context that owns this signal set. 83   @param ctx The execution context that owns this signal set.
84   */ 84   */
HITCBC 85   4 explicit native_signal_set(capy::execution_context& ctx) : signal_set(ctx) 85   4 explicit native_signal_set(capy::execution_context& ctx) : signal_set(ctx)
86   { 86   {
HITCBC 87   4 } 87   4 }
88   88  
89   /** Construct a native signal set with initial signals. 89   /** Construct a native signal set with initial signals.
90   90  
91   For the non-throwing form, construct with the context alone, 91   For the non-throwing form, construct with the context alone,
92   then call @ref signal_set::add for each signal. 92   then call @ref signal_set::add for each signal.
93   93  
94   @param ctx The execution context that owns this signal set. 94   @param ctx The execution context that owns this signal set.
95   @param signal First signal number to add. 95   @param signal First signal number to add.
96   @param signals Additional signal numbers to add. 96   @param signals Additional signal numbers to add.
97   97  
98   @throws std::system_error on failure. 98   @throws std::system_error on failure.
99   99  
100   @see @ref signal_set::add 100   @see @ref signal_set::add
101   */ 101   */
102   template<std::convertible_to<int>... Signals> 102   template<std::convertible_to<int>... Signals>
HITCBC 103   6 native_signal_set( 103   6 native_signal_set(
104   capy::execution_context& ctx, int signal, Signals... signals) 104   capy::execution_context& ctx, int signal, Signals... signals)
HITCBC 105   6 : signal_set(ctx, signal, signals...) 105   6 : signal_set(ctx, signal, signals...)
106   { 106   {
HITCBC 107   6 } 107   6 }
108   108  
109   /** Construct a native signal set from an executor. 109   /** Construct a native signal set from an executor.
110   110  
111   @param ex The executor whose context owns the signal set. 111   @param ex The executor whose context owns the signal set.
112   112  
113   @tparam Ex A type satisfying @ref capy::Executor. Must not 113   @tparam Ex A type satisfying @ref capy::Executor. Must not
114   be `native_signal_set` itself (disables implicit 114   be `native_signal_set` itself (disables implicit
115   conversion from move). 115   conversion from move).
116   */ 116   */
117   template<class Ex> 117   template<class Ex>
118   requires(!std::same_as<std::remove_cvref_t<Ex>, native_signal_set>) && 118   requires(!std::same_as<std::remove_cvref_t<Ex>, native_signal_set>) &&
119   capy::Executor<Ex> 119   capy::Executor<Ex>
HITCBC 120   2 explicit native_signal_set(Ex const& ex) : native_signal_set(ex.context()) 120   2 explicit native_signal_set(Ex const& ex) : native_signal_set(ex.context())
121   { 121   {
HITCBC 122   2 } 122   2 }
123   123  
124   /** Construct a native signal set from an executor with initial signals. 124   /** Construct a native signal set from an executor with initial signals.
125   125  
126   For the non-throwing form, construct with the executor alone, 126   For the non-throwing form, construct with the executor alone,
127   then call @ref signal_set::add for each signal. 127   then call @ref signal_set::add for each signal.
128   128  
129   @param ex The executor whose context owns the signal set. 129   @param ex The executor whose context owns the signal set.
130   @param signal First signal number to add. 130   @param signal First signal number to add.
131   @param signals Additional signal numbers to add. 131   @param signals Additional signal numbers to add.
132   132  
133   @tparam Ex A type satisfying @ref capy::Executor. 133   @tparam Ex A type satisfying @ref capy::Executor.
134   134  
135   @throws std::system_error on failure. 135   @throws std::system_error on failure.
136   136  
137   @see @ref signal_set::add 137   @see @ref signal_set::add
138   */ 138   */
139   template<class Ex, std::convertible_to<int>... Signals> 139   template<class Ex, std::convertible_to<int>... Signals>
140   requires capy::Executor<Ex> 140   requires capy::Executor<Ex>
HITCBC 141   2 native_signal_set(Ex const& ex, int signal, Signals... signals) 141   2 native_signal_set(Ex const& ex, int signal, Signals... signals)
HITCBC 142   2 : native_signal_set(ex.context(), signal, signals...) 142   2 : native_signal_set(ex.context(), signal, signals...)
143   { 143   {
HITCBC 144   2 } 144   2 }
145   145  
146   /** Move construct. 146   /** Move construct.
147   147  
148   @pre No awaitables returned by the source's methods exist. 148   @pre No awaitables returned by the source's methods exist.
149   @pre The execution context associated with the source must 149   @pre The execution context associated with the source must
150   outlive this signal set. 150   outlive this signal set.
151   */ 151   */
152   native_signal_set(native_signal_set&&) noexcept = default; 152   native_signal_set(native_signal_set&&) noexcept = default;
153   153  
154   /** Move assign. 154   /** Move assign.
155   155  
156   @pre No awaitables returned by either `*this` or the source's 156   @pre No awaitables returned by either `*this` or the source's
157   methods exist. 157   methods exist.
158   @pre The execution context associated with the source must 158   @pre The execution context associated with the source must
159   outlive this signal set. 159   outlive this signal set.
160   */ 160   */
161   native_signal_set& operator=(native_signal_set&&) noexcept = default; 161   native_signal_set& operator=(native_signal_set&&) noexcept = default;
162   162  
163   /// Copy construction is disabled; the handle is uniquely owned. 163   /// Copy construction is disabled; the handle is uniquely owned.
164   native_signal_set(native_signal_set const&) = delete; 164   native_signal_set(native_signal_set const&) = delete;
165   /// Copy assignment is disabled; the handle is uniquely owned. 165   /// Copy assignment is disabled; the handle is uniquely owned.
166   native_signal_set& operator=(native_signal_set const&) = delete; 166   native_signal_set& operator=(native_signal_set const&) = delete;
167   167  
168   /** Wait for a signal to be delivered. 168   /** Wait for a signal to be delivered.
169   169  
170   Calls the backend implementation directly, bypassing virtual 170   Calls the backend implementation directly, bypassing virtual
171   dispatch. Otherwise identical to @ref signal_set::wait. 171   dispatch. Otherwise identical to @ref signal_set::wait.
172   172  
173   @return An awaitable yielding `results<int>`. 173   @return An awaitable yielding `results<int>`.
174   174  
175   This signal set must outlive the returned awaitable. 175   This signal set must outlive the returned awaitable.
176   */ 176   */
177   [[nodiscard]] auto wait() 177   [[nodiscard]] auto wait()
178   { 178   {
179   return native_wait_awaitable(*this); 179   return native_wait_awaitable(*this);
180   } 180   }
181   }; 181   };
182   182  
183   } // namespace boost::corosio 183   } // namespace boost::corosio
184   184  
185   #endif 185   #endif