TLA Line data 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 : [[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 : {
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 HIT 2 : explicit native_signal_set(capy::execution_context& ctx) : signal_set(ctx)
99 : {
100 2 : }
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 : @see add for the non-throwing form: construct with the
111 : context alone, then `add()` each signal.
112 : */
113 : template<std::convertible_to<int>... Signals>
114 4 : native_signal_set(
115 : capy::execution_context& ctx, int signal, Signals... signals)
116 4 : : signal_set(ctx, signal, signals...)
117 : {
118 4 : }
119 :
120 : /** Move construct.
121 :
122 : @param other The signal set to move from.
123 :
124 : @pre No awaitables returned by @p other's methods exist.
125 : @pre The execution context associated with @p other must
126 : outlive this signal set.
127 : */
128 : native_signal_set(native_signal_set&&) noexcept = default;
129 :
130 : /** Move assign.
131 :
132 : @param other The signal set to move from.
133 :
134 : @pre No awaitables returned by either `*this` or @p other's
135 : methods exist.
136 : @pre The execution context associated with @p other must
137 : outlive this signal set.
138 : */
139 : native_signal_set& operator=(native_signal_set&&) noexcept = default;
140 :
141 : native_signal_set(native_signal_set const&) = delete;
142 : native_signal_set& operator=(native_signal_set const&) = delete;
143 :
144 : /** Wait for a signal to be delivered.
145 :
146 : Calls the backend implementation directly, bypassing virtual
147 : dispatch. Otherwise identical to @ref signal_set::wait.
148 :
149 : @return An awaitable yielding `io_result<int>`.
150 :
151 : This signal set must outlive the returned awaitable.
152 : */
153 : [[nodiscard]] auto wait()
154 : {
155 : return native_wait_awaitable(*this);
156 : }
157 : };
158 :
159 : } // namespace boost::corosio
160 :
161 : #endif
|