Add custom allocation support on Windows.
This commit is contained in:
parent
80782580c6
commit
011d4f8e9c
@ -37,6 +37,7 @@
|
||||
#include "asio/demuxer_service.hpp"
|
||||
#include "asio/error_handler.hpp"
|
||||
#include "asio/error.hpp"
|
||||
#include "asio/handler_alloc_hook.hpp"
|
||||
#include "asio/ipv4/address.hpp"
|
||||
#include "asio/ipv4/basic_host_resolver.hpp"
|
||||
#include "asio/ipv4/host.hpp"
|
||||
|
@ -17,6 +17,10 @@
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
#include <memory>
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#include "asio/service_factory.hpp"
|
||||
#include "asio/detail/bind_handler.hpp"
|
||||
#include "asio/detail/noncopyable.hpp"
|
||||
@ -52,7 +56,7 @@ namespace asio {
|
||||
*
|
||||
* @sa \ref demuxer_handler_exception
|
||||
*/
|
||||
template <typename Demuxer_Service>
|
||||
template <typename Demuxer_Service, typename Allocator = std::allocator<void> >
|
||||
class basic_demuxer
|
||||
: private noncopyable
|
||||
{
|
||||
@ -61,7 +65,7 @@ public:
|
||||
typedef Demuxer_Service service_type;
|
||||
|
||||
/// The allocator type for the demuxer.
|
||||
typedef typename service_type::allocator_type allocator_type;
|
||||
typedef Allocator allocator_type;
|
||||
|
||||
/// Default constructor.
|
||||
basic_demuxer()
|
||||
@ -70,6 +74,14 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// Construct using the supplied allocator.
|
||||
explicit basic_demuxer(const allocator_type& allocator)
|
||||
: allocator_(allocator),
|
||||
service_registry_(*this),
|
||||
service_(get_service(service_factory<Demuxer_Service>()))
|
||||
{
|
||||
}
|
||||
|
||||
/// Construct using the supplied service_factory to get the demuxer service.
|
||||
explicit basic_demuxer(const service_factory<Demuxer_Service>& factory)
|
||||
: service_registry_(*this),
|
||||
@ -77,6 +89,16 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// Construct using the supplied service_factory to get the demuxer service,
|
||||
/// as well as a custom allocator.
|
||||
explicit basic_demuxer(const service_factory<Demuxer_Service>& factory,
|
||||
const allocator_type& allocator)
|
||||
: allocator_(allocator),
|
||||
service_registry_(*this),
|
||||
service_(get_service(factory))
|
||||
{
|
||||
}
|
||||
|
||||
/// Return a copy of the allocator associated with the demuxer.
|
||||
/**
|
||||
* The get_allocator() returns a copy of the allocator object used by the
|
||||
@ -86,7 +108,7 @@ public:
|
||||
*/
|
||||
allocator_type get_allocator() const
|
||||
{
|
||||
return service_.get_allocator();
|
||||
return allocator_;
|
||||
}
|
||||
|
||||
/// Run the demuxer's event processing loop.
|
||||
@ -199,12 +221,12 @@ public:
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
unspecified
|
||||
#else
|
||||
detail::wrapped_handler<basic_demuxer<Demuxer_Service>, Handler>
|
||||
detail::wrapped_handler<basic_demuxer<Demuxer_Service, Allocator>, Handler>
|
||||
#endif
|
||||
wrap(Handler handler)
|
||||
{
|
||||
return detail::wrapped_handler<basic_demuxer<Demuxer_Service>, Handler>(
|
||||
*this, handler);
|
||||
return detail::wrapped_handler<
|
||||
basic_demuxer<Demuxer_Service, Allocator>, Handler>(*this, handler);
|
||||
}
|
||||
|
||||
/// Obtain the service interface corresponding to the given type.
|
||||
@ -235,8 +257,12 @@ private:
|
||||
detail::signal_init<> init_;
|
||||
#endif
|
||||
|
||||
// The allocator associated with the demuxer.
|
||||
allocator_type allocator_;
|
||||
|
||||
/// The service registry.
|
||||
detail::service_registry<basic_demuxer<Demuxer_Service> > service_registry_;
|
||||
detail::service_registry<basic_demuxer<Demuxer_Service, Allocator> >
|
||||
service_registry_;
|
||||
|
||||
/// The underlying demuxer service implementation.
|
||||
Demuxer_Service& service_;
|
||||
@ -251,8 +277,8 @@ private:
|
||||
* The work class is copy-constructible so that it may be used as a data member
|
||||
* in a handler class. It is not assignable.
|
||||
*/
|
||||
template <typename Demuxer_Service>
|
||||
class basic_demuxer<Demuxer_Service>::work
|
||||
template <typename Demuxer_Service, typename Allocator>
|
||||
class basic_demuxer<Demuxer_Service, typename Allocator>::work
|
||||
{
|
||||
public:
|
||||
/// Constructor notifies the demuxer that work is starting.
|
||||
|
@ -41,7 +41,7 @@ class datagram_socket_service
|
||||
{
|
||||
public:
|
||||
/// The demuxer type.
|
||||
typedef basic_demuxer<demuxer_service<Allocator> > demuxer_type;
|
||||
typedef basic_demuxer<demuxer_service<Allocator>, Allocator> demuxer_type;
|
||||
|
||||
private:
|
||||
// The type of the platform-specific implementation.
|
||||
|
@ -47,7 +47,7 @@ class deadline_timer_service
|
||||
{
|
||||
public:
|
||||
/// The demuxer type.
|
||||
typedef basic_demuxer<demuxer_service<Allocator> > demuxer_type;
|
||||
typedef basic_demuxer<demuxer_service<Allocator>, Allocator> demuxer_type;
|
||||
|
||||
/// The time traits type.
|
||||
typedef Time_Traits traits_type;
|
||||
|
@ -39,15 +39,12 @@ class demuxer_service
|
||||
{
|
||||
public:
|
||||
/// The demuxer type for this service.
|
||||
typedef basic_demuxer<demuxer_service<Allocator> > demuxer_type;
|
||||
|
||||
/// The allocator type for this service.
|
||||
typedef Allocator allocator_type;
|
||||
typedef basic_demuxer<demuxer_service<Allocator>, Allocator> demuxer_type;
|
||||
|
||||
private:
|
||||
// The type of the platform-specific implementation.
|
||||
#if defined(ASIO_HAS_IOCP_DEMUXER)
|
||||
typedef detail::win_iocp_demuxer_service service_impl_type;
|
||||
typedef detail::win_iocp_demuxer_service<Allocator> service_impl_type;
|
||||
#elif defined(ASIO_HAS_EPOLL_REACTOR)
|
||||
typedef detail::task_demuxer_service<detail::epoll_reactor<false> >
|
||||
service_impl_type;
|
||||
@ -66,19 +63,6 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
demuxer_service(demuxer_type& demuxer, const allocator_type& allocator)
|
||||
: service_impl_(demuxer.get_service(service_factory<service_impl_type>())),
|
||||
allocator_(allocator)
|
||||
{
|
||||
}
|
||||
|
||||
/// Return a copy of the allocator associated with the service.
|
||||
allocator_type get_allocator() const
|
||||
{
|
||||
return allocator_;
|
||||
}
|
||||
|
||||
/// Run the demuxer's event processing loop.
|
||||
void run()
|
||||
{
|
||||
@ -126,43 +110,8 @@ public:
|
||||
private:
|
||||
// The service that provides the platform-specific implementation.
|
||||
service_impl_type& service_impl_;
|
||||
|
||||
// The allocator associated with the service.
|
||||
allocator_type allocator_;
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
|
||||
/// Specialisation of service_factory to allow an allocator to be specified.
|
||||
template <typename Allocator>
|
||||
class service_factory<demuxer_service<Allocator> >
|
||||
{
|
||||
public:
|
||||
/// Default constructor.
|
||||
service_factory()
|
||||
{
|
||||
}
|
||||
|
||||
/// Construct with a specified allocator.
|
||||
explicit service_factory(const Allocator& allocator)
|
||||
: allocator_(allocator)
|
||||
{
|
||||
}
|
||||
|
||||
/// Create a service with the specified owner.
|
||||
template <typename Owner>
|
||||
demuxer_service<Allocator>* create(Owner& owner)
|
||||
{
|
||||
return new demuxer_service<Allocator>(owner, allocator_);
|
||||
}
|
||||
|
||||
private:
|
||||
// The allocator to be passed to the service.
|
||||
Allocator allocator_;
|
||||
};
|
||||
|
||||
#endif // !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
@ -17,15 +17,61 @@
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
#include "asio/handler_alloc_hook.hpp"
|
||||
|
||||
// Custom bind handlers so that allocation hooks are correctly forwarded.
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
// Some compilers (notably MSVC6) run into mysterious compiler errors when
|
||||
// trying to use the boost::bind template in this library. The class and
|
||||
// function templates below provide only the functionality of bind to create
|
||||
// function objects with the signature void() as used in handlers passed to a
|
||||
// demuxer's dispatch or post functions. This should make it simpler for the
|
||||
// compiler to work correctly.
|
||||
template <typename Handler, typename Arg1>
|
||||
class binder1;
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
class binder2;
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
|
||||
class binder3;
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
|
||||
typename Arg4>
|
||||
class binder4;
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
|
||||
typename Arg4, typename Arg5>
|
||||
class binder5;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
|
||||
namespace asio {
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
class handler_alloc_hook<
|
||||
asio::detail::binder1<Handler, Arg1> >;
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
class handler_alloc_hook<
|
||||
asio::detail::binder2<Handler, Arg1, Arg2> >;
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
|
||||
class handler_alloc_hook<
|
||||
asio::detail::binder3<Handler, Arg1, Arg2, Arg3> >;
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
|
||||
typename Arg4>
|
||||
class handler_alloc_hook<
|
||||
asio::detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4> >;
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
|
||||
typename Arg4, typename Arg5>
|
||||
class handler_alloc_hook<
|
||||
asio::detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> >;
|
||||
|
||||
} // namespace asio
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
class binder1
|
||||
@ -50,6 +96,8 @@ public:
|
||||
private:
|
||||
Handler handler_;
|
||||
Arg1 arg1_;
|
||||
friend class asio::handler_alloc_hook<
|
||||
binder1<Handler, Arg1> >;
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
@ -83,6 +131,8 @@ private:
|
||||
Handler handler_;
|
||||
Arg1 arg1_;
|
||||
Arg2 arg2_;
|
||||
friend class asio::handler_alloc_hook<
|
||||
binder2<Handler, Arg1, Arg2> >;
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
@ -119,6 +169,8 @@ private:
|
||||
Arg1 arg1_;
|
||||
Arg2 arg2_;
|
||||
Arg3 arg3_;
|
||||
friend class asio::handler_alloc_hook<
|
||||
binder3<Handler, Arg1, Arg2, Arg3> >;
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
|
||||
@ -158,6 +210,8 @@ private:
|
||||
Arg2 arg2_;
|
||||
Arg3 arg3_;
|
||||
Arg4 arg4_;
|
||||
friend class asio::handler_alloc_hook<
|
||||
binder4<Handler, Arg1, Arg2, Arg3, Arg4> >;
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
|
||||
@ -202,6 +256,8 @@ private:
|
||||
Arg3 arg3_;
|
||||
Arg4 arg4_;
|
||||
Arg5 arg5_;
|
||||
friend class asio::handler_alloc_hook<
|
||||
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> >;
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
|
||||
@ -216,6 +272,130 @@ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> bind_handler(Handler handler,
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
class asio::handler_alloc_hook<
|
||||
asio::detail::binder1<Handler, Arg1> >
|
||||
{
|
||||
public:
|
||||
typedef asio::detail::binder1<Handler, Arg1> handler_type;
|
||||
|
||||
template <typename Allocator>
|
||||
static typename Allocator::pointer allocate(handler_type& handler,
|
||||
Allocator& allocator, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::allocate(
|
||||
handler.handler_, allocator, count);
|
||||
}
|
||||
|
||||
template <typename Allocator>
|
||||
static void deallocate(handler_type& handler, Allocator& allocator,
|
||||
typename Allocator::pointer pointer, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::deallocate(
|
||||
handler.handler_, allocator, pointer, count);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
class asio::handler_alloc_hook<
|
||||
asio::detail::binder2<Handler, Arg1, Arg2> >
|
||||
{
|
||||
public:
|
||||
typedef asio::detail::binder2<Handler, Arg1, Arg2> handler_type;
|
||||
|
||||
template <typename Allocator>
|
||||
static typename Allocator::pointer allocate(handler_type& handler,
|
||||
Allocator& allocator, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::allocate(
|
||||
handler.handler_, allocator, count);
|
||||
}
|
||||
|
||||
template <typename Allocator>
|
||||
static void deallocate(handler_type& handler, Allocator& allocator,
|
||||
typename Allocator::pointer pointer, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::deallocate(
|
||||
handler.handler_, allocator, pointer, count);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
|
||||
class asio::handler_alloc_hook<
|
||||
asio::detail::binder3<Handler, Arg1, Arg2, Arg3> >
|
||||
{
|
||||
public:
|
||||
typedef asio::detail::binder3<Handler, Arg1, Arg2, Arg3> handler_type;
|
||||
|
||||
template <typename Allocator>
|
||||
static typename Allocator::pointer allocate(handler_type& handler,
|
||||
Allocator& allocator, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::allocate(
|
||||
handler.handler_, allocator, count);
|
||||
}
|
||||
|
||||
template <typename Allocator>
|
||||
static void deallocate(handler_type& handler, Allocator& allocator,
|
||||
typename Allocator::pointer pointer, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::deallocate(
|
||||
handler.handler_, allocator, pointer, count);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
|
||||
typename Arg4>
|
||||
class asio::handler_alloc_hook<
|
||||
asio::detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4> >
|
||||
{
|
||||
public:
|
||||
typedef asio::detail::binder4<
|
||||
Handler, Arg1, Arg2, Arg3, Arg4> handler_type;
|
||||
|
||||
template <typename Allocator>
|
||||
static typename Allocator::pointer allocate(handler_type& handler,
|
||||
Allocator& allocator, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::allocate(
|
||||
handler.handler_, allocator, count);
|
||||
}
|
||||
|
||||
template <typename Allocator>
|
||||
static void deallocate(handler_type& handler, Allocator& allocator,
|
||||
typename Allocator::pointer pointer, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::deallocate(
|
||||
handler.handler_, allocator, pointer, count);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
|
||||
typename Arg4, typename Arg5>
|
||||
class asio::handler_alloc_hook<
|
||||
asio::detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> >
|
||||
{
|
||||
public:
|
||||
typedef asio::detail::binder5<
|
||||
Handler, Arg1, Arg2, Arg3, Arg4, Arg5> handler_type;
|
||||
|
||||
template <typename Allocator>
|
||||
static typename Allocator::pointer allocate(handler_type& handler,
|
||||
Allocator& allocator, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::allocate(
|
||||
handler.handler_, allocator, count);
|
||||
}
|
||||
|
||||
template <typename Allocator>
|
||||
static void deallocate(handler_type& handler, Allocator& allocator,
|
||||
typename Allocator::pointer pointer, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::deallocate(
|
||||
handler.handler_, allocator, pointer, count);
|
||||
}
|
||||
};
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_DETAIL_BIND_HPP
|
||||
|
216
asio/include/asio/detail/handler_alloc_helpers.hpp
Normal file
216
asio/include/asio/detail/handler_alloc_helpers.hpp
Normal file
@ -0,0 +1,216 @@
|
||||
//
|
||||
// handler_alloc_helpers.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2005 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// 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 ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
|
||||
#define ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
#include "asio/handler_alloc_hook.hpp"
|
||||
#include "asio/detail/noncopyable.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
// Traits for handler allocation.
|
||||
template <typename Handler, typename Object, typename Void_Allocator>
|
||||
struct handler_alloc_traits
|
||||
{
|
||||
typedef Handler handler_type;
|
||||
typedef Void_Allocator void_allocator_type;
|
||||
typedef typename Void_Allocator::template rebind<Object>::other
|
||||
allocator_type;
|
||||
typedef typename allocator_type::value_type value_type;
|
||||
typedef typename allocator_type::pointer pointer_type;
|
||||
};
|
||||
|
||||
template <typename Alloc_Traits>
|
||||
class handler_ptr;
|
||||
|
||||
// Helper class to provide RAII on uninitialised handler memory.
|
||||
template <typename Alloc_Traits>
|
||||
class raw_handler_ptr
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef typename Alloc_Traits::handler_type handler_type;
|
||||
typedef typename Alloc_Traits::void_allocator_type void_allocator_type;
|
||||
typedef typename Alloc_Traits::allocator_type allocator_type;
|
||||
typedef typename Alloc_Traits::value_type value_type;
|
||||
typedef typename Alloc_Traits::pointer_type pointer_type;
|
||||
typedef handler_alloc_hook<handler_type> hook_type;
|
||||
|
||||
// Constructor allocates the memory.
|
||||
raw_handler_ptr(handler_type& handler,
|
||||
const void_allocator_type& void_allocator)
|
||||
: handler_(handler),
|
||||
allocator_(void_allocator),
|
||||
pointer_(hook_type::allocate(handler_, allocator_, 1))
|
||||
{
|
||||
}
|
||||
|
||||
// Destructor automatically deallocates memory, unless it has been stolen by
|
||||
// a handler_ptr object.
|
||||
~raw_handler_ptr()
|
||||
{
|
||||
if (pointer_)
|
||||
hook_type::deallocate(handler_, allocator_, pointer_, 1);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class handler_ptr<Alloc_Traits>;
|
||||
handler_type& handler_;
|
||||
allocator_type allocator_;
|
||||
pointer_type pointer_;
|
||||
};
|
||||
|
||||
// Helper class to provide RAII on uninitialised handler memory.
|
||||
template <typename Alloc_Traits>
|
||||
class handler_ptr
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef typename Alloc_Traits::handler_type handler_type;
|
||||
typedef typename Alloc_Traits::void_allocator_type void_allocator_type;
|
||||
typedef typename Alloc_Traits::allocator_type allocator_type;
|
||||
typedef typename Alloc_Traits::value_type value_type;
|
||||
typedef typename Alloc_Traits::pointer_type pointer_type;
|
||||
typedef handler_alloc_hook<handler_type> hook_type;
|
||||
typedef raw_handler_ptr<Alloc_Traits> raw_ptr_type;
|
||||
|
||||
// Take ownership of existing memory.
|
||||
handler_ptr(handler_type& handler,
|
||||
const void_allocator_type& void_allocator, pointer_type pointer)
|
||||
: handler_(handler),
|
||||
allocator_(void_allocator),
|
||||
pointer_(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
// Construct object in raw memory and take ownership if construction succeeds.
|
||||
handler_ptr(raw_ptr_type& raw_ptr)
|
||||
: handler_(raw_ptr.handler_),
|
||||
allocator_(raw_ptr.allocator_),
|
||||
pointer_(new (raw_ptr.pointer_) value_type)
|
||||
{
|
||||
raw_ptr.pointer_ = 0;
|
||||
}
|
||||
|
||||
// Construct object in raw memory and take ownership if construction succeeds.
|
||||
template <typename Arg1>
|
||||
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1)
|
||||
: handler_(raw_ptr.handler_),
|
||||
allocator_(raw_ptr.allocator_),
|
||||
pointer_(new (raw_ptr.pointer_) value_type(a1))
|
||||
{
|
||||
raw_ptr.pointer_ = 0;
|
||||
}
|
||||
|
||||
// Construct object in raw memory and take ownership if construction succeeds.
|
||||
template <typename Arg1, typename Arg2>
|
||||
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2)
|
||||
: handler_(raw_ptr.handler_),
|
||||
allocator_(raw_ptr.allocator_),
|
||||
pointer_(new (raw_ptr.pointer_) value_type(a1, a2))
|
||||
{
|
||||
raw_ptr.pointer_ = 0;
|
||||
}
|
||||
|
||||
// Construct object in raw memory and take ownership if construction succeeds.
|
||||
template <typename Arg1, typename Arg2, typename Arg3>
|
||||
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3)
|
||||
: handler_(raw_ptr.handler_),
|
||||
allocator_(raw_ptr.allocator_),
|
||||
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3))
|
||||
{
|
||||
raw_ptr.pointer_ = 0;
|
||||
}
|
||||
|
||||
// Construct object in raw memory and take ownership if construction succeeds.
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
|
||||
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4)
|
||||
: handler_(raw_ptr.handler_),
|
||||
allocator_(raw_ptr.allocator_),
|
||||
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4))
|
||||
{
|
||||
raw_ptr.pointer_ = 0;
|
||||
}
|
||||
|
||||
// Construct object in raw memory and take ownership if construction succeeds.
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
|
||||
typename Arg5>
|
||||
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
|
||||
Arg5& a5)
|
||||
: handler_(raw_ptr.handler_),
|
||||
allocator_(raw_ptr.allocator_),
|
||||
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5))
|
||||
{
|
||||
raw_ptr.pointer_ = 0;
|
||||
}
|
||||
|
||||
// Construct object in raw memory and take ownership if construction succeeds.
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
|
||||
typename Arg5, typename Arg6>
|
||||
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
|
||||
Arg5& a5, Arg6& a6)
|
||||
: handler_(raw_ptr.handler_),
|
||||
allocator_(raw_ptr.allocator_),
|
||||
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6))
|
||||
{
|
||||
raw_ptr.pointer_ = 0;
|
||||
}
|
||||
|
||||
// Destructor automatically deallocates memory, unless it has been released.
|
||||
~handler_ptr()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// Get the memory.
|
||||
pointer_type get() const
|
||||
{
|
||||
return pointer_;
|
||||
}
|
||||
|
||||
// Release ownership of the memory.
|
||||
pointer_type release()
|
||||
{
|
||||
pointer_type tmp = pointer_;
|
||||
pointer_ = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// Explicitly destroy and deallocate the memory.
|
||||
void reset()
|
||||
{
|
||||
if (pointer_)
|
||||
{
|
||||
allocator_.destroy(pointer_);
|
||||
hook_type::deallocate(handler_, allocator_, pointer_, 1);
|
||||
pointer_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
handler_type& handler_;
|
||||
allocator_type allocator_;
|
||||
pointer_type pointer_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
|
@ -35,6 +35,9 @@
|
||||
# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
|
||||
# if defined(__BORLANDC__) && !defined(_WSPIAPI_H_)
|
||||
# include <stdlib.h> // Needed for __errno
|
||||
# if defined(__WIN32__) && !defined(WIN32)
|
||||
# define WIN32 // Needed for correct types in winsock2.h
|
||||
# endif // defined(__WIN32__) && !defined(WIN32)
|
||||
# define _WSPIAPI_H_
|
||||
# define ASIO_WSPIAPI_H_DEFINED
|
||||
# endif // defined(__BORLANDC__) && !defined(_WSPIAPI_H_)
|
||||
|
@ -35,21 +35,27 @@
|
||||
|
||||
#include "asio/system_exception.hpp"
|
||||
#include "asio/detail/demuxer_run_call_stack.hpp"
|
||||
#include "asio/detail/handler_alloc_helpers.hpp"
|
||||
#include "asio/detail/socket_types.hpp"
|
||||
#include "asio/detail/win_iocp_operation.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename Allocator>
|
||||
class win_iocp_demuxer_service
|
||||
{
|
||||
public:
|
||||
// Base class for all operations.
|
||||
typedef win_iocp_operation<Allocator> operation;
|
||||
|
||||
// Constructor.
|
||||
template <typename Demuxer>
|
||||
win_iocp_demuxer_service(Demuxer& demuxer)
|
||||
: iocp_(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0)),
|
||||
outstanding_work_(0),
|
||||
interrupted_(0)
|
||||
interrupted_(0),
|
||||
allocator_(demuxer.get_allocator())
|
||||
{
|
||||
if (!iocp_.handle)
|
||||
{
|
||||
@ -72,7 +78,8 @@ public:
|
||||
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
|
||||
return;
|
||||
|
||||
demuxer_run_call_stack<win_iocp_demuxer_service>::context ctx(this);
|
||||
typedef demuxer_run_call_stack<win_iocp_demuxer_service<Allocator> > drcs;
|
||||
typename drcs::context ctx(this);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@ -91,9 +98,28 @@ public:
|
||||
|
||||
if (overlapped)
|
||||
{
|
||||
// Ensure that the demuxer does not exit due to running out of work
|
||||
// while we make the upcall.
|
||||
struct auto_work
|
||||
{
|
||||
auto_work(win_iocp_demuxer_service& demuxer_service)
|
||||
: demuxer_service_(demuxer_service)
|
||||
{
|
||||
demuxer_service_.work_started();
|
||||
}
|
||||
|
||||
~auto_work()
|
||||
{
|
||||
demuxer_service_.work_finished();
|
||||
}
|
||||
|
||||
private:
|
||||
win_iocp_demuxer_service& demuxer_service_;
|
||||
} work(*this);
|
||||
|
||||
// Dispatch the operation.
|
||||
win_iocp_operation* op = static_cast<win_iocp_operation*>(overlapped);
|
||||
op->do_completion(last_error, bytes_transferred);
|
||||
operation* op = static_cast<operation*>(overlapped);
|
||||
op->do_completion(last_error, bytes_transferred, allocator_);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -149,11 +175,11 @@ public:
|
||||
|
||||
template <typename Handler>
|
||||
struct handler_operation
|
||||
: public win_iocp_operation
|
||||
: public operation
|
||||
{
|
||||
handler_operation(win_iocp_demuxer_service& demuxer_service,
|
||||
Handler handler)
|
||||
: win_iocp_operation(&handler_operation<Handler>::do_completion_impl),
|
||||
: operation(&handler_operation<Handler>::do_completion_impl),
|
||||
demuxer_service_(demuxer_service),
|
||||
handler_(handler)
|
||||
{
|
||||
@ -170,11 +196,25 @@ public:
|
||||
handler_operation(const handler_operation&);
|
||||
void operator=(const handler_operation&);
|
||||
|
||||
static void do_completion_impl(win_iocp_operation* op, DWORD, size_t)
|
||||
static void do_completion_impl(operation* op, DWORD, size_t,
|
||||
const Allocator& void_allocator)
|
||||
{
|
||||
std::auto_ptr<handler_operation<Handler> > h(
|
||||
static_cast<handler_operation<Handler>*>(op));
|
||||
h->handler_();
|
||||
// Take ownership of the operation object.
|
||||
typedef handler_operation<Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type, Allocator> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_,
|
||||
void_allocator, handler_op);
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made.
|
||||
Handler handler(handler_op->handler_);
|
||||
|
||||
// Free the memory associated with the handler.
|
||||
ptr.reset();
|
||||
|
||||
// Make the upcall.
|
||||
handler();
|
||||
}
|
||||
|
||||
win_iocp_demuxer_service& demuxer_service_;
|
||||
@ -195,15 +235,22 @@ public:
|
||||
template <typename Handler>
|
||||
void post(Handler handler)
|
||||
{
|
||||
handler_operation<Handler>* op =
|
||||
new handler_operation<Handler>(*this, handler);
|
||||
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op))
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef handler_operation<Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type, Allocator> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler, allocator_);
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr, *this, handler);
|
||||
|
||||
// Enqueue the operation on the I/O completion port.
|
||||
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, ptr.get()))
|
||||
{
|
||||
DWORD last_error = ::GetLastError();
|
||||
delete op;
|
||||
system_exception e("pqcs", last_error);
|
||||
boost::throw_exception(e);
|
||||
}
|
||||
|
||||
// Operation has been successfully posted.
|
||||
ptr.release();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -220,6 +267,9 @@ private:
|
||||
|
||||
// Flag to indicate whether the event loop has been interrupted.
|
||||
long interrupted_;
|
||||
|
||||
// The allocator to be used for allocating dynamic objects.
|
||||
Allocator allocator_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
@ -30,6 +30,7 @@
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename Allocator>
|
||||
class win_iocp_demuxer_service;
|
||||
|
||||
// Base class for all IOCP operations. A function pointer is used instead of
|
||||
@ -38,10 +39,12 @@ class win_iocp_demuxer_service;
|
||||
// This class inherits from OVERLAPPED so that we can downcast to get back to
|
||||
// the win_iocp_operation pointer from the LPOVERLAPPED out parameter of
|
||||
// GetQueuedCompletionStatus.
|
||||
template <typename Allocator>
|
||||
struct win_iocp_operation
|
||||
: public OVERLAPPED
|
||||
{
|
||||
typedef void (*func_type)(win_iocp_operation*, DWORD, size_t);
|
||||
typedef void (*func_type)(win_iocp_operation<Allocator>*,
|
||||
DWORD, size_t, const Allocator&);
|
||||
|
||||
win_iocp_operation(func_type func)
|
||||
: func_(func)
|
||||
@ -53,9 +56,10 @@ struct win_iocp_operation
|
||||
hEvent = 0;
|
||||
}
|
||||
|
||||
void do_completion(DWORD last_error, size_t bytes_transferred)
|
||||
void do_completion(DWORD last_error, size_t bytes_transferred,
|
||||
const Allocator& allocator)
|
||||
{
|
||||
func_(this, last_error, bytes_transferred);
|
||||
func_(this, last_error, bytes_transferred, allocator);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "asio/service_factory.hpp"
|
||||
#include "asio/socket_base.hpp"
|
||||
#include "asio/detail/bind_handler.hpp"
|
||||
#include "asio/detail/handler_alloc_helpers.hpp"
|
||||
#include "asio/detail/select_reactor.hpp"
|
||||
#include "asio/detail/socket_holder.hpp"
|
||||
#include "asio/detail/socket_ops.hpp"
|
||||
@ -52,6 +53,9 @@ template <typename Allocator>
|
||||
class win_iocp_socket_service
|
||||
{
|
||||
public:
|
||||
// Base class for all operations.
|
||||
typedef win_iocp_operation<Allocator> operation;
|
||||
|
||||
struct noop_deleter { void operator()(void*) {} };
|
||||
typedef boost::shared_ptr<void> shared_cancel_token_type;
|
||||
typedef boost::weak_ptr<void> weak_cancel_token_type;
|
||||
@ -118,7 +122,7 @@ public:
|
||||
static impl_type null_impl_;
|
||||
|
||||
// The demuxer type for this service.
|
||||
typedef basic_demuxer<demuxer_service<Allocator> > demuxer_type;
|
||||
typedef basic_demuxer<demuxer_service<Allocator>, Allocator> demuxer_type;
|
||||
|
||||
// The type of the reactor used for connect operations.
|
||||
typedef detail::select_reactor<true> reactor_type;
|
||||
@ -133,7 +137,7 @@ public:
|
||||
demuxer_type& demuxer)
|
||||
: demuxer_(demuxer),
|
||||
demuxer_service_(demuxer.get_service(
|
||||
service_factory<win_iocp_demuxer_service>())),
|
||||
service_factory<win_iocp_demuxer_service<Allocator> >())),
|
||||
reactor_(0)
|
||||
{
|
||||
}
|
||||
@ -185,7 +189,7 @@ public:
|
||||
// socket on the reactor as well to cancel any operations that might be
|
||||
// running there.
|
||||
reactor_type* reactor = static_cast<reactor_type*>(
|
||||
::InterlockedCompareExchangePointer(
|
||||
InterlockedCompareExchangePointer(
|
||||
reinterpret_cast<void**>(&reactor_), 0, 0));
|
||||
if (reactor)
|
||||
reactor->close_descriptor(impl);
|
||||
@ -323,12 +327,12 @@ public:
|
||||
|
||||
template <typename Handler>
|
||||
class send_operation
|
||||
: public win_iocp_operation
|
||||
: public operation
|
||||
{
|
||||
public:
|
||||
send_operation(demuxer_type& demuxer,
|
||||
weak_cancel_token_type cancel_token, Handler handler)
|
||||
: win_iocp_operation(&send_operation<Handler>::do_completion_impl),
|
||||
: operation(&send_operation<Handler>::do_completion_impl),
|
||||
work_(demuxer),
|
||||
cancel_token_(cancel_token),
|
||||
handler_(handler)
|
||||
@ -336,23 +340,36 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static void do_completion_impl(win_iocp_operation* op,
|
||||
DWORD last_error, size_t bytes_transferred)
|
||||
static void do_completion_impl(operation* op,
|
||||
DWORD last_error, size_t bytes_transferred,
|
||||
const Allocator& void_allocator)
|
||||
{
|
||||
std::auto_ptr<send_operation<Handler> > h(
|
||||
static_cast<send_operation<Handler>*>(op));
|
||||
// Take ownership of the operation object.
|
||||
typedef send_operation<Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type, Allocator> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_,
|
||||
void_allocator, handler_op);
|
||||
|
||||
// Map ERROR_NETNAME_DELETED to more useful error.
|
||||
if (last_error == ERROR_NETNAME_DELETED)
|
||||
{
|
||||
if (h->cancel_token_.expired())
|
||||
if (handler_op->cancel_token_.expired())
|
||||
last_error = ERROR_OPERATION_ABORTED;
|
||||
else
|
||||
last_error = WSAECONNRESET;
|
||||
}
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made.
|
||||
Handler handler(handler_op->handler_);
|
||||
|
||||
// Free the memory associated with the handler.
|
||||
ptr.reset();
|
||||
|
||||
// Call the handler.
|
||||
asio::error error(last_error);
|
||||
h->handler_(error, bytes_transferred);
|
||||
handler(error, bytes_transferred);
|
||||
}
|
||||
|
||||
typename demuxer_type::work work_;
|
||||
@ -366,8 +383,12 @@ public:
|
||||
void async_send(impl_type& impl, const Const_Buffers& buffers,
|
||||
socket_base::message_flags flags, Handler handler)
|
||||
{
|
||||
std::auto_ptr<send_operation<Handler> > op(
|
||||
new send_operation<Handler>(demuxer_, impl.cancel_token_, handler));
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef send_operation<Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type, Allocator> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler, demuxer_.get_allocator());
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr,
|
||||
demuxer_, impl.cancel_token_, handler);
|
||||
|
||||
// Copy buffers into WSABUF array.
|
||||
::WSABUF bufs[max_buffers];
|
||||
@ -384,18 +405,19 @@ public:
|
||||
// Send the data.
|
||||
DWORD bytes_transferred = 0;
|
||||
int result = ::WSASend(impl, bufs, i,
|
||||
&bytes_transferred, flags, op.get(), 0);
|
||||
&bytes_transferred, flags, ptr.get(), 0);
|
||||
DWORD last_error = ::WSAGetLastError();
|
||||
|
||||
// Check if the operation completed immediately.
|
||||
if (result != 0 && last_error != WSA_IO_PENDING)
|
||||
{
|
||||
ptr.reset();
|
||||
asio::error error(last_error);
|
||||
demuxer_service_.post(bind_handler(handler, error, bytes_transferred));
|
||||
}
|
||||
else
|
||||
{
|
||||
op.release();
|
||||
ptr.release();
|
||||
}
|
||||
}
|
||||
|
||||
@ -434,24 +456,38 @@ public:
|
||||
|
||||
template <typename Handler>
|
||||
class send_to_operation
|
||||
: public win_iocp_operation
|
||||
: public operation
|
||||
{
|
||||
public:
|
||||
send_to_operation(demuxer_type& demuxer, Handler handler)
|
||||
: win_iocp_operation(&send_to_operation<Handler>::do_completion_impl),
|
||||
: operation(&send_to_operation<Handler>::do_completion_impl),
|
||||
work_(demuxer),
|
||||
handler_(handler)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
static void do_completion_impl(win_iocp_operation* op,
|
||||
DWORD last_error, size_t bytes_transferred)
|
||||
static void do_completion_impl(operation* op,
|
||||
DWORD last_error, size_t bytes_transferred,
|
||||
const Allocator& void_allocator)
|
||||
{
|
||||
std::auto_ptr<send_to_operation<Handler> > h(
|
||||
static_cast<send_to_operation<Handler>*>(op));
|
||||
// Take ownership of the operation object.
|
||||
typedef send_to_operation<Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type, Allocator> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_,
|
||||
void_allocator, handler_op);
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made.
|
||||
Handler handler(handler_op->handler_);
|
||||
|
||||
// Free the memory associated with the handler.
|
||||
ptr.reset();
|
||||
|
||||
// Call the handler.
|
||||
asio::error error(last_error);
|
||||
h->handler_(error, bytes_transferred);
|
||||
handler(error, bytes_transferred);
|
||||
}
|
||||
|
||||
typename demuxer_type::work work_;
|
||||
@ -465,8 +501,11 @@ public:
|
||||
socket_base::message_flags flags, const Endpoint& destination,
|
||||
Handler handler)
|
||||
{
|
||||
std::auto_ptr<send_to_operation<Handler> > op(
|
||||
new send_to_operation<Handler>(demuxer_, handler));
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef send_to_operation<Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type, Allocator> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler, demuxer_.get_allocator());
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr, demuxer_, handler);
|
||||
|
||||
// Copy buffers into WSABUF array.
|
||||
::WSABUF bufs[max_buffers];
|
||||
@ -483,18 +522,19 @@ public:
|
||||
// Send the data.
|
||||
DWORD bytes_transferred = 0;
|
||||
int result = ::WSASendTo(impl, bufs, i, &bytes_transferred, flags,
|
||||
destination.data(), destination.size(), op.get(), 0);
|
||||
destination.data(), destination.size(), ptr.get(), 0);
|
||||
DWORD last_error = ::WSAGetLastError();
|
||||
|
||||
// Check if the operation completed immediately.
|
||||
if (result != 0 && last_error != WSA_IO_PENDING)
|
||||
{
|
||||
ptr.reset();
|
||||
asio::error error(last_error);
|
||||
demuxer_service_.post(bind_handler(handler, error, bytes_transferred));
|
||||
}
|
||||
else
|
||||
{
|
||||
op.release();
|
||||
ptr.release();
|
||||
}
|
||||
}
|
||||
|
||||
@ -539,12 +579,12 @@ public:
|
||||
|
||||
template <typename Handler>
|
||||
class receive_operation
|
||||
: public win_iocp_operation
|
||||
: public operation
|
||||
{
|
||||
public:
|
||||
receive_operation(demuxer_type& demuxer,
|
||||
weak_cancel_token_type cancel_token, Handler handler)
|
||||
: win_iocp_operation(&receive_operation<Handler>::do_completion_impl),
|
||||
: operation(&receive_operation<Handler>::do_completion_impl),
|
||||
work_(demuxer),
|
||||
cancel_token_(cancel_token),
|
||||
handler_(handler)
|
||||
@ -552,16 +592,21 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static void do_completion_impl(win_iocp_operation* op,
|
||||
DWORD last_error, size_t bytes_transferred)
|
||||
static void do_completion_impl(operation* op,
|
||||
DWORD last_error, size_t bytes_transferred,
|
||||
const Allocator& void_allocator)
|
||||
{
|
||||
std::auto_ptr<receive_operation<Handler> > h(
|
||||
static_cast<receive_operation<Handler>*>(op));
|
||||
// Take ownership of the operation object.
|
||||
typedef receive_operation<Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type, Allocator> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_,
|
||||
void_allocator, handler_op);
|
||||
|
||||
// Map ERROR_NETNAME_DELETED to more useful error.
|
||||
if (last_error == ERROR_NETNAME_DELETED)
|
||||
{
|
||||
if (h->cancel_token_.expired())
|
||||
if (handler_op->cancel_token_.expired())
|
||||
last_error = ERROR_OPERATION_ABORTED;
|
||||
else
|
||||
last_error = WSAECONNRESET;
|
||||
@ -573,8 +618,16 @@ public:
|
||||
last_error = asio::error::eof;
|
||||
}
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made.
|
||||
Handler handler(handler_op->handler_);
|
||||
|
||||
// Free the memory associated with the handler.
|
||||
ptr.reset();
|
||||
|
||||
// Call the handler.
|
||||
asio::error error(last_error);
|
||||
h->handler_(error, bytes_transferred);
|
||||
handler(error, bytes_transferred);
|
||||
}
|
||||
|
||||
typename demuxer_type::work work_;
|
||||
@ -588,8 +641,12 @@ public:
|
||||
void async_receive(impl_type& impl, const Mutable_Buffers& buffers,
|
||||
socket_base::message_flags flags, Handler handler)
|
||||
{
|
||||
std::auto_ptr<receive_operation<Handler> > op(
|
||||
new receive_operation<Handler>(demuxer_, impl.cancel_token_, handler));
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef receive_operation<Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type, Allocator> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler, demuxer_.get_allocator());
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr,
|
||||
demuxer_, impl.cancel_token_, handler);
|
||||
|
||||
// Copy buffers into WSABUF array.
|
||||
::WSABUF bufs[max_buffers];
|
||||
@ -606,16 +663,17 @@ public:
|
||||
DWORD bytes_transferred = 0;
|
||||
DWORD recv_flags = flags;
|
||||
int result = ::WSARecv(impl, bufs, i,
|
||||
&bytes_transferred, &recv_flags, op.get(), 0);
|
||||
&bytes_transferred, &recv_flags, ptr.get(), 0);
|
||||
DWORD last_error = ::WSAGetLastError();
|
||||
if (result != 0 && last_error != WSA_IO_PENDING)
|
||||
{
|
||||
ptr.reset();
|
||||
asio::error error(last_error);
|
||||
demuxer_service_.post(bind_handler(handler, error, bytes_transferred));
|
||||
}
|
||||
else
|
||||
{
|
||||
op.release();
|
||||
ptr.release();
|
||||
}
|
||||
}
|
||||
|
||||
@ -662,12 +720,12 @@ public:
|
||||
|
||||
template <typename Endpoint, typename Handler>
|
||||
class receive_from_operation
|
||||
: public win_iocp_operation
|
||||
: public operation
|
||||
{
|
||||
public:
|
||||
receive_from_operation(demuxer_type& demuxer, Endpoint& endpoint,
|
||||
Handler handler)
|
||||
: win_iocp_operation(
|
||||
: operation(
|
||||
&receive_from_operation<Endpoint, Handler>::do_completion_impl),
|
||||
endpoint_(endpoint),
|
||||
endpoint_size_(endpoint.size()),
|
||||
@ -682,11 +740,16 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static void do_completion_impl(win_iocp_operation* op,
|
||||
DWORD last_error, size_t bytes_transferred)
|
||||
static void do_completion_impl(operation* op,
|
||||
DWORD last_error, size_t bytes_transferred,
|
||||
const Allocator& void_allocator)
|
||||
{
|
||||
std::auto_ptr<receive_from_operation<Endpoint, Handler> > h(
|
||||
static_cast<receive_from_operation<Endpoint, Handler>*>(op));
|
||||
// Take ownership of the operation object.
|
||||
typedef receive_from_operation<Endpoint, Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type, Allocator> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_,
|
||||
void_allocator, handler_op);
|
||||
|
||||
// Check for connection closed.
|
||||
if (last_error == 0 && bytes_transferred == 0)
|
||||
@ -694,9 +757,19 @@ public:
|
||||
last_error = asio::error::eof;
|
||||
}
|
||||
|
||||
h->endpoint_.size(h->endpoint_size_);
|
||||
// Record the size of the endpoint returned by the operation.
|
||||
handler_op->endpoint_.size(handler_op->endpoint_size_);
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made.
|
||||
Handler handler(handler_op->handler_);
|
||||
|
||||
// Free the memory associated with the handler.
|
||||
ptr.reset();
|
||||
|
||||
// Call the handler.
|
||||
asio::error error(last_error);
|
||||
h->handler_(error, bytes_transferred);
|
||||
handler(error, bytes_transferred);
|
||||
}
|
||||
|
||||
Endpoint& endpoint_;
|
||||
@ -712,9 +785,11 @@ public:
|
||||
void async_receive_from(impl_type& impl, const Mutable_Buffers& buffers,
|
||||
socket_base::message_flags flags, Endpoint& sender_endp, Handler handler)
|
||||
{
|
||||
std::auto_ptr<receive_from_operation<Endpoint, Handler> > op(
|
||||
new receive_from_operation<Endpoint, Handler>(
|
||||
demuxer_, sender_endp, handler));
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef receive_from_operation<Endpoint, Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type, Allocator> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler, demuxer_.get_allocator());
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr, demuxer_, sender_endp, handler);
|
||||
|
||||
// Copy buffers into WSABUF array.
|
||||
::WSABUF bufs[max_buffers];
|
||||
@ -731,16 +806,17 @@ public:
|
||||
DWORD bytes_transferred = 0;
|
||||
DWORD recv_flags = flags;
|
||||
int result = ::WSARecvFrom(impl, bufs, i, &bytes_transferred, &recv_flags,
|
||||
sender_endp.data(), &op->endpoint_size(), op.get(), 0);
|
||||
sender_endp.data(), &ptr.get()->endpoint_size(), ptr.get(), 0);
|
||||
DWORD last_error = ::WSAGetLastError();
|
||||
if (result != 0 && last_error != WSA_IO_PENDING)
|
||||
{
|
||||
ptr.reset();
|
||||
asio::error error(last_error);
|
||||
demuxer_service_.post(bind_handler(handler, error, bytes_transferred));
|
||||
}
|
||||
else
|
||||
{
|
||||
op.release();
|
||||
ptr.release();
|
||||
}
|
||||
}
|
||||
|
||||
@ -793,12 +869,12 @@ public:
|
||||
|
||||
template <typename Socket, typename Handler>
|
||||
class accept_operation
|
||||
: public win_iocp_operation
|
||||
: public operation
|
||||
{
|
||||
public:
|
||||
accept_operation(demuxer_type& demuxer, impl_type& impl,
|
||||
socket_type new_socket, Socket& peer, Handler handler)
|
||||
: win_iocp_operation(
|
||||
: operation(
|
||||
&accept_operation<Socket, Handler>::do_completion_impl),
|
||||
demuxer_(demuxer),
|
||||
impl_(impl),
|
||||
@ -825,11 +901,16 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static void do_completion_impl(win_iocp_operation* op,
|
||||
DWORD last_error, size_t bytes_transferred)
|
||||
static void do_completion_impl(operation* op,
|
||||
DWORD last_error, size_t bytes_transferred,
|
||||
const Allocator& void_allocator)
|
||||
{
|
||||
std::auto_ptr<accept_operation<Socket, Handler> > h(
|
||||
static_cast<accept_operation<Socket, Handler>*>(op));
|
||||
// Take ownership of the operation object.
|
||||
typedef accept_operation<Socket, Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type, Allocator> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_,
|
||||
void_allocator, handler_op);
|
||||
|
||||
// Check for connection aborted.
|
||||
if (last_error == ERROR_NETNAME_DELETED)
|
||||
@ -837,32 +918,37 @@ public:
|
||||
last_error = asio::error::connection_aborted;
|
||||
}
|
||||
|
||||
// Check whether the operation was successful.
|
||||
if (last_error != 0)
|
||||
{
|
||||
asio::error error(last_error);
|
||||
h->handler_(error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
|
||||
// and getpeername will work on the accepted socket.
|
||||
DWORD update_ctx_param = h->impl_;
|
||||
if (socket_ops::setsockopt(h->new_socket_.get(), SOL_SOCKET,
|
||||
SO_UPDATE_ACCEPT_CONTEXT, &update_ctx_param, sizeof(DWORD)) != 0)
|
||||
if (last_error == 0)
|
||||
{
|
||||
asio::error error(socket_ops::get_error());
|
||||
h->handler_(error);
|
||||
return;
|
||||
DWORD update_ctx_param = handler_op->impl_;
|
||||
if (socket_ops::setsockopt(handler_op->new_socket_.get(), SOL_SOCKET,
|
||||
SO_UPDATE_ACCEPT_CONTEXT, &update_ctx_param, sizeof(DWORD)) != 0)
|
||||
{
|
||||
last_error = socket_ops::get_error();
|
||||
}
|
||||
}
|
||||
|
||||
// Socket was successfully connected. Transfer ownership of the socket to
|
||||
// the peer object.
|
||||
impl_type new_socket(h->new_socket_.get());
|
||||
h->peer_.set_impl(new_socket);
|
||||
h->new_socket_.release();
|
||||
asio::error error(asio::error::success);
|
||||
h->handler_(error);
|
||||
// If the socket was successfully accepted, transfer ownership of the
|
||||
// socket to the peer object.
|
||||
if (last_error == 0)
|
||||
{
|
||||
impl_type new_socket(handler_op->new_socket_.get());
|
||||
handler_op->peer_.set_impl(new_socket);
|
||||
handler_op->new_socket_.release();
|
||||
}
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made.
|
||||
Handler handler(handler_op->handler_);
|
||||
|
||||
// Free the memory associated with the handler.
|
||||
ptr.reset();
|
||||
|
||||
// Call the handler.
|
||||
asio::error error(last_error);
|
||||
handler(error);
|
||||
}
|
||||
|
||||
demuxer_type& demuxer_;
|
||||
@ -916,39 +1002,44 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new operation object. Ownership of new socket is transferred.
|
||||
std::auto_ptr<accept_operation<Socket, Handler> > op(
|
||||
new accept_operation<Socket, Handler>(
|
||||
demuxer_, impl, sock.get(), peer, handler));
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef accept_operation<Socket, Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type, Allocator> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler, demuxer_.get_allocator());
|
||||
socket_type new_socket = sock.get();
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr,
|
||||
demuxer_, impl, new_socket, peer, handler);
|
||||
sock.release();
|
||||
|
||||
// Accept a connection.
|
||||
DWORD bytes_read = 0;
|
||||
BOOL result = ::AcceptEx(impl, op->new_socket(), op->output_buffer(), 0,
|
||||
op->address_length(), op->address_length(), &bytes_read, op.get());
|
||||
BOOL result = ::AcceptEx(impl, ptr.get()->new_socket(),
|
||||
ptr.get()->output_buffer(), 0, ptr.get()->address_length(),
|
||||
ptr.get()->address_length(), &bytes_read, ptr.get());
|
||||
DWORD last_error = ::WSAGetLastError();
|
||||
|
||||
// Check if the operation completed immediately.
|
||||
if (!result && last_error != WSA_IO_PENDING)
|
||||
{
|
||||
ptr.reset();
|
||||
asio::error error(last_error);
|
||||
demuxer_service_.post(bind_handler(handler, error));
|
||||
}
|
||||
else
|
||||
{
|
||||
op.release();
|
||||
ptr.release();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Socket, typename Endpoint, typename Handler>
|
||||
class accept_endp_operation
|
||||
: public win_iocp_operation
|
||||
: public operation
|
||||
{
|
||||
public:
|
||||
accept_endp_operation(demuxer_type& demuxer, impl_type& impl,
|
||||
socket_type new_socket, Socket& peer, Endpoint& peer_endpoint,
|
||||
Handler handler)
|
||||
: win_iocp_operation(&accept_endp_operation<
|
||||
: operation(&accept_endp_operation<
|
||||
Socket, Endpoint, Handler>::do_completion_impl),
|
||||
demuxer_(demuxer),
|
||||
impl_(impl),
|
||||
@ -976,11 +1067,16 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static void do_completion_impl(win_iocp_operation* op,
|
||||
DWORD last_error, size_t bytes_transferred)
|
||||
static void do_completion_impl(operation* op,
|
||||
DWORD last_error, size_t bytes_transferred,
|
||||
const Allocator& void_allocator)
|
||||
{
|
||||
std::auto_ptr<accept_endp_operation<Socket, Endpoint, Handler> > h(
|
||||
static_cast<accept_endp_operation<Socket, Endpoint, Handler>*>(op));
|
||||
// Take ownership of the operation object.
|
||||
typedef accept_endp_operation<Socket, Endpoint, Handler> op_type;
|
||||
op_type* handler_op(static_cast<op_type*>(op));
|
||||
typedef handler_alloc_traits<Handler, op_type, Allocator> alloc_traits;
|
||||
handler_ptr<alloc_traits> ptr(handler_op->handler_,
|
||||
void_allocator, handler_op);
|
||||
|
||||
// Check for connection aborted.
|
||||
if (last_error == ERROR_NETNAME_DELETED)
|
||||
@ -988,50 +1084,60 @@ public:
|
||||
last_error = asio::error::connection_aborted;
|
||||
}
|
||||
|
||||
// Check whether the operation was successful.
|
||||
if (last_error != 0)
|
||||
{
|
||||
asio::error error(last_error);
|
||||
h->handler_(error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the address of the peer.
|
||||
LPSOCKADDR local_addr = 0;
|
||||
int local_addr_length = 0;
|
||||
LPSOCKADDR remote_addr = 0;
|
||||
int remote_addr_length = 0;
|
||||
GetAcceptExSockaddrs(h->output_buffer(), 0, h->address_length(),
|
||||
h->address_length(), &local_addr, &local_addr_length, &remote_addr,
|
||||
&remote_addr_length);
|
||||
if (remote_addr_length > h->peer_endpoint_.size())
|
||||
if (last_error == 0)
|
||||
{
|
||||
asio::error error(asio::error::invalid_argument);
|
||||
h->handler_(error);
|
||||
return;
|
||||
LPSOCKADDR local_addr = 0;
|
||||
int local_addr_length = 0;
|
||||
LPSOCKADDR remote_addr = 0;
|
||||
int remote_addr_length = 0;
|
||||
GetAcceptExSockaddrs(handler_op->output_buffer(), 0,
|
||||
handler_op->address_length(), handler_op->address_length(),
|
||||
&local_addr, &local_addr_length, &remote_addr, &remote_addr_length);
|
||||
if (remote_addr_length > handler_op->peer_endpoint_.size())
|
||||
{
|
||||
last_error = asio::error::invalid_argument;
|
||||
}
|
||||
else
|
||||
{
|
||||
handler_op->peer_endpoint_.size(remote_addr_length);
|
||||
using namespace std; // For memcpy.
|
||||
memcpy(handler_op->peer_endpoint_.data(),
|
||||
remote_addr, remote_addr_length);
|
||||
}
|
||||
}
|
||||
h->peer_endpoint_.size(remote_addr_length);
|
||||
using namespace std; // For memcpy.
|
||||
memcpy(h->peer_endpoint_.data(), remote_addr, remote_addr_length);
|
||||
|
||||
// Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
|
||||
// and getpeername will work on the accepted socket.
|
||||
DWORD update_ctx_param = h->impl_;
|
||||
if (socket_ops::setsockopt(h->new_socket_.get(), SOL_SOCKET,
|
||||
SO_UPDATE_ACCEPT_CONTEXT, &update_ctx_param, sizeof(DWORD)) != 0)
|
||||
if (last_error == 0)
|
||||
{
|
||||
asio::error error(socket_ops::get_error());
|
||||
h->handler_(error);
|
||||
return;
|
||||
DWORD update_ctx_param = handler_op->impl_;
|
||||
if (socket_ops::setsockopt(handler_op->new_socket_.get(), SOL_SOCKET,
|
||||
SO_UPDATE_ACCEPT_CONTEXT, &update_ctx_param, sizeof(DWORD)) != 0)
|
||||
{
|
||||
last_error = socket_ops::get_error();
|
||||
}
|
||||
}
|
||||
|
||||
// Socket was successfully connected. Transfer ownership of the socket to
|
||||
// the peer object.
|
||||
impl_type new_socket(h->new_socket_.get());
|
||||
h->peer_.set_impl(new_socket);
|
||||
h->new_socket_.release();
|
||||
asio::error error(asio::error::success);
|
||||
h->handler_(error);
|
||||
// If the socket was successfully accepted, transfer ownership of the
|
||||
// socket to the peer object.
|
||||
if (last_error == 0)
|
||||
{
|
||||
impl_type new_socket(handler_op->new_socket_.get());
|
||||
handler_op->peer_.set_impl(new_socket);
|
||||
handler_op->new_socket_.release();
|
||||
}
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made.
|
||||
Handler handler(handler_op->handler_);
|
||||
|
||||
// Free the memory associated with the handler.
|
||||
ptr.reset();
|
||||
|
||||
// Call the handler.
|
||||
asio::error error(last_error);
|
||||
handler(error);
|
||||
}
|
||||
|
||||
demuxer_type& demuxer_;
|
||||
@ -1087,27 +1193,32 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new operation object. Ownership of new socket is transferred.
|
||||
std::auto_ptr<accept_endp_operation<Socket, Endpoint, Handler> > op(
|
||||
new accept_endp_operation<Socket, Endpoint, Handler>(
|
||||
demuxer_, impl, sock.get(), peer, peer_endpoint, handler));
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef accept_endp_operation<Socket, Endpoint, Handler> value_type;
|
||||
typedef handler_alloc_traits<Handler, value_type, Allocator> alloc_traits;
|
||||
raw_handler_ptr<alloc_traits> raw_ptr(handler, demuxer_.get_allocator());
|
||||
socket_type new_socket = sock.get();
|
||||
handler_ptr<alloc_traits> ptr(raw_ptr,
|
||||
demuxer_, impl, new_socket, peer, peer_endpoint, handler);
|
||||
sock.release();
|
||||
|
||||
// Accept a connection.
|
||||
DWORD bytes_read = 0;
|
||||
BOOL result = ::AcceptEx(impl, op->new_socket(), op->output_buffer(), 0,
|
||||
op->address_length(), op->address_length(), &bytes_read, op.get());
|
||||
BOOL result = ::AcceptEx(impl, ptr.get()->new_socket(),
|
||||
ptr.get()->output_buffer(), 0, ptr.get()->address_length(),
|
||||
ptr.get()->address_length(), &bytes_read, ptr.get());
|
||||
DWORD last_error = ::WSAGetLastError();
|
||||
|
||||
// Check if the operation completed immediately.
|
||||
if (!result && last_error != WSA_IO_PENDING)
|
||||
{
|
||||
ptr.reset();
|
||||
asio::error error(last_error);
|
||||
demuxer_service_.post(bind_handler(handler, error));
|
||||
}
|
||||
else
|
||||
{
|
||||
op.release();
|
||||
ptr.release();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1224,7 +1335,7 @@ public:
|
||||
{
|
||||
// Check if the reactor was already obtained from the demuxer.
|
||||
reactor_type* reactor = static_cast<reactor_type*>(
|
||||
::InterlockedCompareExchangePointer(
|
||||
InterlockedCompareExchangePointer(
|
||||
reinterpret_cast<void**>(&reactor_), 0, 0));
|
||||
if (!reactor)
|
||||
{
|
||||
@ -1293,7 +1404,7 @@ private:
|
||||
|
||||
// The demuxer service used for running asynchronous operations and
|
||||
// dispatching handlers.
|
||||
win_iocp_demuxer_service& demuxer_service_;
|
||||
win_iocp_demuxer_service<Allocator>& demuxer_service_;
|
||||
|
||||
// The reactor used for performing connect operations. This object is created
|
||||
// only if needed.
|
||||
|
@ -17,11 +17,29 @@
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
#include "asio/handler_alloc_hook.hpp"
|
||||
#include "asio/detail/bind_handler.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename Dispatcher, typename Handler>
|
||||
class wrapped_handler;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
|
||||
namespace asio {
|
||||
|
||||
template <typename Dispatcher, typename Handler>
|
||||
class handler_alloc_hook<
|
||||
asio::detail::wrapped_handler<Dispatcher, Handler> >;
|
||||
|
||||
} // namespace asio
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename Dispatcher, typename Handler>
|
||||
class wrapped_handler
|
||||
{
|
||||
@ -113,11 +131,37 @@ public:
|
||||
private:
|
||||
Dispatcher& dispatcher_;
|
||||
Handler handler_;
|
||||
friend class asio::handler_alloc_hook<
|
||||
wrapped_handler<Dispatcher, Handler> >;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
|
||||
template <typename Dispatcher, typename Handler>
|
||||
class asio::handler_alloc_hook<
|
||||
asio::detail::wrapped_handler<Dispatcher, Handler> >
|
||||
{
|
||||
public:
|
||||
typedef asio::detail::wrapped_handler<Dispatcher, Handler> handler_type;
|
||||
|
||||
template <typename Allocator>
|
||||
static typename Allocator::pointer allocate(handler_type& handler,
|
||||
Allocator& allocator, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::allocate(
|
||||
handler.handler_, allocator, count);
|
||||
}
|
||||
|
||||
template <typename Allocator>
|
||||
static void deallocate(handler_type& handler, Allocator& allocator,
|
||||
typename Allocator::pointer pointer, typename Allocator::size_type count)
|
||||
{
|
||||
return asio::handler_alloc_hook<Handler>::deallocate(
|
||||
handler.handler_, allocator, pointer, count);
|
||||
}
|
||||
};
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_DETAIL_WRAPPED_HANDLER_HPP
|
||||
|
129
asio/include/asio/handler_alloc_hook.hpp
Normal file
129
asio/include/asio/handler_alloc_hook.hpp
Normal file
@ -0,0 +1,129 @@
|
||||
//
|
||||
// handler_alloc_hook.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2005 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// 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 ASIO_HANDLER_ALLOC_HOOK_HPP
|
||||
#define ASIO_HANDLER_ALLOC_HOOK_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
|
||||
/// Allocation hook for handlers.
|
||||
/**
|
||||
* Asynchronous operations may need to allocate temporary objects. Since
|
||||
* asynchronous operations have a handler function object, these temporary
|
||||
* objects can be said to be associated with the handler.
|
||||
*
|
||||
* Specialise this class template for your own handlers to provide custom
|
||||
* allocation for these temporary objects. The default implementation simply
|
||||
* forwards the calls to the supplied allocator object.
|
||||
*
|
||||
* @note All temporary objects associated with a handler will be deallocated
|
||||
* before the upcall to the handler is performed. This allows the same memory to
|
||||
* be reused for a subsequent asynchronous operation initiated by the handler.
|
||||
*
|
||||
* @par Example:
|
||||
* @code
|
||||
* class my_handler;
|
||||
*
|
||||
* template <>
|
||||
* class asio::handler_alloc_hook<my_handler>
|
||||
* {
|
||||
* public:
|
||||
* template <typename Allocator>
|
||||
* static typename Allocator::pointer allocate(
|
||||
* Handler& handler, Allocator& allocator,
|
||||
* typename Allocator::size_type count)
|
||||
* {
|
||||
* typedef typename Allocator::pointer pointer_type;
|
||||
* typedef typename Allocator::value_type value_type;
|
||||
* void* mem = ::operator new(sizeof(value_type) * count);
|
||||
* return static_cast<pointer_type>(mem);
|
||||
* }
|
||||
*
|
||||
* template <typename Allocator>
|
||||
* static void deallocate(Handler& handler,
|
||||
* Allocator& allocator,
|
||||
* typename Allocator::pointer pointer,
|
||||
* typename Allocator::size_type count)
|
||||
* {
|
||||
* ::operator delete(pointer);
|
||||
* }
|
||||
* };
|
||||
* @endcode
|
||||
*/
|
||||
template <typename Handler>
|
||||
class handler_alloc_hook
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Handle a request to allocate some memory associated with a handler. The
|
||||
* default implementation is:
|
||||
* @code
|
||||
* return allocator.allocate(count);
|
||||
* @endcode
|
||||
*
|
||||
* @param handler A reference to the user handler object. May be used to
|
||||
* access pre-allocated memory that is associated with a handler object. Note
|
||||
* that this handler may be a copy of the original handler object passed to
|
||||
* the original function.
|
||||
*
|
||||
* @param allocator The allocator object associated with the demuxer. The
|
||||
* allocator has been rebound such that its value_type is the internal asio
|
||||
* type to be allocated.
|
||||
*
|
||||
* @param count The number of objects to be allocated.
|
||||
*
|
||||
* @throws std::bad_alloc Thrown if memory cannot be allocated.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
static typename Allocator::pointer allocate(Handler& handler,
|
||||
Allocator& allocator, typename Allocator::size_type count)
|
||||
{
|
||||
return allocator.allocate(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request to deallocate some memory associated with a handler. The
|
||||
* default implementation is:
|
||||
* @code
|
||||
* allocator.deallocate(pointer, count);
|
||||
* @endcode
|
||||
*
|
||||
* @param handler A reference to the user handler object. May be used to
|
||||
* access pre-allocated memory that is associated with a handler object. Note
|
||||
* that this handler may be a copy of the original handler object passed to
|
||||
* the original function.
|
||||
*
|
||||
* @param allocator The allocator object associated with the demuxer. The
|
||||
* allocator has been rebound such that its value_type is the internal asio
|
||||
* type to be allocated.
|
||||
*
|
||||
* @param A pointer to the memory to be deallocated.
|
||||
*
|
||||
* @param count The number of objects to be deallocated.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
static void deallocate(Handler& handler, Allocator& allocator,
|
||||
typename Allocator::pointer pointer, typename Allocator::size_type count)
|
||||
{
|
||||
allocator.deallocate(pointer, count);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_HANDLER_ALLOC_HOOK_HPP
|
@ -35,7 +35,7 @@ class locking_dispatcher_service
|
||||
{
|
||||
public:
|
||||
/// The demuxer type for this service.
|
||||
typedef basic_demuxer<demuxer_service<Allocator> > demuxer_type;
|
||||
typedef basic_demuxer<demuxer_service<Allocator>, Allocator> demuxer_type;
|
||||
|
||||
private:
|
||||
// The type of the platform-specific implementation.
|
||||
|
@ -40,7 +40,7 @@ class socket_acceptor_service
|
||||
{
|
||||
public:
|
||||
/// The demuxer type.
|
||||
typedef basic_demuxer<demuxer_service<Allocator> > demuxer_type;
|
||||
typedef basic_demuxer<demuxer_service<Allocator>, Allocator> demuxer_type;
|
||||
|
||||
private:
|
||||
// The type of the platform-specific implementation.
|
||||
|
@ -41,7 +41,7 @@ class stream_socket_service
|
||||
{
|
||||
public:
|
||||
/// The demuxer type.
|
||||
typedef basic_demuxer<demuxer_service<Allocator> > demuxer_type;
|
||||
typedef basic_demuxer<demuxer_service<Allocator>, Allocator> demuxer_type;
|
||||
|
||||
private:
|
||||
// The type of the platform-specific implementation.
|
||||
|
@ -222,16 +222,13 @@ void demuxer_test()
|
||||
BOOST_CHECK(count == 3);
|
||||
BOOST_CHECK(exception_count == 2);
|
||||
|
||||
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
// Use a non-default allocator type.
|
||||
typedef std::allocator<int> allocator_type;
|
||||
typedef demuxer_service<allocator_type> demuxer_service_type;
|
||||
typedef basic_demuxer<demuxer_service_type> demuxer_type;
|
||||
typedef basic_demuxer<demuxer_service_type, allocator_type> demuxer_type;
|
||||
allocator_type allocator;
|
||||
service_factory<demuxer_service_type> factory(allocator);
|
||||
demuxer_type d3(factory);
|
||||
demuxer_type d3(allocator);
|
||||
d3.run();
|
||||
#endif // !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
}
|
||||
|
||||
test_suite* init_unit_test_suite(int argc, char* argv[])
|
||||
|
Loading…
Reference in New Issue
Block a user