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 /** Abstract base for asynchronous signal sets.
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 io_signal_set& s_;
44
45 1143x explicit wait_awaitable(io_signal_set& s) noexcept : s_(s) {}
46
47 std::coroutine_handle<>
48 1106x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
49 {
50 1106x return s_.get().wait(h, ex, token_, &ec_, &value_);
51 }
52 };
53
54 public:
55 /** Define backend hooks for signal set wait and cancel.
56
57 Platform backends derive from this to implement
58 signal delivery notification.
59 */
60 struct implementation : io_object::implementation
61 {
62 /** Initiate an asynchronous wait for a signal.
63
64 @param h Coroutine handle to resume on completion.
65 @param ex Executor for dispatching the completion.
66 @param token Stop token for cancellation.
67 @param ec Output error code.
68 @param signo Output signal number.
69
70 @return Coroutine handle to resume immediately.
71 */
72 virtual std::coroutine_handle<> wait(
73 std::coroutine_handle<> h,
74 capy::executor_ref ex,
75 std::stop_token token,
76 std::error_code* ec,
77 int* signo) = 0;
78
79 /** Cancel all pending wait operations.
80
81 Cancelled waiters complete with an error that
82 compares equal to `capy::cond::canceled`.
83 */
84 virtual void cancel() noexcept = 0;
85 };
86
87 /** Cancel all operations associated with the signal set.
88
89 Forces the completion of any pending asynchronous wait
90 operations. Each cancelled operation completes with an error
91 code that compares equal to `capy::cond::canceled`.
92
93 Cancellation does not alter the set of registered signals.
94 */
95 17x void cancel() noexcept
96 {
97 17x do_cancel();
98 17x }
99
100 /** Wait for a signal to be delivered.
101
102 The operation supports cancellation via `std::stop_token` through
103 the affine awaitable protocol. If the associated stop token is
104 triggered, the operation completes immediately with an error
105 that compares equal to `capy::cond::canceled`.
106
107 This signal set must outlive the returned awaitable.
108
109 @note On Windows a stop request resumes the awaiting coroutine
110 inline, on the thread that called `request_stop()`. On POSIX
111 it always resumes on a thread running the execution context.
112
113 @return An awaitable that completes with `io_result<int>`.
114 Returns the signal number when a signal is delivered,
115 or an error code on failure.
116 */
117 1143x [[nodiscard]] auto wait()
118 {
119 1143x return wait_awaitable(*this);
120 }
121
122 protected:
123 /** Dispatch cancel to the concrete implementation. */
124 virtual void do_cancel() noexcept = 0;
125
126 190x explicit io_signal_set(handle h) noexcept : io_object(std::move(h)) {}
127
128 /// Move construct.
129 2x io_signal_set(io_signal_set&& other) noexcept : io_object(std::move(other))
130 {
131 2x }
132
133 /// Move assign.
134 io_signal_set& operator=(io_signal_set&& other) noexcept
135 {
136 if (this != &other)
137 h_ = std::move(other.h_);
138 return *this;
139 }
140
141 io_signal_set(io_signal_set const&) = delete;
142 io_signal_set& operator=(io_signal_set const&) = delete;
143
144 private:
145 1106x implementation& get() const noexcept
146 {
147 1106x return *static_cast<implementation*>(h_.get());
148 }
149 };
150
151 } // namespace boost::corosio
152
153 #endif
154