include/boost/corosio/native/native_signal_set.hpp

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