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 205889 : explicit wait_awaitable(io_signal_set& s) noexcept : s_(s) {}
52 :
53 : std::coroutine_handle<>
54 205842 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
55 : {
56 205842 : 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 : @return An awaitable that completes with `results<int>`.
117 : Returns the signal number when a signal is delivered,
118 : or an error code on failure.
119 : */
120 205889 : [[nodiscard]] auto wait()
121 : {
122 205889 : return wait_awaitable(*this);
123 : }
124 :
125 : protected:
126 : /** Dispatch cancel to the concrete implementation. */
127 : virtual void do_cancel() noexcept = 0;
128 :
129 : /** Adopt an existing handle.
130 :
131 : @param h The handle the signal set takes ownership of.
132 : */
133 3478 : explicit io_signal_set(handle h) noexcept : io_object(std::move(h)) {}
134 :
135 : /// Move construct.
136 4 : io_signal_set(io_signal_set&& other) noexcept : io_object(std::move(other))
137 : {
138 4 : }
139 :
140 : /// Move assign.
141 : io_signal_set& operator=(io_signal_set&& other) noexcept
142 : {
143 : if (this != &other)
144 : h_ = std::move(other.h_);
145 : return *this;
146 : }
147 :
148 : /// Copy construction is disabled; the handle is uniquely owned.
149 : io_signal_set(io_signal_set const&) = delete;
150 : /// Copy assignment is disabled; the handle is uniquely owned.
151 : io_signal_set& operator=(io_signal_set const&) = delete;
152 :
153 : private:
154 205842 : implementation& get() const noexcept
155 : {
156 205842 : return *static_cast<implementation*>(h_.get());
157 : }
158 : };
159 :
160 : } // namespace boost::corosio
161 :
162 : #endif
|