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