include/boost/corosio/io/io_signal_set.hpp

95.2% Lines (20/21) 100.0% Functions (9/9)
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_IO_IO_SIGNAL_SET_HPP
11 #define BOOST_COROSIO_IO_IO_SIGNAL_SET_HPP
12
13 #include <boost/corosio/detail/config.hpp>
14 #include <boost/corosio/io/io_object.hpp>
15 #include <boost/capy/io_result.hpp>
16 #include <boost/capy/error.hpp>
17 #include <boost/capy/ex/executor_ref.hpp>
18 #include <boost/capy/ex/io_env.hpp>
19
20 #include <coroutine>
21 #include <stop_token>
22 #include <system_error>
23
24 namespace boost::corosio {
25
26 /** Abstract base for asynchronous signal sets.
27
28 Provides the common signal set interface: `wait` and `cancel`.
29 Concrete classes like @ref signal_set add signal registration
30 (add, remove, clear) and platform-specific flags.
31
32 @par Thread Safety
33 Distinct objects: Safe.
34 Shared objects: Unsafe.
35
36 @see signal_set, io_object
37 */
38 class BOOST_COROSIO_DECL io_signal_set : public io_object
39 {
40 struct wait_awaitable
41 {
42 io_signal_set& s_;
43 std::stop_token token_;
44 mutable std::error_code ec_;
45 mutable int signal_number_ = 0;
46
47 26x explicit wait_awaitable(io_signal_set& s) noexcept : s_(s) {}
48
49 26x bool await_ready() const noexcept
50 {
51 26x return token_.stop_requested();
52 }
53
54 26x capy::io_result<int> await_resume() const noexcept
55 {
56 26x if (token_.stop_requested())
57 return {capy::error::canceled};
58 26x return {ec_, signal_number_};
59 }
60
61 26x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
62 -> std::coroutine_handle<>
63 {
64 26x token_ = env->stop_token;
65 78x return s_.get().wait(
66 78x h, env->executor, token_, &ec_, &signal_number_);
67 }
68 };
69
70 public:
71 /** Define backend hooks for signal set wait and cancel.
72
73 Platform backends derive from this to implement
74 signal delivery notification.
75 */
76 struct implementation : io_object::implementation
77 {
78 /** Initiate an asynchronous wait for a signal.
79
80 @param h Coroutine handle to resume on completion.
81 @param ex Executor for dispatching the completion.
82 @param token Stop token for cancellation.
83 @param ec Output error code.
84 @param signo Output signal number.
85
86 @return Coroutine handle to resume immediately.
87 */
88 virtual std::coroutine_handle<> wait(
89 std::coroutine_handle<> h,
90 capy::executor_ref ex,
91 std::stop_token token,
92 std::error_code* ec,
93 int* signo) = 0;
94
95 /** Cancel all pending wait operations.
96
97 Cancelled waiters complete with an error that
98 compares equal to `capy::cond::canceled`.
99 */
100 virtual void cancel() = 0;
101 };
102
103 /** Cancel all operations associated with the signal set.
104
105 Forces the completion of any pending asynchronous wait
106 operations. Each cancelled operation completes with an error
107 code that compares equal to `capy::cond::canceled`.
108
109 Cancellation does not alter the set of registered signals.
110 */
111 12x void cancel()
112 {
113 12x do_cancel();
114 12x }
115
116 /** Wait for a signal to be delivered.
117
118 The operation supports cancellation via `std::stop_token` through
119 the affine awaitable protocol. If the associated stop token is
120 triggered, the operation completes immediately with an error
121 that compares equal to `capy::cond::canceled`.
122
123 This signal set must outlive the returned awaitable.
124
125 @return An awaitable that completes with `io_result<int>`.
126 Returns the signal number when a signal is delivered,
127 or an error code on failure.
128 */
129 26x auto wait()
130 {
131 26x return wait_awaitable(*this);
132 }
133
134 protected:
135 /** Dispatch cancel to the concrete implementation. */
136 virtual void do_cancel() = 0;
137
138 88x explicit io_signal_set(handle h) noexcept : io_object(std::move(h)) {}
139
140 /// Move construct.
141 2x io_signal_set(io_signal_set&& other) noexcept : io_object(std::move(other))
142 {
143 2x }
144
145 /// Move assign.
146 io_signal_set& operator=(io_signal_set&& other) noexcept
147 {
148 if (this != &other)
149 h_ = std::move(other.h_);
150 return *this;
151 }
152
153 io_signal_set(io_signal_set const&) = delete;
154 io_signal_set& operator=(io_signal_set const&) = delete;
155
156 private:
157 26x implementation& get() const noexcept
158 {
159 26x return *static_cast<implementation*>(h_.get());
160 }
161 };
162
163 } // namespace boost::corosio
164
165 #endif
166