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 : 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 : template<std::convertible_to<int>... Signals>
111 4 : native_signal_set(
112 : capy::execution_context& ctx, int signal, Signals... signals)
113 4 : : signal_set(ctx, signal, signals...)
114 : {
115 4 : }
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
|