Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-31 08:33:32

0001 //
0002 // detail/impl/signal_set_service.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2025 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 (!config(service->context()).get("scheduler", "locking", true)
0663         || !config(state->service_list_->context()).get(
0664             "scheduler", "locking", true))
0665     {
0666       std::logic_error ex(
0667           "Thread-unsafe execution context objects require "
0668           "exclusive access to signal handling.");
0669       boost::asio::detail::throw_exception(ex);
0670     }
0671   }
0672 
0673   // Insert service into linked list of all services.
0674   service->next_ = state->service_list_;
0675   service->prev_ = 0;
0676   if (state->service_list_)
0677     state->service_list_->prev_ = service;
0678   state->service_list_ = service;
0679 
0680 #if !defined(BOOST_ASIO_WINDOWS) \
0681   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0682   && !defined(__CYGWIN__)
0683   // Register for pipe readiness notifications.
0684   int read_descriptor = state->read_descriptor_;
0685   lock.unlock();
0686 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0687   (void)read_descriptor;
0688   service->io_uring_service_.register_internal_io_object(
0689       service->io_object_data_, io_uring_service::read_op, new pipe_read_op);
0690 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0691   service->reactor_.register_internal_descriptor(reactor::read_op,
0692       read_descriptor, service->reactor_data_, new pipe_read_op);
0693 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0694 #endif // !defined(BOOST_ASIO_WINDOWS)
0695        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0696        //   && !defined(__CYGWIN__)
0697 }
0698 
0699 void signal_set_service::remove_service(signal_set_service* service)
0700 {
0701   signal_state* state = get_signal_state();
0702   static_mutex::scoped_lock lock(state->mutex_);
0703 
0704   if (service->next_ || service->prev_ || state->service_list_ == service)
0705   {
0706 #if !defined(BOOST_ASIO_WINDOWS) \
0707   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0708   && !defined(__CYGWIN__)
0709     // Disable the pipe readiness notifications.
0710     int read_descriptor = state->read_descriptor_;
0711     lock.unlock();
0712 # if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0713     (void)read_descriptor;
0714     service->io_uring_service_.deregister_io_object(service->io_object_data_);
0715     service->io_uring_service_.cleanup_io_object(service->io_object_data_);
0716     lock.lock();
0717 # else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0718     service->reactor_.deregister_internal_descriptor(
0719         read_descriptor, service->reactor_data_);
0720     service->reactor_.cleanup_descriptor_data(service->reactor_data_);
0721     lock.lock();
0722 # endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
0723 #endif // !defined(BOOST_ASIO_WINDOWS)
0724        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0725        //   && !defined(__CYGWIN__)
0726 
0727     // Remove service from linked list of all services.
0728     if (state->service_list_ == service)
0729       state->service_list_ = service->next_;
0730     if (service->prev_)
0731       service->prev_->next_ = service->next_;
0732     if (service->next_)
0733       service->next_->prev_= service->prev_;
0734     service->next_ = 0;
0735     service->prev_ = 0;
0736 
0737 #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
0738     // If this is the last service to be removed, close the pipe.
0739     if (state->service_list_ == 0)
0740       close_descriptors();
0741 #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
0742   }
0743 }
0744 
0745 void signal_set_service::open_descriptors()
0746 {
0747 #if !defined(BOOST_ASIO_WINDOWS) \
0748   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0749   && !defined(__CYGWIN__)
0750   signal_state* state = get_signal_state();
0751 
0752   int pipe_fds[2];
0753   if (::pipe(pipe_fds) == 0)
0754   {
0755     state->read_descriptor_ = pipe_fds[0];
0756     ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK);
0757 
0758     state->write_descriptor_ = pipe_fds[1];
0759     ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK);
0760 
0761 #if defined(FD_CLOEXEC)
0762     ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC);
0763     ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC);
0764 #endif // defined(FD_CLOEXEC)
0765   }
0766   else
0767   {
0768     boost::system::error_code ec(errno,
0769         boost::asio::error::get_system_category());
0770     boost::asio::detail::throw_error(ec, "signal_set_service pipe");
0771   }
0772 #endif // !defined(BOOST_ASIO_WINDOWS)
0773        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0774        //   && !defined(__CYGWIN__)
0775 }
0776 
0777 void signal_set_service::close_descriptors()
0778 {
0779 #if !defined(BOOST_ASIO_WINDOWS) \
0780   && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
0781   && !defined(__CYGWIN__)
0782   signal_state* state = get_signal_state();
0783 
0784   if (state->read_descriptor_ != -1)
0785     ::close(state->read_descriptor_);
0786   state->read_descriptor_ = -1;
0787 
0788   if (state->write_descriptor_ != -1)
0789     ::close(state->write_descriptor_);
0790   state->write_descriptor_ = -1;
0791 #endif // !defined(BOOST_ASIO_WINDOWS)
0792        //   && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
0793        //   && !defined(__CYGWIN__)
0794 }
0795 
0796 void signal_set_service::start_wait_op(
0797     signal_set_service::implementation_type& impl, signal_op* op)
0798 {
0799   scheduler_.work_started();
0800 
0801   signal_state* state = get_signal_state();
0802   static_mutex::scoped_lock lock(state->mutex_);
0803 
0804   registration* reg = impl.signals_;
0805   while (reg)
0806   {
0807     if (reg->undelivered_ > 0)
0808     {
0809       --reg->undelivered_;
0810       op->signal_number_ = reg->signal_number_;
0811       scheduler_.post_deferred_completion(op);
0812       return;
0813     }
0814 
0815     reg = reg->next_in_set_;
0816   }
0817 
0818   impl.queue_.push(op);
0819 }
0820 
0821 } // namespace detail
0822 } // namespace asio
0823 } // namespace boost
0824 
0825 #include <boost/asio/detail/pop_options.hpp>
0826 
0827 #endif // BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP