TLA Line data 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 HIT 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 MIS 0 : return {capy::error::canceled};
58 HIT 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 : /** Define backend hooks for signal set wait and cancel.
72 :
73 : Platform backends derive from this to implement
74 : signal delivery notification.
75 : */
76 : struct implementation : io_object::implementation
77 : {
78 : /** Initiate an asynchronous wait for a signal.
79 :
80 : @param h Coroutine handle to resume on completion.
81 : @param ex Executor for dispatching the completion.
82 : @param token Stop token for cancellation.
83 : @param ec Output error code.
84 : @param signo Output signal number.
85 :
86 : @return Coroutine handle to resume immediately.
87 : */
88 : virtual std::coroutine_handle<> wait(
89 : std::coroutine_handle<> h,
90 : capy::executor_ref ex,
91 : std::stop_token token,
92 : std::error_code* ec,
93 : int* signo) = 0;
94 :
95 : /** Cancel all pending wait operations.
96 :
97 : Cancelled waiters complete with an error that
98 : compares equal to `capy::cond::canceled`.
99 : */
100 : virtual void cancel() = 0;
101 : };
102 :
103 : /** Cancel all operations associated with the signal set.
104 :
105 : Forces the completion of any pending asynchronous wait
106 : operations. Each cancelled operation completes with an error
107 : code that compares equal to `capy::cond::canceled`.
108 :
109 : Cancellation does not alter the set of registered signals.
110 : */
111 12 : void cancel()
112 : {
113 12 : do_cancel();
114 12 : }
115 :
116 : /** Wait for a signal to be delivered.
117 :
118 : The operation supports cancellation via `std::stop_token` through
119 : the affine awaitable protocol. If the associated stop token is
120 : triggered, the operation completes immediately with an error
121 : that compares equal to `capy::cond::canceled`.
122 :
123 : This signal set must outlive the returned awaitable.
124 :
125 : @return An awaitable that completes with `io_result<int>`.
126 : Returns the signal number when a signal is delivered,
127 : or an error code on failure.
128 : */
129 26 : auto wait()
130 : {
131 26 : return wait_awaitable(*this);
132 : }
133 :
134 : protected:
135 : /** Dispatch cancel to the concrete implementation. */
136 : virtual void do_cancel() = 0;
137 :
138 88 : explicit io_signal_set(handle h) noexcept : io_object(std::move(h)) {}
139 :
140 : /// Move construct.
141 2 : io_signal_set(io_signal_set&& other) noexcept : io_object(std::move(other))
142 : {
143 2 : }
144 :
145 : /// Move assign.
146 : io_signal_set& operator=(io_signal_set&& other) noexcept
147 : {
148 : if (this != &other)
149 : h_ = std::move(other.h_);
150 : return *this;
151 : }
152 :
153 : io_signal_set(io_signal_set const&) = delete;
154 : io_signal_set& operator=(io_signal_set const&) = delete;
155 :
156 : private:
157 26 : implementation& get() const noexcept
158 : {
159 26 : return *static_cast<implementation*>(h_.get());
160 : }
161 : };
162 :
163 : } // namespace boost::corosio
164 :
165 : #endif
|