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