1 //
2 // detail/signal_set_service.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef BOOST_ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP
12 #define BOOST_ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/config.hpp>
19 
20 #include <cstddef>
21 #include <signal.h>
22 #include <boost/asio/error.hpp>
23 #include <boost/asio/execution_context.hpp>
24 #include <boost/asio/detail/handler_alloc_helpers.hpp>
25 #include <boost/asio/detail/memory.hpp>
26 #include <boost/asio/detail/op_queue.hpp>
27 #include <boost/asio/detail/signal_handler.hpp>
28 #include <boost/asio/detail/signal_op.hpp>
29 #include <boost/asio/detail/socket_types.hpp>
30 
31 #if defined(BOOST_ASIO_HAS_IOCP)
32 # include <boost/asio/detail/win_iocp_io_context.hpp>
33 #else // defined(BOOST_ASIO_HAS_IOCP)
34 # include <boost/asio/detail/scheduler.hpp>
35 #endif // defined(BOOST_ASIO_HAS_IOCP)
36 
37 #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
38 # include <boost/asio/detail/reactor.hpp>
39 #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
40 
41 #include <boost/asio/detail/push_options.hpp>
42 
43 namespace boost {
44 namespace asio {
45 namespace detail {
46 
47 #if defined(NSIG) && (NSIG > 0)
48 enum { max_signal_number = NSIG };
49 #else
50 enum { max_signal_number = 128 };
51 #endif
52 
53 extern BOOST_ASIO_DECL struct signal_state* get_signal_state();
54 
55 extern "C" BOOST_ASIO_DECL void boost_asio_signal_handler(int signal_number);
56 
57 class signal_set_service :
58   public execution_context_service_base<signal_set_service>
59 {
60 public:
61   // Type used for tracking an individual signal registration.
62   class registration
63   {
64   public:
65     // Default constructor.
registration()66     registration()
67       : signal_number_(0),
68         queue_(0),
69         undelivered_(0),
70         next_in_table_(0),
71         prev_in_table_(0),
72         next_in_set_(0)
73     {
74     }
75 
76   private:
77     // Only this service will have access to the internal values.
78     friend class signal_set_service;
79 
80     // The signal number that is registered.
81     int signal_number_;
82 
83     // The waiting signal handlers.
84     op_queue<signal_op>* queue_;
85 
86     // The number of undelivered signals.
87     std::size_t undelivered_;
88 
89     // Pointers to adjacent registrations in the registrations_ table.
90     registration* next_in_table_;
91     registration* prev_in_table_;
92 
93     // Link to next registration in the signal set.
94     registration* next_in_set_;
95   };
96 
97   // The implementation type of the signal_set.
98   class implementation_type
99   {
100   public:
101     // Default constructor.
implementation_type()102     implementation_type()
103       : signals_(0)
104     {
105     }
106 
107   private:
108     // Only this service will have access to the internal values.
109     friend class signal_set_service;
110 
111     // The pending signal handlers.
112     op_queue<signal_op> queue_;
113 
114     // Linked list of registered signals.
115     registration* signals_;
116   };
117 
118   // Constructor.
119   BOOST_ASIO_DECL signal_set_service(execution_context& context);
120 
121   // Destructor.
122   BOOST_ASIO_DECL ~signal_set_service();
123 
124   // Destroy all user-defined handler objects owned by the service.
125   BOOST_ASIO_DECL void shutdown();
126 
127   // Perform fork-related housekeeping.
128   BOOST_ASIO_DECL void notify_fork(
129       boost::asio::execution_context::fork_event fork_ev);
130 
131   // Construct a new signal_set implementation.
132   BOOST_ASIO_DECL void construct(implementation_type& impl);
133 
134   // Destroy a signal_set implementation.
135   BOOST_ASIO_DECL void destroy(implementation_type& impl);
136 
137   // Add a signal to a signal_set.
138   BOOST_ASIO_DECL boost::system::error_code add(implementation_type& impl,
139       int signal_number, boost::system::error_code& ec);
140 
141   // Remove a signal to a signal_set.
142   BOOST_ASIO_DECL boost::system::error_code remove(implementation_type& impl,
143       int signal_number, boost::system::error_code& ec);
144 
145   // Remove all signals from a signal_set.
146   BOOST_ASIO_DECL boost::system::error_code clear(implementation_type& impl,
147       boost::system::error_code& ec);
148 
149   // Cancel all operations associated with the signal set.
150   BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl,
151       boost::system::error_code& ec);
152 
153   // Start an asynchronous operation to wait for a signal to be delivered.
154   template <typename Handler, typename IoExecutor>
async_wait(implementation_type & impl,Handler & handler,const IoExecutor & io_ex)155   void async_wait(implementation_type& impl,
156       Handler& handler, const IoExecutor& io_ex)
157   {
158     // Allocate and construct an operation to wrap the handler.
159     typedef signal_handler<Handler, IoExecutor> op;
160     typename op::ptr p = { boost::asio::detail::addressof(handler),
161       op::ptr::allocate(handler), 0 };
162     p.p = new (p.v) op(handler, io_ex);
163 
164     BOOST_ASIO_HANDLER_CREATION((scheduler_.context(),
165           *p.p, "signal_set", &impl, 0, "async_wait"));
166 
167     start_wait_op(impl, p.p);
168     p.v = p.p = 0;
169   }
170 
171   // Deliver notification that a particular signal occurred.
172   BOOST_ASIO_DECL static void deliver_signal(int signal_number);
173 
174 private:
175   // Helper function to add a service to the global signal state.
176   BOOST_ASIO_DECL static void add_service(signal_set_service* service);
177 
178   // Helper function to remove a service from the global signal state.
179   BOOST_ASIO_DECL static void remove_service(signal_set_service* service);
180 
181   // Helper function to create the pipe descriptors.
182   BOOST_ASIO_DECL static void open_descriptors();
183 
184   // Helper function to close the pipe descriptors.
185   BOOST_ASIO_DECL static void close_descriptors();
186 
187   // Helper function to start a wait operation.
188   BOOST_ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op);
189 
190   // The scheduler used for dispatching handlers.
191 #if defined(BOOST_ASIO_HAS_IOCP)
192   typedef class win_iocp_io_context scheduler_impl;
193 #else
194   typedef class scheduler scheduler_impl;
195 #endif
196   scheduler_impl& scheduler_;
197 
198 #if !defined(BOOST_ASIO_WINDOWS) \
199   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
200   && !defined(__CYGWIN__)
201   // The type used for registering for pipe reactor notifications.
202   class pipe_read_op;
203 
204   // The reactor used for waiting for pipe readiness.
205   reactor& reactor_;
206 
207   // The per-descriptor reactor data used for the pipe.
208   reactor::per_descriptor_data reactor_data_;
209 #endif // !defined(BOOST_ASIO_WINDOWS)
210        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
211        //   && !defined(__CYGWIN__)
212 
213   // A mapping from signal number to the registered signal sets.
214   registration* registrations_[max_signal_number];
215 
216   // Pointers to adjacent services in linked list.
217   signal_set_service* next_;
218   signal_set_service* prev_;
219 };
220 
221 } // namespace detail
222 } // namespace asio
223 } // namespace boost
224 
225 #include <boost/asio/detail/pop_options.hpp>
226 
227 #if defined(BOOST_ASIO_HEADER_ONLY)
228 # include <boost/asio/detail/impl/signal_set_service.ipp>
229 #endif // defined(BOOST_ASIO_HEADER_ONLY)
230 
231 #endif // BOOST_ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP
232