Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:02:39

0001 //
0002 // detail/impl/signal_set_service.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
0012 #define BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #include <cstring>
0021 #include <stdexcept>
0022 #include <boost/asio/detail/signal_blocker.hpp>
0023 #include <boost/asio/detail/signal_set_service.hpp>
0024 #include <boost/asio/detail/static_mutex.hpp>
0025 #include <boost/asio/detail/throw_exception.hpp>
0026 
0027 #if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0028 # include <boost/asio/detail/io_uring_service.hpp>
0029 #else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0030 # include <boost/asio/detail/reactor.hpp>
0031 #endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0032 
0033 #include <boost/asio/detail/push_options.hpp>
0034 
0035 namespace boost {
0036 namespace asio {
0037 namespace detail {
0038 
0039 struct signal_state
0040 {
0041   // Mutex used for protecting global state.
0042   static_mutex mutex_;
0043 
0044   // The read end of the pipe used for signal notifications.
0045   int read_descriptor_;
0046 
0047   // The write end of the pipe used for signal notifications.
0048   int write_descriptor_;
0049 
0050   // Whether the signal state has been prepared for a fork.
0051   bool fork_prepared_;
0052 
0053   // The head of a linked list of all signal_set_service instances.
0054   class signal_set_service* service_list_;
0055 
0056   // A count of the number of objects that are registered for each signal.
0057   std::size_t registration_count_[max_signal_number];
0058 
0059   // The flags used for each registered signal.
0060   signal_set_base::flags_t flags_[max_signal_number];
0061 };
0062 
0063 signal_state* get_signal_state()
0064 {
0065   static signal_state state = {
0066     BOOST_ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0,
0067     { 0 }, { signal_set_base::flags_t() } };
0068   return &state;
0069 }
0070 
0071 void boost_asio_signal_handler(int signal_number)
0072 {
0073 #if defined(BOOST_ASIO_WINDOWS) \
0074   || defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0075   || defined(__CYGWIN__)
0076   signal_set_service::deliver_signal(signal_number);
0077 #else // defined(BOOST_ASIO_WINDOWS)
0078       //   || defined(BOOST_ASIO_WINDOWS_RUNTIME)
0079       //   || defined(__CYGWIN__)
0080   int saved_errno = errno;
0081   signal_state* state = get_signal_state();
0082   signed_size_type result = ::write(state->write_descriptor_,
0083       &signal_number, sizeof(signal_number));
0084   (void)result;
0085   errno = saved_errno;
0086 #endif // defined(BOOST_ASIO_WINDOWS)
0087        //   || defined(BOOST_ASIO_WINDOWS_RUNTIME)
0088        //   || defined(__CYGWIN__)
0089 
0090 #if defined(BOOST_ASIO_HAS_SIGNAL) && !defined(BOOST_ASIO_HAS_SIGACTION)
0091   ::signal(signal_number, boost_asio_signal_handler);
0092 #endif // defined(BOOST_ASIO_HAS_SIGNAL) && !defined(BOOST_ASIO_HAS_SIGACTION)
0093 }
0094 
0095 #if !defined(BOOST_ASIO_WINDOWS) \
0096   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0097   && !defined(__CYGWIN__)
0098 class signal_set_service::pipe_read_op :
0099 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0100   public io_uring_operation
0101 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0102   public reactor_op
0103 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0104 {
0105 public:
0106 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0107   pipe_read_op()
0108     : io_uring_operation(boost::system::error_code(), &pipe_read_op::do_prepare,
0109         &pipe_read_op::do_perform, pipe_read_op::do_complete)
0110   {
0111   }
0112 
0113   static void do_prepare(io_uring_operation*, ::io_uring_sqe* sqe)
0114   {
0115     signal_state* state = get_signal_state();
0116 
0117     int fd = state->read_descriptor_;
0118     ::io_uring_prep_poll_add(sqe, fd, POLLIN);
0119   }
0120 
0121   static bool do_perform(io_uring_operation*, bool)
0122   {
0123     signal_state* state = get_signal_state();
0124 
0125     int fd = state->read_descriptor_;
0126     int signal_number = 0;
0127     while (::read(fd, &signal_number, sizeof(int)) == sizeof(int))
0128       if (signal_number >= 0 && signal_number < max_signal_number)
0129         signal_set_service::deliver_signal(signal_number);
0130 
0131     return false;
0132   }
0133 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0134   pipe_read_op()
0135     : reactor_op(boost::system::error_code(),
0136         &pipe_read_op::do_perform, pipe_read_op::do_complete)
0137   {
0138   }
0139 
0140   static status do_perform(reactor_op*)
0141   {
0142     signal_state* state = get_signal_state();
0143 
0144     int fd = state->read_descriptor_;
0145     int signal_number = 0;
0146     while (::read(fd, &signal_number, sizeof(int)) == sizeof(int))
0147       if (signal_number >= 0 && signal_number < max_signal_number)
0148         signal_set_service::deliver_signal(signal_number);
0149 
0150     return not_done;
0151   }
0152 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0153 
0154   static void do_complete(void* /*owner*/, operation* base,
0155       const boost::system::error_code& /*ec*/,
0156       std::size_t /*bytes_transferred*/)
0157   {
0158     pipe_read_op* o(static_cast<pipe_read_op*>(base));
0159     delete o;
0160   }
0161 };
0162 #endif // !defined(BOOST_ASIO_WINDOWS)
0163        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0164        //   && !defined(__CYGWIN__)
0165 
0166 signal_set_service::signal_set_service(execution_context& context)
0167   : execution_context_service_base<signal_set_service>(context),
0168     scheduler_(boost::asio::use_service<scheduler_impl>(context)),
0169 #if !defined(BOOST_ASIO_WINDOWS) \
0170   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0171   && !defined(__CYGWIN__)
0172 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0173     io_uring_service_(boost::asio::use_service<io_uring_service>(context)),
0174 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0175     reactor_(boost::asio::use_service<reactor>(context)),
0176 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0177 #endif // !defined(BOOST_ASIO_WINDOWS)
0178        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0179        //   && !defined(__CYGWIN__)
0180     next_(0),
0181     prev_(0)
0182 {
0183   get_signal_state()->mutex_.init();
0184 
0185 #if !defined(BOOST_ASIO_WINDOWS) \
0186   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0187   && !defined(__CYGWIN__)
0188 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0189   io_uring_service_.init_task();
0190 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0191   reactor_.init_task();
0192 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0193 #endif // !defined(BOOST_ASIO_WINDOWS)
0194        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0195        //   && !defined(__CYGWIN__)
0196 
0197   for (int i = 0; i < max_signal_number; ++i)
0198     registrations_[i] = 0;
0199 
0200   add_service(this);
0201 }
0202 
0203 signal_set_service::~signal_set_service()
0204 {
0205   remove_service(this);
0206 }
0207 
0208 void signal_set_service::shutdown()
0209 {
0210   remove_service(this);
0211 
0212   op_queue<operation> ops;
0213 
0214   for (int i = 0; i < max_signal_number; ++i)
0215   {
0216     registration* reg = registrations_[i];
0217     while (reg)
0218     {
0219       ops.push(*reg->queue_);
0220       reg = reg->next_in_table_;
0221     }
0222   }
0223 
0224   scheduler_.abandon_operations(ops);
0225 }
0226 
0227 void signal_set_service::notify_fork(execution_context::fork_event fork_ev)
0228 {
0229 #if !defined(BOOST_ASIO_WINDOWS) \
0230   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0231   && !defined(__CYGWIN__)
0232   signal_state* state = get_signal_state();
0233   static_mutex::scoped_lock lock(state->mutex_);
0234 
0235   switch (fork_ev)
0236   {
0237   case execution_context::fork_prepare:
0238     {
0239       int read_descriptor = state->read_descriptor_;
0240       state->fork_prepared_ = true;
0241       lock.unlock();
0242 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0243       (void)read_descriptor;
0244       io_uring_service_.deregister_io_object(io_object_data_);
0245       io_uring_service_.cleanup_io_object(io_object_data_);
0246 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0247       reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_);
0248       reactor_.cleanup_descriptor_data(reactor_data_);
0249 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0250     }
0251     break;
0252   case execution_context::fork_parent:
0253     if (state->fork_prepared_)
0254     {
0255       int read_descriptor = state->read_descriptor_;
0256       state->fork_prepared_ = false;
0257       lock.unlock();
0258 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0259       (void)read_descriptor;
0260       io_uring_service_.register_internal_io_object(io_object_data_,
0261           io_uring_service::read_op, new pipe_read_op);
0262 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0263       reactor_.register_internal_descriptor(reactor::read_op,
0264           read_descriptor, reactor_data_, new pipe_read_op);
0265 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0266     }
0267     break;
0268   case execution_context::fork_child:
0269     if (state->fork_prepared_)
0270     {
0271       boost::asio::detail::signal_blocker blocker;
0272       close_descriptors();
0273       open_descriptors();
0274       int read_descriptor = state->read_descriptor_;
0275       state->fork_prepared_ = false;
0276       lock.unlock();
0277 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0278       (void)read_descriptor;
0279       io_uring_service_.register_internal_io_object(io_object_data_,
0280           io_uring_service::read_op, new pipe_read_op);
0281 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0282       reactor_.register_internal_descriptor(reactor::read_op,
0283           read_descriptor, reactor_data_, new pipe_read_op);
0284 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0285     }
0286     break;
0287   default:
0288     break;
0289   }
0290 #else // !defined(BOOST_ASIO_WINDOWS)
0291       //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0292       //   && !defined(__CYGWIN__)
0293   (void)fork_ev;
0294 #endif // !defined(BOOST_ASIO_WINDOWS)
0295        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0296        //   && !defined(__CYGWIN__)
0297 }
0298 
0299 void signal_set_service::construct(
0300     signal_set_service::implementation_type& impl)
0301 {
0302   impl.signals_ = 0;
0303 }
0304 
0305 void signal_set_service::destroy(
0306     signal_set_service::implementation_type& impl)
0307 {
0308   boost::system::error_code ignored_ec;
0309   clear(impl, ignored_ec);
0310   cancel(impl, ignored_ec);
0311 }
0312 
0313 boost::system::error_code signal_set_service::add(
0314     signal_set_service::implementation_type& impl, int signal_number,
0315     signal_set_base::flags_t f, boost::system::error_code& ec)
0316 {
0317   // Check that the signal number is valid.
0318   if (signal_number < 0 || signal_number >= max_signal_number)
0319   {
0320     ec = boost::asio::error::invalid_argument;
0321     return ec;
0322   }
0323 
0324   // Check that the specified flags are supported.
0325 #if !defined(BOOST_ASIO_HAS_SIGACTION)
0326   if (f != signal_set_base::flags::dont_care)
0327   {
0328     ec = boost::asio::error::operation_not_supported;
0329     return ec;
0330   }
0331 #endif // !defined(BOOST_ASIO_HAS_SIGACTION)
0332 
0333   signal_state* state = get_signal_state();
0334   static_mutex::scoped_lock lock(state->mutex_);
0335 
0336   // Find the appropriate place to insert the registration.
0337   registration** insertion_point = &impl.signals_;
0338   registration* next = impl.signals_;
0339   while (next && next->signal_number_ < signal_number)
0340   {
0341     insertion_point = &next->next_in_set_;
0342     next = next->next_in_set_;
0343   }
0344 
0345   // Only do something if the signal is not already registered.
0346   if (next == 0 || next->signal_number_ != signal_number)
0347   {
0348     registration* new_registration = new registration;
0349 
0350 #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
0351     // Register for the signal if we're the first.
0352     if (state->registration_count_[signal_number] == 0)
0353     {
0354 # if defined(BOOST_ASIO_HAS_SIGACTION)
0355       using namespace std; // For memset.
0356       struct sigaction sa;
0357       memset(&sa, 0, sizeof(sa));
0358       sa.sa_handler = boost_asio_signal_handler;
0359       sigfillset(&sa.sa_mask);
0360       if (f != signal_set_base::flags::dont_care)
0361         sa.sa_flags = static_cast<int>(f);
0362       if (::sigaction(signal_number, &sa, 0) == -1)
0363 # else // defined(BOOST_ASIO_HAS_SIGACTION)
0364       if (::signal(signal_number, boost_asio_signal_handler) == SIG_ERR)
0365 # endif // defined(BOOST_ASIO_HAS_SIGACTION)
0366       {
0367 # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0368         ec = boost::asio::error::invalid_argument;
0369 # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0370         ec = boost::system::error_code(errno,
0371             boost::asio::error::get_system_category());
0372 # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0373         delete new_registration;
0374         return ec;
0375       }
0376 # if defined(BOOST_ASIO_HAS_SIGACTION)
0377       state->flags_[signal_number] = f;
0378 # endif // defined(BOOST_ASIO_HAS_SIGACTION)
0379     }
0380 # if defined(BOOST_ASIO_HAS_SIGACTION)
0381     // Otherwise check to see if the flags have changed.
0382     else if (f != signal_set_base::flags::dont_care)
0383     {
0384       if (f != state->flags_[signal_number])
0385       {
0386         using namespace std; // For memset.
0387         if (state->flags_[signal_number] != signal_set_base::flags::dont_care)
0388         {
0389           ec = boost::asio::error::invalid_argument;
0390           delete new_registration;
0391           return ec;
0392         }
0393         struct sigaction sa;
0394         memset(&sa, 0, sizeof(sa));
0395         sa.sa_handler = boost_asio_signal_handler;
0396         sigfillset(&sa.sa_mask);
0397         sa.sa_flags = static_cast<int>(f);
0398         if (::sigaction(signal_number, &sa, 0) == -1)
0399         {
0400           ec = boost::system::error_code(errno,
0401               boost::asio::error::get_system_category());
0402           delete new_registration;
0403           return ec;
0404         }
0405         state->flags_[signal_number] = f;
0406       }
0407     }
0408 # endif // defined(BOOST_ASIO_HAS_SIGACTION)
0409 #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
0410 
0411     // Record the new registration in the set.
0412     new_registration->signal_number_ = signal_number;
0413     new_registration->queue_ = &impl.queue_;
0414     new_registration->next_in_set_ = next;
0415     *insertion_point = new_registration;
0416 
0417     // Insert registration into the registration table.
0418     new_registration->next_in_table_ = registrations_[signal_number];
0419     if (registrations_[signal_number])
0420       registrations_[signal_number]->prev_in_table_ = new_registration;
0421     registrations_[signal_number] = new_registration;
0422 
0423     ++state->registration_count_[signal_number];
0424   }
0425 
0426   ec = boost::system::error_code();
0427   return ec;
0428 }
0429 
0430 boost::system::error_code signal_set_service::remove(
0431     signal_set_service::implementation_type& impl,
0432     int signal_number, boost::system::error_code& ec)
0433 {
0434   // Check that the signal number is valid.
0435   if (signal_number < 0 || signal_number >= max_signal_number)
0436   {
0437     ec = boost::asio::error::invalid_argument;
0438     return ec;
0439   }
0440 
0441   signal_state* state = get_signal_state();
0442   static_mutex::scoped_lock lock(state->mutex_);
0443 
0444   // Find the signal number in the list of registrations.
0445   registration** deletion_point = &impl.signals_;
0446   registration* reg = impl.signals_;
0447   while (reg && reg->signal_number_ < signal_number)
0448   {
0449     deletion_point = &reg->next_in_set_;
0450     reg = reg->next_in_set_;
0451   }
0452 
0453   if (reg != 0 && reg->signal_number_ == signal_number)
0454   {
0455 #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
0456     // Set signal handler back to the default if we're the last.
0457     if (state->registration_count_[signal_number] == 1)
0458     {
0459 # if defined(BOOST_ASIO_HAS_SIGACTION)
0460       using namespace std; // For memset.
0461       struct sigaction sa;
0462       memset(&sa, 0, sizeof(sa));
0463       sa.sa_handler = SIG_DFL;
0464       if (::sigaction(signal_number, &sa, 0) == -1)
0465 # else // defined(BOOST_ASIO_HAS_SIGACTION)
0466       if (::signal(signal_number, SIG_DFL) == SIG_ERR)
0467 # endif // defined(BOOST_ASIO_HAS_SIGACTION)
0468       {
0469 # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0470         ec = boost::asio::error::invalid_argument;
0471 # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0472         ec = boost::system::error_code(errno,
0473             boost::asio::error::get_system_category());
0474 # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0475         return ec;
0476       }
0477 # if defined(BOOST_ASIO_HAS_SIGACTION)
0478       state->flags_[signal_number] = signal_set_base::flags_t();
0479 # endif // defined(BOOST_ASIO_HAS_SIGACTION)
0480     }
0481 #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
0482 
0483     // Remove the registration from the set.
0484     *deletion_point = reg->next_in_set_;
0485 
0486     // Remove the registration from the registration table.
0487     if (registrations_[signal_number] == reg)
0488       registrations_[signal_number] = reg->next_in_table_;
0489     if (reg->prev_in_table_)
0490       reg->prev_in_table_->next_in_table_ = reg->next_in_table_;
0491     if (reg->next_in_table_)
0492       reg->next_in_table_->prev_in_table_ = reg->prev_in_table_;
0493 
0494     --state->registration_count_[signal_number];
0495 
0496     delete reg;
0497   }
0498 
0499   ec = boost::system::error_code();
0500   return ec;
0501 }
0502 
0503 boost::system::error_code signal_set_service::clear(
0504     signal_set_service::implementation_type& impl,
0505     boost::system::error_code& ec)
0506 {
0507   signal_state* state = get_signal_state();
0508   static_mutex::scoped_lock lock(state->mutex_);
0509 
0510   while (registration* reg = impl.signals_)
0511   {
0512 #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
0513     // Set signal handler back to the default if we're the last.
0514     if (state->registration_count_[reg->signal_number_] == 1)
0515     {
0516 # if defined(BOOST_ASIO_HAS_SIGACTION)
0517       using namespace std; // For memset.
0518       struct sigaction sa;
0519       memset(&sa, 0, sizeof(sa));
0520       sa.sa_handler = SIG_DFL;
0521       if (::sigaction(reg->signal_number_, &sa, 0) == -1)
0522 # else // defined(BOOST_ASIO_HAS_SIGACTION)
0523       if (::signal(reg->signal_number_, SIG_DFL) == SIG_ERR)
0524 # endif // defined(BOOST_ASIO_HAS_SIGACTION)
0525       {
0526 # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0527         ec = boost::asio::error::invalid_argument;
0528 # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0529         ec = boost::system::error_code(errno,
0530             boost::asio::error::get_system_category());
0531 # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0532         return ec;
0533       }
0534 # if defined(BOOST_ASIO_HAS_SIGACTION)
0535       state->flags_[reg->signal_number_] = signal_set_base::flags_t();
0536 # endif // defined(BOOST_ASIO_HAS_SIGACTION)
0537     }
0538 #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
0539 
0540     // Remove the registration from the registration table.
0541     if (registrations_[reg->signal_number_] == reg)
0542       registrations_[reg->signal_number_] = reg->next_in_table_;
0543     if (reg->prev_in_table_)
0544       reg->prev_in_table_->next_in_table_ = reg->next_in_table_;
0545     if (reg->next_in_table_)
0546       reg->next_in_table_->prev_in_table_ = reg->prev_in_table_;
0547 
0548     --state->registration_count_[reg->signal_number_];
0549 
0550     impl.signals_ = reg->next_in_set_;
0551     delete reg;
0552   }
0553 
0554   ec = boost::system::error_code();
0555   return ec;
0556 }
0557 
0558 boost::system::error_code signal_set_service::cancel(
0559     signal_set_service::implementation_type& impl,
0560     boost::system::error_code& ec)
0561 {
0562   BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(),
0563         "signal_set", &impl, 0, "cancel"));
0564 
0565   op_queue<operation> ops;
0566   {
0567     signal_state* state = get_signal_state();
0568     static_mutex::scoped_lock lock(state->mutex_);
0569 
0570     while (signal_op* op = impl.queue_.front())
0571     {
0572       op->ec_ = boost::asio::error::operation_aborted;
0573       impl.queue_.pop();
0574       ops.push(op);
0575     }
0576   }
0577 
0578   scheduler_.post_deferred_completions(ops);
0579 
0580   ec = boost::system::error_code();
0581   return ec;
0582 }
0583 
0584 void signal_set_service::cancel_ops_by_key(
0585     signal_set_service::implementation_type& impl, void* cancellation_key)
0586 {
0587   op_queue<operation> ops;
0588   {
0589     op_queue<signal_op> other_ops;
0590     signal_state* state = get_signal_state();
0591     static_mutex::scoped_lock lock(state->mutex_);
0592 
0593     while (signal_op* op = impl.queue_.front())
0594     {
0595       impl.queue_.pop();
0596       if (op->cancellation_key_ == cancellation_key)
0597       {
0598         op->ec_ = boost::asio::error::operation_aborted;
0599         ops.push(op);
0600       }
0601       else
0602         other_ops.push(op);
0603     }
0604 
0605     impl.queue_.push(other_ops);
0606   }
0607 
0608   scheduler_.post_deferred_completions(ops);
0609 }
0610 
0611 void signal_set_service::deliver_signal(int signal_number)
0612 {
0613   signal_state* state = get_signal_state();
0614   static_mutex::scoped_lock lock(state->mutex_);
0615 
0616   signal_set_service* service = state->service_list_;
0617   while (service)
0618   {
0619     op_queue<operation> ops;
0620 
0621     registration* reg = service->registrations_[signal_number];
0622     while (reg)
0623     {
0624       if (reg->queue_->empty())
0625       {
0626         ++reg->undelivered_;
0627       }
0628       else
0629       {
0630         while (signal_op* op = reg->queue_->front())
0631         {
0632           op->signal_number_ = signal_number;
0633           reg->queue_->pop();
0634           ops.push(op);
0635         }
0636       }
0637 
0638       reg = reg->next_in_table_;
0639     }
0640 
0641     service->scheduler_.post_deferred_completions(ops);
0642 
0643     service = service->next_;
0644   }
0645 }
0646 
0647 void signal_set_service::add_service(signal_set_service* service)
0648 {
0649   signal_state* state = get_signal_state();
0650   static_mutex::scoped_lock lock(state->mutex_);
0651 
0652 #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
0653   // If this is the first service to be created, open a new pipe.
0654   if (state->service_list_ == 0)
0655     open_descriptors();
0656 #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
0657 
0658   // If a scheduler_ object is thread-unsafe then it must be the only
0659   // scheduler used to create signal_set objects.
0660   if (state->service_list_ != 0)
0661   {
0662     if (!BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
0663           service->scheduler_.concurrency_hint())
0664         || !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
0665           state->service_list_->scheduler_.concurrency_hint()))
0666     {
0667       std::logic_error ex(
0668           "Thread-unsafe execution context objects require "
0669           "exclusive access to signal handling.");
0670       boost::asio::detail::throw_exception(ex);
0671     }
0672   }
0673 
0674   // Insert service into linked list of all services.
0675   service->next_ = state->service_list_;
0676   service->prev_ = 0;
0677   if (state->service_list_)
0678     state->service_list_->prev_ = service;
0679   state->service_list_ = service;
0680 
0681 #if !defined(BOOST_ASIO_WINDOWS) \
0682   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0683   && !defined(__CYGWIN__)
0684   // Register for pipe readiness notifications.
0685   int read_descriptor = state->read_descriptor_;
0686   lock.unlock();
0687 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0688   (void)read_descriptor;
0689   service->io_uring_service_.register_internal_io_object(
0690       service->io_object_data_, io_uring_service::read_op, new pipe_read_op);
0691 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0692   service->reactor_.register_internal_descriptor(reactor::read_op,
0693       read_descriptor, service->reactor_data_, new pipe_read_op);
0694 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0695 #endif // !defined(BOOST_ASIO_WINDOWS)
0696        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0697        //   && !defined(__CYGWIN__)
0698 }
0699 
0700 void signal_set_service::remove_service(signal_set_service* service)
0701 {
0702   signal_state* state = get_signal_state();
0703   static_mutex::scoped_lock lock(state->mutex_);
0704 
0705   if (service->next_ || service->prev_ || state->service_list_ == service)
0706   {
0707 #if !defined(BOOST_ASIO_WINDOWS) \
0708   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0709   && !defined(__CYGWIN__)
0710     // Disable the pipe readiness notifications.
0711     int read_descriptor = state->read_descriptor_;
0712     lock.unlock();
0713 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0714     (void)read_descriptor;
0715     service->io_uring_service_.deregister_io_object(service->io_object_data_);
0716     service->io_uring_service_.cleanup_io_object(service->io_object_data_);
0717     lock.lock();
0718 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0719     service->reactor_.deregister_internal_descriptor(
0720         read_descriptor, service->reactor_data_);
0721     service->reactor_.cleanup_descriptor_data(service->reactor_data_);
0722     lock.lock();
0723 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0724 #endif // !defined(BOOST_ASIO_WINDOWS)
0725        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0726        //   && !defined(__CYGWIN__)
0727 
0728     // Remove service from linked list of all services.
0729     if (state->service_list_ == service)
0730       state->service_list_ = service->next_;
0731     if (service->prev_)
0732       service->prev_->next_ = service->next_;
0733     if (service->next_)
0734       service->next_->prev_= service->prev_;
0735     service->next_ = 0;
0736     service->prev_ = 0;
0737 
0738 #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
0739     // If this is the last service to be removed, close the pipe.
0740     if (state->service_list_ == 0)
0741       close_descriptors();
0742 #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
0743   }
0744 }
0745 
0746 void signal_set_service::open_descriptors()
0747 {
0748 #if !defined(BOOST_ASIO_WINDOWS) \
0749   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0750   && !defined(__CYGWIN__)
0751   signal_state* state = get_signal_state();
0752 
0753   int pipe_fds[2];
0754   if (::pipe(pipe_fds) == 0)
0755   {
0756     state->read_descriptor_ = pipe_fds[0];
0757     ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK);
0758 
0759     state->write_descriptor_ = pipe_fds[1];
0760     ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK);
0761 
0762 #if defined(FD_CLOEXEC)
0763     ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC);
0764     ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC);
0765 #endif // defined(FD_CLOEXEC)
0766   }
0767   else
0768   {
0769     boost::system::error_code ec(errno,
0770         boost::asio::error::get_system_category());
0771     boost::asio::detail::throw_error(ec, "signal_set_service pipe");
0772   }
0773 #endif // !defined(BOOST_ASIO_WINDOWS)
0774        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0775        //   && !defined(__CYGWIN__)
0776 }
0777 
0778 void signal_set_service::close_descriptors()
0779 {
0780 #if !defined(BOOST_ASIO_WINDOWS) \
0781   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0782   && !defined(__CYGWIN__)
0783   signal_state* state = get_signal_state();
0784 
0785   if (state->read_descriptor_ != -1)
0786     ::close(state->read_descriptor_);
0787   state->read_descriptor_ = -1;
0788 
0789   if (state->write_descriptor_ != -1)
0790     ::close(state->write_descriptor_);
0791   state->write_descriptor_ = -1;
0792 #endif // !defined(BOOST_ASIO_WINDOWS)
0793        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0794        //   && !defined(__CYGWIN__)
0795 }
0796 
0797 void signal_set_service::start_wait_op(
0798     signal_set_service::implementation_type& impl, signal_op* op)
0799 {
0800   scheduler_.work_started();
0801 
0802   signal_state* state = get_signal_state();
0803   static_mutex::scoped_lock lock(state->mutex_);
0804 
0805   registration* reg = impl.signals_;
0806   while (reg)
0807   {
0808     if (reg->undelivered_ > 0)
0809     {
0810       --reg->undelivered_;
0811       op->signal_number_ = reg->signal_number_;
0812       scheduler_.post_deferred_completion(op);
0813       return;
0814     }
0815 
0816     reg = reg->next_in_set_;
0817   }
0818 
0819   impl.queue_.push(op);
0820 }
0821 
0822 } // namespace detail
0823 } // namespace asio
0824 } // namespace boost
0825 
0826 #include <boost/asio/detail/pop_options.hpp>
0827 
0828 #endif // BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP