immediate_executor is supported. (#2672)

This commit is contained in:
Klemens Morgenstern
2023-10-13 16:33:23 +08:00
committed by GitHub
parent 177a1222a6
commit dd875463ff
25 changed files with 475 additions and 219 deletions

View File

@ -212,11 +212,13 @@ public:
std::size_t bytes_transferred // Number of bytes read. std::size_t bytes_transferred // Number of bytes read.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@note The `async_read_some` operation may not read all of the requested number of @note The `async_read_some` operation may not read all of the requested number of
bytes. Consider using the function `net::async_read` if you need bytes. Consider using the function `net::async_read` if you need
to ensure that the requested amount of data is read before the asynchronous to ensure that the requested amount of data is read before the asynchronous
@ -295,11 +297,13 @@ public:
std::size_t bytes_transferred // Number of bytes written. std::size_t bytes_transferred // Number of bytes written.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@note The `async_write_some` operation may not transmit all of the data to @note The `async_write_some` operation may not transmit all of the data to
the peer. Consider using the function `net::async_write` if you need the peer. Consider using the function `net::async_write` if you need
to ensure that all data is written before the asynchronous operation completes. to ensure that all data is written before the asynchronous operation completes.

View File

@ -0,0 +1,71 @@
//
// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net)
//
// 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 BOOST_BEAST_TEST_IMMEDIATE_EXECUTOR_HPP
#define BOOST_BEAST_TEST_IMMEDIATE_EXECUTOR_HPP
#include <boost/asio/any_io_executor.hpp>
namespace boost
{
namespace beast
{
namespace test
{
/** A immediate executor that directly invokes and counts how often that happened. */
class immediate_executor
{
std::size_t &count_;
public:
immediate_executor(std::size_t & count) noexcept : count_(count) {}
asio::execution_context &query(asio::execution::context_t) const
{
BOOST_ASSERT(false);
return *static_cast<asio::execution_context*>(nullptr);
}
constexpr static asio::execution::blocking_t
query(asio::execution::blocking_t) noexcept
{
return asio::execution::blocking_t::never_t{};
}
constexpr static asio::execution::relationship_t
query(asio::execution::relationship_t) noexcept
{
return asio::execution::relationship_t::fork_t{};
}
// this function takes the function F and runs it on the event loop.
template<class F>
void
execute(F f) const
{
count_++;
std::forward<F>(f)();
}
bool
operator==(immediate_executor const &other) const noexcept
{
return true;
}
bool
operator!=(immediate_executor const &other) const noexcept
{
return false;
}
};
}
}
}
#endif //BOOST_BEAST_TEST_IMMEDIATE_EXECUTOR_HPP

View File

@ -23,7 +23,6 @@
#include <boost/asio/executor_work_guard.hpp> #include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/any_io_executor.hpp> #include <boost/asio/any_io_executor.hpp>
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp> #include <boost/weak_ptr.hpp>
@ -454,11 +453,13 @@ public:
std::size_t bytes_transferred // Number of bytes read. std::size_t bytes_transferred // Number of bytes read.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@note The `async_read_some` operation may not read all of the requested number of @note The `async_read_some` operation may not read all of the requested number of
bytes. Consider using the function `net::async_read` if you need bytes. Consider using the function `net::async_read` if you need
to ensure that the requested amount of data is read before the asynchronous to ensure that the requested amount of data is read before the asynchronous
@ -534,11 +535,13 @@ public:
std::size_t bytes_transferred // Number of bytes written. std::size_t bytes_transferred // Number of bytes written.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@note The `async_write_some` operation may not transmit all of the data to @note The `async_write_some` operation may not transmit all of the data to
the peer. Consider using the function `net::async_write` if you need the peer. Consider using the function `net::async_write` if you need
to ensure that all data is written before the asynchronous operation completes. to ensure that all data is written before the asynchronous operation completes.

View File

@ -18,10 +18,12 @@
#include <boost/beast/core/detail/work_guard.hpp> #include <boost/beast/core/detail/work_guard.hpp>
#include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp> #include <boost/asio/associated_executor.hpp>
#include <boost/asio/associated_immediate_executor.hpp>
#include <boost/asio/bind_executor.hpp> #include <boost/asio/bind_executor.hpp>
#include <boost/asio/handler_alloc_hook.hpp> #include <boost/asio/handler_alloc_hook.hpp>
#include <boost/asio/handler_continuation_hook.hpp> #include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp> #include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <boost/core/exchange.hpp> #include <boost/core/exchange.hpp>
#include <boost/core/empty_value.hpp> #include <boost/core/empty_value.hpp>
@ -30,6 +32,7 @@
namespace boost { namespace boost {
namespace beast { namespace beast {
/** Base class to assist writing composed operations. /** Base class to assist writing composed operations.
A function object submitted to intermediate initiating functions during A function object submitted to intermediate initiating functions during
@ -207,7 +210,25 @@ public:
>::type; >::type;
#endif #endif
private: /** The type of the immediate executor associated with this object.
If a class derived from @ref boost::beast::async_base is a completion
handler, then the associated immediage executor of the derived class will
be this type.
*/
using immediate_executor_type =
#if BOOST_BEAST_DOXYGEN
__implementation_defined__;
#else
typename
net::associated_immediate_executor<
Handler,
typename detail::select_work_guard_t<Executor1>::executor_type
>::type;
#endif
private:
virtual virtual
void void
@ -309,15 +330,31 @@ public:
h_, wg1_.get_executor()); h_, wg1_.get_executor());
} }
/** The type of cancellation_slot associated with this object. /** Returns the immediate executor associated with this handler.
If the handler has none it returns asios default immediate
executor based on the executor of the object.
If a class derived from @ref async_base is a completion If a class derived from @ref boost::beast::async_base is a completion
handler, then the associated cancellation_slot of the handler, then the object returned from this function will be used
derived class will be this type. as the associated immediate executor of the derived class.
The default type is a filtering cancellation slot,
that only allows terminal cancellation.
*/ */
immediate_executor_type
get_immediate_executor() const noexcept
{
return net::get_associated_immediate_executor(
h_, wg1_.get_executor());
}
/** The type of cancellation_slot associated with this object.
If a class derived from @ref async_base is a completion
handler, then the associated cancellation_slot of the
derived class will be this type.
The default type is a filtering cancellation slot,
that only allows terminal cancellation.
*/
using cancellation_slot_type = using cancellation_slot_type =
beast::detail::filtering_cancellation_slot<net::associated_cancellation_slot_t<Handler>>; beast::detail::filtering_cancellation_slot<net::associated_cancellation_slot_t<Handler>>;
@ -373,7 +410,9 @@ public:
is invoked. is invoked.
@param is_continuation If this value is `false`, then the @param is_continuation If this value is `false`, then the
handler will be submitted to the executor using `net::post`. handler will be submitted to the to the immediate executor using
`net::dispatch`. If the handler has no immediate executor,
this will submit to the executor via `net::post`.
Otherwise the handler will be invoked as if by calling Otherwise the handler will be invoked as if by calling
@ref boost::beast::async_base::complete_now. @ref boost::beast::async_base::complete_now.
@ -388,14 +427,12 @@ public:
this->before_invoke_hook(); this->before_invoke_hook();
if(! is_continuation) if(! is_continuation)
{ {
auto const ex = get_executor(); auto const ex = this->get_immediate_executor();
net::post( net::dispatch(
wg1_.get_executor(), ex,
net::bind_executor( beast::bind_front_handler(
ex, std::move(h_),
beast::bind_front_handler( std::forward<Args>(args)...));
std::move(h_),
std::forward<Args>(args)...)));
wg1_.reset(); wg1_.reset();
} }
else else

View File

@ -928,10 +928,13 @@ public:
error_code ec // Result of operation error_code ec // Result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
@ -993,10 +996,13 @@ public:
typename Protocol::endpoint const& endpoint typename Protocol::endpoint const& endpoint
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
@ -1079,11 +1085,13 @@ public:
typename Protocol::endpoint const& endpoint typename Protocol::endpoint const& endpoint
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Example @par Example
The following connect condition function object can be used to output The following connect condition function object can be used to output
information about the individual connection attempts: information about the individual connection attempts:
@ -1173,11 +1181,13 @@ public:
Iterator iterator Iterator iterator
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following This asynchronous operation supports cancellation for the following
@ -1244,11 +1254,13 @@ public:
Iterator iterator Iterator iterator
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following This asynchronous operation supports cancellation for the following
@ -1377,11 +1389,13 @@ public:
std::size_t bytes_transferred // Number of bytes read. std::size_t bytes_transferred // Number of bytes read.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@note The `async_read_some` operation may not receive all of the requested @note The `async_read_some` operation may not receive all of the requested
number of bytes. Consider using the function `net::async_read` if you need number of bytes. Consider using the function `net::async_read` if you need
to ensure that the requested amount of data is read before the asynchronous to ensure that the requested amount of data is read before the asynchronous
@ -1511,11 +1525,13 @@ public:
std::size_t bytes_transferred // Number of bytes written. std::size_t bytes_transferred // Number of bytes written.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@note The `async_write_some` operation may not transmit all of the requested @note The `async_write_some` operation may not transmit all of the requested
number of bytes. Consider using the function `net::async_write` if you need number of bytes. Consider using the function `net::async_write` if you need
to ensure that the requested amount of data is sent before the asynchronous to ensure that the requested amount of data is sent before the asynchronous

View File

@ -256,11 +256,13 @@ public:
std::size_t bytes_transferred // number of bytes transferred std::size_t bytes_transferred // number of bytes transferred
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
*/ by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`. */
template< template<
class MutableBufferSequence, class MutableBufferSequence,
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler = BOOST_BEAST_ASYNC_TPARAM2 ReadHandler =
@ -335,11 +337,13 @@ public:
std::size_t bytes_transferred // number of bytes transferred std::size_t bytes_transferred // number of bytes transferred
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
*/ by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`. */
template< template<
class ConstBufferSequence, class ConstBufferSequence,
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler = BOOST_BEAST_ASYNC_TPARAM2 WriteHandler =

View File

@ -167,10 +167,11 @@ write(
std::size_t bytes_transferred // the number of bytes written to the stream std::size_t bytes_transferred // the number of bytes written to the stream
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from an immediate completion will be dispatched to it.
within this function. Invocation of the handler will be Otherwise, the handler will not be invoked from within
performed in a manner equivalent to using `net::post`. this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@see BuffersGenerator @see BuffersGenerator
*/ */

View File

@ -210,8 +210,9 @@ read(
// prior to the error. // prior to the error.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.
*/ */

View File

@ -308,8 +308,9 @@ detect_ssl(
bool result // The result of the detector bool result // The result of the detector
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.
*/ */

View File

@ -241,11 +241,13 @@ public:
std::size_t bytes_transferred // Number of bytes read. std::size_t bytes_transferred // Number of bytes read.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@note The `read_some` operation may not read all of the requested number of @note The `read_some` operation may not read all of the requested number of
bytes. Consider using the function `net::async_read` if you need bytes. Consider using the function `net::async_read` if you need
to ensure that the requested amount of data is read before the asynchronous to ensure that the requested amount of data is read before the asynchronous
@ -323,11 +325,13 @@ public:
std::size_t bytes_transferred // Number of bytes written. std::size_t bytes_transferred // Number of bytes written.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@note The `async_write_some` operation may not transmit all of the data to @note The `async_write_some` operation may not transmit all of the data to
the peer. Consider using the function `net::async_write` if you need the peer. Consider using the function `net::async_write` if you need
to ensure that all data is written before the asynchronous operation completes. to ensure that all data is written before the asynchronous operation completes.

View File

@ -16,7 +16,7 @@
#include <boost/beast/core/read_size.hpp> #include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/stream_traits.hpp> #include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/is_invocable.hpp> #include <boost/beast/core/detail/is_invocable.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/dispatch.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
namespace boost { namespace boost {
@ -80,11 +80,13 @@ public:
std::move(*this)); std::move(*this));
} }
step_ = 3; step_ = 3;
return net::post( {
s_.get_executor(), const auto ex = this->get_immediate_executor();
beast::bind_front_handler( return net::dispatch(
std::move(*this), ec, 0)); ex,
beast::bind_front_handler(
std::move(*this), ec, 0));
}
case 1: case 1:
// upcall // upcall
break; break;

View File

@ -244,8 +244,13 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"http::async_read_some")); "http::async_read_some"));
net::post(
s_.get_executor(), const auto ex =
asio::get_associated_immediate_executor(
self, s_.get_executor());
net::dispatch(
ex,
beast::bind_front_handler(std::move(self), ec)); beast::bind_front_handler(std::move(self), ec));
} }
} }
@ -285,7 +290,11 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"http::async_read")); "http::async_read"));
net::post(s_.get_executor(), std::move(self)); const auto ex =
asio::get_associated_immediate_executor(
self, s_.get_executor());
net::dispatch(ex, std::move(self));
} }
} }
else else

View File

@ -18,7 +18,7 @@
#include <boost/beast/core/stream_traits.hpp> #include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/is_invocable.hpp> #include <boost/beast/core/detail/is_invocable.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/dispatch.hpp>
#include <boost/asio/write.hpp> #include <boost/asio/write.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
@ -102,8 +102,9 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"http::async_write_some")); "http::async_write_some"));
return net::post( auto ex = asio::get_associated_immediate_executor(*this, s_.get_executor());
s_.get_executor(), return net::dispatch(
ex,
beast::bind_front_handler( beast::bind_front_handler(
std::move(*this), ec, 0)); std::move(*this), ec, 0));
} }
@ -120,8 +121,9 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"http::async_write_some")); "http::async_write_some"));
return net::post( const auto ex = this->get_immediate_executor();
s_.get_executor(), return net::dispatch(
ex,
beast::bind_front_handler( beast::bind_front_handler(
std::move(*this), ec, 0)); std::move(*this), ec, 0));
} }
@ -219,8 +221,9 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"http::async_write")); "http::async_write"));
net::post( const auto ex = this->get_immediate_executor();
s_.get_executor(), net::dispatch(
ex,
std::move(*this)); std::move(*this));
} }
goto upcall; goto upcall;

View File

@ -192,8 +192,9 @@ read_some(
std::size_t bytes_transferred // the total number of bytes transferred from the stream std::size_t bytes_transferred // the total number of bytes transferred from the stream
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.
@ -400,8 +401,9 @@ read_header(
std::size_t bytes_transferred // the total number of bytes transferred from the stream std::size_t bytes_transferred // the total number of bytes transferred from the stream
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.
@ -610,8 +612,9 @@ read(
std::size_t bytes_transferred // the total number of bytes transferred from the stream std::size_t bytes_transferred // the total number of bytes transferred from the stream
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.
@ -829,8 +832,9 @@ read(
std::size_t bytes_transferred // the total number of bytes transferred from the stream std::size_t bytes_transferred // the total number of bytes transferred from the stream
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.

View File

@ -156,8 +156,9 @@ write_some(
std::size_t bytes_transferred // the number of bytes written to the stream std::size_t bytes_transferred // the number of bytes written to the stream
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.
@ -295,8 +296,9 @@ write_header(
std::size_t bytes_transferred // the number of bytes written to the stream std::size_t bytes_transferred // the number of bytes written to the stream
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.
@ -431,8 +433,9 @@ write(
std::size_t bytes_transferred // the number of bytes written to the stream std::size_t bytes_transferred // the number of bytes written to the stream
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.
@ -668,8 +671,9 @@ write(
std::size_t bytes_transferred // the number of bytes written to the stream std::size_t bytes_transferred // the number of bytes written to the stream
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.
@ -742,8 +746,9 @@ async_write(
std::size_t bytes_transferred // the number of bytes written to the stream std::size_t bytes_transferred // the number of bytes written to the stream
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.

View File

@ -23,7 +23,6 @@
#include <boost/beast/core/detail/buffer.hpp> #include <boost/beast/core/detail/buffer.hpp>
#include <boost/beast/version.hpp> #include <boost/beast/version.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/post.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <memory> #include <memory>

View File

@ -18,7 +18,7 @@
#include <boost/beast/core/stream_traits.hpp> #include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/bind_continuation.hpp> #include <boost/beast/core/detail/bind_continuation.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/dispatch.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <memory> #include <memory>
@ -106,7 +106,8 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"websocket::async_close")); "websocket::async_close"));
net::post(sp->stream().get_executor(), std::move(*this)); const auto ex = this->get_immediate_executor();
net::dispatch(ex, std::move(*this));
} }
BOOST_ASSERT(impl.wr_block.is_locked(this)); BOOST_ASSERT(impl.wr_block.is_locked(this));
} }
@ -167,7 +168,8 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"websocket::async_close")); "websocket::async_close"));
net::post(sp->stream().get_executor(), std::move(*this)); const auto ex = this->get_immediate_executor();
net::dispatch(ex, std::move(*this));
} }
BOOST_ASSERT(impl.rd_block.is_locked(this)); BOOST_ASSERT(impl.rd_block.is_locked(this));
if(impl.check_stop_now(ec)) if(impl.check_stop_now(ec))

View File

@ -17,6 +17,7 @@
#include <boost/beast/websocket/detail/frame.hpp> #include <boost/beast/websocket/detail/frame.hpp>
#include <boost/beast/websocket/impl/stream_impl.hpp> #include <boost/beast/websocket/impl/stream_impl.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <memory> #include <memory>
@ -99,7 +100,8 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"websocket::async_ping")); "websocket::async_ping"));
net::post(sp->stream().get_executor(), std::move(*this)); const auto ex = this->get_immediate_executor();
net::dispatch(ex, std::move(*this));
} }
BOOST_ASSERT(impl.wr_block.is_locked(this)); BOOST_ASSERT(impl.wr_block.is_locked(this));
} }

View File

@ -26,7 +26,6 @@
#include <boost/beast/core/detail/clamp.hpp> #include <boost/beast/core/detail/clamp.hpp>
#include <boost/beast/core/detail/config.hpp> #include <boost/beast/core/detail/config.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/post.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
@ -122,7 +121,8 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"websocket::async_read_some")); "websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this)); const auto ex = this->get_immediate_executor();
net::dispatch(ex, std::move(*this));
} }
BOOST_ASSERT(impl.rd_block.is_locked(this)); BOOST_ASSERT(impl.rd_block.is_locked(this));
@ -238,7 +238,8 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"websocket::async_read_some")); "websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this)); const auto ex = this->get_immediate_executor();
net::dispatch(ex, std::move(*this));
} }
BOOST_ASSERT(cont); BOOST_ASSERT(cont);
// VFALCO call check_stop_now() here? // VFALCO call check_stop_now() here?
@ -291,7 +292,8 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"websocket::async_read_some")); "websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this)); const auto ex = this->get_immediate_executor();
net::dispatch(ex, std::move(*this));
} }
BOOST_ASSERT(impl.wr_block.is_locked(this)); BOOST_ASSERT(impl.wr_block.is_locked(this));
if(impl.check_stop_now(ec)) if(impl.check_stop_now(ec))
@ -335,7 +337,8 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"websocket::async_read_some")); "websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this)); const auto ex = this->get_immediate_executor();
net::dispatch(ex, std::move(*this));
} }
BOOST_ASSERT(cont); BOOST_ASSERT(cont);
} }
@ -366,7 +369,8 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"websocket::async_read_some")); "websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this)); const auto ex = this->get_immediate_executor();
net::dispatch(ex, std::move(*this));
} }
BOOST_ASSERT(cont); BOOST_ASSERT(cont);
} }
@ -648,7 +652,8 @@ public:
__FILE__, __LINE__, __FILE__, __LINE__,
"websocket::async_read_some")); "websocket::async_read_some"));
net::post(sp->stream().get_executor(), std::move(*this)); const auto ex = this->get_immediate_executor();
net::dispatch(ex, std::move(*this));
} }
BOOST_ASSERT(impl.wr_block.is_locked(this)); BOOST_ASSERT(impl.wr_block.is_locked(this));
if(impl.check_stop_now(ec)) if(impl.check_stop_now(ec))

View File

@ -16,7 +16,7 @@
#include <boost/beast/core/detail/bind_continuation.hpp> #include <boost/beast/core/detail/bind_continuation.hpp>
#include <boost/beast/core/detail/is_invocable.hpp> #include <boost/beast/core/detail/is_invocable.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/dispatch.hpp>
#include <memory> #include <memory>
namespace boost { namespace boost {
@ -128,7 +128,8 @@ public:
"websocket::tcp::async_teardown" "websocket::tcp::async_teardown"
)); ));
net::post(s_.get_executor(), bind_front_handler( const auto ex = this->get_immediate_executor();
net::dispatch(ex, bind_front_handler(
std::move(*this), ec)); std::move(*this), ec));
} }
} }

View File

@ -199,7 +199,8 @@ operator()(
"websocket::async_write_some" "websocket::async_write_some"
)); ));
net::post(sp->stream().get_executor(), std::move(*this)); const auto ex = this->get_immediate_executor();
net::dispatch(ex, std::move(*this));
} }
BOOST_ASSERT(impl.wr_block.is_locked(this)); BOOST_ASSERT(impl.wr_block.is_locked(this));
} }

View File

@ -63,8 +63,9 @@ teardown(
error_code const& error // result of operation error_code const& error // result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.

View File

@ -931,11 +931,13 @@ public:
error_code const& ec // Result of operation error_code const& ec // Result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Example @par Example
@code @code
ws.async_handshake("localhost", "/", ws.async_handshake("localhost", "/",
@ -1013,11 +1015,13 @@ public:
error_code const& ec // Result of operation error_code const& ec // Result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Example @par Example
@code @code
response_type res; response_type res;
@ -1354,11 +1358,13 @@ public:
error_code const& ec // Result of operation error_code const& ec // Result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@see @see
@li <a href="https://tools.ietf.org/html/rfc6455#section-4.2">Websocket Opening Handshake Server Requirements (RFC6455)</a> @li <a href="https://tools.ietf.org/html/rfc6455#section-4.2">Websocket Opening Handshake Server Requirements (RFC6455)</a>
*/ */
@ -1421,11 +1427,13 @@ public:
error_code const& ec // Result of operation error_code const& ec // Result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@see @see
@li <a href="https://tools.ietf.org/html/rfc6455#section-4.2">Websocket Opening Handshake Server Requirements (RFC6455)</a> @li <a href="https://tools.ietf.org/html/rfc6455#section-4.2">Websocket Opening Handshake Server Requirements (RFC6455)</a>
*/ */
@ -1486,11 +1494,13 @@ public:
error_code const& ec // Result of operation error_code const& ec // Result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@see @see
@li <a href="https://tools.ietf.org/html/rfc6455#section-4.2">Websocket Opening Handshake Server Requirements (RFC6455)</a> @li <a href="https://tools.ietf.org/html/rfc6455#section-4.2">Websocket Opening Handshake Server Requirements (RFC6455)</a>
*/ */
@ -1622,11 +1632,13 @@ public:
error_code const& ec // Result of operation error_code const& ec // Result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following This asynchronous operation supports cancellation for the following
@ -1741,11 +1753,13 @@ public:
error_code const& ec // Result of operation error_code const& ec // Result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following This asynchronous operation supports cancellation for the following
@ -1864,11 +1878,13 @@ public:
error_code const& ec // Result of operation error_code const& ec // Result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following This asynchronous operation supports cancellation for the following
@ -2040,11 +2056,13 @@ public:
std::size_t bytes_written // Number of bytes appended to buffer std::size_t bytes_written // Number of bytes appended to buffer
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following This asynchronous operation supports cancellation for the following
@ -2234,11 +2252,13 @@ public:
std::size_t bytes_written // Number of bytes appended to buffer std::size_t bytes_written // Number of bytes appended to buffer
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following This asynchronous operation supports cancellation for the following
@ -2439,11 +2459,13 @@ public:
std::size_t bytes_written // Number of bytes written to the buffers std::size_t bytes_written // Number of bytes written to the buffers
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
@ -2578,11 +2600,13 @@ public:
// this will be less than the buffer_size. // this will be less than the buffer_size.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following This asynchronous operation supports cancellation for the following
@ -2717,11 +2741,13 @@ public:
// this will be less than the buffer_size. // this will be less than the buffer_size.
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
this function. Invocation of the handler will be performed in a Otherwise, the handler will not be invoked from within
manner equivalent to using `net::post`. this function. Invocation of the handler will be performed
by dispatching to the immediate executor. If no
immediate executor is specified, this is equivalent
to using `net::post`.
@par Per-Operation Cancellation @par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following This asynchronous operation supports cancellation for the following

View File

@ -78,8 +78,9 @@ teardown(
error_code const& error // result of operation error_code const& error // result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.
@ -158,8 +159,9 @@ teardown(
error_code const& error // result of operation error_code const& error // result of operation
); );
@endcode @endcode
Regardless of whether the asynchronous operation completes If the handler has an associated immediate executor,
immediately or not, the handler will not be invoked from within an immediate completion will be dispatched to it.
Otherwise, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`. manner equivalent to using `net::post`.

View File

@ -12,10 +12,12 @@
#include <boost/beast/_experimental/test/stream.hpp> #include <boost/beast/_experimental/test/stream.hpp>
#include <boost/beast/_experimental/test/tcp.hpp> #include <boost/beast/_experimental/test/tcp.hpp>
#include <boost/beast/_experimental/test/immediate_executor.hpp>
#include "test.hpp" #include "test.hpp"
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/strand.hpp> #include <boost/asio/strand.hpp>
#include <boost/asio/bind_immediate_executor.hpp>
#if BOOST_ASIO_HAS_CO_AWAIT #if BOOST_ASIO_HAS_CO_AWAIT
#include <boost/asio/use_awaitable.hpp> #include <boost/asio/use_awaitable.hpp>
#endif #endif
@ -729,6 +731,55 @@ public:
ws.async_close({}, move_only_handler{}); ws.async_close({}, move_only_handler{});
} }
void
testImmediate()
{
doFailLoop([&](test::fail_count& fc)
{
std::string const s = "Hello, world!";
multi_buffer b;
net::io_context ioc;
stream<test::stream> ws{ioc, fc};
std::size_t count = 0;
std::size_t ic = 0u;
test::immediate_executor imex{ic};
ws.async_read(b,
asio::bind_immediate_executor(imex,
[&](error_code ec, std::size_t)
{
if(ec != net::error::operation_aborted)
BOOST_THROW_EXCEPTION(
system_error{ec});
++count;
}));
ws.async_write(net::buffer(s),
asio::bind_immediate_executor(imex,
[&](error_code ec, std::size_t)
{
if(ec != net::error::operation_aborted)
BOOST_THROW_EXCEPTION(
system_error{ec});
++count;
}));
ws.async_ping({},
asio::bind_immediate_executor(imex,
[&](error_code ec)
{
if(ec != net::error::operation_aborted)
BOOST_THROW_EXCEPTION(
system_error{ec});
++count;
}));
BEAST_EXPECT(ioc.run() == 0);
BEAST_EXPECT(count == 3);
BEAST_EXPECT(ic == 6);
});
}
struct copyable_handler struct copyable_handler
{ {
template<class... Args> template<class... Args>
@ -754,6 +805,7 @@ public:
testTimeout(); testTimeout();
testSuspend(); testSuspend();
testMoveOnly(); testMoveOnly();
testImmediate();
#if BOOST_ASIO_HAS_CO_AWAIT #if BOOST_ASIO_HAS_CO_AWAIT
boost::ignore_unused(&close_test::testAwaitableCompiles); boost::ignore_unused(&close_test::testAwaitableCompiles);
#endif #endif