2
0
mirror of https://github.com/boostorg/asio.git synced 2026-02-23 14:02:13 +00:00

Add cancellation_slot support to signal sets.

This commit is contained in:
Christopher Kohlhoff
2022-03-02 21:50:26 +11:00
parent 61ca6c72e8
commit 4e163b8ac1
5 changed files with 84 additions and 0 deletions

View File

@@ -519,6 +519,16 @@ public:
*
* @par Completion Signature
* @code void(boost::system::error_code, int) @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, int))

View File

@@ -528,6 +528,33 @@ boost::system::error_code signal_set_service::cancel(
return ec;
}
void signal_set_service::cancel_ops_by_key(
signal_set_service::implementation_type& impl, void* cancellation_key)
{
op_queue<operation> ops;
{
op_queue<signal_op> other_ops;
signal_state* state = get_signal_state();
static_mutex::scoped_lock lock(state->mutex_);
while (signal_op* op = impl.queue_.front())
{
impl.queue_.pop();
if (op->cancellation_key_ == cancellation_key)
{
op->ec_ = boost::asio::error::operation_aborted;
ops.push(op);
}
else
other_ops.push(op);
}
impl.queue_.push(other_ops);
}
scheduler_.post_deferred_completions(ops);
}
void signal_set_service::deliver_signal(int signal_number)
{
signal_state* state = get_signal_state();

View File

@@ -31,12 +31,16 @@ public:
// The error code to be passed to the completion handler.
boost::system::error_code ec_;
// The operation key used for targeted cancellation.
void* cancellation_key_;
// The signal number to be passed to the completion handler.
int signal_number_;
protected:
signal_op(func_type func)
: operation(func),
cancellation_key_(0),
signal_number_(0)
{
}

View File

@@ -19,6 +19,8 @@
#include <cstddef>
#include <signal.h>
#include <boost/asio/associated_cancellation_slot.hpp>
#include <boost/asio/cancellation_type.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
@@ -154,17 +156,31 @@ public:
BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl,
boost::system::error_code& ec);
// Cancel a specific operation associated with the signal set.
BOOST_ASIO_DECL void cancel_ops_by_key(implementation_type& impl,
void* cancellation_key);
// Start an asynchronous operation to wait for a signal to be delivered.
template <typename Handler, typename IoExecutor>
void async_wait(implementation_type& impl,
Handler& handler, const IoExecutor& io_ex)
{
typename associated_cancellation_slot<Handler>::type slot
= boost::asio::get_associated_cancellation_slot(handler);
// Allocate and construct an operation to wrap the handler.
typedef signal_handler<Handler, IoExecutor> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler, io_ex);
// Optionally register for per-operation cancellation.
if (slot.is_connected())
{
p.p->cancellation_key_ =
&slot.template emplace<signal_op_cancellation>(this, &impl);
}
BOOST_ASIO_HANDLER_CREATION((scheduler_.context(),
*p.p, "signal_set", &impl, 0, "async_wait"));
@@ -191,6 +207,32 @@ private:
// Helper function to start a wait operation.
BOOST_ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op);
// Helper class used to implement per-operation cancellation
class signal_op_cancellation
{
public:
signal_op_cancellation(signal_set_service* s, implementation_type* i)
: service_(s),
implementation_(i)
{
}
void operator()(cancellation_type_t type)
{
if (!!(type &
(cancellation_type::terminal
| cancellation_type::partial
| cancellation_type::total)))
{
service_->cancel_ops_by_key(*implementation_, this);
}
}
private:
signal_set_service* service_;
implementation_type* implementation_;
};
// The scheduler used for dispatching handlers.
#if defined(BOOST_ASIO_HAS_IOCP)
typedef class win_iocp_io_context scheduler_impl;