mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
New Context object for composed operations and continuation hooks
This commit is contained in:
@@ -302,6 +302,12 @@
|
|||||||
<ClInclude Include="BeastConfig.h" />
|
<ClInclude Include="BeastConfig.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\modules\beast_asio\basics\beast_HandlerCall.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\modules\beast_asio\basics\beast_PeerRole.cpp">
|
<ClCompile Include="..\..\modules\beast_asio\basics\beast_PeerRole.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
|||||||
@@ -1315,6 +1315,9 @@
|
|||||||
<ClCompile Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectLogicPROXY.cpp">
|
<ClCompile Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectLogicPROXY.cpp">
|
||||||
<Filter>beast_asio\handshake</Filter>
|
<Filter>beast_asio\handshake</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_asio\basics\beast_HandlerCall.cpp">
|
||||||
|
<Filter>beast_asio\basics</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="..\..\TODO.txt" />
|
<Text Include="..\..\TODO.txt" />
|
||||||
|
|||||||
353
modules/beast_asio/basics/beast_HandlerCall.cpp
Normal file
353
modules/beast_asio/basics/beast_HandlerCall.cpp
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
//
|
||||||
|
// Context
|
||||||
|
//
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
HandlerCall::Context::Context (Call* call) noexcept
|
||||||
|
: m_call (call)
|
||||||
|
{
|
||||||
|
bassert (m_call != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall::Context::Context () noexcept
|
||||||
|
: m_call (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall::Context::Context (Context const& other) noexcept
|
||||||
|
: m_call (other.m_call)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall::Context::Context (HandlerCall const& handler) noexcept
|
||||||
|
: m_call (handler.m_call.get ())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall::Context& HandlerCall::Context::operator= (Context other) noexcept
|
||||||
|
{
|
||||||
|
m_call = other.m_call;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandlerCall::Context::operator== (Call const* call) const noexcept
|
||||||
|
{
|
||||||
|
return m_call == call;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandlerCall::Context::operator!= (Call const* call) const noexcept
|
||||||
|
{
|
||||||
|
return m_call != call;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandlerCall::Context::isComposed () const noexcept
|
||||||
|
{
|
||||||
|
return m_call->is_continuation ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandlerCall::Context::isNull () const noexcept
|
||||||
|
{
|
||||||
|
return m_call == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandlerCall::Context::isNotNull () const noexcept
|
||||||
|
{
|
||||||
|
return m_call != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandlerCall::Context::operator== (Context other) const noexcept
|
||||||
|
{
|
||||||
|
return m_call == other.m_call;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandlerCall::Context::operator!= (Context other) const noexcept
|
||||||
|
{
|
||||||
|
return m_call != other.m_call;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* HandlerCall::Context::allocate (std::size_t size) const
|
||||||
|
{
|
||||||
|
return m_call->allocate (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::Context::deallocate (void* p, std::size_t size) const
|
||||||
|
{
|
||||||
|
m_call->deallocate (p, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Call
|
||||||
|
//
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
HandlerCall::Call::Call (Context context) noexcept
|
||||||
|
: m_context (context.isNull () ? Context (this) : context)
|
||||||
|
, m_is_continuation (false)
|
||||||
|
, m_is_final_continuation (false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall::Call::~Call ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall::Context HandlerCall::Call::getContext () const noexcept
|
||||||
|
{
|
||||||
|
return m_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandlerCall::Call::is_continuation () const noexcept
|
||||||
|
{
|
||||||
|
// If this goes off it means someone isn't calling getContext()!
|
||||||
|
bassert (m_context == this);
|
||||||
|
return m_is_continuation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::Call::set_continuation () noexcept
|
||||||
|
{
|
||||||
|
// Setting it twice means some code is sloppy!
|
||||||
|
bassert (! m_is_continuation);
|
||||||
|
|
||||||
|
m_is_continuation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::Call::set_final_continuation () noexcept
|
||||||
|
{
|
||||||
|
// Soemone called endComposed without calling beginComposed!
|
||||||
|
bassert (m_is_continuation);
|
||||||
|
// When true, we will clear
|
||||||
|
// m_is_continuation on our next completion
|
||||||
|
m_is_final_continuation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::Call::check_continuation () noexcept
|
||||||
|
{
|
||||||
|
if (m_is_final_continuation)
|
||||||
|
{
|
||||||
|
bassert (m_is_continuation);
|
||||||
|
|
||||||
|
m_is_continuation = false;
|
||||||
|
m_is_final_continuation = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::Call::operator() ()
|
||||||
|
{
|
||||||
|
check_continuation ();
|
||||||
|
dispatch ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::Call::operator() (error_code const& ec)
|
||||||
|
{
|
||||||
|
check_continuation ();
|
||||||
|
dispatch (ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::Call::operator() (error_code const& ec, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
check_continuation ();
|
||||||
|
dispatch (ec, bytes_transferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::Call::dispatch ()
|
||||||
|
{
|
||||||
|
pure_virtual_called ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::Call::dispatch (error_code const&)
|
||||||
|
{
|
||||||
|
pure_virtual_called ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::Call::dispatch (error_code const&, std::size_t)
|
||||||
|
{
|
||||||
|
pure_virtual_called ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* HandlerCall::Call::pure_virtual_called ()
|
||||||
|
{
|
||||||
|
// These shouldn't be getting called. But since the object returned
|
||||||
|
// by most implementations of bind have operator() up to high arity
|
||||||
|
// levels, it is not generally possible to write a traits test that
|
||||||
|
// works in all scenarios for detecting a particular signature of a
|
||||||
|
// handler.
|
||||||
|
//
|
||||||
|
fatal_error ("pure virtual called");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// HandlerCall
|
||||||
|
//
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
HandlerCall::HandlerCall () noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall::HandlerCall (HandlerCall const& other) noexcept
|
||||||
|
: m_call (other.m_call)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall& HandlerCall::operator= (HandlerCall const& other) noexcept
|
||||||
|
{
|
||||||
|
m_call = other.m_call;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
HandlerCall::HandlerCall (HandlerCall&& other) noexcept
|
||||||
|
: m_call (other.m_call)
|
||||||
|
{
|
||||||
|
other.m_call = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall& HandlerCall::operator= (HandlerCall&& other) noexcept
|
||||||
|
{
|
||||||
|
m_call = other.m_call;
|
||||||
|
other.m_call = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool HandlerCall::isNull () const noexcept
|
||||||
|
{
|
||||||
|
return m_call == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandlerCall::isNotNull () const noexcept
|
||||||
|
{
|
||||||
|
return m_call != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall::Context HandlerCall::getContext () const noexcept
|
||||||
|
{
|
||||||
|
bassert (m_call != nullptr);
|
||||||
|
return m_call->getContext ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandlerCall::isFinal () const noexcept
|
||||||
|
{
|
||||||
|
return m_call->getContext () == m_call.get ();
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall& HandlerCall::beginComposed () noexcept
|
||||||
|
{
|
||||||
|
// If this goes off it means that your handler is
|
||||||
|
// already sharing a context with another handler!
|
||||||
|
// You have to call beginComposed on the original handler.
|
||||||
|
//
|
||||||
|
bassert (isFinal ());
|
||||||
|
m_call->set_continuation ();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerCall& HandlerCall::endComposed () noexcept
|
||||||
|
{
|
||||||
|
// If this goes off it means that your handler is
|
||||||
|
// already sharing a context with another handler!
|
||||||
|
// You have to call beginComposed on the original handler.
|
||||||
|
//
|
||||||
|
bassert (isFinal ());
|
||||||
|
m_call->set_final_continuation ();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::operator() ()
|
||||||
|
{
|
||||||
|
(*m_call)();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::operator() (error_code const& ec)
|
||||||
|
{
|
||||||
|
(*m_call)(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerCall::operator() (error_code const& ec, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
(*m_call)(ec, bytes_transferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Specializations
|
||||||
|
//
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void* asio_handler_allocate (std::size_t size, HandlerCall* call)
|
||||||
|
{
|
||||||
|
// Always go through the call's context.
|
||||||
|
return call->getContext ().allocate (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* asio_handler_allocate (std::size_t size, HandlerCall::Call* call)
|
||||||
|
{
|
||||||
|
// Always go through the call's context.
|
||||||
|
return call->getContext ().allocate (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* asio_handler_allocate (std::size_t size, HandlerCall::Context* context)
|
||||||
|
{
|
||||||
|
return context->allocate (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void asio_handler_deallocate (void* p, std::size_t size, HandlerCall* call)
|
||||||
|
{
|
||||||
|
// Always go through the call's context.
|
||||||
|
call->getContext ().deallocate (p, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void asio_handler_deallocate (void* p, std::size_t size, HandlerCall::Call* call)
|
||||||
|
{
|
||||||
|
// Always go through the call's context.
|
||||||
|
call->getContext ().deallocate (p, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void asio_handler_deallocate (void* p, std::size_t size, HandlerCall::Context* context)
|
||||||
|
{
|
||||||
|
context->deallocate (p, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool asio_handler_is_continuation (HandlerCall* call)
|
||||||
|
{
|
||||||
|
return call->getContext().isComposed ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool asio_handler_is_continuation (HandlerCall::Call* call)
|
||||||
|
{
|
||||||
|
return call->getContext().isComposed ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool asio_handler_is_continuation (HandlerCall::Context*)
|
||||||
|
{
|
||||||
|
// Something is horribly wrong if we're trying to
|
||||||
|
// use a Context as a completion handler?
|
||||||
|
//
|
||||||
|
fatal_error ("A function was unexpectedly called.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -43,22 +43,56 @@ class HandlerCall
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
typedef boost::system::error_code error_code;
|
typedef boost::system::error_code error_code;
|
||||||
|
typedef boost::function <void(void)> invoked_type;
|
||||||
|
|
||||||
|
// Forward declarations needed for friendship
|
||||||
|
template <typename>
|
||||||
|
struct CallType;
|
||||||
|
struct Call;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef void result_type;
|
typedef void result_type;
|
||||||
|
|
||||||
// Really there are only 3 kings of functions.
|
struct Context;
|
||||||
// Except for the composed connect, which we haven't done yet.
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** HandlerCall construction tags.
|
||||||
|
|
||||||
|
These tags are used at the end of HandlerCall constructor parameter
|
||||||
|
lists to tell it what kind of Handler you are passing. For example:
|
||||||
|
|
||||||
|
@code
|
||||||
|
|
||||||
|
struct MyClass
|
||||||
|
{
|
||||||
|
void on_connect (error_code const& ec);
|
||||||
|
|
||||||
|
void connect (Address address)
|
||||||
|
{
|
||||||
|
HandlerCall myHandler (
|
||||||
|
bind (&MyClass::foo, this),
|
||||||
|
Connect ());
|
||||||
|
|
||||||
|
socket.async_connect (address, myHandler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
It would be nice if we could deduce the type of handler from the template
|
||||||
|
argument alone, but the return value of most implementations of bind seem
|
||||||
|
to satisfy the traits of ANY handler so that was scrapped.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
// These are the three basic supported function signatures
|
||||||
|
//
|
||||||
|
// ComposedConnectHandler is to-do
|
||||||
//
|
//
|
||||||
struct Post { }; // void()
|
struct Post { }; // void()
|
||||||
struct Error { }; // void(error_code)
|
struct Error { }; // void(error_code)
|
||||||
struct Transfer { }; // void(error_code, std::size_t)
|
struct Transfer { }; // void(error_code, std::size_t)
|
||||||
|
|
||||||
// These tags tell us what kind of Handler we have.
|
|
||||||
// It would be nice if we could deduce this, but the
|
|
||||||
// return value of a bind() seems to satisfy the
|
|
||||||
// requirements of ANY handler so that was scrapped.
|
|
||||||
|
|
||||||
// CompletionHandler
|
// CompletionHandler
|
||||||
//
|
//
|
||||||
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/CompletionHandler.html
|
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/CompletionHandler.html
|
||||||
@@ -99,177 +133,454 @@ public:
|
|||||||
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/BufferedHandshakeHandler.html
|
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/BufferedHandshakeHandler.html
|
||||||
//
|
//
|
||||||
typedef Transfer BufferedHandshake;
|
typedef Transfer BufferedHandshake;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
HandlerCall () noexcept
|
/** Construct a null HandlerCall.
|
||||||
{
|
|
||||||
}
|
A default constructed handler has no associated call. Passing
|
||||||
|
it as a handler to an asynchronous operation will result in
|
||||||
|
undefined behavior. This constructor exists so that you can do
|
||||||
|
things like have a class member "originalHandler" which starts
|
||||||
|
out as null, and then later assign it. Routines are provided to
|
||||||
|
test the handler against null.
|
||||||
|
*/
|
||||||
|
HandlerCall () noexcept;
|
||||||
|
|
||||||
|
/** Construct a HandlerCall.
|
||||||
|
|
||||||
|
Handler must meet this requirement:
|
||||||
|
CompletionHandler
|
||||||
|
|
||||||
|
HandlerCall will meet this requirement:
|
||||||
|
CompletionHandler
|
||||||
|
*/
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
HandlerCall (BOOST_ASIO_MOVE_ARG(Handler) handler, Completion)
|
HandlerCall (BOOST_ASIO_MOVE_ARG(Handler) handler, Completion,
|
||||||
|
Context context = Context ())
|
||||||
: m_call (construct <PostCallType> (
|
: m_call (construct <PostCallType> (
|
||||||
BOOST_ASIO_MOVE_CAST(Handler)(handler)))
|
BOOST_ASIO_MOVE_CAST(Handler)(handler),
|
||||||
|
context))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Construct a HandlerCall with one bound parameter.
|
||||||
|
|
||||||
|
Produce a CompletionHandler that includes one bound parameter.
|
||||||
|
This can be useful if you want to call io_service::post() on
|
||||||
|
the handler and you need to give it an already existing value,
|
||||||
|
like an error_code.
|
||||||
|
|
||||||
|
Invoking operator() on the HandlerCall will be the same as:
|
||||||
|
|
||||||
|
@code
|
||||||
|
|
||||||
|
handler (arg1);
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Handler must meet one of these requirements:
|
||||||
|
AcceptHandler
|
||||||
|
ConnectHandler
|
||||||
|
ShutdownHandler
|
||||||
|
HandshakeHandler
|
||||||
|
|
||||||
|
HandlerCall will meet this requirement:
|
||||||
|
CompletionHandler
|
||||||
|
*/
|
||||||
template <typename Handler, typename Arg1>
|
template <typename Handler, typename Arg1>
|
||||||
HandlerCall (BOOST_ASIO_MOVE_ARG(Handler) handler, Arg1 arg1, Completion)
|
HandlerCall (BOOST_ASIO_MOVE_ARG(Handler) handler, Arg1 arg1, Completion,
|
||||||
|
Context context = Context ())
|
||||||
: m_call (construct <PostCallType1> (
|
: m_call (construct <PostCallType1> (
|
||||||
BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1))
|
BOOST_ASIO_MOVE_CAST(Handler)(handler),
|
||||||
|
context, arg1))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Construct a HandlerCall with two bound parameters.
|
||||||
|
|
||||||
|
Produce a CompletionHandler that includes two bound parameters.
|
||||||
|
This can be useful if you want to call io_service::post() on
|
||||||
|
the handler and you need to give it two already existing values,
|
||||||
|
like an error_code and bytes_transferred.
|
||||||
|
|
||||||
|
Invoking operator() on the HandlerCall will be the same as:
|
||||||
|
|
||||||
|
@code
|
||||||
|
|
||||||
|
handler (arg1, arg2);
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Handler must meet one of these requirements:
|
||||||
|
ReadHandler
|
||||||
|
WriteHandler
|
||||||
|
BufferedHandshakeHandler
|
||||||
|
|
||||||
|
The HandlerCall will meet these requirements:
|
||||||
|
CompletionHandler
|
||||||
|
*/
|
||||||
template <typename Handler, typename Arg1, typename Arg2>
|
template <typename Handler, typename Arg1, typename Arg2>
|
||||||
HandlerCall (BOOST_ASIO_MOVE_ARG(Handler) handler, Arg1 arg1, Arg2 arg2, Completion)
|
HandlerCall (BOOST_ASIO_MOVE_ARG(Handler) handler,
|
||||||
|
Arg1 arg1, Arg2 arg2, Completion, Context context = Context ())
|
||||||
: m_call (construct <PostCallType2> (
|
: m_call (construct <PostCallType2> (
|
||||||
BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2))
|
BOOST_ASIO_MOVE_CAST(Handler)(handler),
|
||||||
|
context, arg1, arg2))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Construct a HandlerCall from a handler that takes an error_code
|
||||||
|
|
||||||
|
Handler must meet one of these requirements:
|
||||||
|
AcceptHandler
|
||||||
|
ConnectHandler
|
||||||
|
ShutdownHandler
|
||||||
|
HandshakeHandler
|
||||||
|
|
||||||
|
The HandlerCall will meet these requirements:
|
||||||
|
AcceptHandler
|
||||||
|
ConnectHandler
|
||||||
|
ShutdownHandler
|
||||||
|
HandshakeHandler
|
||||||
|
*/
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
HandlerCall (BOOST_ASIO_MOVE_ARG(Handler) handler, Error)
|
HandlerCall (BOOST_ASIO_MOVE_ARG(Handler) handler, Error,
|
||||||
|
Context context = Context ())
|
||||||
: m_call (construct <ErrorCallType> (
|
: m_call (construct <ErrorCallType> (
|
||||||
BOOST_ASIO_MOVE_CAST(Handler)(handler)))
|
BOOST_ASIO_MOVE_CAST(Handler)(handler),
|
||||||
|
context))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Construct a HandlerCall from a handler that takes an error_code and std::size
|
||||||
|
|
||||||
|
Handler must meet one of these requirements:
|
||||||
|
ReadHandler
|
||||||
|
WriteHandler
|
||||||
|
BufferedHandshakeHandler
|
||||||
|
|
||||||
|
The HandlerCall will meet these requirements:
|
||||||
|
ReadHandler
|
||||||
|
WriteHandler
|
||||||
|
BufferedHandshakeHandler
|
||||||
|
*/
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
HandlerCall (BOOST_ASIO_MOVE_ARG(Handler) handler, Transfer)
|
HandlerCall (BOOST_ASIO_MOVE_ARG(Handler) handler, Transfer,
|
||||||
|
Context context = Context ())
|
||||||
: m_call (construct <TransferCallType> (
|
: m_call (construct <TransferCallType> (
|
||||||
BOOST_ASIO_MOVE_CAST(Handler)(handler)))
|
BOOST_ASIO_MOVE_CAST(Handler)(handler),
|
||||||
|
context))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline HandlerCall (HandlerCall const& other) noexcept
|
/** Copy construction and assignment.
|
||||||
: m_call (other.m_call)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline HandlerCall& operator= (HandlerCall const& other) noexcept
|
HandlerCall is a very lightweight object that holds a shared
|
||||||
{
|
pointer to the wrapped handler. It is cheap to copy and pass
|
||||||
m_call = other.m_call;
|
around.
|
||||||
return *this;
|
|
||||||
}
|
Construction and assignment from other HandlerCall objects
|
||||||
|
executes in constant time, does not allocate or free memory,
|
||||||
|
and invokes no methods calls on the wrapped handler, except
|
||||||
|
for the case where the last reference on an existing handler
|
||||||
|
is removed.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
HandlerCall (HandlerCall const& other) noexcept;
|
||||||
|
HandlerCall& operator= (HandlerCall const& other) noexcept;
|
||||||
|
|
||||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
inline HandlerCall (HandlerCall && other) noexcept
|
HandlerCall (HandlerCall&& other) noexcept;
|
||||||
: m_call (other.m_call)
|
HandlerCall& operator= (HandlerCall&& other) noexcept;
|
||||||
{
|
|
||||||
other.m_call = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline HandlerCall& operator= (HandlerCall&& other) noexcept
|
|
||||||
{
|
|
||||||
m_call = other.m_call;
|
|
||||||
other.m_call = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
/** @} */
|
||||||
|
|
||||||
inline bool isNull () const noexcept
|
//--------------------------------------------------------------------------
|
||||||
{
|
|
||||||
return m_call == nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool isNotNull () const noexcept
|
/** Returns true if the HandlerCall is null.
|
||||||
{
|
|
||||||
return m_call != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void operator() ()
|
A null HandlerCall object may not be passed to
|
||||||
{
|
an asynchronous completion function.
|
||||||
(*m_call)();
|
*/
|
||||||
}
|
bool isNull () const noexcept;
|
||||||
|
|
||||||
inline void operator() (error_code const& ec)
|
/** Returns true if the HandlerCall is not null. */
|
||||||
{
|
bool isNotNull () const noexcept;
|
||||||
(*m_call)(ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void operator() (error_code const& ec, std::size_t bytes_transferred)
|
/** Retrieve the context associated with a handler.
|
||||||
|
|
||||||
|
The context will only be valid while the handler exists. In particular,
|
||||||
|
if the handler is dispatched all references to its context will become
|
||||||
|
invalid, and undefined behavior will result.
|
||||||
|
|
||||||
|
The typical use case is to acquire the context from a caller provided
|
||||||
|
completion handler, and use the context in a series of composed
|
||||||
|
operations. At the conclusion of the composed operations, the original
|
||||||
|
handler is invoked and the context is no longer needed.
|
||||||
|
|
||||||
|
Various methods are provided for easily creating your own completion
|
||||||
|
handlers that are associated with an existing context.
|
||||||
|
*/
|
||||||
|
Context getContext () const noexcept;
|
||||||
|
|
||||||
|
/** Determine if this handler is the final handler in a composed chain.
|
||||||
|
A Context is usually shared during a composed operation.
|
||||||
|
Normally you won't need to call this but it's useful for diagnostics.
|
||||||
|
Really what this means it that the context is its own wrapped handler.
|
||||||
|
*/
|
||||||
|
bool isFinal () const noexcept;
|
||||||
|
|
||||||
|
/** Mark this handler as part of a composed operation.
|
||||||
|
|
||||||
|
This is only valid to call if the handler is not already sharing
|
||||||
|
the context of another handler (i.e. it is already part of a
|
||||||
|
composed operation).
|
||||||
|
|
||||||
|
Any handlers that share the same context will result in true being
|
||||||
|
passed to the asio_is_continuation_hook. When you are ready to
|
||||||
|
issue the final call to the original handler (which will also
|
||||||
|
destroy the context), call endComposed on the original
|
||||||
|
handler.
|
||||||
|
|
||||||
|
To be clear, beginComposed and endComposed are called on the same
|
||||||
|
HandlerCall object, and that object was not constructed from another
|
||||||
|
context.
|
||||||
|
|
||||||
|
@see isComposed, endComposed
|
||||||
|
*/
|
||||||
|
HandlerCall& beginComposed () noexcept;
|
||||||
|
|
||||||
|
/** Indicate the end of a composed operation.
|
||||||
|
|
||||||
|
A composed operation starts with a handler that uses itself as its own
|
||||||
|
context. The composed operation issues new asynchronous calls with its
|
||||||
|
own callback, using the original handler's context. To optimize the
|
||||||
|
strategy for calling completion handlers, call beginComposed.
|
||||||
|
*/
|
||||||
|
HandlerCall& endComposed () noexcept;
|
||||||
|
|
||||||
|
/** Invoke the wrapped handler.
|
||||||
|
|
||||||
|
Normally you will not need to call this yourself. Since this is a
|
||||||
|
polymorphic wrapper, any attempt to use an operator that doesn't
|
||||||
|
correspond to the signature of the wrapped handler (taking into
|
||||||
|
account arguments bound at construction), will result in a fatal
|
||||||
|
error at run-time.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
void operator() ();
|
||||||
|
void operator() (error_code const& ec);
|
||||||
|
void operator() (error_code const& ec, std::size_t bytes_transferred);
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** The context of execution of a particular handler.
|
||||||
|
|
||||||
|
When writing composed operations (a sequence of asynchronous function
|
||||||
|
calls), it is important that the intermediate handlers run in the same
|
||||||
|
context as the handler originally provided to signal the end of the
|
||||||
|
composed operation.
|
||||||
|
|
||||||
|
An object of this type abstracts the execution context of any handler.
|
||||||
|
You can extract the context from an existing handler and associate
|
||||||
|
new handlers you create with that context. This allows composed
|
||||||
|
operations to be written easily, lifting the burden of meeting the
|
||||||
|
composed operation requirements.
|
||||||
|
|
||||||
|
In all cases, the Context will only be valid while the original handler
|
||||||
|
exists. It is the caller's responsibility to manage the usage and
|
||||||
|
lifetimes of these objects.
|
||||||
|
|
||||||
|
Context objects are lightweight and just hold a reference to the
|
||||||
|
underlying context. They are cheap to copy and pass around.
|
||||||
|
|
||||||
|
Supports these concepts:
|
||||||
|
DefaultConstructible
|
||||||
|
CopyConstructible
|
||||||
|
CopyAssignable
|
||||||
|
Destructible
|
||||||
|
*/
|
||||||
|
struct Context
|
||||||
{
|
{
|
||||||
(*m_call)(ec, bytes_transferred);
|
/** Construct a null Context.
|
||||||
}
|
When a null Context is specified as the Context to use when
|
||||||
|
creating a HandlerCall, it means to use the wrapped handler
|
||||||
|
as its own context. This is the default behavior.
|
||||||
|
*/
|
||||||
|
Context () noexcept;
|
||||||
|
|
||||||
|
/** Construct a Context from another Context. */
|
||||||
|
Context (Context const& other) noexcept;
|
||||||
|
|
||||||
|
/** Construct a Context from an existing handler's Context. */
|
||||||
|
Context (HandlerCall const& handler) noexcept;
|
||||||
|
|
||||||
|
/** Assign this Context from another Context. */
|
||||||
|
Context& operator= (Context other) noexcept;
|
||||||
|
|
||||||
|
/** Determine if this context is a composed asynchronous operation.
|
||||||
|
|
||||||
|
When a handler begins a composed operation it becomes its own
|
||||||
|
context (it is not constructed with a specified context). When
|
||||||
|
a composed operation starts, this will return true for all
|
||||||
|
handlers which share the context including the original handler.
|
||||||
|
|
||||||
|
You have to indicate that a composed operation is starting by
|
||||||
|
calling beginComposed on the original handler, performing
|
||||||
|
your operations using its context, and then call endComposed
|
||||||
|
before calling the original handler.
|
||||||
|
|
||||||
|
@see beginComposed, endComposed
|
||||||
|
*/
|
||||||
|
bool isComposed () const noexcept;
|
||||||
|
|
||||||
|
/** Determine whether or not this Context is a null Context.
|
||||||
|
Note that a non-null Context is no guarantee of
|
||||||
|
the validity of the context.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
bool isNull () const noexcept;
|
||||||
|
bool isNotNull () const noexcept;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** Compare two contexts.
|
||||||
|
This determines if the two contexts refer to the same underlying
|
||||||
|
completion handler and would have the same execution guarantees.
|
||||||
|
The behavior is undefined if either of the contexts have been
|
||||||
|
destroyed.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
bool operator== (Context other) const noexcept;
|
||||||
|
bool operator!= (Context other) const noexcept;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** Allocate and deallocate memory.
|
||||||
|
This takes into account any hooks installed by the context.
|
||||||
|
Normally you wont need to call this unless you are writing your
|
||||||
|
own asio_handler_invoke hook, or creating wrapped handlers.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
void* allocate (std::size_t size) const;
|
||||||
|
void deallocate (void* p, std::size_t size) const;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** Invoke the specified Function on the context.
|
||||||
|
|
||||||
|
This is equivalent to the following:
|
||||||
|
|
||||||
|
@code
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
void callOnContext (Function f, Context& context)
|
||||||
|
{
|
||||||
|
using boost_asio_handler_invoke_helpers;
|
||||||
|
invoke <Function, Context> (f, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Usually you won't need to call this unless you
|
||||||
|
are writing your own asio_handler_invoke hook.
|
||||||
|
|
||||||
|
The boost::function object is created partially on the
|
||||||
|
stack, using a custom Allocator which calls into the handler's
|
||||||
|
context to perform allocation and deallocation. We take ownership
|
||||||
|
of the passed Function object.
|
||||||
|
|
||||||
|
All of the safety guarantees of the original context are preserved
|
||||||
|
when going through this invoke function.
|
||||||
|
*/
|
||||||
|
template <typename Function>
|
||||||
|
void invoke (BOOST_ASIO_MOVE_ARG(Function) f)
|
||||||
|
{
|
||||||
|
invoked_type invoked (BOOST_ASIO_MOVE_CAST(Function)(f),
|
||||||
|
Allocator <invoked_type> (*this));
|
||||||
|
m_call->invoke (invoked);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (Call const* call) const noexcept;
|
||||||
|
bool operator!= (Call const* call) const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename Handler>
|
||||||
|
friend struct CallType;
|
||||||
|
friend struct Call;
|
||||||
|
|
||||||
|
Context (Call* call) noexcept;
|
||||||
|
|
||||||
|
// Note that we only store a pointer here. If the original
|
||||||
|
// Call is destroyed, the context will become invalid.
|
||||||
|
//
|
||||||
|
Call* m_call;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Implementation
|
// Implementation
|
||||||
//
|
//
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
struct Call;
|
// These construct the Call, a reference counted polymorphic wrapper around
|
||||||
|
// the handler and its context. We use MoveAssignable (rvalue-references)
|
||||||
// These construct the reference counted polymorphic wrapper (Call)
|
|
||||||
// around the handler. We use MoveAssignable (rvalue-references)
|
|
||||||
// assignments to take ownership of the object and bring it to our stack.
|
// assignments to take ownership of the object and bring it to our stack.
|
||||||
// From there, we use the context's hooked allocation function to create
|
// From there, we use the context's hooked allocation function to create a
|
||||||
// a single piece of memory to hold our wrapper. Then we use placement
|
// single piece of memory to hold our wrapper. Then we use placement new to
|
||||||
// new to construct the wrapper. The wrapper uses rvalue assignment
|
// construct the wrapper. The wrapper uses rvalue assignment to take
|
||||||
// to take ownership of the handler from the stack.
|
// ownership of the handler from the stack.
|
||||||
|
|
||||||
template <template <typename> class Container, typename Handler>
|
template <template <typename> class Container, typename Handler>
|
||||||
static Call* construct (BOOST_ASIO_MOVE_ARG(Handler) handler)
|
static Call* construct (BOOST_ASIO_MOVE_ARG(Handler) handler,
|
||||||
|
Context context)
|
||||||
{
|
{
|
||||||
typedef Container <Handler> ContainerType;
|
typedef Container <Handler> ContainerType;
|
||||||
Handler local (BOOST_ASIO_MOVE_CAST(Handler)(handler)); // move to stack
|
Handler local (BOOST_ASIO_MOVE_CAST(Handler)(handler));
|
||||||
std::size_t const size (sizeof (ContainerType));
|
std::size_t const size (sizeof (ContainerType));
|
||||||
void* const p = boost_asio_handler_alloc_helpers::
|
void* const p = boost_asio_handler_alloc_helpers::
|
||||||
allocate <Handler> (size, local);
|
allocate <Handler> (size, local);
|
||||||
return ::new (p) ContainerType (
|
return ::new (p) ContainerType (
|
||||||
BOOST_ASIO_MOVE_CAST(Handler)(local), size);
|
BOOST_ASIO_MOVE_CAST(Handler)(local), size, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <template <typename, typename> class Container,
|
template <template <typename, typename> class Container,
|
||||||
typename Handler, typename Arg1>
|
typename Handler, typename Arg1>
|
||||||
static Call* construct (BOOST_ASIO_MOVE_ARG(Handler) handler, Arg1 arg1)
|
static Call* construct (BOOST_ASIO_MOVE_ARG(Handler) handler,
|
||||||
|
Context context, Arg1 arg1)
|
||||||
{
|
{
|
||||||
typedef Container <Handler, Arg1> ContainerType;
|
typedef Container <Handler, Arg1> ContainerType;
|
||||||
Handler local (BOOST_ASIO_MOVE_CAST(Handler)(handler)); // move to stack
|
Handler local (BOOST_ASIO_MOVE_CAST(Handler)(handler));
|
||||||
std::size_t const size (sizeof (ContainerType));
|
std::size_t const size (sizeof (ContainerType));
|
||||||
void* const p = boost_asio_handler_alloc_helpers::
|
void* const p = boost_asio_handler_alloc_helpers::
|
||||||
allocate <Handler> (size, local);
|
allocate <Handler> (size, local);
|
||||||
return ::new (p) ContainerType (
|
return ::new (p) ContainerType (
|
||||||
BOOST_ASIO_MOVE_CAST(Handler)(local), size, arg1);
|
BOOST_ASIO_MOVE_CAST(Handler)(local),
|
||||||
|
size, context, arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <template <typename, typename, typename> class Container,
|
template <template <typename, typename, typename> class Container,
|
||||||
typename Handler, typename Arg1, typename Arg2>
|
typename Handler, typename Arg1, typename Arg2>
|
||||||
static Call* construct (BOOST_ASIO_MOVE_ARG(Handler) handler, Arg1 arg1, Arg2 arg2)
|
static Call* construct (BOOST_ASIO_MOVE_ARG(Handler) handler,
|
||||||
|
Context context, Arg1 arg1, Arg2 arg2)
|
||||||
{
|
{
|
||||||
typedef Container <Handler, Arg1, Arg2> ContainerType;
|
typedef Container <Handler, Arg1, Arg2> ContainerType;
|
||||||
Handler local (BOOST_ASIO_MOVE_CAST(Handler)(handler)); // move to stack
|
Handler local (BOOST_ASIO_MOVE_CAST(Handler)(handler));
|
||||||
std::size_t const size (sizeof (ContainerType));
|
std::size_t const size (sizeof (ContainerType));
|
||||||
void* const p = boost_asio_handler_alloc_helpers::
|
void* const p = boost_asio_handler_alloc_helpers::
|
||||||
allocate <Handler> (size, local);
|
allocate <Handler> (size, local);
|
||||||
return ::new (p) ContainerType (
|
return ::new (p) ContainerType (
|
||||||
BOOST_ASIO_MOVE_CAST(Handler)(local), size, arg1, arg2);
|
BOOST_ASIO_MOVE_CAST(Handler)(local),
|
||||||
}
|
size, context, arg1, arg2);
|
||||||
|
|
||||||
inline void* allocate (std::size_t size)
|
|
||||||
{
|
|
||||||
return m_call->allocate (size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void deallocate (void* p, std::size_t size)
|
|
||||||
{
|
|
||||||
m_call->deallocate (p, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void destroy ()
|
|
||||||
{
|
|
||||||
m_call->destroy ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
//
|
||||||
// Custom Allocator compatible with std::allocator and boost::function
|
// Custom Allocator compatible with std::allocator and boost::function
|
||||||
// which uses the underlying context to allocate memory. This is
|
// which uses the underlying context to allocate memory. This is vastly
|
||||||
// vastly more efficient in a variety of situations especially during
|
// more efficient in a variety of situations especially during an upcall.
|
||||||
// an upcall.
|
//
|
||||||
|
// The context must be valid for the duration of the invocation.
|
||||||
//
|
//
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Allocator
|
struct Allocator
|
||||||
@@ -282,14 +593,16 @@ private:
|
|||||||
typedef std::size_t size_type;
|
typedef std::size_t size_type;
|
||||||
typedef std::ptrdiff_t difference_type;
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
|
||||||
explicit Allocator (SharedObjectPtr <Call> const& call)
|
// Make sure this is the right context!
|
||||||
: m_call (call)
|
//
|
||||||
|
explicit Allocator (Context context)
|
||||||
|
: m_context (context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
Allocator (Allocator <U> const& other)
|
Allocator (Allocator <U> const& other)
|
||||||
: m_call (other.m_call)
|
: m_context (other.m_context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,13 +625,13 @@ private:
|
|||||||
pointer allocate (size_type n) const
|
pointer allocate (size_type n) const
|
||||||
{
|
{
|
||||||
size_type const bytes = n * sizeof (value_type);
|
size_type const bytes = n * sizeof (value_type);
|
||||||
return static_cast <pointer> (m_call->allocate (bytes));
|
return static_cast <pointer> (m_context.allocate (bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
void deallocate (pointer p, size_type n) const
|
void deallocate (pointer p, size_type n) const
|
||||||
{
|
{
|
||||||
size_type const bytes = n * sizeof (value_type);
|
size_type const bytes = n * sizeof (value_type);
|
||||||
m_call->deallocate (p, bytes);
|
m_context.deallocate (p, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type max_size () const noexcept
|
size_type max_size () const noexcept
|
||||||
@@ -340,83 +653,61 @@ private:
|
|||||||
template <class>
|
template <class>
|
||||||
friend struct Allocator;
|
friend struct Allocator;
|
||||||
|
|
||||||
// The wrapped handler is stored in a reference counted
|
// The context must remain valid for the lifetime of the allocator.
|
||||||
// container, so copies and pass by value is very cheap.
|
|
||||||
//
|
//
|
||||||
SharedObjectPtr <Call> m_call;
|
Context m_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// We use a boost::function to hold the Function from asio_handler_invoke.
|
|
||||||
//
|
|
||||||
typedef boost::function <void(void)> invoked_type;
|
|
||||||
|
|
||||||
// Invoke the specified Function object. The boost::function object is
|
|
||||||
// created partially on the stack, using a custom Allocator which calls
|
|
||||||
// into the handler's context to perform allocation and deallocation.
|
|
||||||
// We take ownership of the passed Function object, and then ownership
|
|
||||||
//
|
|
||||||
// All of the safety guarantees of the original context are preserved
|
|
||||||
// when going through this invoke function.
|
|
||||||
//
|
|
||||||
template <typename Function>
|
|
||||||
void invoke (BOOST_ASIO_MOVE_ARG(Function) f)
|
|
||||||
{
|
|
||||||
invoked_type invoked (BOOST_ASIO_MOVE_CAST(Function)(f),
|
|
||||||
Allocator <invoked_type> (m_call));
|
|
||||||
m_call->invoke (invoked);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Abstract handler wrapper
|
// Abstract handler wrapper
|
||||||
//
|
//
|
||||||
struct Call : public SharedObject
|
struct Call : public SharedObject
|
||||||
{
|
{
|
||||||
Call ()
|
public:
|
||||||
{
|
explicit Call (Context context) noexcept;
|
||||||
}
|
~Call ();
|
||||||
|
|
||||||
~Call ()
|
Context getContext () const noexcept;
|
||||||
{
|
|
||||||
|
|
||||||
}
|
// Determine if the completion handler is a continuation
|
||||||
|
// of a composed operation. It's generally not possible
|
||||||
|
// to know this from here, so there's an interface to
|
||||||
|
// set the flag.
|
||||||
|
//
|
||||||
|
// Our asio_handler_is_continuation hook calls this.
|
||||||
|
//
|
||||||
|
bool is_continuation () const noexcept;
|
||||||
|
void set_continuation () noexcept;
|
||||||
|
void set_final_continuation () noexcept;
|
||||||
|
|
||||||
virtual void operator() ()
|
void operator() ();
|
||||||
{
|
void operator() (error_code const&);
|
||||||
pure_virtual_called ();
|
void operator() (error_code const&, std::size_t);
|
||||||
}
|
|
||||||
|
|
||||||
virtual void operator() (error_code const&)
|
|
||||||
{
|
|
||||||
pure_virtual_called ();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void operator() (error_code const&, std::size_t)
|
|
||||||
{
|
|
||||||
pure_virtual_called ();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void* allocate (std::size_t) = 0;
|
virtual void* allocate (std::size_t) = 0;
|
||||||
|
|
||||||
virtual void deallocate (void*, std::size_t) = 0;
|
virtual void deallocate (void*, std::size_t) = 0;
|
||||||
|
virtual void destroy () = 0;
|
||||||
|
|
||||||
virtual void invoke (invoked_type&) = 0;
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
virtual void destroy () = 0;
|
protected:
|
||||||
|
void check_continuation () noexcept;
|
||||||
|
|
||||||
static void* pure_virtual_called ()
|
virtual void dispatch ();
|
||||||
{
|
virtual void dispatch (error_code const&);
|
||||||
// These shouldn't be getting called. But since the object returned
|
virtual void dispatch (error_code const&, std::size_t);
|
||||||
// by most implementations of bind have operator() up to high arity
|
|
||||||
// levels, it is not generally possible to write a traits test that
|
static void* pure_virtual_called ();
|
||||||
// works in all scenarios for detecting a particular signature of a
|
|
||||||
// handler.
|
Context const m_context;
|
||||||
//
|
bool m_is_continuation;
|
||||||
fatal_error ("pure virtual called");
|
bool m_is_final_continuation;
|
||||||
return nullptr;
|
|
||||||
}
|
private:
|
||||||
|
// called by Context
|
||||||
|
friend struct Context;
|
||||||
|
virtual void invoke (invoked_type&) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Required for gaining access to our hooks
|
// Required for gaining access to our hooks
|
||||||
@@ -436,9 +727,18 @@ private:
|
|||||||
// The size parameter corresponds to how much we allocated using
|
// The size parameter corresponds to how much we allocated using
|
||||||
// the custom allocator, and is required for deallocation.
|
// the custom allocator, and is required for deallocation.
|
||||||
//
|
//
|
||||||
CallType (BOOST_ASIO_MOVE_ARG(Handler) handler, std::size_t size)
|
// If the passed context is null, we will use the handler itself
|
||||||
: m_handler (BOOST_ASIO_MOVE_CAST(Handler)(handler))
|
// as the context (this is what normally happens when you pass a
|
||||||
|
// handler into an asynchronous function operation).
|
||||||
|
//
|
||||||
|
// Context must have Call as a base or this will result in
|
||||||
|
// undefined behavior.
|
||||||
|
//
|
||||||
|
CallType (BOOST_ASIO_MOVE_ARG(Handler) handler,
|
||||||
|
std::size_t size, Context context)
|
||||||
|
: Call (context)
|
||||||
, m_size (size)
|
, m_size (size)
|
||||||
|
, m_handler (BOOST_ASIO_MOVE_CAST(Handler)(handler))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,10 +747,12 @@ private:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate using the handler's context.
|
// Allocate using the original handler as the context.
|
||||||
//
|
//
|
||||||
void* allocate (std::size_t bytes)
|
void* allocate (std::size_t bytes)
|
||||||
{
|
{
|
||||||
|
// If this goes off someone didn't call getContext()!
|
||||||
|
bassert (m_context == this);
|
||||||
return boost_asio_handler_alloc_helpers::
|
return boost_asio_handler_alloc_helpers::
|
||||||
allocate <Handler> (bytes, m_handler);
|
allocate <Handler> (bytes, m_handler);
|
||||||
}
|
}
|
||||||
@@ -460,6 +762,8 @@ private:
|
|||||||
//
|
//
|
||||||
void deallocate (void* p, std::size_t size)
|
void deallocate (void* p, std::size_t size)
|
||||||
{
|
{
|
||||||
|
// If this goes off someone didn't call getContext()!
|
||||||
|
bassert (m_context == this);
|
||||||
boost_asio_handler_alloc_helpers::
|
boost_asio_handler_alloc_helpers::
|
||||||
deallocate <Handler> (p, size, m_handler);
|
deallocate <Handler> (p, size, m_handler);
|
||||||
}
|
}
|
||||||
@@ -469,6 +773,8 @@ private:
|
|||||||
//
|
//
|
||||||
void invoke (invoked_type& invoked)
|
void invoke (invoked_type& invoked)
|
||||||
{
|
{
|
||||||
|
// If this goes off someone didn't call getContext()!
|
||||||
|
bassert (m_context == this);
|
||||||
boost_asio_handler_invoke_helpers::
|
boost_asio_handler_invoke_helpers::
|
||||||
invoke <invoked_type, Handler> (invoked, m_handler);
|
invoke <invoked_type, Handler> (invoked, m_handler);
|
||||||
}
|
}
|
||||||
@@ -515,8 +821,10 @@ private:
|
|||||||
pure_virtual_called ();
|
pure_virtual_called ();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
std::size_t const m_size;
|
std::size_t const m_size;
|
||||||
|
|
||||||
|
protected:
|
||||||
Handler m_handler;
|
Handler m_handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -525,12 +833,14 @@ private:
|
|||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
struct PostCallType : CallType <Handler>
|
struct PostCallType : CallType <Handler>
|
||||||
{
|
{
|
||||||
PostCallType (BOOST_ASIO_MOVE_ARG(Handler) handler, std::size_t size)
|
PostCallType (BOOST_ASIO_MOVE_ARG(Handler) handler,
|
||||||
: CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler), size)
|
std::size_t size, Context context)
|
||||||
|
: CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler),
|
||||||
|
size, context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator() ()
|
void dispatch ()
|
||||||
{
|
{
|
||||||
this->m_handler ();
|
this->m_handler ();
|
||||||
}
|
}
|
||||||
@@ -539,13 +849,15 @@ private:
|
|||||||
template <typename Handler, typename Arg1>
|
template <typename Handler, typename Arg1>
|
||||||
struct PostCallType1 : CallType <Handler>
|
struct PostCallType1 : CallType <Handler>
|
||||||
{
|
{
|
||||||
PostCallType1 (BOOST_ASIO_MOVE_ARG(Handler) handler, std::size_t size, Arg1 arg1)
|
PostCallType1 (BOOST_ASIO_MOVE_ARG(Handler) handler,
|
||||||
: CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler), size)
|
std::size_t size, Context context, Arg1 arg1)
|
||||||
|
: CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler),
|
||||||
|
size, context)
|
||||||
, m_arg1 (arg1)
|
, m_arg1 (arg1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator() ()
|
void dispatch ()
|
||||||
{
|
{
|
||||||
this->m_handler (m_arg1);
|
this->m_handler (m_arg1);
|
||||||
}
|
}
|
||||||
@@ -556,14 +868,16 @@ private:
|
|||||||
template <typename Handler, typename Arg1, typename Arg2>
|
template <typename Handler, typename Arg1, typename Arg2>
|
||||||
struct PostCallType2 : CallType <Handler>
|
struct PostCallType2 : CallType <Handler>
|
||||||
{
|
{
|
||||||
PostCallType2 (BOOST_ASIO_MOVE_ARG(Handler) handler, std::size_t size, Arg1 arg1, Arg2 arg2)
|
PostCallType2 (BOOST_ASIO_MOVE_ARG(Handler) handler,
|
||||||
: CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler), size)
|
std::size_t size, Context context, Arg1 arg1, Arg2 arg2)
|
||||||
|
: CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler),
|
||||||
|
size, context)
|
||||||
, m_arg1 (arg1)
|
, m_arg1 (arg1)
|
||||||
, m_arg2 (arg2)
|
, m_arg2 (arg2)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator() ()
|
void dispatch ()
|
||||||
{
|
{
|
||||||
this->m_handler (m_arg1, m_arg2);
|
this->m_handler (m_arg1, m_arg2);
|
||||||
}
|
}
|
||||||
@@ -575,12 +889,14 @@ private:
|
|||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
struct ErrorCallType : CallType <Handler>
|
struct ErrorCallType : CallType <Handler>
|
||||||
{
|
{
|
||||||
ErrorCallType (BOOST_ASIO_MOVE_ARG(Handler) handler, std::size_t size)
|
ErrorCallType (BOOST_ASIO_MOVE_ARG(Handler) handler,
|
||||||
: CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler), size)
|
std::size_t size, Context context)
|
||||||
|
: CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler),
|
||||||
|
size, context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator() (error_code const& ec)
|
void dispatch (error_code const& ec)
|
||||||
{
|
{
|
||||||
this->m_handler (ec);
|
this->m_handler (ec);
|
||||||
}
|
}
|
||||||
@@ -589,12 +905,14 @@ private:
|
|||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
struct TransferCallType : CallType <Handler>
|
struct TransferCallType : CallType <Handler>
|
||||||
{
|
{
|
||||||
TransferCallType (BOOST_ASIO_MOVE_ARG(Handler) handler, std::size_t size)
|
TransferCallType (BOOST_ASIO_MOVE_ARG(Handler) handler,
|
||||||
: CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler), size)
|
std::size_t size, Context context)
|
||||||
|
: CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler),
|
||||||
|
size, context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator() (error_code const& ec, std::size_t bytes_transferred)
|
void dispatch (error_code const& ec, std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
this->m_handler (ec, bytes_transferred);
|
this->m_handler (ec, bytes_transferred);
|
||||||
}
|
}
|
||||||
@@ -606,6 +924,15 @@ private:
|
|||||||
friend void* asio_handler_allocate (std::size_t, HandlerCall*);
|
friend void* asio_handler_allocate (std::size_t, HandlerCall*);
|
||||||
friend void asio_handler_deallocate (void*, std::size_t, HandlerCall*);
|
friend void asio_handler_deallocate (void*, std::size_t, HandlerCall*);
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
friend void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function), Call*);
|
||||||
|
friend void* asio_handler_allocate (std::size_t, Call*);
|
||||||
|
friend void asio_handler_deallocate (void*, std::size_t, Call*);
|
||||||
|
|
||||||
|
friend bool asio_handler_is_continuation (HandlerCall* call);
|
||||||
|
friend bool asio_handler_is_continuation (HandlerCall::Call* call);
|
||||||
|
friend bool asio_handler_is_continuation (HandlerCall::Context* context);
|
||||||
|
|
||||||
SharedObjectPtr <Call> m_call;
|
SharedObjectPtr <Call> m_call;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -672,32 +999,56 @@ public:
|
|||||||
//
|
//
|
||||||
// Specializations
|
// Specializations
|
||||||
//
|
//
|
||||||
// asio_handler_invoke, asio_handler_allocate, asio_handler_deallocate
|
// ContainerDeletePolicy
|
||||||
|
// asio_handler_invoke
|
||||||
|
// asio_handler_allocate
|
||||||
|
// asio_handler_deallocate
|
||||||
//
|
//
|
||||||
|
|
||||||
template <class Function>
|
|
||||||
void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function) f, HandlerCall* call)
|
|
||||||
{
|
|
||||||
call->invoke (BOOST_ASIO_MOVE_CAST(Function)(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void* asio_handler_allocate (std::size_t size, HandlerCall* call)
|
|
||||||
{
|
|
||||||
return call->allocate (size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void asio_handler_deallocate (void* p, std::size_t size, HandlerCall* call)
|
|
||||||
{
|
|
||||||
call->deallocate (p, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct ContainerDeletePolicy <HandlerCall::Call>
|
struct ContainerDeletePolicy <HandlerCall::Call>
|
||||||
{
|
{
|
||||||
|
// SharedObjectPtr will use this when
|
||||||
|
// the reference count drops to zero.
|
||||||
|
//
|
||||||
static void destroy (HandlerCall::Call* call)
|
static void destroy (HandlerCall::Call* call)
|
||||||
{
|
{
|
||||||
call->destroy ();
|
call->destroy ();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function) f, HandlerCall::Context* context)
|
||||||
|
{
|
||||||
|
context->invoke (BOOST_ASIO_MOVE_CAST(Function)(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function) f, HandlerCall* call)
|
||||||
|
{
|
||||||
|
// Always go through the call's context.
|
||||||
|
call->getContext().invoke (BOOST_ASIO_MOVE_CAST(Function)(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function) f, HandlerCall::Call* call)
|
||||||
|
{
|
||||||
|
// Always go through the call's context.
|
||||||
|
call->getContext().invoke (BOOST_ASIO_MOVE_CAST(Function)(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void* asio_handler_allocate (std::size_t size, HandlerCall* call);
|
||||||
|
void* asio_handler_allocate (std::size_t size, HandlerCall::Call* call);
|
||||||
|
void* asio_handler_allocate (std::size_t size, HandlerCall::Context* context);
|
||||||
|
|
||||||
|
void asio_handler_deallocate (void* p, std::size_t size, HandlerCall* call);
|
||||||
|
void asio_handler_deallocate (void* p, std::size_t size, HandlerCall::Call* call);
|
||||||
|
void asio_handler_deallocate (void* p, std::size_t size, HandlerCall::Context* context);
|
||||||
|
|
||||||
|
bool asio_handler_is_continuation (HandlerCall* call);
|
||||||
|
bool asio_handler_is_continuation (HandlerCall::Call* call);
|
||||||
|
bool asio_handler_is_continuation (HandlerCall::Context* context);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
namespace beast
|
namespace beast
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#include "basics/beast_HandlerCall.cpp"
|
||||||
#include "basics/beast_PeerRole.cpp"
|
#include "basics/beast_PeerRole.cpp"
|
||||||
|
|
||||||
#include "sockets/beast_SocketBase.cpp"
|
#include "sockets/beast_SocketBase.cpp"
|
||||||
|
|||||||
@@ -152,13 +152,11 @@ public:
|
|||||||
m_origHandler = ErrorCall (
|
m_origHandler = ErrorCall (
|
||||||
BOOST_ASIO_MOVE_CAST(HandshakeHandler)
|
BOOST_ASIO_MOVE_CAST(HandshakeHandler)
|
||||||
(HandshakeHandler(init.handler)));
|
(HandshakeHandler(init.handler)));
|
||||||
bassert (m_origBufferedHandler.isNull ());
|
|
||||||
async_do_handshake (type, ConstBuffers ());
|
async_do_handshake (type, ConstBuffers ());
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
#else
|
#else
|
||||||
m_origHandler = ErrorCall (
|
m_origHandler = ErrorCall (
|
||||||
BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler));
|
BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler));
|
||||||
bassert (m_origBufferedHandler.isNull ());
|
|
||||||
async_do_handshake (type, ConstBuffers ());
|
async_do_handshake (type, ConstBuffers ());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -184,13 +182,11 @@ public:
|
|||||||
m_origBufferedHandler = TransferCall (
|
m_origBufferedHandler = TransferCall (
|
||||||
BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)
|
BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)
|
||||||
(BufferedHandshakeHandler(init.handler)));
|
(BufferedHandshakeHandler(init.handler)));
|
||||||
bassert (m_origHandler.isNull ());
|
|
||||||
async_do_handshake (type, ConstBuffers (buffers));
|
async_do_handshake (type, ConstBuffers (buffers));
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
#else
|
#else
|
||||||
m_origBufferedHandler = TransferCall (
|
m_origBufferedHandler = TransferCall (
|
||||||
BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler(handler)));
|
BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler(handler)));
|
||||||
bassert (m_origHandler.isNull ());
|
|
||||||
async_do_handshake (type, ConstBuffers (buffers));
|
async_do_handshake (type, ConstBuffers (buffers));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -245,6 +241,22 @@ public:
|
|||||||
|
|
||||||
void async_do_handshake (handshake_type type, ConstBuffers const& buffers)
|
void async_do_handshake (handshake_type type, ConstBuffers const& buffers)
|
||||||
{
|
{
|
||||||
|
// Get the execution context from the original handler
|
||||||
|
// and signal the beginning of our composed operation.
|
||||||
|
//
|
||||||
|
if (m_origHandler.isNotNull ())
|
||||||
|
{
|
||||||
|
m_origHandler.beginComposed ();
|
||||||
|
m_context = m_origHandler.getContext ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_origBufferedHandler.beginComposed ();
|
||||||
|
m_context = m_origBufferedHandler.getContext ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bassert (m_context.isNotNull ());
|
||||||
|
|
||||||
// Transfer caller data to our buffer.
|
// Transfer caller data to our buffer.
|
||||||
// We commit the bytes in on_async_read_some.
|
// We commit the bytes in on_async_read_some.
|
||||||
//
|
//
|
||||||
@@ -280,7 +292,11 @@ public:
|
|||||||
if (! m_origBufferedHandler.isNull ())
|
if (! m_origBufferedHandler.isNull ())
|
||||||
{
|
{
|
||||||
bassert (m_origHandler.isNull ());
|
bassert (m_origHandler.isNull ());
|
||||||
// continuation?
|
|
||||||
|
// The composed operation has completed and
|
||||||
|
// the original handler will eventually get called.
|
||||||
|
//
|
||||||
|
m_origBufferedHandler.endComposed ();
|
||||||
m_callback->on_async_detect (m_logic.get (), ec,
|
m_callback->on_async_detect (m_logic.get (), ec,
|
||||||
ConstBuffers (m_buffer.data ()), m_origBufferedHandler);
|
ConstBuffers (m_buffer.data ()), m_origBufferedHandler);
|
||||||
|
|
||||||
@@ -288,11 +304,12 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bassert (! m_origHandler.isNull ())
|
// The composed operation has completed and
|
||||||
// continuation?
|
// the original handler will eventually get called.
|
||||||
|
//
|
||||||
|
m_origHandler.endComposed ();
|
||||||
m_callback->on_async_detect (m_logic.get (), ec,
|
m_callback->on_async_detect (m_logic.get (), ec,
|
||||||
ConstBuffers (m_buffer.data ()), m_origHandler);
|
ConstBuffers (m_buffer.data ()), m_origHandler);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,27 +319,33 @@ public:
|
|||||||
buffer_type::mutable_buffers_type buffers (m_buffer.prepare (
|
buffer_type::mutable_buffers_type buffers (m_buffer.prepare (
|
||||||
needed - available));
|
needed - available));
|
||||||
|
|
||||||
// need a continuation hook here?
|
// Perform the asynchronous operation using the context
|
||||||
m_next_layer.async_read_some (buffers, boost::bind (
|
// of the original handler. This ensures that we meet the
|
||||||
&this_type::on_async_read_some, this, boost::asio::placeholders::error,
|
// execution safety requirements of the handler.
|
||||||
boost::asio::placeholders::bytes_transferred));
|
//
|
||||||
|
HandlerCall handler (boost::bind (
|
||||||
|
&this_type::on_async_read_some, this,
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred),
|
||||||
|
HandlerCall::Read (), m_context);
|
||||||
|
m_next_layer.async_read_some (buffers, handler);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error condition
|
||||||
|
|
||||||
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
|
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
|
||||||
if (! m_origBufferedHandler.isNull ())
|
if (! m_origBufferedHandler.isNull ())
|
||||||
{
|
{
|
||||||
bassert (m_origHandler.isNull ());
|
m_origBufferedHandler.endComposed ();
|
||||||
// continuation?
|
|
||||||
m_callback->on_async_detect (m_logic.get (), ec,
|
m_callback->on_async_detect (m_logic.get (), ec,
|
||||||
ConstBuffers (m_buffer.data ()), m_origBufferedHandler);
|
ConstBuffers (m_buffer.data ()), m_origBufferedHandler);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bassert (! m_origHandler.isNull ())
|
m_origBufferedHandler.endComposed ();
|
||||||
// continuation?
|
|
||||||
m_callback->on_async_detect (m_logic.get (), ec,
|
m_callback->on_async_detect (m_logic.get (), ec,
|
||||||
ConstBuffers (m_buffer.data ()), m_origHandler);
|
ConstBuffers (m_buffer.data ()), m_origHandler);
|
||||||
}
|
}
|
||||||
@@ -335,6 +358,7 @@ private:
|
|||||||
HandshakeDetectLogicType <Logic> m_logic;
|
HandshakeDetectLogicType <Logic> m_logic;
|
||||||
ErrorCall m_origHandler;
|
ErrorCall m_origHandler;
|
||||||
TransferCall m_origBufferedHandler;
|
TransferCall m_origBufferedHandler;
|
||||||
|
HandlerCall::Context m_context;
|
||||||
};
|
};
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user