123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- //
- // 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
|