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