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 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 12x void cancel()
92 {
93 12x do_cancel();
94 12x }
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 26x auto wait()
110 {
111 26x return wait_awaitable(*this);
112 }
113
114 protected:
115 /** Dispatch cancel to the concrete implementation. */
116 virtual void do_cancel() = 0;
117
118 88x explicit io_signal_set(handle h) noexcept : io_object(std::move(h)) {}
119
120 /// Move construct.
121 2x io_signal_set(io_signal_set&& other) noexcept : io_object(std::move(other))
122 {
123 2x }
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 26x implementation& get() const noexcept
138 {
139 26x return *static_cast<implementation*>(h_.get());
140 }
141 };
142
143 } // namespace boost::corosio
144
145 #endif
146