diff options
Diffstat (limited to '3rdParty/Boost/boost/asio/detail/strand_service.hpp')
-rw-r--r-- | 3rdParty/Boost/boost/asio/detail/strand_service.hpp | 532 |
1 files changed, 532 insertions, 0 deletions
diff --git a/3rdParty/Boost/boost/asio/detail/strand_service.hpp b/3rdParty/Boost/boost/asio/detail/strand_service.hpp new file mode 100644 index 0000000..2c89a61 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/strand_service.hpp @@ -0,0 +1,532 @@ +// +// strand_service.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP +#define BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/push_options.hpp> + +#include <boost/asio/detail/push_options.hpp> +#include <boost/aligned_storage.hpp> +#include <boost/assert.hpp> +#include <boost/detail/atomic_count.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/io_service.hpp> +#include <boost/asio/detail/bind_handler.hpp> +#include <boost/asio/detail/call_stack.hpp> +#include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/mutex.hpp> +#include <boost/asio/detail/noncopyable.hpp> +#include <boost/asio/detail/service_base.hpp> + +namespace boost { +namespace asio { +namespace detail { + +// Default service implementation for a strand. +class strand_service + : public boost::asio::detail::service_base<strand_service> +{ +public: + class handler_base; + class invoke_current_handler; + class post_next_waiter_on_exit; + + // The underlying implementation of a strand. + class strand_impl + { +#if defined (__BORLANDC__) + public: +#else + private: +#endif + void add_ref() + { + ++ref_count_; + } + + void release() + { + if (--ref_count_ == 0) + delete this; + } + + private: + // Only this service will have access to the internal values. + friend class strand_service; + friend class post_next_waiter_on_exit; + friend class invoke_current_handler; + + strand_impl(strand_service& owner) + : owner_(owner), + current_handler_(0), + first_waiter_(0), + last_waiter_(0), + ref_count_(0) + { + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(owner_.mutex_); + next_ = owner_.impl_list_; + prev_ = 0; + if (owner_.impl_list_) + owner_.impl_list_->prev_ = this; + owner_.impl_list_ = this; + } + + ~strand_impl() + { + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(owner_.mutex_); + if (owner_.impl_list_ == this) + owner_.impl_list_ = next_; + if (prev_) + prev_->next_ = next_; + if (next_) + next_->prev_= prev_; + next_ = 0; + prev_ = 0; + lock.unlock(); + + if (current_handler_) + { + current_handler_->destroy(); + } + + while (first_waiter_) + { + handler_base* next = first_waiter_->next_; + first_waiter_->destroy(); + first_waiter_ = next; + } + } + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // The service that owns this implementation. + strand_service& owner_; + + // The handler that is ready to execute. If this pointer is non-null then it + // indicates that a handler holds the lock. + handler_base* current_handler_; + + // The start of the list of waiting handlers for the strand. + handler_base* first_waiter_; + + // The end of the list of waiting handlers for the strand. + handler_base* last_waiter_; + + // Storage for posted handlers. + typedef boost::aligned_storage<128> handler_storage_type; +#if defined(__BORLANDC__) + boost::aligned_storage<128> handler_storage_; +#else + handler_storage_type handler_storage_; +#endif + + // Pointers to adjacent socket implementations in linked list. + strand_impl* next_; + strand_impl* prev_; + + // The reference count on the strand implementation. + boost::detail::atomic_count ref_count_; + +#if !defined(__BORLANDC__) + friend void intrusive_ptr_add_ref(strand_impl* p) + { + p->add_ref(); + } + + friend void intrusive_ptr_release(strand_impl* p) + { + p->release(); + } +#endif + }; + + friend class strand_impl; + + typedef boost::intrusive_ptr<strand_impl> implementation_type; + + // Base class for all handler types. + class handler_base + { + public: + typedef void (*invoke_func_type)(handler_base*, + strand_service&, implementation_type&); + typedef void (*destroy_func_type)(handler_base*); + + handler_base(invoke_func_type invoke_func, destroy_func_type destroy_func) + : next_(0), + invoke_func_(invoke_func), + destroy_func_(destroy_func) + { + } + + void invoke(strand_service& service_impl, implementation_type& impl) + { + invoke_func_(this, service_impl, impl); + } + + void destroy() + { + destroy_func_(this); + } + + protected: + ~handler_base() + { + } + + private: + friend class strand_service; + friend class strand_impl; + friend class post_next_waiter_on_exit; + handler_base* next_; + invoke_func_type invoke_func_; + destroy_func_type destroy_func_; + }; + + // Helper class to allow handlers to be dispatched. + class invoke_current_handler + { + public: + invoke_current_handler(strand_service& service_impl, + const implementation_type& impl) + : service_impl_(service_impl), + impl_(impl) + { + } + + void operator()() + { + impl_->current_handler_->invoke(service_impl_, impl_); + } + + friend void* asio_handler_allocate(std::size_t size, + invoke_current_handler* this_handler) + { + return this_handler->do_handler_allocate(size); + } + + friend void asio_handler_deallocate(void*, std::size_t, + invoke_current_handler*) + { + } + + void* do_handler_allocate(std::size_t size) + { +#if defined(__BORLANDC__) + BOOST_ASSERT(size <= boost::aligned_storage<128>::size); +#else + BOOST_ASSERT(size <= strand_impl::handler_storage_type::size); +#endif + (void)size; + return impl_->handler_storage_.address(); + } + + // The asio_handler_invoke hook is not defined here since the default one + // provides the correct behaviour, and including it here breaks MSVC 7.1 + // in some situations. + + private: + strand_service& service_impl_; + implementation_type impl_; + }; + + // Helper class to automatically enqueue next waiter on block exit. + class post_next_waiter_on_exit + { + public: + post_next_waiter_on_exit(strand_service& service_impl, + implementation_type& impl) + : service_impl_(service_impl), + impl_(impl), + cancelled_(false) + { + } + + ~post_next_waiter_on_exit() + { + if (!cancelled_) + { + boost::asio::detail::mutex::scoped_lock lock(impl_->mutex_); + impl_->current_handler_ = impl_->first_waiter_; + if (impl_->current_handler_) + { + impl_->first_waiter_ = impl_->first_waiter_->next_; + if (impl_->first_waiter_ == 0) + impl_->last_waiter_ = 0; + lock.unlock(); + service_impl_.get_io_service().post( + invoke_current_handler(service_impl_, impl_)); + } + } + } + + void cancel() + { + cancelled_ = true; + } + + private: + strand_service& service_impl_; + implementation_type& impl_; + bool cancelled_; + }; + + // Class template for a waiter. + template <typename Handler> + class handler_wrapper + : public handler_base + { + public: + handler_wrapper(Handler handler) + : handler_base(&handler_wrapper<Handler>::do_invoke, + &handler_wrapper<Handler>::do_destroy), + handler_(handler) + { + } + + static void do_invoke(handler_base* base, + strand_service& service_impl, implementation_type& impl) + { + // Take ownership of the handler object. + typedef handler_wrapper<Handler> this_type; + this_type* h(static_cast<this_type*>(base)); + typedef handler_alloc_traits<Handler, this_type> alloc_traits; + handler_ptr<alloc_traits> ptr(h->handler_, h); + + post_next_waiter_on_exit p1(service_impl, impl); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. + Handler handler(h->handler_); + + // A handler object must still be valid when the next waiter is posted + // since destroying the last handler might cause the strand object to be + // destroyed. Therefore we create a second post_next_waiter_on_exit object + // that will be destroyed before the handler object. + p1.cancel(); + post_next_waiter_on_exit p2(service_impl, impl); + + // Free the memory associated with the handler. + ptr.reset(); + + // Indicate that this strand is executing on the current thread. + call_stack<strand_impl>::context ctx(impl.get()); + + // Make the upcall. + boost_asio_handler_invoke_helpers::invoke(handler, &handler); + } + + static void do_destroy(handler_base* base) + { + // Take ownership of the handler object. + typedef handler_wrapper<Handler> this_type; + this_type* h(static_cast<this_type*>(base)); + typedef handler_alloc_traits<Handler, this_type> alloc_traits; + handler_ptr<alloc_traits> ptr(h->handler_, h); + + // A sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + Handler handler(h->handler_); + (void)handler; + + // Free the memory associated with the handler. + ptr.reset(); + } + + private: + Handler handler_; + }; + + // Construct a new strand service for the specified io_service. + explicit strand_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base<strand_service>(io_service), + mutex_(), + impl_list_(0) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + // Construct a list of all handlers to be destroyed. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + strand_impl* impl = impl_list_; + handler_base* first_handler = 0; + while (impl) + { + if (impl->current_handler_) + { + impl->current_handler_->next_ = first_handler; + first_handler = impl->current_handler_; + impl->current_handler_ = 0; + } + if (impl->first_waiter_) + { + impl->last_waiter_->next_ = first_handler; + first_handler = impl->first_waiter_; + impl->first_waiter_ = 0; + impl->last_waiter_ = 0; + } + impl = impl->next_; + } + + // Destroy all handlers without holding the lock. + lock.unlock(); + while (first_handler) + { + handler_base* next = first_handler->next_; + first_handler->destroy(); + first_handler = next; + } + } + + // Construct a new strand implementation. + void construct(implementation_type& impl) + { + impl = implementation_type(new strand_impl(*this)); + } + + // Destroy a strand implementation. + void destroy(implementation_type& impl) + { + implementation_type().swap(impl); + } + + // Request the io_service to invoke the given handler. + template <typename Handler> + void dispatch(implementation_type& impl, Handler handler) + { + if (call_stack<strand_impl>::contains(impl.get())) + { + boost_asio_handler_invoke_helpers::invoke(handler, &handler); + } + else + { + // Allocate and construct an object to wrap the handler. + typedef handler_wrapper<Handler> value_type; + typedef handler_alloc_traits<Handler, value_type> alloc_traits; + raw_handler_ptr<alloc_traits> raw_ptr(handler); + handler_ptr<alloc_traits> ptr(raw_ptr, handler); + + boost::asio::detail::mutex::scoped_lock lock(impl->mutex_); + + if (impl->current_handler_ == 0) + { + // This handler now has the lock, so can be dispatched immediately. + impl->current_handler_ = ptr.release(); + lock.unlock(); + this->get_io_service().dispatch(invoke_current_handler(*this, impl)); + } + else + { + // Another handler already holds the lock, so this handler must join + // the list of waiters. The handler will be posted automatically when + // its turn comes. + if (impl->last_waiter_) + { + impl->last_waiter_->next_ = ptr.get(); + impl->last_waiter_ = impl->last_waiter_->next_; + } + else + { + impl->first_waiter_ = ptr.get(); + impl->last_waiter_ = ptr.get(); + } + ptr.release(); + } + } + } + + // Request the io_service to invoke the given handler and return immediately. + template <typename Handler> + void post(implementation_type& impl, Handler handler) + { + // Allocate and construct an object to wrap the handler. + typedef handler_wrapper<Handler> value_type; + typedef handler_alloc_traits<Handler, value_type> alloc_traits; + raw_handler_ptr<alloc_traits> raw_ptr(handler); + handler_ptr<alloc_traits> ptr(raw_ptr, handler); + + boost::asio::detail::mutex::scoped_lock lock(impl->mutex_); + + if (impl->current_handler_ == 0) + { + // This handler now has the lock, so can be dispatched immediately. + impl->current_handler_ = ptr.release(); + lock.unlock(); + this->get_io_service().post(invoke_current_handler(*this, impl)); + } + else + { + // Another handler already holds the lock, so this handler must join the + // list of waiters. The handler will be posted automatically when its turn + // comes. + if (impl->last_waiter_) + { + impl->last_waiter_->next_ = ptr.get(); + impl->last_waiter_ = impl->last_waiter_->next_; + } + else + { + impl->first_waiter_ = ptr.get(); + impl->last_waiter_ = ptr.get(); + } + ptr.release(); + } + } + +private: + // Mutex to protect access to the linked list of implementations. + boost::asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + strand_impl* impl_list_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#if defined(__BORLANDC__) + +namespace boost { + +inline void intrusive_ptr_add_ref( + boost::asio::detail::strand_service::strand_impl* p) +{ + p->add_ref(); +} + +inline void intrusive_ptr_release( + boost::asio::detail::strand_service::strand_impl* p) +{ + p->release(); +} + +} // namespace boost + +#endif // defined(__BORLANDC__) + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP |