include/boost/corosio/io/io_signal_set.hpp

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