forked from boostorg/beast
beast support per-op cancellation
- websocket supports cancellation. - Iterating test for ws cancellation. - Only terminal cancellation is forwarded by default. - basic_stream supports cancellation. - supported cancellation is documented. - http cancellation additions. - Added cancellation_slot tests to http, utils and saved_handler. - Added post to write.cpp, to avoid SIGSEV in test. - Refresher describes cancellation in more detail.
This commit is contained in:
committed by
Klemens Morgenstern
parent
0bf3d971a0
commit
3ebff60b1a
@@ -283,6 +283,7 @@ public:
|
||||
, pg_()
|
||||
, b_(b)
|
||||
{
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
if (buffer_bytes(b_) == 0 && state().pending)
|
||||
{
|
||||
// Workaround:
|
||||
@@ -452,6 +453,7 @@ public:
|
||||
, pg0_(impl_->read.pending)
|
||||
, pg1_(impl_->write.pending)
|
||||
{
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
if(state().timer.expiry() != stream_base::never())
|
||||
{
|
||||
BOOST_ASIO_HANDLER_LOCATION((
|
||||
@@ -489,6 +491,7 @@ public:
|
||||
, pg0_(impl_->read.pending)
|
||||
, pg1_(impl_->write.pending)
|
||||
{
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
if(state().timer.expiry() != stream_base::never())
|
||||
{
|
||||
BOOST_ASIO_HANDLER_LOCATION((
|
||||
@@ -526,6 +529,7 @@ public:
|
||||
, pg0_(impl_->read.pending)
|
||||
, pg1_(impl_->write.pending)
|
||||
{
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
if(state().timer.expiry() != stream_base::never())
|
||||
{
|
||||
BOOST_ASIO_HANDLER_LOCATION((
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
#include <boost/beast/core/detail/allocator.hpp>
|
||||
#include <boost/asio/associated_allocator.hpp>
|
||||
#include <boost/asio/associated_cancellation_slot.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/empty_value.hpp>
|
||||
@@ -28,9 +30,10 @@ class saved_handler::base
|
||||
{
|
||||
protected:
|
||||
~base() = default;
|
||||
|
||||
saved_handler * owner_;
|
||||
public:
|
||||
base() = default;
|
||||
base(saved_handler * owner) : owner_(owner){}
|
||||
void set_owner(saved_handler * new_owner) { owner_ = new_owner;}
|
||||
virtual void destroy() = 0;
|
||||
virtual void invoke() = 0;
|
||||
};
|
||||
@@ -72,11 +75,12 @@ class saved_handler::impl final : public base
|
||||
net::executor_work_guard<
|
||||
net::associated_executor_t<Handler>> wg2_;
|
||||
#endif // defined(BOOST_ASIO_NO_TS_EXECUTORS)
|
||||
|
||||
net::cancellation_slot slot_{net::get_associated_cancellation_slot(v_.h)};
|
||||
public:
|
||||
template<class Handler_>
|
||||
impl(alloc_type const& a, Handler_&& h)
|
||||
: v_(a, std::forward<Handler_>(h))
|
||||
impl(alloc_type const& a, Handler_&& h,
|
||||
saved_handler * owner)
|
||||
: base(owner), v_(a, std::forward<Handler_>(h))
|
||||
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
|
||||
, wg2_(net::prefer(
|
||||
net::get_associated_executor(v_.h),
|
||||
@@ -87,10 +91,15 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
~impl()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
destroy() override
|
||||
{
|
||||
auto v = std::move(v_);
|
||||
slot_.clear();
|
||||
alloc_traits::destroy(v.get(), this);
|
||||
alloc_traits::deallocate(v.get(), this, 1);
|
||||
}
|
||||
@@ -98,11 +107,22 @@ public:
|
||||
void
|
||||
invoke() override
|
||||
{
|
||||
slot_.clear();
|
||||
auto v = std::move(v_);
|
||||
alloc_traits::destroy(v.get(), this);
|
||||
alloc_traits::deallocate(v.get(), this, 1);
|
||||
v.h();
|
||||
}
|
||||
|
||||
void self_complete()
|
||||
{
|
||||
slot_.clear();
|
||||
owner_->p_ = nullptr;
|
||||
auto v = std::move(v_);
|
||||
alloc_traits::destroy(v.get(), this);
|
||||
alloc_traits::deallocate(v.get(), this, 1);
|
||||
v.h(net::error::operation_aborted);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -110,7 +130,8 @@ public:
|
||||
template<class Handler, class Allocator>
|
||||
void
|
||||
saved_handler::
|
||||
emplace(Handler&& handler, Allocator const& alloc)
|
||||
emplace(Handler&& handler, Allocator const& alloc,
|
||||
net::cancellation_type cancel_type)
|
||||
{
|
||||
// Can't delete a handler before invoking
|
||||
BOOST_ASSERT(! has_value());
|
||||
@@ -140,22 +161,47 @@ emplace(Handler&& handler, Allocator const& alloc)
|
||||
alloc_traits::deallocate(a, p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
auto cancel_slot = net::get_associated_cancellation_slot(handler);
|
||||
storage s(alloc);
|
||||
alloc_traits::construct(s.a, s.p,
|
||||
s.a, std::forward<Handler>(handler));
|
||||
p_ = boost::exchange(s.p, nullptr);
|
||||
s.a, std::forward<Handler>(handler), this);
|
||||
|
||||
auto tmp = boost::exchange(s.p, nullptr);
|
||||
p_ = tmp;
|
||||
|
||||
if (cancel_slot.is_connected())
|
||||
{
|
||||
struct cancel_op
|
||||
{
|
||||
impl<Handler, Allocator>* p;
|
||||
net::cancellation_type accepted_ct;
|
||||
cancel_op(impl<Handler, Allocator>* p,
|
||||
net::cancellation_type accepted_ct)
|
||||
: p(p), accepted_ct(accepted_ct) {}
|
||||
|
||||
void operator()(net::cancellation_type ct)
|
||||
{
|
||||
if ((ct & accepted_ct) != net::cancellation_type::none)
|
||||
p->self_complete();
|
||||
}
|
||||
};
|
||||
cancel_slot.template emplace<cancel_op>(tmp, cancel_type);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Handler>
|
||||
void
|
||||
saved_handler::
|
||||
emplace(Handler&& handler)
|
||||
emplace(Handler&& handler, net::cancellation_type cancel_type)
|
||||
{
|
||||
// Can't delete a handler before invoking
|
||||
BOOST_ASSERT(! has_value());
|
||||
emplace(
|
||||
std::forward<Handler>(handler),
|
||||
net::get_associated_allocator(handler));
|
||||
net::get_associated_allocator(handler),
|
||||
cancel_type);
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
@@ -27,6 +27,7 @@ saved_handler::
|
||||
saved_handler(saved_handler&& other) noexcept
|
||||
: p_(boost::exchange(other.p_, nullptr))
|
||||
{
|
||||
p_->set_owner(this);
|
||||
}
|
||||
|
||||
saved_handler&
|
||||
@@ -36,6 +37,7 @@ operator=(saved_handler&& other) noexcept
|
||||
// Can't delete a handler before invoking
|
||||
BOOST_ASSERT(! has_value());
|
||||
p_ = boost::exchange(other.p_, nullptr);
|
||||
p_->set_owner(this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user