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