Add a small block recycling optimisation.
diff --git a/asio/include/Makefile.am b/asio/include/Makefile.am index 33b0929..0af7e3d 100644 --- a/asio/include/Makefile.am +++ b/asio/include/Makefile.am
@@ -182,7 +182,9 @@ asio/detail/task_io_service_fwd.hpp \ asio/detail/task_io_service.hpp \ asio/detail/task_io_service_operation.hpp \ + asio/detail/task_io_service_thread_info.hpp \ asio/detail/thread.hpp \ + asio/detail/thread_info_base.hpp \ asio/detail/throw_error.hpp \ asio/detail/timer_queue_base.hpp \ asio/detail/timer_queue_fwd.hpp \ @@ -216,6 +218,7 @@ asio/detail/win_iocp_socket_send_op.hpp \ asio/detail/win_iocp_socket_service_base.hpp \ asio/detail/win_iocp_socket_service.hpp \ + asio/detail/win_iocp_thread_info.hpp \ asio/detail/win_mutex.hpp \ asio/detail/win_object_handle_service.hpp \ asio/detail/winsock_init.hpp \ @@ -232,6 +235,7 @@ asio/impl/connect.hpp \ asio/impl/error_code.ipp \ asio/impl/error.ipp \ + asio/impl/handler_alloc_hook.ipp \ asio/impl/io_service.hpp \ asio/impl/io_service.ipp \ asio/impl/read_at.hpp \
diff --git a/asio/include/asio/detail/call_stack.hpp b/asio/include/asio/detail/call_stack.hpp index 1dcac22..1af3e4c 100644 --- a/asio/include/asio/detail/call_stack.hpp +++ b/asio/include/asio/detail/call_stack.hpp
@@ -101,6 +101,13 @@ return 0; } + // Obtain the value at the top of the stack. + static Value* top() + { + context* elem = top_; + return elem ? elem->value_ : 0; + } + private: // The top of the stack of calls for the current thread. static tss_ptr<context> top_;
diff --git a/asio/include/asio/detail/impl/task_io_service.ipp b/asio/include/asio/detail/impl/task_io_service.ipp index 1a74a22..12373a8 100755 --- a/asio/include/asio/detail/impl/task_io_service.ipp +++ b/asio/include/asio/detail/impl/task_io_service.ipp
@@ -23,20 +23,13 @@ #include "asio/detail/event.hpp" #include "asio/detail/reactor.hpp" #include "asio/detail/task_io_service.hpp" +#include "asio/detail/task_io_service_thread_info.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { -struct task_io_service::thread_info -{ - event* wakeup_event; - op_queue<operation> private_op_queue; - long private_outstanding_work; - thread_info* next; -}; - struct task_io_service::task_cleanup { ~task_cleanup()
diff --git a/asio/include/asio/detail/impl/win_iocp_io_service.hpp b/asio/include/asio/detail/impl/win_iocp_io_service.hpp index a6c0d23..0fe7df6 100644 --- a/asio/include/asio/detail/impl/win_iocp_io_service.hpp +++ b/asio/include/asio/detail/impl/win_iocp_io_service.hpp
@@ -32,7 +32,7 @@ template <typename Handler> void win_iocp_io_service::dispatch(Handler handler) { - if (call_stack<win_iocp_io_service>::contains(this)) + if (thread_call_stack::contains(this)) { fenced_block b(fenced_block::full); asio_handler_invoke_helpers::invoke(handler, handler);
diff --git a/asio/include/asio/detail/impl/win_iocp_io_service.ipp b/asio/include/asio/detail/impl/win_iocp_io_service.ipp index 8f5722c..9a8fc53 100644 --- a/asio/include/asio/detail/impl/win_iocp_io_service.ipp +++ b/asio/include/asio/detail/impl/win_iocp_io_service.ipp
@@ -153,7 +153,8 @@ return 0; } - call_stack<win_iocp_io_service>::context ctx(this); + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); size_t n = 0; while (do_one(true, ec)) @@ -171,7 +172,8 @@ return 0; } - call_stack<win_iocp_io_service>::context ctx(this); + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); return do_one(true, ec); } @@ -185,7 +187,8 @@ return 0; } - call_stack<win_iocp_io_service>::context ctx(this); + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); size_t n = 0; while (do_one(false, ec)) @@ -203,7 +206,8 @@ return 0; } - call_stack<win_iocp_io_service>::context ctx(this); + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); return do_one(false, ec); }
diff --git a/asio/include/asio/detail/task_io_service.hpp b/asio/include/asio/detail/task_io_service.hpp index 8da47df..a6caecb 100644 --- a/asio/include/asio/detail/task_io_service.hpp +++ b/asio/include/asio/detail/task_io_service.hpp
@@ -127,7 +127,7 @@ private: // Structure containing information about an idle thread. - struct thread_info; + typedef task_io_service_thread_info thread_info; // Request invocation of the given operation, avoiding the thread-private // queue, and return immediately. Assumes that work_started() has not yet
diff --git a/asio/include/asio/detail/task_io_service_fwd.hpp b/asio/include/asio/detail/task_io_service_fwd.hpp index 0ff6af0..a9e52c6 100644 --- a/asio/include/asio/detail/task_io_service_fwd.hpp +++ b/asio/include/asio/detail/task_io_service_fwd.hpp
@@ -19,6 +19,8 @@ namespace detail { class task_io_service; +class task_io_service_operation; +struct task_io_service_thread_info; } // namespace detail } // namespace asio
diff --git a/asio/include/asio/detail/task_io_service_thread_info.hpp b/asio/include/asio/detail/task_io_service_thread_info.hpp new file mode 100644 index 0000000..0210112 --- /dev/null +++ b/asio/include/asio/detail/task_io_service_thread_info.hpp
@@ -0,0 +1,41 @@ +// +// detail/task_io_service_thread_info.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2012 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_TASK_IO_SERVICE_THREAD_INFO_HPP +#define ASIO_DETAIL_TASK_IO_SERVICE_THREAD_INFO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/event.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/task_io_service_fwd.hpp" +#include "asio/detail/thread_info_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct task_io_service_thread_info : public thread_info_base +{ + event* wakeup_event; + op_queue<task_io_service_operation> private_op_queue; + long private_outstanding_work; + task_io_service_thread_info* next; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_TASK_IO_SERVICE_THREAD_INFO_HPP
diff --git a/asio/include/asio/detail/thread_info_base.hpp b/asio/include/asio/detail/thread_info_base.hpp new file mode 100644 index 0000000..9da68b3 --- /dev/null +++ b/asio/include/asio/detail/thread_info_base.hpp
@@ -0,0 +1,90 @@ +// +// detail/thread_info_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2012 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_THREAD_INFO_BASE_HPP +#define ASIO_DETAIL_THREAD_INFO_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <cstddef> +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class thread_info_base + : private noncopyable +{ +public: + thread_info_base() + : reusable_memory_(0) + { + } + + ~thread_info_base() + { + if (reusable_memory_) + ::operator delete(reusable_memory_); + } + + static void* allocate(thread_info_base* this_thread, std::size_t size) + { + if (this_thread && this_thread->reusable_memory_) + { + void* const pointer = this_thread->reusable_memory_; + this_thread->reusable_memory_ = 0; + + unsigned char* const mem = static_cast<unsigned char*>(pointer); + if (static_cast<std::size_t>(mem[0]) >= size) + { + mem[size] = mem[0]; + return pointer; + } + + ::operator delete(pointer); + } + + void* const pointer = ::operator new(size + 1); + unsigned char* const mem = static_cast<unsigned char*>(pointer); + mem[size] = (size <= UCHAR_MAX) ? static_cast<unsigned char>(size) : 0; + return pointer; + } + + static void deallocate(thread_info_base* this_thread, + void* pointer, std::size_t size) + { + if (size <= UCHAR_MAX) + { + if (this_thread && this_thread->reusable_memory_ == 0) + { + unsigned char* const mem = static_cast<unsigned char*>(pointer); + mem[0] = mem[size]; + this_thread->reusable_memory_ = pointer; + return; + } + } + + ::operator delete(pointer); + } + +private: + void* reusable_memory_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_THREAD_INFO_BASE_HPP
diff --git a/asio/include/asio/detail/win_iocp_io_service.hpp b/asio/include/asio/detail/win_iocp_io_service.hpp index 181df84..0a0a609 100644 --- a/asio/include/asio/detail/win_iocp_io_service.hpp +++ b/asio/include/asio/detail/win_iocp_io_service.hpp
@@ -33,6 +33,7 @@ #include "asio/detail/wait_op.hpp" #include "asio/detail/win_iocp_io_service_fwd.hpp" #include "asio/detail/win_iocp_operation.hpp" +#include "asio/detail/win_iocp_thread_info.hpp" #include "asio/detail/push_options.hpp" @@ -106,7 +107,7 @@ // Return whether a handler can be dispatched immediately. bool can_dispatch() { - return call_stack<win_iocp_io_service>::contains(this) != 0; + return thread_call_stack::contains(this) != 0; } // Request invocation of the given handler. @@ -289,6 +290,10 @@ // The operations that are ready to dispatch. op_queue<win_iocp_operation> completed_ops_; + + // Per-thread call stack to track the state of each thread in the io_service. + typedef call_stack<win_iocp_io_service, + win_iocp_thread_info> thread_call_stack; }; } // namespace detail
diff --git a/asio/include/asio/detail/win_iocp_thread_info.hpp b/asio/include/asio/detail/win_iocp_thread_info.hpp new file mode 100644 index 0000000..32377b6 --- /dev/null +++ b/asio/include/asio/detail/win_iocp_thread_info.hpp
@@ -0,0 +1,34 @@ +// +// detail/win_iocp_thread_info.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2012 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_WIN_IOCP_THREAD_INFO_HPP +#define ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/thread_info_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct win_iocp_thread_info : public thread_info_base +{ +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP
diff --git a/asio/include/asio/handler_alloc_hook.hpp b/asio/include/asio/handler_alloc_hook.hpp index 3f4ba1e..3d2cd15 100644 --- a/asio/include/asio/handler_alloc_hook.hpp +++ b/asio/include/asio/handler_alloc_hook.hpp
@@ -31,10 +31,8 @@ * Implement asio_handler_allocate and asio_handler_deallocate for your own * handlers to provide custom allocation for these temporary objects. * - * This default implementation is simply: - * @code - * return ::operator new(size); - * @endcode + * The default implementation of these allocation hooks uses <tt>::operator + * new</tt> and <tt>::operator delete</tt>. * * @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 @@ -56,31 +54,28 @@ * } * @endcode */ -inline void* asio_handler_allocate(std::size_t size, ...) -{ - return ::operator new(size); -} +ASIO_DECL void* asio_handler_allocate( + std::size_t size, ...); /// Default deallocation function for handlers. /** * Implement asio_handler_allocate and asio_handler_deallocate for your own * handlers to provide custom allocation for the associated temporary objects. * - * This default implementation is simply: - * @code - * ::operator delete(pointer); - * @endcode + * The default implementation of these allocation hooks uses <tt>::operator + * new</tt> and <tt>::operator delete</tt>. * * @sa asio_handler_allocate. */ -inline void asio_handler_deallocate(void* pointer, std::size_t size, ...) -{ - (void)(size); - ::operator delete(pointer); -} +ASIO_DECL void asio_handler_deallocate( + void* pointer, std::size_t size, ...); } // namespace asio #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/handler_alloc_hook.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_HANDLER_ALLOC_HOOK_HPP
diff --git a/asio/include/asio/impl/handler_alloc_hook.ipp b/asio/include/asio/impl/handler_alloc_hook.ipp new file mode 100644 index 0000000..0e374ce --- /dev/null +++ b/asio/include/asio/impl/handler_alloc_hook.ipp
@@ -0,0 +1,74 @@ +// +// impl/handler_alloc_hook.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2012 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_IMPL_HANDLER_ALLOC_HOOK_IPP +#define ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/call_stack.hpp" +#include "asio/handler_alloc_hook.hpp" + +#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +# if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_service_fwd.hpp" +# include "asio/detail/win_iocp_thread_info.hpp" +# else // defined(ASIO_HAS_IOCP) +# include "asio/detail/task_io_service_thread_info.hpp" +# endif // defined(ASIO_HAS_IOCP) +#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +void* asio_handler_allocate(std::size_t size, ...) +{ +#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +# if defined(ASIO_HAS_IOCP) + typedef detail::win_iocp_io_service io_service_impl; + typedef detail::win_iocp_thread_info thread_info; +# else // defined(ASIO_HAS_IOCP) + typedef detail::task_io_service io_service_impl; + typedef detail::task_io_service_thread_info thread_info; +# endif // defined(ASIO_HAS_IOCP) + typedef detail::call_stack<io_service_impl, thread_info> call_stack; + return thread_info::allocate(call_stack::top(), size); +#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return ::operator new(size); +#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +} + +void asio_handler_deallocate(void* pointer, std::size_t size, ...) +{ +#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +# if defined(ASIO_HAS_IOCP) + typedef detail::win_iocp_io_service io_service_impl; + typedef detail::win_iocp_thread_info thread_info; +# else // defined(ASIO_HAS_IOCP) + typedef detail::task_io_service io_service_impl; + typedef detail::task_io_service_thread_info thread_info; +# endif // defined(ASIO_HAS_IOCP) + typedef detail::call_stack<io_service_impl, thread_info> call_stack; + thread_info::deallocate(call_stack::top(), pointer, size); +#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + (void)size; + ::operator delete(pointer); +#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP
diff --git a/asio/include/asio/impl/src.hpp b/asio/include/asio/impl/src.hpp index 8bfe0ad..0835ce8 100644 --- a/asio/include/asio/impl/src.hpp +++ b/asio/include/asio/impl/src.hpp
@@ -21,6 +21,7 @@ #include "asio/impl/error.ipp" #include "asio/impl/error_code.ipp" +#include "asio/impl/handler_alloc_hook.ipp" #include "asio/impl/io_service.ipp" #include "asio/impl/serial_port_base.ipp" #include "asio/detail/impl/descriptor_ops.ipp"