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