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/results.hpp>
17 : #include <boost/capy/error.hpp>
18 : #include <boost/capy/ex/executor_ref.hpp>
19 : #include <boost/capy/ex/await_context.hpp>
20 :
21 : #include <boost/capy/continuation.hpp>
22 :
23 : #include <coroutine>
24 : #include <stop_token>
25 : #include <system_error>
26 :
27 : namespace boost::corosio {
28 :
29 : /** Delivers a registered signal to the waiting coroutine.
30 :
31 : Provides the common signal set interface: `wait` and `cancel`.
32 : Concrete classes like @ref signal_set add signal registration
33 : (add, remove, clear) and platform-specific flags.
34 :
35 : @par Thread Safety
36 : Distinct objects: Safe.
37 : Shared objects: Unsafe.
38 :
39 : @see signal_set, io_object
40 : */
41 : class BOOST_COROSIO_DECL io_signal_set : public io_object
42 : {
43 : struct wait_awaitable : detail::value_op_base<wait_awaitable, int>
44 : {
45 : private:
46 : friend io_signal_set;
47 : friend detail::value_op_base<wait_awaitable, int>;
48 :
49 : io_signal_set& s_;
50 :
51 HIT 206016 : explicit wait_awaitable(io_signal_set& s) noexcept : s_(s) {}
52 :
53 : std::coroutine_handle<>
54 205987 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
55 : {
56 205987 : return s_.get().wait(cont, ex, token_, &ec_, &value_);
57 : }
58 : };
59 :
60 : public:
61 : /** Define backend hooks for signal set wait and cancel.
62 :
63 : Platform backends derive from this to implement
64 : signal delivery notification.
65 : */
66 : struct implementation : io_object::implementation
67 : {
68 : /** Initiate an asynchronous wait for a signal.
69 :
70 : @param cont Continuation to resume on completion; it lives in
71 : the awaiting frame until then.
72 : @param ex Executor for dispatching the completion.
73 : @param token Stop token for cancellation.
74 : @param ec Output error code.
75 : @param signo Output signal number.
76 :
77 : @return Coroutine handle to resume immediately.
78 : */
79 : virtual std::coroutine_handle<> wait(
80 : capy::continuation& cont,
81 : capy::executor_ref ex,
82 : std::stop_token token,
83 : std::error_code* ec,
84 : int* signo) = 0;
85 :
86 : /** Cancel all pending wait operations.
87 :
88 : Cancelled waiters complete with an error that
89 : compares equal to `capy::cond::canceled`.
90 : */
91 : virtual void cancel() noexcept = 0;
92 : };
93 :
94 : /** Cancel all operations associated with the signal set.
95 :
96 : Forces the completion of any pending asynchronous wait
97 : operations. Each cancelled operation completes with an error
98 : code that compares equal to `capy::cond::canceled`.
99 :
100 : Cancellation does not alter the set of registered signals.
101 : */
102 200021 : void cancel() noexcept
103 : {
104 200021 : do_cancel();
105 200021 : }
106 :
107 : /** Wait for a signal to be delivered.
108 :
109 : The operation supports cancellation via `std::stop_token` through
110 : the affine awaitable protocol. If the associated stop token is
111 : triggered, the operation completes immediately with an error
112 : that compares equal to `capy::cond::canceled`.
113 :
114 : This signal set must outlive the returned awaitable.
115 :
116 : @note On Windows a stop request resumes the awaiting coroutine
117 : inline, on the thread that called `request_stop()`. On POSIX
118 : it always resumes on a thread running the execution context.
119 :
120 : @return An awaitable that completes with `results<int>`.
121 : Returns the signal number when a signal is delivered,
122 : or an error code on failure.
123 : */
124 206016 : [[nodiscard]] auto wait()
125 : {
126 206016 : return wait_awaitable(*this);
127 : }
128 :
129 : protected:
130 : /** Dispatch cancel to the concrete implementation. */
131 : virtual void do_cancel() noexcept = 0;
132 :
133 : /** Adopt an existing handle.
134 :
135 : @param h The handle the signal set takes ownership of.
136 : */
137 3476 : explicit io_signal_set(handle h) noexcept : io_object(std::move(h)) {}
138 :
139 : /// Move construct.
140 4 : io_signal_set(io_signal_set&& other) noexcept : io_object(std::move(other))
141 : {
142 4 : }
143 :
144 : /// Move assign.
145 : io_signal_set& operator=(io_signal_set&& other) noexcept
146 : {
147 : if (this != &other)
148 : h_ = std::move(other.h_);
149 : return *this;
150 : }
151 :
152 : /// Copy construction is disabled; the handle is uniquely owned.
153 : io_signal_set(io_signal_set const&) = delete;
154 : /// Copy assignment is disabled; the handle is uniquely owned.
155 : io_signal_set& operator=(io_signal_set const&) = delete;
156 :
157 : private:
158 205987 : implementation& get() const noexcept
159 : {
160 205987 : return *static_cast<implementation*>(h_.get());
161 : }
162 : };
163 :
164 : } // namespace boost::corosio
165 :
166 : #endif
|