Chris@16: // Chris@16: // detail/impl/signal_set_service.ipp Chris@16: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Chris@16: // Chris@101: // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: Chris@16: #ifndef BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP Chris@16: #define BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: # pragma once Chris@16: #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace asio { Chris@16: namespace detail { Chris@16: Chris@16: struct signal_state Chris@16: { Chris@16: // Mutex used for protecting global state. Chris@16: static_mutex mutex_; Chris@16: Chris@16: // The read end of the pipe used for signal notifications. Chris@16: int read_descriptor_; Chris@16: Chris@16: // The write end of the pipe used for signal notifications. Chris@16: int write_descriptor_; Chris@16: Chris@16: // Whether the signal state has been prepared for a fork. Chris@16: bool fork_prepared_; Chris@16: Chris@16: // The head of a linked list of all signal_set_service instances. Chris@16: class signal_set_service* service_list_; Chris@16: Chris@16: // A count of the number of objects that are registered for each signal. Chris@16: std::size_t registration_count_[max_signal_number]; Chris@16: }; Chris@16: Chris@16: signal_state* get_signal_state() Chris@16: { Chris@16: static signal_state state = { Chris@16: BOOST_ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } }; Chris@16: return &state; Chris@16: } Chris@16: Chris@16: void boost_asio_signal_handler(int signal_number) Chris@16: { Chris@16: #if defined(BOOST_ASIO_WINDOWS) \ Chris@16: || defined(BOOST_ASIO_WINDOWS_RUNTIME) \ Chris@16: || defined(__CYGWIN__) Chris@16: signal_set_service::deliver_signal(signal_number); Chris@16: #else // defined(BOOST_ASIO_WINDOWS) Chris@16: // || defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // || defined(__CYGWIN__) Chris@16: int saved_errno = errno; Chris@16: signal_state* state = get_signal_state(); Chris@16: signed_size_type result = ::write(state->write_descriptor_, Chris@16: &signal_number, sizeof(signal_number)); Chris@16: (void)result; Chris@16: errno = saved_errno; Chris@16: #endif // defined(BOOST_ASIO_WINDOWS) Chris@16: // || defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // || defined(__CYGWIN__) Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_SIGNAL) && !defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: ::signal(signal_number, boost_asio_signal_handler); Chris@16: #endif // defined(BOOST_ASIO_HAS_SIGNAL) && !defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: } Chris@16: Chris@16: #if !defined(BOOST_ASIO_WINDOWS) \ Chris@16: && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ Chris@16: && !defined(__CYGWIN__) Chris@16: class signal_set_service::pipe_read_op : public reactor_op Chris@16: { Chris@16: public: Chris@16: pipe_read_op() Chris@16: : reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete) Chris@16: { Chris@16: } Chris@16: Chris@16: static bool do_perform(reactor_op*) Chris@16: { Chris@16: signal_state* state = get_signal_state(); Chris@16: Chris@16: int fd = state->read_descriptor_; Chris@16: int signal_number = 0; Chris@16: while (::read(fd, &signal_number, sizeof(int)) == sizeof(int)) Chris@16: if (signal_number >= 0 && signal_number < max_signal_number) Chris@16: signal_set_service::deliver_signal(signal_number); Chris@16: Chris@16: return false; Chris@16: } Chris@16: Chris@16: static void do_complete(io_service_impl* /*owner*/, operation* base, Chris@16: const boost::system::error_code& /*ec*/, Chris@16: std::size_t /*bytes_transferred*/) Chris@16: { Chris@16: pipe_read_op* o(static_cast(base)); Chris@16: delete o; Chris@16: } Chris@16: }; Chris@16: #endif // !defined(BOOST_ASIO_WINDOWS) Chris@16: // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // && !defined(__CYGWIN__) Chris@16: Chris@16: signal_set_service::signal_set_service( Chris@16: boost::asio::io_service& io_service) Chris@16: : io_service_(boost::asio::use_service(io_service)), Chris@16: #if !defined(BOOST_ASIO_WINDOWS) \ Chris@16: && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ Chris@16: && !defined(__CYGWIN__) Chris@16: reactor_(boost::asio::use_service(io_service)), Chris@16: #endif // !defined(BOOST_ASIO_WINDOWS) Chris@16: // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // && !defined(__CYGWIN__) Chris@16: next_(0), Chris@16: prev_(0) Chris@16: { Chris@16: get_signal_state()->mutex_.init(); Chris@16: Chris@16: #if !defined(BOOST_ASIO_WINDOWS) \ Chris@16: && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ Chris@16: && !defined(__CYGWIN__) Chris@16: reactor_.init_task(); Chris@16: #endif // !defined(BOOST_ASIO_WINDOWS) Chris@16: // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // && !defined(__CYGWIN__) Chris@16: Chris@16: for (int i = 0; i < max_signal_number; ++i) Chris@16: registrations_[i] = 0; Chris@16: Chris@16: add_service(this); Chris@16: } Chris@16: Chris@16: signal_set_service::~signal_set_service() Chris@16: { Chris@16: remove_service(this); Chris@16: } Chris@16: Chris@16: void signal_set_service::shutdown_service() Chris@16: { Chris@16: remove_service(this); Chris@16: Chris@16: op_queue ops; Chris@16: Chris@16: for (int i = 0; i < max_signal_number; ++i) Chris@16: { Chris@16: registration* reg = registrations_[i]; Chris@16: while (reg) Chris@16: { Chris@16: ops.push(*reg->queue_); Chris@16: reg = reg->next_in_table_; Chris@16: } Chris@16: } Chris@16: Chris@16: io_service_.abandon_operations(ops); Chris@16: } Chris@16: Chris@16: void signal_set_service::fork_service( Chris@16: boost::asio::io_service::fork_event fork_ev) Chris@16: { Chris@16: #if !defined(BOOST_ASIO_WINDOWS) \ Chris@16: && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ Chris@16: && !defined(__CYGWIN__) Chris@16: signal_state* state = get_signal_state(); Chris@16: static_mutex::scoped_lock lock(state->mutex_); Chris@16: Chris@16: switch (fork_ev) Chris@16: { Chris@16: case boost::asio::io_service::fork_prepare: Chris@16: { Chris@16: int read_descriptor = state->read_descriptor_; Chris@16: state->fork_prepared_ = true; Chris@16: lock.unlock(); Chris@16: reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_); Chris@16: } Chris@16: break; Chris@16: case boost::asio::io_service::fork_parent: Chris@16: if (state->fork_prepared_) Chris@16: { Chris@16: int read_descriptor = state->read_descriptor_; Chris@16: state->fork_prepared_ = false; Chris@16: lock.unlock(); Chris@16: reactor_.register_internal_descriptor(reactor::read_op, Chris@16: read_descriptor, reactor_data_, new pipe_read_op); Chris@16: } Chris@16: break; Chris@16: case boost::asio::io_service::fork_child: Chris@16: if (state->fork_prepared_) Chris@16: { Chris@16: boost::asio::detail::signal_blocker blocker; Chris@16: close_descriptors(); Chris@16: open_descriptors(); Chris@16: int read_descriptor = state->read_descriptor_; Chris@16: state->fork_prepared_ = false; Chris@16: lock.unlock(); Chris@16: reactor_.register_internal_descriptor(reactor::read_op, Chris@16: read_descriptor, reactor_data_, new pipe_read_op); Chris@16: } Chris@16: break; Chris@16: default: Chris@16: break; Chris@16: } Chris@16: #else // !defined(BOOST_ASIO_WINDOWS) Chris@16: // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // && !defined(__CYGWIN__) Chris@16: (void)fork_ev; Chris@16: #endif // !defined(BOOST_ASIO_WINDOWS) Chris@16: // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // && !defined(__CYGWIN__) Chris@16: } Chris@16: Chris@16: void signal_set_service::construct( Chris@16: signal_set_service::implementation_type& impl) Chris@16: { Chris@16: impl.signals_ = 0; Chris@16: } Chris@16: Chris@16: void signal_set_service::destroy( Chris@16: signal_set_service::implementation_type& impl) Chris@16: { Chris@16: boost::system::error_code ignored_ec; Chris@16: clear(impl, ignored_ec); Chris@16: cancel(impl, ignored_ec); Chris@16: } Chris@16: Chris@16: boost::system::error_code signal_set_service::add( Chris@16: signal_set_service::implementation_type& impl, Chris@16: int signal_number, boost::system::error_code& ec) Chris@16: { Chris@16: // Check that the signal number is valid. Chris@101: if (signal_number < 0 || signal_number >= max_signal_number) Chris@16: { Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: return ec; Chris@16: } Chris@16: Chris@16: signal_state* state = get_signal_state(); Chris@16: static_mutex::scoped_lock lock(state->mutex_); Chris@16: Chris@16: // Find the appropriate place to insert the registration. Chris@16: registration** insertion_point = &impl.signals_; Chris@16: registration* next = impl.signals_; Chris@16: while (next && next->signal_number_ < signal_number) Chris@16: { Chris@16: insertion_point = &next->next_in_set_; Chris@16: next = next->next_in_set_; Chris@16: } Chris@16: Chris@16: // Only do something if the signal is not already registered. Chris@16: if (next == 0 || next->signal_number_ != signal_number) Chris@16: { Chris@16: registration* new_registration = new registration; Chris@16: Chris@16: #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: // Register for the signal if we're the first. Chris@16: if (state->registration_count_[signal_number] == 0) Chris@16: { Chris@16: # if defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: using namespace std; // For memset. Chris@16: struct sigaction sa; Chris@16: memset(&sa, 0, sizeof(sa)); Chris@16: sa.sa_handler = boost_asio_signal_handler; Chris@16: sigfillset(&sa.sa_mask); Chris@16: if (::sigaction(signal_number, &sa, 0) == -1) Chris@16: # else // defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: if (::signal(signal_number, boost_asio_signal_handler) == SIG_ERR) Chris@16: # endif // defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: { Chris@16: # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) Chris@16: ec = boost::system::error_code(errno, Chris@16: boost::asio::error::get_system_category()); Chris@16: # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) Chris@16: delete new_registration; Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: Chris@16: // Record the new registration in the set. Chris@16: new_registration->signal_number_ = signal_number; Chris@16: new_registration->queue_ = &impl.queue_; Chris@16: new_registration->next_in_set_ = next; Chris@16: *insertion_point = new_registration; Chris@16: Chris@16: // Insert registration into the registration table. Chris@16: new_registration->next_in_table_ = registrations_[signal_number]; Chris@16: if (registrations_[signal_number]) Chris@16: registrations_[signal_number]->prev_in_table_ = new_registration; Chris@16: registrations_[signal_number] = new_registration; Chris@16: Chris@16: ++state->registration_count_[signal_number]; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: boost::system::error_code signal_set_service::remove( Chris@16: signal_set_service::implementation_type& impl, Chris@16: int signal_number, boost::system::error_code& ec) Chris@16: { Chris@16: // Check that the signal number is valid. Chris@101: if (signal_number < 0 || signal_number >= max_signal_number) Chris@16: { Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: return ec; Chris@16: } Chris@16: Chris@16: signal_state* state = get_signal_state(); Chris@16: static_mutex::scoped_lock lock(state->mutex_); Chris@16: Chris@16: // Find the signal number in the list of registrations. Chris@16: registration** deletion_point = &impl.signals_; Chris@16: registration* reg = impl.signals_; Chris@16: while (reg && reg->signal_number_ < signal_number) Chris@16: { Chris@16: deletion_point = ®->next_in_set_; Chris@16: reg = reg->next_in_set_; Chris@16: } Chris@16: Chris@16: if (reg != 0 && reg->signal_number_ == signal_number) Chris@16: { Chris@16: #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: // Set signal handler back to the default if we're the last. Chris@16: if (state->registration_count_[signal_number] == 1) Chris@16: { Chris@16: # if defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: using namespace std; // For memset. Chris@16: struct sigaction sa; Chris@16: memset(&sa, 0, sizeof(sa)); Chris@16: sa.sa_handler = SIG_DFL; Chris@16: if (::sigaction(signal_number, &sa, 0) == -1) Chris@16: # else // defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: if (::signal(signal_number, SIG_DFL) == SIG_ERR) Chris@16: # endif // defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: { Chris@16: # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) Chris@16: ec = boost::system::error_code(errno, Chris@16: boost::asio::error::get_system_category()); Chris@16: # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: Chris@16: // Remove the registration from the set. Chris@16: *deletion_point = reg->next_in_set_; Chris@16: Chris@16: // Remove the registration from the registration table. Chris@16: if (registrations_[signal_number] == reg) Chris@16: registrations_[signal_number] = reg->next_in_table_; Chris@16: if (reg->prev_in_table_) Chris@16: reg->prev_in_table_->next_in_table_ = reg->next_in_table_; Chris@16: if (reg->next_in_table_) Chris@16: reg->next_in_table_->prev_in_table_ = reg->prev_in_table_; Chris@16: Chris@16: --state->registration_count_[signal_number]; Chris@16: Chris@16: delete reg; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: boost::system::error_code signal_set_service::clear( Chris@16: signal_set_service::implementation_type& impl, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: signal_state* state = get_signal_state(); Chris@16: static_mutex::scoped_lock lock(state->mutex_); Chris@16: Chris@16: while (registration* reg = impl.signals_) Chris@16: { Chris@16: #if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: // Set signal handler back to the default if we're the last. Chris@16: if (state->registration_count_[reg->signal_number_] == 1) Chris@16: { Chris@16: # if defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: using namespace std; // For memset. Chris@16: struct sigaction sa; Chris@16: memset(&sa, 0, sizeof(sa)); Chris@16: sa.sa_handler = SIG_DFL; Chris@16: if (::sigaction(reg->signal_number_, &sa, 0) == -1) Chris@16: # else // defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: if (::signal(reg->signal_number_, SIG_DFL) == SIG_ERR) Chris@16: # endif // defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: { Chris@16: # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) Chris@16: ec = boost::asio::error::invalid_argument; Chris@16: # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) Chris@16: ec = boost::system::error_code(errno, Chris@16: boost::asio::error::get_system_category()); Chris@16: # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) Chris@16: return ec; Chris@16: } Chris@16: } Chris@16: #endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) Chris@16: Chris@16: // Remove the registration from the registration table. Chris@16: if (registrations_[reg->signal_number_] == reg) Chris@16: registrations_[reg->signal_number_] = reg->next_in_table_; Chris@16: if (reg->prev_in_table_) Chris@16: reg->prev_in_table_->next_in_table_ = reg->next_in_table_; Chris@16: if (reg->next_in_table_) Chris@16: reg->next_in_table_->prev_in_table_ = reg->prev_in_table_; Chris@16: Chris@16: --state->registration_count_[reg->signal_number_]; Chris@16: Chris@16: impl.signals_ = reg->next_in_set_; Chris@16: delete reg; Chris@16: } Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: boost::system::error_code signal_set_service::cancel( Chris@16: signal_set_service::implementation_type& impl, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: BOOST_ASIO_HANDLER_OPERATION(("signal_set", &impl, "cancel")); Chris@16: Chris@16: op_queue ops; Chris@16: { Chris@16: signal_state* state = get_signal_state(); Chris@16: static_mutex::scoped_lock lock(state->mutex_); Chris@16: Chris@16: while (signal_op* op = impl.queue_.front()) Chris@16: { Chris@16: op->ec_ = boost::asio::error::operation_aborted; Chris@16: impl.queue_.pop(); Chris@16: ops.push(op); Chris@16: } Chris@16: } Chris@16: Chris@16: io_service_.post_deferred_completions(ops); Chris@16: Chris@16: ec = boost::system::error_code(); Chris@16: return ec; Chris@16: } Chris@16: Chris@16: void signal_set_service::deliver_signal(int signal_number) Chris@16: { Chris@16: signal_state* state = get_signal_state(); Chris@16: static_mutex::scoped_lock lock(state->mutex_); Chris@16: Chris@16: signal_set_service* service = state->service_list_; Chris@16: while (service) Chris@16: { Chris@16: op_queue ops; Chris@16: Chris@16: registration* reg = service->registrations_[signal_number]; Chris@16: while (reg) Chris@16: { Chris@16: if (reg->queue_->empty()) Chris@16: { Chris@16: ++reg->undelivered_; Chris@16: } Chris@16: else Chris@16: { Chris@16: while (signal_op* op = reg->queue_->front()) Chris@16: { Chris@16: op->signal_number_ = signal_number; Chris@16: reg->queue_->pop(); Chris@16: ops.push(op); Chris@16: } Chris@16: } Chris@16: Chris@16: reg = reg->next_in_table_; Chris@16: } Chris@16: Chris@16: service->io_service_.post_deferred_completions(ops); Chris@16: Chris@16: service = service->next_; Chris@16: } Chris@16: } Chris@16: Chris@16: void signal_set_service::add_service(signal_set_service* service) Chris@16: { Chris@16: signal_state* state = get_signal_state(); Chris@16: static_mutex::scoped_lock lock(state->mutex_); Chris@16: Chris@16: #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) Chris@16: // If this is the first service to be created, open a new pipe. Chris@16: if (state->service_list_ == 0) Chris@16: open_descriptors(); Chris@16: #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) Chris@16: Chris@16: // Insert service into linked list of all services. Chris@16: service->next_ = state->service_list_; Chris@16: service->prev_ = 0; Chris@16: if (state->service_list_) Chris@16: state->service_list_->prev_ = service; Chris@16: state->service_list_ = service; Chris@16: Chris@16: #if !defined(BOOST_ASIO_WINDOWS) \ Chris@16: && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ Chris@16: && !defined(__CYGWIN__) Chris@16: // Register for pipe readiness notifications. Chris@16: int read_descriptor = state->read_descriptor_; Chris@16: lock.unlock(); Chris@16: service->reactor_.register_internal_descriptor(reactor::read_op, Chris@16: read_descriptor, service->reactor_data_, new pipe_read_op); Chris@16: #endif // !defined(BOOST_ASIO_WINDOWS) Chris@16: // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // && !defined(__CYGWIN__) Chris@16: } Chris@16: Chris@16: void signal_set_service::remove_service(signal_set_service* service) Chris@16: { Chris@16: signal_state* state = get_signal_state(); Chris@16: static_mutex::scoped_lock lock(state->mutex_); Chris@16: Chris@16: if (service->next_ || service->prev_ || state->service_list_ == service) Chris@16: { Chris@16: #if !defined(BOOST_ASIO_WINDOWS) \ Chris@16: && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ Chris@16: && !defined(__CYGWIN__) Chris@16: // Disable the pipe readiness notifications. Chris@16: int read_descriptor = state->read_descriptor_; Chris@16: lock.unlock(); Chris@16: service->reactor_.deregister_descriptor( Chris@16: read_descriptor, service->reactor_data_, false); Chris@16: lock.lock(); Chris@16: #endif // !defined(BOOST_ASIO_WINDOWS) Chris@16: // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // && !defined(__CYGWIN__) Chris@16: Chris@16: // Remove service from linked list of all services. Chris@16: if (state->service_list_ == service) Chris@16: state->service_list_ = service->next_; Chris@16: if (service->prev_) Chris@16: service->prev_->next_ = service->next_; Chris@16: if (service->next_) Chris@16: service->next_->prev_= service->prev_; Chris@16: service->next_ = 0; Chris@16: service->prev_ = 0; Chris@16: Chris@16: #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) Chris@16: // If this is the last service to be removed, close the pipe. Chris@16: if (state->service_list_ == 0) Chris@16: close_descriptors(); Chris@16: #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) Chris@16: } Chris@16: } Chris@16: Chris@16: void signal_set_service::open_descriptors() Chris@16: { Chris@16: #if !defined(BOOST_ASIO_WINDOWS) \ Chris@16: && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ Chris@16: && !defined(__CYGWIN__) Chris@16: signal_state* state = get_signal_state(); Chris@16: Chris@16: int pipe_fds[2]; Chris@16: if (::pipe(pipe_fds) == 0) Chris@16: { Chris@16: state->read_descriptor_ = pipe_fds[0]; Chris@16: ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK); Chris@16: Chris@16: state->write_descriptor_ = pipe_fds[1]; Chris@16: ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK); Chris@16: Chris@16: #if defined(FD_CLOEXEC) Chris@16: ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC); Chris@16: ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC); Chris@16: #endif // defined(FD_CLOEXEC) Chris@16: } Chris@16: else Chris@16: { Chris@16: boost::system::error_code ec(errno, Chris@16: boost::asio::error::get_system_category()); Chris@16: boost::asio::detail::throw_error(ec, "signal_set_service pipe"); Chris@16: } Chris@16: #endif // !defined(BOOST_ASIO_WINDOWS) Chris@16: // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // && !defined(__CYGWIN__) Chris@16: } Chris@16: Chris@16: void signal_set_service::close_descriptors() Chris@16: { Chris@16: #if !defined(BOOST_ASIO_WINDOWS) \ Chris@16: && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ Chris@16: && !defined(__CYGWIN__) Chris@16: signal_state* state = get_signal_state(); Chris@16: Chris@16: if (state->read_descriptor_ != -1) Chris@16: ::close(state->read_descriptor_); Chris@16: state->read_descriptor_ = -1; Chris@16: Chris@16: if (state->write_descriptor_ != -1) Chris@16: ::close(state->write_descriptor_); Chris@16: state->write_descriptor_ = -1; Chris@16: #endif // !defined(BOOST_ASIO_WINDOWS) Chris@16: // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: // && !defined(__CYGWIN__) Chris@16: } Chris@16: Chris@16: void signal_set_service::start_wait_op( Chris@16: signal_set_service::implementation_type& impl, signal_op* op) Chris@16: { Chris@16: io_service_.work_started(); Chris@16: Chris@16: signal_state* state = get_signal_state(); Chris@16: static_mutex::scoped_lock lock(state->mutex_); Chris@16: Chris@16: registration* reg = impl.signals_; Chris@16: while (reg) Chris@16: { Chris@16: if (reg->undelivered_ > 0) Chris@16: { Chris@16: --reg->undelivered_; Chris@16: op->signal_number_ = reg->signal_number_; Chris@16: io_service_.post_deferred_completion(op); Chris@16: return; Chris@16: } Chris@16: Chris@16: reg = reg->next_in_set_; Chris@16: } Chris@16: Chris@16: impl.queue_.push(op); Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP