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