Chris@16
|
1 //
|
Chris@16
|
2 // detail/impl/signal_set_service.ipp
|
Chris@16
|
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
Chris@16
|
4 //
|
Chris@101
|
5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
Chris@16
|
6 //
|
Chris@16
|
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 //
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
|
Chris@16
|
12 #define BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
|
Chris@16
|
13
|
Chris@16
|
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
15 # pragma once
|
Chris@16
|
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/asio/detail/config.hpp>
|
Chris@16
|
19
|
Chris@16
|
20 #include <cstring>
|
Chris@16
|
21 #include <boost/asio/detail/reactor.hpp>
|
Chris@16
|
22 #include <boost/asio/detail/signal_blocker.hpp>
|
Chris@16
|
23 #include <boost/asio/detail/signal_set_service.hpp>
|
Chris@16
|
24 #include <boost/asio/detail/static_mutex.hpp>
|
Chris@16
|
25
|
Chris@16
|
26 #include <boost/asio/detail/push_options.hpp>
|
Chris@16
|
27
|
Chris@16
|
28 namespace boost {
|
Chris@16
|
29 namespace asio {
|
Chris@16
|
30 namespace detail {
|
Chris@16
|
31
|
Chris@16
|
32 struct signal_state
|
Chris@16
|
33 {
|
Chris@16
|
34 // Mutex used for protecting global state.
|
Chris@16
|
35 static_mutex mutex_;
|
Chris@16
|
36
|
Chris@16
|
37 // The read end of the pipe used for signal notifications.
|
Chris@16
|
38 int read_descriptor_;
|
Chris@16
|
39
|
Chris@16
|
40 // The write end of the pipe used for signal notifications.
|
Chris@16
|
41 int write_descriptor_;
|
Chris@16
|
42
|
Chris@16
|
43 // Whether the signal state has been prepared for a fork.
|
Chris@16
|
44 bool fork_prepared_;
|
Chris@16
|
45
|
Chris@16
|
46 // The head of a linked list of all signal_set_service instances.
|
Chris@16
|
47 class signal_set_service* service_list_;
|
Chris@16
|
48
|
Chris@16
|
49 // A count of the number of objects that are registered for each signal.
|
Chris@16
|
50 std::size_t registration_count_[max_signal_number];
|
Chris@16
|
51 };
|
Chris@16
|
52
|
Chris@16
|
53 signal_state* get_signal_state()
|
Chris@16
|
54 {
|
Chris@16
|
55 static signal_state state = {
|
Chris@16
|
56 BOOST_ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } };
|
Chris@16
|
57 return &state;
|
Chris@16
|
58 }
|
Chris@16
|
59
|
Chris@16
|
60 void boost_asio_signal_handler(int signal_number)
|
Chris@16
|
61 {
|
Chris@16
|
62 #if defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
63 || defined(BOOST_ASIO_WINDOWS_RUNTIME) \
|
Chris@16
|
64 || defined(__CYGWIN__)
|
Chris@16
|
65 signal_set_service::deliver_signal(signal_number);
|
Chris@16
|
66 #else // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
67 // || defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
68 // || defined(__CYGWIN__)
|
Chris@16
|
69 int saved_errno = errno;
|
Chris@16
|
70 signal_state* state = get_signal_state();
|
Chris@16
|
71 signed_size_type result = ::write(state->write_descriptor_,
|
Chris@16
|
72 &signal_number, sizeof(signal_number));
|
Chris@16
|
73 (void)result;
|
Chris@16
|
74 errno = saved_errno;
|
Chris@16
|
75 #endif // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
76 // || defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
77 // || defined(__CYGWIN__)
|
Chris@16
|
78
|
Chris@16
|
79 #if defined(BOOST_ASIO_HAS_SIGNAL) && !defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
80 ::signal(signal_number, boost_asio_signal_handler);
|
Chris@16
|
81 #endif // defined(BOOST_ASIO_HAS_SIGNAL) && !defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
82 }
|
Chris@16
|
83
|
Chris@16
|
84 #if !defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
85 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
|
Chris@16
|
86 && !defined(__CYGWIN__)
|
Chris@16
|
87 class signal_set_service::pipe_read_op : public reactor_op
|
Chris@16
|
88 {
|
Chris@16
|
89 public:
|
Chris@16
|
90 pipe_read_op()
|
Chris@16
|
91 : reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete)
|
Chris@16
|
92 {
|
Chris@16
|
93 }
|
Chris@16
|
94
|
Chris@16
|
95 static bool do_perform(reactor_op*)
|
Chris@16
|
96 {
|
Chris@16
|
97 signal_state* state = get_signal_state();
|
Chris@16
|
98
|
Chris@16
|
99 int fd = state->read_descriptor_;
|
Chris@16
|
100 int signal_number = 0;
|
Chris@16
|
101 while (::read(fd, &signal_number, sizeof(int)) == sizeof(int))
|
Chris@16
|
102 if (signal_number >= 0 && signal_number < max_signal_number)
|
Chris@16
|
103 signal_set_service::deliver_signal(signal_number);
|
Chris@16
|
104
|
Chris@16
|
105 return false;
|
Chris@16
|
106 }
|
Chris@16
|
107
|
Chris@16
|
108 static void do_complete(io_service_impl* /*owner*/, operation* base,
|
Chris@16
|
109 const boost::system::error_code& /*ec*/,
|
Chris@16
|
110 std::size_t /*bytes_transferred*/)
|
Chris@16
|
111 {
|
Chris@16
|
112 pipe_read_op* o(static_cast<pipe_read_op*>(base));
|
Chris@16
|
113 delete o;
|
Chris@16
|
114 }
|
Chris@16
|
115 };
|
Chris@16
|
116 #endif // !defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
117 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
118 // && !defined(__CYGWIN__)
|
Chris@16
|
119
|
Chris@16
|
120 signal_set_service::signal_set_service(
|
Chris@16
|
121 boost::asio::io_service& io_service)
|
Chris@16
|
122 : io_service_(boost::asio::use_service<io_service_impl>(io_service)),
|
Chris@16
|
123 #if !defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
124 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
|
Chris@16
|
125 && !defined(__CYGWIN__)
|
Chris@16
|
126 reactor_(boost::asio::use_service<reactor>(io_service)),
|
Chris@16
|
127 #endif // !defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
128 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
129 // && !defined(__CYGWIN__)
|
Chris@16
|
130 next_(0),
|
Chris@16
|
131 prev_(0)
|
Chris@16
|
132 {
|
Chris@16
|
133 get_signal_state()->mutex_.init();
|
Chris@16
|
134
|
Chris@16
|
135 #if !defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
136 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
|
Chris@16
|
137 && !defined(__CYGWIN__)
|
Chris@16
|
138 reactor_.init_task();
|
Chris@16
|
139 #endif // !defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
140 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
141 // && !defined(__CYGWIN__)
|
Chris@16
|
142
|
Chris@16
|
143 for (int i = 0; i < max_signal_number; ++i)
|
Chris@16
|
144 registrations_[i] = 0;
|
Chris@16
|
145
|
Chris@16
|
146 add_service(this);
|
Chris@16
|
147 }
|
Chris@16
|
148
|
Chris@16
|
149 signal_set_service::~signal_set_service()
|
Chris@16
|
150 {
|
Chris@16
|
151 remove_service(this);
|
Chris@16
|
152 }
|
Chris@16
|
153
|
Chris@16
|
154 void signal_set_service::shutdown_service()
|
Chris@16
|
155 {
|
Chris@16
|
156 remove_service(this);
|
Chris@16
|
157
|
Chris@16
|
158 op_queue<operation> ops;
|
Chris@16
|
159
|
Chris@16
|
160 for (int i = 0; i < max_signal_number; ++i)
|
Chris@16
|
161 {
|
Chris@16
|
162 registration* reg = registrations_[i];
|
Chris@16
|
163 while (reg)
|
Chris@16
|
164 {
|
Chris@16
|
165 ops.push(*reg->queue_);
|
Chris@16
|
166 reg = reg->next_in_table_;
|
Chris@16
|
167 }
|
Chris@16
|
168 }
|
Chris@16
|
169
|
Chris@16
|
170 io_service_.abandon_operations(ops);
|
Chris@16
|
171 }
|
Chris@16
|
172
|
Chris@16
|
173 void signal_set_service::fork_service(
|
Chris@16
|
174 boost::asio::io_service::fork_event fork_ev)
|
Chris@16
|
175 {
|
Chris@16
|
176 #if !defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
177 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
|
Chris@16
|
178 && !defined(__CYGWIN__)
|
Chris@16
|
179 signal_state* state = get_signal_state();
|
Chris@16
|
180 static_mutex::scoped_lock lock(state->mutex_);
|
Chris@16
|
181
|
Chris@16
|
182 switch (fork_ev)
|
Chris@16
|
183 {
|
Chris@16
|
184 case boost::asio::io_service::fork_prepare:
|
Chris@16
|
185 {
|
Chris@16
|
186 int read_descriptor = state->read_descriptor_;
|
Chris@16
|
187 state->fork_prepared_ = true;
|
Chris@16
|
188 lock.unlock();
|
Chris@16
|
189 reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_);
|
Chris@16
|
190 }
|
Chris@16
|
191 break;
|
Chris@16
|
192 case boost::asio::io_service::fork_parent:
|
Chris@16
|
193 if (state->fork_prepared_)
|
Chris@16
|
194 {
|
Chris@16
|
195 int read_descriptor = state->read_descriptor_;
|
Chris@16
|
196 state->fork_prepared_ = false;
|
Chris@16
|
197 lock.unlock();
|
Chris@16
|
198 reactor_.register_internal_descriptor(reactor::read_op,
|
Chris@16
|
199 read_descriptor, reactor_data_, new pipe_read_op);
|
Chris@16
|
200 }
|
Chris@16
|
201 break;
|
Chris@16
|
202 case boost::asio::io_service::fork_child:
|
Chris@16
|
203 if (state->fork_prepared_)
|
Chris@16
|
204 {
|
Chris@16
|
205 boost::asio::detail::signal_blocker blocker;
|
Chris@16
|
206 close_descriptors();
|
Chris@16
|
207 open_descriptors();
|
Chris@16
|
208 int read_descriptor = state->read_descriptor_;
|
Chris@16
|
209 state->fork_prepared_ = false;
|
Chris@16
|
210 lock.unlock();
|
Chris@16
|
211 reactor_.register_internal_descriptor(reactor::read_op,
|
Chris@16
|
212 read_descriptor, reactor_data_, new pipe_read_op);
|
Chris@16
|
213 }
|
Chris@16
|
214 break;
|
Chris@16
|
215 default:
|
Chris@16
|
216 break;
|
Chris@16
|
217 }
|
Chris@16
|
218 #else // !defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
219 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
220 // && !defined(__CYGWIN__)
|
Chris@16
|
221 (void)fork_ev;
|
Chris@16
|
222 #endif // !defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
223 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
224 // && !defined(__CYGWIN__)
|
Chris@16
|
225 }
|
Chris@16
|
226
|
Chris@16
|
227 void signal_set_service::construct(
|
Chris@16
|
228 signal_set_service::implementation_type& impl)
|
Chris@16
|
229 {
|
Chris@16
|
230 impl.signals_ = 0;
|
Chris@16
|
231 }
|
Chris@16
|
232
|
Chris@16
|
233 void signal_set_service::destroy(
|
Chris@16
|
234 signal_set_service::implementation_type& impl)
|
Chris@16
|
235 {
|
Chris@16
|
236 boost::system::error_code ignored_ec;
|
Chris@16
|
237 clear(impl, ignored_ec);
|
Chris@16
|
238 cancel(impl, ignored_ec);
|
Chris@16
|
239 }
|
Chris@16
|
240
|
Chris@16
|
241 boost::system::error_code signal_set_service::add(
|
Chris@16
|
242 signal_set_service::implementation_type& impl,
|
Chris@16
|
243 int signal_number, boost::system::error_code& ec)
|
Chris@16
|
244 {
|
Chris@16
|
245 // Check that the signal number is valid.
|
Chris@101
|
246 if (signal_number < 0 || signal_number >= max_signal_number)
|
Chris@16
|
247 {
|
Chris@16
|
248 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
249 return ec;
|
Chris@16
|
250 }
|
Chris@16
|
251
|
Chris@16
|
252 signal_state* state = get_signal_state();
|
Chris@16
|
253 static_mutex::scoped_lock lock(state->mutex_);
|
Chris@16
|
254
|
Chris@16
|
255 // Find the appropriate place to insert the registration.
|
Chris@16
|
256 registration** insertion_point = &impl.signals_;
|
Chris@16
|
257 registration* next = impl.signals_;
|
Chris@16
|
258 while (next && next->signal_number_ < signal_number)
|
Chris@16
|
259 {
|
Chris@16
|
260 insertion_point = &next->next_in_set_;
|
Chris@16
|
261 next = next->next_in_set_;
|
Chris@16
|
262 }
|
Chris@16
|
263
|
Chris@16
|
264 // Only do something if the signal is not already registered.
|
Chris@16
|
265 if (next == 0 || next->signal_number_ != signal_number)
|
Chris@16
|
266 {
|
Chris@16
|
267 registration* new_registration = new registration;
|
Chris@16
|
268
|
Chris@16
|
269 #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
270 // Register for the signal if we're the first.
|
Chris@16
|
271 if (state->registration_count_[signal_number] == 0)
|
Chris@16
|
272 {
|
Chris@16
|
273 # if defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
274 using namespace std; // For memset.
|
Chris@16
|
275 struct sigaction sa;
|
Chris@16
|
276 memset(&sa, 0, sizeof(sa));
|
Chris@16
|
277 sa.sa_handler = boost_asio_signal_handler;
|
Chris@16
|
278 sigfillset(&sa.sa_mask);
|
Chris@16
|
279 if (::sigaction(signal_number, &sa, 0) == -1)
|
Chris@16
|
280 # else // defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
281 if (::signal(signal_number, boost_asio_signal_handler) == SIG_ERR)
|
Chris@16
|
282 # endif // defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
283 {
|
Chris@16
|
284 # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
285 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
286 # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
287 ec = boost::system::error_code(errno,
|
Chris@16
|
288 boost::asio::error::get_system_category());
|
Chris@16
|
289 # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
290 delete new_registration;
|
Chris@16
|
291 return ec;
|
Chris@16
|
292 }
|
Chris@16
|
293 }
|
Chris@16
|
294 #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
295
|
Chris@16
|
296 // Record the new registration in the set.
|
Chris@16
|
297 new_registration->signal_number_ = signal_number;
|
Chris@16
|
298 new_registration->queue_ = &impl.queue_;
|
Chris@16
|
299 new_registration->next_in_set_ = next;
|
Chris@16
|
300 *insertion_point = new_registration;
|
Chris@16
|
301
|
Chris@16
|
302 // Insert registration into the registration table.
|
Chris@16
|
303 new_registration->next_in_table_ = registrations_[signal_number];
|
Chris@16
|
304 if (registrations_[signal_number])
|
Chris@16
|
305 registrations_[signal_number]->prev_in_table_ = new_registration;
|
Chris@16
|
306 registrations_[signal_number] = new_registration;
|
Chris@16
|
307
|
Chris@16
|
308 ++state->registration_count_[signal_number];
|
Chris@16
|
309 }
|
Chris@16
|
310
|
Chris@16
|
311 ec = boost::system::error_code();
|
Chris@16
|
312 return ec;
|
Chris@16
|
313 }
|
Chris@16
|
314
|
Chris@16
|
315 boost::system::error_code signal_set_service::remove(
|
Chris@16
|
316 signal_set_service::implementation_type& impl,
|
Chris@16
|
317 int signal_number, boost::system::error_code& ec)
|
Chris@16
|
318 {
|
Chris@16
|
319 // Check that the signal number is valid.
|
Chris@101
|
320 if (signal_number < 0 || signal_number >= max_signal_number)
|
Chris@16
|
321 {
|
Chris@16
|
322 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
323 return ec;
|
Chris@16
|
324 }
|
Chris@16
|
325
|
Chris@16
|
326 signal_state* state = get_signal_state();
|
Chris@16
|
327 static_mutex::scoped_lock lock(state->mutex_);
|
Chris@16
|
328
|
Chris@16
|
329 // Find the signal number in the list of registrations.
|
Chris@16
|
330 registration** deletion_point = &impl.signals_;
|
Chris@16
|
331 registration* reg = impl.signals_;
|
Chris@16
|
332 while (reg && reg->signal_number_ < signal_number)
|
Chris@16
|
333 {
|
Chris@16
|
334 deletion_point = ®->next_in_set_;
|
Chris@16
|
335 reg = reg->next_in_set_;
|
Chris@16
|
336 }
|
Chris@16
|
337
|
Chris@16
|
338 if (reg != 0 && reg->signal_number_ == signal_number)
|
Chris@16
|
339 {
|
Chris@16
|
340 #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
341 // Set signal handler back to the default if we're the last.
|
Chris@16
|
342 if (state->registration_count_[signal_number] == 1)
|
Chris@16
|
343 {
|
Chris@16
|
344 # if defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
345 using namespace std; // For memset.
|
Chris@16
|
346 struct sigaction sa;
|
Chris@16
|
347 memset(&sa, 0, sizeof(sa));
|
Chris@16
|
348 sa.sa_handler = SIG_DFL;
|
Chris@16
|
349 if (::sigaction(signal_number, &sa, 0) == -1)
|
Chris@16
|
350 # else // defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
351 if (::signal(signal_number, SIG_DFL) == SIG_ERR)
|
Chris@16
|
352 # endif // defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
353 {
|
Chris@16
|
354 # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
355 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
356 # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
357 ec = boost::system::error_code(errno,
|
Chris@16
|
358 boost::asio::error::get_system_category());
|
Chris@16
|
359 # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
360 return ec;
|
Chris@16
|
361 }
|
Chris@16
|
362 }
|
Chris@16
|
363 #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
364
|
Chris@16
|
365 // Remove the registration from the set.
|
Chris@16
|
366 *deletion_point = reg->next_in_set_;
|
Chris@16
|
367
|
Chris@16
|
368 // Remove the registration from the registration table.
|
Chris@16
|
369 if (registrations_[signal_number] == reg)
|
Chris@16
|
370 registrations_[signal_number] = reg->next_in_table_;
|
Chris@16
|
371 if (reg->prev_in_table_)
|
Chris@16
|
372 reg->prev_in_table_->next_in_table_ = reg->next_in_table_;
|
Chris@16
|
373 if (reg->next_in_table_)
|
Chris@16
|
374 reg->next_in_table_->prev_in_table_ = reg->prev_in_table_;
|
Chris@16
|
375
|
Chris@16
|
376 --state->registration_count_[signal_number];
|
Chris@16
|
377
|
Chris@16
|
378 delete reg;
|
Chris@16
|
379 }
|
Chris@16
|
380
|
Chris@16
|
381 ec = boost::system::error_code();
|
Chris@16
|
382 return ec;
|
Chris@16
|
383 }
|
Chris@16
|
384
|
Chris@16
|
385 boost::system::error_code signal_set_service::clear(
|
Chris@16
|
386 signal_set_service::implementation_type& impl,
|
Chris@16
|
387 boost::system::error_code& ec)
|
Chris@16
|
388 {
|
Chris@16
|
389 signal_state* state = get_signal_state();
|
Chris@16
|
390 static_mutex::scoped_lock lock(state->mutex_);
|
Chris@16
|
391
|
Chris@16
|
392 while (registration* reg = impl.signals_)
|
Chris@16
|
393 {
|
Chris@16
|
394 #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
395 // Set signal handler back to the default if we're the last.
|
Chris@16
|
396 if (state->registration_count_[reg->signal_number_] == 1)
|
Chris@16
|
397 {
|
Chris@16
|
398 # if defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
399 using namespace std; // For memset.
|
Chris@16
|
400 struct sigaction sa;
|
Chris@16
|
401 memset(&sa, 0, sizeof(sa));
|
Chris@16
|
402 sa.sa_handler = SIG_DFL;
|
Chris@16
|
403 if (::sigaction(reg->signal_number_, &sa, 0) == -1)
|
Chris@16
|
404 # else // defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
405 if (::signal(reg->signal_number_, SIG_DFL) == SIG_ERR)
|
Chris@16
|
406 # endif // defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
407 {
|
Chris@16
|
408 # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
409 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
410 # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
411 ec = boost::system::error_code(errno,
|
Chris@16
|
412 boost::asio::error::get_system_category());
|
Chris@16
|
413 # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
414 return ec;
|
Chris@16
|
415 }
|
Chris@16
|
416 }
|
Chris@16
|
417 #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
|
Chris@16
|
418
|
Chris@16
|
419 // Remove the registration from the registration table.
|
Chris@16
|
420 if (registrations_[reg->signal_number_] == reg)
|
Chris@16
|
421 registrations_[reg->signal_number_] = reg->next_in_table_;
|
Chris@16
|
422 if (reg->prev_in_table_)
|
Chris@16
|
423 reg->prev_in_table_->next_in_table_ = reg->next_in_table_;
|
Chris@16
|
424 if (reg->next_in_table_)
|
Chris@16
|
425 reg->next_in_table_->prev_in_table_ = reg->prev_in_table_;
|
Chris@16
|
426
|
Chris@16
|
427 --state->registration_count_[reg->signal_number_];
|
Chris@16
|
428
|
Chris@16
|
429 impl.signals_ = reg->next_in_set_;
|
Chris@16
|
430 delete reg;
|
Chris@16
|
431 }
|
Chris@16
|
432
|
Chris@16
|
433 ec = boost::system::error_code();
|
Chris@16
|
434 return ec;
|
Chris@16
|
435 }
|
Chris@16
|
436
|
Chris@16
|
437 boost::system::error_code signal_set_service::cancel(
|
Chris@16
|
438 signal_set_service::implementation_type& impl,
|
Chris@16
|
439 boost::system::error_code& ec)
|
Chris@16
|
440 {
|
Chris@16
|
441 BOOST_ASIO_HANDLER_OPERATION(("signal_set", &impl, "cancel"));
|
Chris@16
|
442
|
Chris@16
|
443 op_queue<operation> ops;
|
Chris@16
|
444 {
|
Chris@16
|
445 signal_state* state = get_signal_state();
|
Chris@16
|
446 static_mutex::scoped_lock lock(state->mutex_);
|
Chris@16
|
447
|
Chris@16
|
448 while (signal_op* op = impl.queue_.front())
|
Chris@16
|
449 {
|
Chris@16
|
450 op->ec_ = boost::asio::error::operation_aborted;
|
Chris@16
|
451 impl.queue_.pop();
|
Chris@16
|
452 ops.push(op);
|
Chris@16
|
453 }
|
Chris@16
|
454 }
|
Chris@16
|
455
|
Chris@16
|
456 io_service_.post_deferred_completions(ops);
|
Chris@16
|
457
|
Chris@16
|
458 ec = boost::system::error_code();
|
Chris@16
|
459 return ec;
|
Chris@16
|
460 }
|
Chris@16
|
461
|
Chris@16
|
462 void signal_set_service::deliver_signal(int signal_number)
|
Chris@16
|
463 {
|
Chris@16
|
464 signal_state* state = get_signal_state();
|
Chris@16
|
465 static_mutex::scoped_lock lock(state->mutex_);
|
Chris@16
|
466
|
Chris@16
|
467 signal_set_service* service = state->service_list_;
|
Chris@16
|
468 while (service)
|
Chris@16
|
469 {
|
Chris@16
|
470 op_queue<operation> ops;
|
Chris@16
|
471
|
Chris@16
|
472 registration* reg = service->registrations_[signal_number];
|
Chris@16
|
473 while (reg)
|
Chris@16
|
474 {
|
Chris@16
|
475 if (reg->queue_->empty())
|
Chris@16
|
476 {
|
Chris@16
|
477 ++reg->undelivered_;
|
Chris@16
|
478 }
|
Chris@16
|
479 else
|
Chris@16
|
480 {
|
Chris@16
|
481 while (signal_op* op = reg->queue_->front())
|
Chris@16
|
482 {
|
Chris@16
|
483 op->signal_number_ = signal_number;
|
Chris@16
|
484 reg->queue_->pop();
|
Chris@16
|
485 ops.push(op);
|
Chris@16
|
486 }
|
Chris@16
|
487 }
|
Chris@16
|
488
|
Chris@16
|
489 reg = reg->next_in_table_;
|
Chris@16
|
490 }
|
Chris@16
|
491
|
Chris@16
|
492 service->io_service_.post_deferred_completions(ops);
|
Chris@16
|
493
|
Chris@16
|
494 service = service->next_;
|
Chris@16
|
495 }
|
Chris@16
|
496 }
|
Chris@16
|
497
|
Chris@16
|
498 void signal_set_service::add_service(signal_set_service* service)
|
Chris@16
|
499 {
|
Chris@16
|
500 signal_state* state = get_signal_state();
|
Chris@16
|
501 static_mutex::scoped_lock lock(state->mutex_);
|
Chris@16
|
502
|
Chris@16
|
503 #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
|
Chris@16
|
504 // If this is the first service to be created, open a new pipe.
|
Chris@16
|
505 if (state->service_list_ == 0)
|
Chris@16
|
506 open_descriptors();
|
Chris@16
|
507 #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
|
Chris@16
|
508
|
Chris@16
|
509 // Insert service into linked list of all services.
|
Chris@16
|
510 service->next_ = state->service_list_;
|
Chris@16
|
511 service->prev_ = 0;
|
Chris@16
|
512 if (state->service_list_)
|
Chris@16
|
513 state->service_list_->prev_ = service;
|
Chris@16
|
514 state->service_list_ = service;
|
Chris@16
|
515
|
Chris@16
|
516 #if !defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
517 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
|
Chris@16
|
518 && !defined(__CYGWIN__)
|
Chris@16
|
519 // Register for pipe readiness notifications.
|
Chris@16
|
520 int read_descriptor = state->read_descriptor_;
|
Chris@16
|
521 lock.unlock();
|
Chris@16
|
522 service->reactor_.register_internal_descriptor(reactor::read_op,
|
Chris@16
|
523 read_descriptor, service->reactor_data_, new pipe_read_op);
|
Chris@16
|
524 #endif // !defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
525 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
526 // && !defined(__CYGWIN__)
|
Chris@16
|
527 }
|
Chris@16
|
528
|
Chris@16
|
529 void signal_set_service::remove_service(signal_set_service* service)
|
Chris@16
|
530 {
|
Chris@16
|
531 signal_state* state = get_signal_state();
|
Chris@16
|
532 static_mutex::scoped_lock lock(state->mutex_);
|
Chris@16
|
533
|
Chris@16
|
534 if (service->next_ || service->prev_ || state->service_list_ == service)
|
Chris@16
|
535 {
|
Chris@16
|
536 #if !defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
537 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
|
Chris@16
|
538 && !defined(__CYGWIN__)
|
Chris@16
|
539 // Disable the pipe readiness notifications.
|
Chris@16
|
540 int read_descriptor = state->read_descriptor_;
|
Chris@16
|
541 lock.unlock();
|
Chris@16
|
542 service->reactor_.deregister_descriptor(
|
Chris@16
|
543 read_descriptor, service->reactor_data_, false);
|
Chris@16
|
544 lock.lock();
|
Chris@16
|
545 #endif // !defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
546 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
547 // && !defined(__CYGWIN__)
|
Chris@16
|
548
|
Chris@16
|
549 // Remove service from linked list of all services.
|
Chris@16
|
550 if (state->service_list_ == service)
|
Chris@16
|
551 state->service_list_ = service->next_;
|
Chris@16
|
552 if (service->prev_)
|
Chris@16
|
553 service->prev_->next_ = service->next_;
|
Chris@16
|
554 if (service->next_)
|
Chris@16
|
555 service->next_->prev_= service->prev_;
|
Chris@16
|
556 service->next_ = 0;
|
Chris@16
|
557 service->prev_ = 0;
|
Chris@16
|
558
|
Chris@16
|
559 #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
|
Chris@16
|
560 // If this is the last service to be removed, close the pipe.
|
Chris@16
|
561 if (state->service_list_ == 0)
|
Chris@16
|
562 close_descriptors();
|
Chris@16
|
563 #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
|
Chris@16
|
564 }
|
Chris@16
|
565 }
|
Chris@16
|
566
|
Chris@16
|
567 void signal_set_service::open_descriptors()
|
Chris@16
|
568 {
|
Chris@16
|
569 #if !defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
570 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
|
Chris@16
|
571 && !defined(__CYGWIN__)
|
Chris@16
|
572 signal_state* state = get_signal_state();
|
Chris@16
|
573
|
Chris@16
|
574 int pipe_fds[2];
|
Chris@16
|
575 if (::pipe(pipe_fds) == 0)
|
Chris@16
|
576 {
|
Chris@16
|
577 state->read_descriptor_ = pipe_fds[0];
|
Chris@16
|
578 ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK);
|
Chris@16
|
579
|
Chris@16
|
580 state->write_descriptor_ = pipe_fds[1];
|
Chris@16
|
581 ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK);
|
Chris@16
|
582
|
Chris@16
|
583 #if defined(FD_CLOEXEC)
|
Chris@16
|
584 ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC);
|
Chris@16
|
585 ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC);
|
Chris@16
|
586 #endif // defined(FD_CLOEXEC)
|
Chris@16
|
587 }
|
Chris@16
|
588 else
|
Chris@16
|
589 {
|
Chris@16
|
590 boost::system::error_code ec(errno,
|
Chris@16
|
591 boost::asio::error::get_system_category());
|
Chris@16
|
592 boost::asio::detail::throw_error(ec, "signal_set_service pipe");
|
Chris@16
|
593 }
|
Chris@16
|
594 #endif // !defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
595 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
596 // && !defined(__CYGWIN__)
|
Chris@16
|
597 }
|
Chris@16
|
598
|
Chris@16
|
599 void signal_set_service::close_descriptors()
|
Chris@16
|
600 {
|
Chris@16
|
601 #if !defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
602 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
|
Chris@16
|
603 && !defined(__CYGWIN__)
|
Chris@16
|
604 signal_state* state = get_signal_state();
|
Chris@16
|
605
|
Chris@16
|
606 if (state->read_descriptor_ != -1)
|
Chris@16
|
607 ::close(state->read_descriptor_);
|
Chris@16
|
608 state->read_descriptor_ = -1;
|
Chris@16
|
609
|
Chris@16
|
610 if (state->write_descriptor_ != -1)
|
Chris@16
|
611 ::close(state->write_descriptor_);
|
Chris@16
|
612 state->write_descriptor_ = -1;
|
Chris@16
|
613 #endif // !defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
614 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
615 // && !defined(__CYGWIN__)
|
Chris@16
|
616 }
|
Chris@16
|
617
|
Chris@16
|
618 void signal_set_service::start_wait_op(
|
Chris@16
|
619 signal_set_service::implementation_type& impl, signal_op* op)
|
Chris@16
|
620 {
|
Chris@16
|
621 io_service_.work_started();
|
Chris@16
|
622
|
Chris@16
|
623 signal_state* state = get_signal_state();
|
Chris@16
|
624 static_mutex::scoped_lock lock(state->mutex_);
|
Chris@16
|
625
|
Chris@16
|
626 registration* reg = impl.signals_;
|
Chris@16
|
627 while (reg)
|
Chris@16
|
628 {
|
Chris@16
|
629 if (reg->undelivered_ > 0)
|
Chris@16
|
630 {
|
Chris@16
|
631 --reg->undelivered_;
|
Chris@16
|
632 op->signal_number_ = reg->signal_number_;
|
Chris@16
|
633 io_service_.post_deferred_completion(op);
|
Chris@16
|
634 return;
|
Chris@16
|
635 }
|
Chris@16
|
636
|
Chris@16
|
637 reg = reg->next_in_set_;
|
Chris@16
|
638 }
|
Chris@16
|
639
|
Chris@16
|
640 impl.queue_.push(op);
|
Chris@16
|
641 }
|
Chris@16
|
642
|
Chris@16
|
643 } // namespace detail
|
Chris@16
|
644 } // namespace asio
|
Chris@16
|
645 } // namespace boost
|
Chris@16
|
646
|
Chris@16
|
647 #include <boost/asio/detail/pop_options.hpp>
|
Chris@16
|
648
|
Chris@16
|
649 #endif // BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
|