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 - /** Abstract base for asynchronous signal sets. 27 + /** Delivers a registered signal to the waiting coroutine.
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   { 42   {
  43 + private:
  44 + friend io_signal_set;
  45 + friend detail::value_op_base<wait_awaitable, int>;
  46 +
43   io_signal_set& s_; 47   io_signal_set& s_;
44   48  
HITCBC 45   1143 explicit wait_awaitable(io_signal_set& s) noexcept : s_(s) {} 49   1143 explicit wait_awaitable(io_signal_set& s) noexcept : s_(s) {}
46   50  
47   std::coroutine_handle<> 51   std::coroutine_handle<>
HITCBC 48   1120 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 52   1102 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
49   { 53   {
HITCBC 50   1120 return s_.get().wait(h, ex, token_, &ec_, &value_); 54   1102 return s_.get().wait(h, ex, token_, &ec_, &value_);
51   } 55   }
52   }; 56   };
53   57  
54   public: 58   public:
55   /** Define backend hooks for signal set wait and cancel. 59   /** Define backend hooks for signal set wait and cancel.
56   60  
57   Platform backends derive from this to implement 61   Platform backends derive from this to implement
58   signal delivery notification. 62   signal delivery notification.
59   */ 63   */
60   struct implementation : io_object::implementation 64   struct implementation : io_object::implementation
61   { 65   {
62   /** Initiate an asynchronous wait for a signal. 66   /** Initiate an asynchronous wait for a signal.
63   67  
64   @param h Coroutine handle to resume on completion. 68   @param h Coroutine handle to resume on completion.
65   @param ex Executor for dispatching the completion. 69   @param ex Executor for dispatching the completion.
66   @param token Stop token for cancellation. 70   @param token Stop token for cancellation.
67   @param ec Output error code. 71   @param ec Output error code.
68   @param signo Output signal number. 72   @param signo Output signal number.
69   73  
70   @return Coroutine handle to resume immediately. 74   @return Coroutine handle to resume immediately.
71   */ 75   */
72   virtual std::coroutine_handle<> wait( 76   virtual std::coroutine_handle<> wait(
73   std::coroutine_handle<> h, 77   std::coroutine_handle<> h,
74   capy::executor_ref ex, 78   capy::executor_ref ex,
75   std::stop_token token, 79   std::stop_token token,
76   std::error_code* ec, 80   std::error_code* ec,
77   int* signo) = 0; 81   int* signo) = 0;
78   82  
79   /** Cancel all pending wait operations. 83   /** Cancel all pending wait operations.
80   84  
81   Cancelled waiters complete with an error that 85   Cancelled waiters complete with an error that
82   compares equal to `capy::cond::canceled`. 86   compares equal to `capy::cond::canceled`.
83   */ 87   */
84   virtual void cancel() noexcept = 0; 88   virtual void cancel() noexcept = 0;
85   }; 89   };
86   90  
87   /** Cancel all operations associated with the signal set. 91   /** Cancel all operations associated with the signal set.
88   92  
89   Forces the completion of any pending asynchronous wait 93   Forces the completion of any pending asynchronous wait
90   operations. Each cancelled operation completes with an error 94   operations. Each cancelled operation completes with an error
91   code that compares equal to `capy::cond::canceled`. 95   code that compares equal to `capy::cond::canceled`.
92   96  
93   Cancellation does not alter the set of registered signals. 97   Cancellation does not alter the set of registered signals.
94   */ 98   */
HITCBC 95   17 void cancel() noexcept 99   17 void cancel() noexcept
96   { 100   {
HITCBC 97   17 do_cancel(); 101   17 do_cancel();
HITCBC 98   17 } 102   17 }
99   103  
100   /** Wait for a signal to be delivered. 104   /** Wait for a signal to be delivered.
101   105  
102   The operation supports cancellation via `std::stop_token` through 106   The operation supports cancellation via `std::stop_token` through
103   the affine awaitable protocol. If the associated stop token is 107   the affine awaitable protocol. If the associated stop token is
104   triggered, the operation completes immediately with an error 108   triggered, the operation completes immediately with an error
105   that compares equal to `capy::cond::canceled`. 109   that compares equal to `capy::cond::canceled`.
106   110  
107   This signal set must outlive the returned awaitable. 111   This signal set must outlive the returned awaitable.
108   112  
109   @note On Windows a stop request resumes the awaiting coroutine 113   @note On Windows a stop request resumes the awaiting coroutine
110   inline, on the thread that called `request_stop()`. On POSIX 114   inline, on the thread that called `request_stop()`. On POSIX
111   it always resumes on a thread running the execution context. 115   it always resumes on a thread running the execution context.
112   116  
113   @return An awaitable that completes with `io_result<int>`. 117   @return An awaitable that completes with `io_result<int>`.
114   Returns the signal number when a signal is delivered, 118   Returns the signal number when a signal is delivered,
115   or an error code on failure. 119   or an error code on failure.
116   */ 120   */
HITCBC 117   1143 [[nodiscard]] auto wait() 121   1143 [[nodiscard]] auto wait()
118   { 122   {
HITCBC 119   1143 return wait_awaitable(*this); 123   1143 return wait_awaitable(*this);
120   } 124   }
121   125  
122   protected: 126   protected:
123   /** Dispatch cancel to the concrete implementation. */ 127   /** Dispatch cancel to the concrete implementation. */
124   virtual void do_cancel() noexcept = 0; 128   virtual void do_cancel() noexcept = 0;
125   129  
  130 + /** Adopt an existing handle.
  131 +
  132 + @param h The handle the signal set takes ownership of.
  133 + */
HITCBC 126   190 explicit io_signal_set(handle h) noexcept : io_object(std::move(h)) {} 134   190 explicit io_signal_set(handle h) noexcept : io_object(std::move(h)) {}
127   135  
128   /// Move construct. 136   /// Move construct.
HITCBC 129   2 io_signal_set(io_signal_set&& other) noexcept : io_object(std::move(other)) 137   2 io_signal_set(io_signal_set&& other) noexcept : io_object(std::move(other))
130   { 138   {
HITCBC 131   2 } 139   2 }
132   140  
133   /// Move assign. 141   /// Move assign.
134   io_signal_set& operator=(io_signal_set&& other) noexcept 142   io_signal_set& operator=(io_signal_set&& other) noexcept
135   { 143   {
136   if (this != &other) 144   if (this != &other)
137   h_ = std::move(other.h_); 145   h_ = std::move(other.h_);
138   return *this; 146   return *this;
139   } 147   }
140   148  
141 - io_signal_set(io_signal_set const&) = delete; 149 + /// Copy construction is disabled; the handle is uniquely owned.
  150 + io_signal_set(io_signal_set const&) = delete;
  151 + /// Copy assignment is disabled; the handle is uniquely owned.
142   io_signal_set& operator=(io_signal_set const&) = delete; 152   io_signal_set& operator=(io_signal_set const&) = delete;
143   153  
144   private: 154   private:
HITCBC 145   1120 implementation& get() const noexcept 155   1102 implementation& get() const noexcept
146   { 156   {
HITCBC 147   1120 return *static_cast<implementation*>(h_.get()); 157   1102 return *static_cast<implementation*>(h_.get());
148   } 158   }
149   }; 159   };
150   160  
151   } // namespace boost::corosio 161   } // namespace boost::corosio
152   162  
153   #endif 163   #endif