Add custom allocation support on Windows.

This commit is contained in:
chris_kohlhoff 2005-12-27 03:52:40 +00:00
parent 80782580c6
commit 011d4f8e9c
17 changed files with 940 additions and 230 deletions

View File

@ -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"

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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"

View File

@ -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

View 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

View File

@ -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_)

View File

@ -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

View File

@ -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:

View File

@ -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.

View File

@ -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

View 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

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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[])