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