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