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/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 HIT 1143 : explicit wait_awaitable(io_signal_set& s) noexcept : s_(s) {}
46 :
47 : std::coroutine_handle<>
48 1113 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
49 : {
50 1113 : 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 17 : void cancel() noexcept
96 : {
97 17 : do_cancel();
98 17 : }
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 1143 : [[nodiscard]] auto wait()
118 : {
119 1143 : return wait_awaitable(*this);
120 : }
121 :
122 : protected:
123 : /** Dispatch cancel to the concrete implementation. */
124 : virtual void do_cancel() noexcept = 0;
125 :
126 190 : explicit io_signal_set(handle h) noexcept : io_object(std::move(h)) {}
127 :
128 : /// Move construct.
129 2 : io_signal_set(io_signal_set&& other) noexcept : io_object(std::move(other))
130 : {
131 2 : }
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 1113 : implementation& get() const noexcept
146 : {
147 1113 : return *static_cast<implementation*>(h_.get());
148 : }
149 : };
150 :
151 : } // namespace boost::corosio
152 :
153 : #endif
|