include/boost/corosio/native/native_signal_set.hpp

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