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