include/boost/corosio/io/io_signal_set.hpp

95.2% Lines (20/21) 100.0% Functions (9/9)
include/boost/corosio/io/io_signal_set.hpp
Line 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 26 explicit wait_awaitable(io_signal_set& s) noexcept : s_(s) {}
48
49 26 bool await_ready() const noexcept
50 {
51 26 return token_.stop_requested();
52 }
53
54 26 capy::io_result<int> await_resume() const noexcept
55 {
56 26 if (token_.stop_requested())
57 return {capy::error::canceled};
58 26 return {ec_, signal_number_};
59 }
60
61 26 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
62 -> std::coroutine_handle<>
63 {
64 26 token_ = env->stop_token;
65 78 return s_.get().wait(
66 78 h, env->executor, token_, &ec_, &signal_number_);
67 }
68 };
69
70 public:
71 struct implementation : io_object::implementation
72 {
73 virtual std::coroutine_handle<> wait(
74 std::coroutine_handle<>,
75 capy::executor_ref,
76 std::stop_token,
77 std::error_code*,
78 int*) = 0;
79
80 virtual void cancel() = 0;
81 };
82
83 /** Cancel all operations associated with the signal set.
84
85 Forces the completion of any pending asynchronous wait
86 operations. Each cancelled operation completes with an error
87 code that compares equal to `capy::cond::canceled`.
88
89 Cancellation does not alter the set of registered signals.
90 */
91 12 void cancel()
92 {
93 12 do_cancel();
94 12 }
95
96 /** Wait for a signal to be delivered.
97
98 The operation supports cancellation via `std::stop_token` through
99 the affine awaitable protocol. If the associated stop token is
100 triggered, the operation completes immediately with an error
101 that compares equal to `capy::cond::canceled`.
102
103 This signal set must outlive the returned awaitable.
104
105 @return An awaitable that completes with `io_result<int>`.
106 Returns the signal number when a signal is delivered,
107 or an error code on failure.
108 */
109 26 auto wait()
110 {
111 26 return wait_awaitable(*this);
112 }
113
114 protected:
115 /** Dispatch cancel to the concrete implementation. */
116 virtual void do_cancel() = 0;
117
118 88 explicit io_signal_set(handle h) noexcept : io_object(std::move(h)) {}
119
120 /// Move construct.
121 2 io_signal_set(io_signal_set&& other) noexcept : io_object(std::move(other))
122 {
123 2 }
124
125 /// Move assign.
126 io_signal_set& operator=(io_signal_set&& other) noexcept
127 {
128 if (this != &other)
129 h_ = std::move(other.h_);
130 return *this;
131 }
132
133 io_signal_set(io_signal_set const&) = delete;
134 io_signal_set& operator=(io_signal_set const&) = delete;
135
136 private:
137 26 implementation& get() const noexcept
138 {
139 26 return *static_cast<implementation*>(h_.get());
140 }
141 };
142
143 } // namespace boost::corosio
144
145 #endif
146