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