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:
@@ -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))
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user