From d76ada0ab59634e3333f9eb5a92d0e850f60d7bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Thu, 6 May 2010 19:44:27 +0200 Subject: Updated Boost to 1.43.0. diff --git a/3rdParty/Boost/src/boost/array.hpp b/3rdParty/Boost/src/boost/array.hpp index d58b93a..6496469 100644 --- a/3rdParty/Boost/src/boost/array.hpp +++ b/3rdParty/Boost/src/boost/array.hpp @@ -13,6 +13,10 @@ * accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * + * 10 Mar 2010 - (mtc) fill method added, matching resolution of the standard library working group. + * See or Trac issue #3168 + * Eventually, we should remove "assign" which is now a synonym for "fill" (Marshall Clow) + * 10 Mar 2010 - added workaround for SUNCC and !STLPort [trac #3893] (Marshall Clow) * 29 Jan 2004 - c_array() added, BOOST_NO_PRIVATE_IN_AGGREGATE removed (Nico Josuttis) * 23 Aug 2002 - fix for Non-MSVC compilers combined with MSVC libraries. * 05 Aug 2001 - minor update (Nico Josuttis) @@ -29,6 +33,8 @@ #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) # pragma warning(push) # pragma warning(disable:4996) // 'std::equal': Function call with parameters that may be unsafe +# pragma warning(disable:4510) // boost::array' : default constructor could not be generated +# pragma warning(disable:4610) // warning C4610: class 'boost::array' can never be instantiated - user defined constructor required #endif #include @@ -78,6 +84,11 @@ namespace boost { reference, iterator, reference> > reverse_iterator; typedef std::reverse_iterator > const_reverse_iterator; +#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; #else // workaround for broken reverse_iterator implementations typedef std::reverse_iterator reverse_iterator; @@ -158,7 +169,8 @@ namespace boost { } // assign one value to all elements - void assign (const T& value) + void assign (const T& value) { fill ( value ); } // A synonym for fill + void fill (const T& value) { std::fill_n(begin(),size(),value); } @@ -166,7 +178,8 @@ namespace boost { // check range (may be private because it is static) static void rangecheck (size_type i) { if (i >= size()) { - throw std::out_of_range("array<>: index out of range"); + std::out_of_range e("array<>: index out of range"); + boost::throw_exception(e); } } @@ -202,6 +215,11 @@ namespace boost { reference, iterator, reference> > reverse_iterator; typedef std::reverse_iterator > const_reverse_iterator; +#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; #else // workaround for broken reverse_iterator implementations typedef std::reverse_iterator reverse_iterator; @@ -276,12 +294,14 @@ namespace boost { } // assign one value to all elements - void assign (const T& ) { } - + void assign (const T& value) { fill ( value ); } + void fill (const T& ) {} + // check range (may be private because it is static) static reference failed_rangecheck () { std::out_of_range e("attempt to access element of an empty array"); boost::throw_exception(e); +#if defined(BOOST_NO_EXCEPTIONS) || !defined(BOOST_MSVC) // // We need to return something here to keep // some compilers happy: however we will never @@ -289,6 +309,7 @@ namespace boost { // static T placeholder; return placeholder; +#endif } }; #endif diff --git a/3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp b/3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp index 9e96401..695e8e1 100644 --- a/3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp +++ b/3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp @@ -50,7 +50,8 @@ // init_buffers(); // boost::system::error_code ec; // this->basic_socket::close(ec); -// typedef typename Protocol::resolver_query resolver_query; +// typedef typename Protocol::resolver resolver_type; +// typedef typename resolver_type::query resolver_query; // resolver_query query(x1, ..., xn); // resolve_and_connect(query, ec); // return !ec ? this : 0; @@ -65,7 +66,8 @@ init_buffers(); \ boost::system::error_code ec; \ this->basic_socket::close(ec); \ - typedef typename Protocol::resolver_query resolver_query; \ + typedef typename Protocol::resolver resolver_type; \ + typedef typename resolver_type::query resolver_query; \ resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \ resolve_and_connect(query, ec); \ return !ec ? this : 0; \ @@ -259,7 +261,7 @@ private: boost::system::error_code& ec) { typedef typename Protocol::resolver resolver_type; - typedef typename Protocol::resolver_iterator iterator_type; + typedef typename resolver_type::iterator iterator_type; resolver_type resolver( boost::base_from_member::member); iterator_type i = resolver.resolve(query, ec); diff --git a/3rdParty/Boost/src/boost/asio/buffers_iterator.hpp b/3rdParty/Boost/src/boost/asio/buffers_iterator.hpp index 0d29213..0b654b8 100644 --- a/3rdParty/Boost/src/boost/asio/buffers_iterator.hpp +++ b/3rdParty/Boost/src/boost/asio/buffers_iterator.hpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -76,11 +76,10 @@ namespace detail /// A random access iterator over the bytes in a buffer sequence. template class buffers_iterator - : public boost::iterator_facade< - buffers_iterator, - typename detail::buffers_iterator_types< - BufferSequence, ByteType>::byte_type, - boost::random_access_traversal_tag> + : public boost::iterator< + std::random_access_iterator_tag, + typename detail::buffers_iterator_types< + BufferSequence, ByteType>::byte_type> { private: typedef typename detail::buffers_iterator_types< @@ -139,9 +138,132 @@ public: return new_iter; } -private: - friend class boost::iterator_core_access; + /// Dereference an iterator. + byte_type& operator*() const + { + return dereference(); + } + + /// Dereference an iterator. + byte_type* operator->() const + { + return &dereference(); + } + + /// Access an individual element. + byte_type& operator[](std::ptrdiff_t difference) const + { + buffers_iterator tmp(*this); + tmp.advance(difference); + return *tmp; + } + + /// Increment operator (prefix). + buffers_iterator& operator++() + { + increment(); + return *this; + } + + /// Increment operator (postfix). + buffers_iterator operator++(int) + { + buffers_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Decrement operator (prefix). + buffers_iterator& operator--() + { + decrement(); + return *this; + } + + /// Decrement operator (postfix). + buffers_iterator operator--(int) + { + buffers_iterator tmp(*this); + --*this; + return tmp; + } + /// Addition operator. + buffers_iterator& operator+=(std::ptrdiff_t difference) + { + advance(difference); + return *this; + } + + /// Subtraction operator. + buffers_iterator& operator-=(std::ptrdiff_t difference) + { + advance(-difference); + return *this; + } + + /// Addition operator. + friend buffers_iterator operator+(const buffers_iterator& iter, + std::ptrdiff_t difference) + { + buffers_iterator tmp(iter); + tmp.advance(difference); + return tmp; + } + + /// Subtraction operator. + friend buffers_iterator operator-(const buffers_iterator& iter, + std::ptrdiff_t difference) + { + buffers_iterator tmp(iter); + tmp.advance(-difference); + return tmp; + } + + /// Subtraction operator. + friend std::ptrdiff_t operator-(const buffers_iterator& a, + const buffers_iterator& b) + { + return b.distance_to(a); + } + + /// Test two iterators for equality. + friend bool operator==(const buffers_iterator& a, const buffers_iterator& b) + { + return a.equal(b); + } + + /// Test two iterators for inequality. + friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b) + { + return !a.equal(b); + } + + /// Compare two iterators. + friend bool operator<(const buffers_iterator& a, const buffers_iterator& b) + { + return a.distance_to(b) > 0; + } + + /// Compare two iterators. + friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b) + { + return !(b < a); + } + + /// Compare two iterators. + friend bool operator>(const buffers_iterator& a, const buffers_iterator& b) + { + return b < a; + } + + /// Compare two iterators. + friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b) + { + return !(a < b); + } + +private: // Dereference the iterator. byte_type& dereference() const { diff --git a/3rdParty/Boost/src/boost/asio/datagram_socket_service.hpp b/3rdParty/Boost/src/boost/asio/datagram_socket_service.hpp index 93deddc..74bf703 100644 --- a/3rdParty/Boost/src/boost/asio/datagram_socket_service.hpp +++ b/3rdParty/Boost/src/boost/asio/datagram_socket_service.hpp @@ -28,17 +28,7 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include #else -# include # include #endif @@ -70,18 +60,8 @@ private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_socket_service< - Protocol, detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_socket_service< - Protocol, detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_socket_service< - Protocol, detail::dev_poll_reactor > service_impl_type; #else - typedef detail::reactive_socket_service< - Protocol, detail::select_reactor > service_impl_type; + typedef detail::reactive_socket_service service_impl_type; #endif public: @@ -103,13 +83,14 @@ public: explicit datagram_socket_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< datagram_socket_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new datagram socket implementation. @@ -324,8 +305,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/3rdParty/Boost/src/boost/asio/deadline_timer_service.hpp b/3rdParty/Boost/src/boost/asio/deadline_timer_service.hpp index 90e7482..624791d 100644 --- a/3rdParty/Boost/src/boost/asio/deadline_timer_service.hpp +++ b/3rdParty/Boost/src/boost/asio/deadline_timer_service.hpp @@ -27,18 +27,6 @@ #include #include -#if defined(BOOST_ASIO_HAS_IOCP) -# include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -#else -# include -#endif - namespace boost { namespace asio { @@ -70,22 +58,7 @@ public: private: // The type of the platform-specific implementation. -#if defined(BOOST_ASIO_HAS_IOCP) - typedef detail::deadline_timer_service< - traits_type, detail::win_iocp_io_service> service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::deadline_timer_service< - traits_type, detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::deadline_timer_service< - traits_type, detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::deadline_timer_service< - traits_type, detail::dev_poll_reactor > service_impl_type; -#else - typedef detail::deadline_timer_service< - traits_type, detail::select_reactor > service_impl_type; -#endif + typedef detail::deadline_timer_service service_impl_type; public: /// The implementation type of the deadline timer. @@ -99,13 +72,14 @@ public: explicit deadline_timer_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< deadline_timer_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new timer implementation. @@ -166,8 +140,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/3rdParty/Boost/src/boost/asio/detail/base_from_completion_cond.hpp b/3rdParty/Boost/src/boost/asio/detail/base_from_completion_cond.hpp new file mode 100644 index 0000000..1b1f142 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/base_from_completion_cond.hpp @@ -0,0 +1,67 @@ +// +// base_from_completion_cond.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_BASE_FROM_COMPLETION_COND_HPP +#define BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class base_from_completion_cond +{ +protected: + explicit base_from_completion_cond(CompletionCondition completion_condition) + : completion_condition_(completion_condition) + { + } + + std::size_t check(const boost::system::error_code& ec, + std::size_t total_transferred) + { + return detail::adapt_completion_condition_result( + completion_condition_(ec, total_transferred)); + } + +private: + CompletionCondition completion_condition_; +}; + +template <> +class base_from_completion_cond +{ +protected: + explicit base_from_completion_cond(transfer_all_t) + { + } + + static std::size_t check(const boost::system::error_code& ec, + std::size_t total_transferred) + { + return transfer_all_t()(ec, total_transferred); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/buffer_sequence_adapter.hpp b/3rdParty/Boost/src/boost/asio/detail/buffer_sequence_adapter.hpp new file mode 100644 index 0000000..ce9652e --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/buffer_sequence_adapter.hpp @@ -0,0 +1,254 @@ +// +// buffer_sequence_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_BUFFER_SEQUENCE_ADAPTER_HPP +#define BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class buffer_sequence_adapter_base +{ +protected: +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + typedef WSABUF native_buffer_type; + + static void init_native_buffer(WSABUF& buf, + const boost::asio::mutable_buffer& buffer) + { + buf.buf = boost::asio::buffer_cast(buffer); + buf.len = boost::asio::buffer_size(buffer); + } + + static void init_native_buffer(WSABUF& buf, + const boost::asio::const_buffer& buffer) + { + buf.buf = const_cast(boost::asio::buffer_cast(buffer)); + buf.len = boost::asio::buffer_size(buffer); + } +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + typedef iovec native_buffer_type; + + static void init_iov_base(void*& base, void* addr) + { + base = addr; + } + + template + static void init_iov_base(T& base, void* addr) + { + base = static_cast(addr); + } + + static void init_native_buffer(iovec& iov, + const boost::asio::mutable_buffer& buffer) + { + init_iov_base(iov.iov_base, boost::asio::buffer_cast(buffer)); + iov.iov_len = boost::asio::buffer_size(buffer); + } + + static void init_native_buffer(iovec& iov, + const boost::asio::const_buffer& buffer) + { + init_iov_base(iov.iov_base, const_cast( + boost::asio::buffer_cast(buffer))); + iov.iov_len = boost::asio::buffer_size(buffer); + } +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +}; + +// Helper class to translate buffers into the native buffer representation. +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter(const Buffers& buffers) + : count_(0), total_buffer_size_(0) + { + typename Buffers::const_iterator iter = buffers.begin(); + typename Buffers::const_iterator end = buffers.end(); + for (; iter != end && count_ < max_buffers; ++iter, ++count_) + { + Buffer buffer(*iter); + init_native_buffer(buffers_[count_], buffer); + total_buffer_size_ += boost::asio::buffer_size(buffer); + } + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return count_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const Buffers& buffers) + { + typename Buffers::const_iterator iter = buffers.begin(); + typename Buffers::const_iterator end = buffers.end(); + std::size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + if (boost::asio::buffer_size(Buffer(*iter)) > 0) + return false; + return true; + } + + static void validate(const Buffers& buffers) + { + typename Buffers::const_iterator iter = buffers.begin(); + typename Buffers::const_iterator end = buffers.end(); + for (; iter != end; ++iter) + { + Buffer buffer(*iter); + boost::asio::buffer_cast(buffer); + } + } + + static Buffer first(const Buffers& buffers) + { + typename Buffers::const_iterator iter = buffers.begin(); + typename Buffers::const_iterator end = buffers.end(); + for (; iter != end; ++iter) + { + Buffer buffer(*iter); + if (boost::asio::buffer_size(buffer) != 0) + return buffer; + } + return Buffer(); + } + +private: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + + native_buffer_type buffers_[max_buffers]; + std::size_t count_; + std::size_t total_buffer_size_; +}; + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::asio::mutable_buffers_1& buffers) + { + init_native_buffer(buffer_, buffers); + total_buffer_size_ = boost::asio::buffer_size(buffers); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::asio::mutable_buffers_1& buffers) + { + return boost::asio::buffer_size(buffers) == 0; + } + + static void validate(const boost::asio::mutable_buffers_1& buffers) + { + boost::asio::buffer_cast(buffers); + } + + static Buffer first(const boost::asio::mutable_buffers_1& buffers) + { + return Buffer(buffers); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::asio::const_buffers_1& buffers) + { + init_native_buffer(buffer_, buffers); + total_buffer_size_ = boost::asio::buffer_size(buffers); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::asio::const_buffers_1& buffers) + { + return boost::asio::buffer_size(buffers) == 0; + } + + static void validate(const boost::asio::const_buffers_1& buffers) + { + boost::asio::buffer_cast(buffers); + } + + static Buffer first(const boost::asio::const_buffers_1& buffers) + { + return Buffer(buffers); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/completion_handler.hpp b/3rdParty/Boost/src/boost/asio/detail/completion_handler.hpp new file mode 100644 index 0000000..d78e6c8 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/completion_handler.hpp @@ -0,0 +1,73 @@ +// +// completion_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_COMPLETION_HANDLER_HPP +#define BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class completion_handler : public operation +{ +public: + completion_handler(Handler h) + : operation(&completion_handler::do_complete), + handler_(h) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + completion_handler* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // Make the upcall if required. + if (owner) + { + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/consuming_buffers.hpp b/3rdParty/Boost/src/boost/asio/detail/consuming_buffers.hpp index bf04b1b..3604cba 100644 --- a/3rdParty/Boost/src/boost/asio/detail/consuming_buffers.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/consuming_buffers.hpp @@ -21,12 +21,11 @@ #include #include #include -#include +#include #include #include #include -#include namespace boost { namespace asio { @@ -35,9 +34,7 @@ namespace detail { // A proxy iterator for a sub-range in a list of buffers. template class consuming_buffers_iterator - : public boost::iterator_facade< - consuming_buffers_iterator, - const Buffer, boost::forward_traversal_tag> + : public boost::iterator { public: // Default constructor creates an end iterator. @@ -60,9 +57,48 @@ public: { } -private: - friend class boost::iterator_core_access; + // Dereference an iterator. + const Buffer& operator*() const + { + return dereference(); + } + + // Dereference an iterator. + const Buffer* operator->() const + { + return &dereference(); + } + + // Increment operator (prefix). + consuming_buffers_iterator& operator++() + { + increment(); + return *this; + } + // Increment operator (postfix). + consuming_buffers_iterator operator++(int) + { + consuming_buffers_iterator tmp(*this); + ++*this; + return tmp; + } + + // Test two iterators for equality. + friend bool operator==(const consuming_buffers_iterator& a, + const consuming_buffers_iterator& b) + { + return a.equal(b); + } + + // Test two iterators for inequality. + friend bool operator!=(const consuming_buffers_iterator& a, + const consuming_buffers_iterator& b) + { + return !a.equal(b); + } + +private: void increment() { if (!at_end_) @@ -170,7 +206,7 @@ public: } // Set the maximum size for a single transfer. - void set_max_size(std::size_t max_size) + void prepare(std::size_t max_size) { max_size_ = max_size; } @@ -226,7 +262,7 @@ public: // No-op. } - void set_max_size(std::size_t) + void prepare(std::size_t) { // No-op. } diff --git a/3rdParty/Boost/src/boost/asio/detail/deadline_timer_service.hpp b/3rdParty/Boost/src/boost/asio/detail/deadline_timer_service.hpp index 7885c9a..5ba21b1 100644 --- a/3rdParty/Boost/src/boost/asio/detail/deadline_timer_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/deadline_timer_service.hpp @@ -26,21 +26,20 @@ #include #include #include -#include +#include #include -#include #include #include +#include #include +#include namespace boost { namespace asio { namespace detail { -template +template class deadline_timer_service - : public boost::asio::detail::service_base< - deadline_timer_service > { public: // The time type. @@ -60,9 +59,7 @@ public: // Constructor. deadline_timer_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - deadline_timer_service >(io_service), - scheduler_(boost::asio::use_service(io_service)) + : scheduler_(boost::asio::use_service(io_service)) { scheduler_.init_task(); scheduler_.add_timer_queue(timer_queue_); @@ -156,34 +153,58 @@ public: } template - class wait_handler : - public handler_base_from_member + class wait_handler : public timer_op { public: - wait_handler(boost::asio::io_service& io_service, Handler handler) - : handler_base_from_member(handler), - io_service_(io_service), - work_(io_service) + wait_handler(Handler handler) + : timer_op(&wait_handler::do_complete), + handler_(handler) { } - void operator()(const boost::system::error_code& result) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - io_service_.post(detail::bind_handler(this->handler_, result)); + // Take ownership of the handler object. + wait_handler* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // Make the upcall if required. + if (owner) + { + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder1 + handler(h->handler_, h->ec_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } private: - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; + Handler handler_; }; // Start an asynchronous wait on the timer. template void async_wait(implementation_type& impl, Handler handler) { + // Allocate and construct an operation to wrap the handler. + typedef wait_handler value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + impl.might_have_pending_waits = true; - scheduler_.schedule_timer(timer_queue_, impl.expiry, - wait_handler(this->get_io_service(), handler), &impl); + + scheduler_.schedule_timer(timer_queue_, impl.expiry, ptr.get(), &impl); + ptr.release(); } private: @@ -191,7 +212,7 @@ private: timer_queue timer_queue_; // The object that schedules and executes timers. Usually a reactor. - Timer_Scheduler& scheduler_; + timer_scheduler& scheduler_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor.hpp b/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor.hpp index 7315384..e00f501 100644 --- a/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor.hpp @@ -33,27 +33,30 @@ #include #include -#include #include #include -#include -#include +#include +#include #include #include #include -#include #include -#include +#include +#include +#include +#include namespace boost { namespace asio { namespace detail { -template class dev_poll_reactor - : public boost::asio::detail::service_base > + : public boost::asio::detail::service_base { public: + enum { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + // Per-descriptor data. struct per_descriptor_data { @@ -61,28 +64,13 @@ public: // Constructor. dev_poll_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - dev_poll_reactor >(io_service), + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), mutex_(), dev_poll_fd_(do_dev_poll_create()), - wait_in_progress_(false), interrupter_(), - read_op_queue_(), - write_op_queue_(), - except_op_queue_(), - pending_cancellations_(), - stop_thread_(false), - thread_(0), shutdown_(false) { - // Start the reactor's internal thread only if needed. - if (Own_Thread) - { - boost::asio::detail::signal_blocker sb; - thread_ = new boost::asio::detail::thread( - bind_handler(&dev_poll_reactor::call_run_thread, this)); - } - // Add the interrupter's descriptor to /dev/poll. ::pollfd ev = { 0 }; ev.fd = interrupter_.read_descriptor(); @@ -103,35 +91,20 @@ public: { boost::asio::detail::mutex::scoped_lock lock(mutex_); shutdown_ = true; - stop_thread_ = true; lock.unlock(); - if (thread_) - { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; - } + op_queue ops; - read_op_queue_.destroy_operations(); - write_op_queue_.destroy_operations(); - except_op_queue_.destroy_operations(); + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->destroy_timers(); - timer_queues_.clear(); + timer_queues_.get_all_timers(ops); } - // Initialise the task, but only if the reactor is not in its own thread. + // Initialise the task. void init_task() { - if (!Own_Thread) - { - typedef task_io_service > - task_io_service_type; - use_service(this->get_io_service()).init_task(); - } + io_service_.init_task(); } // Register a socket with the reactor. Returns 0 on success, system error @@ -141,121 +114,46 @@ public: return 0; } - // Start a new read operation. The handler object will be invoked when the - // given descriptor is ready to be read, or an error has occurred. - template - void start_read_op(socket_type descriptor, per_descriptor_data&, - Handler handler, bool allow_speculative_read = true) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (allow_speculative_read) - { - if (!read_op_queue_.has_operation(descriptor)) - { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - } - } - - if (read_op_queue_.enqueue_operation(descriptor, handler)) - { - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLIN | POLLERR | POLLHUP; - if (write_op_queue_.has_operation(descriptor)) - ev.events |= POLLOUT; - if (except_op_queue_.has_operation(descriptor)) - ev.events |= POLLPRI; - interrupter_.interrupt(); - } - } - - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready to be written, or an error has occurred. - template - void start_write_op(socket_type descriptor, per_descriptor_data&, - Handler handler, bool allow_speculative_write = true) + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool allow_speculative) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) return; - if (allow_speculative_write) + if (allow_speculative) { - if (!write_op_queue_.has_operation(descriptor)) + if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) + if (!op_queue_[op_type].has_operation(descriptor)) { - handler.complete(ec, bytes_transferred); - return; + if (op->perform()) + { + lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } } } } - if (write_op_queue_.enqueue_operation(descriptor, handler)) + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) { ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLOUT | POLLERR | POLLHUP; - if (read_op_queue_.has_operation(descriptor)) + ev.events = POLLERR | POLLHUP; + if (op_type == read_op + || op_queue_[read_op].has_operation(descriptor)) ev.events |= POLLIN; - if (except_op_queue_.has_operation(descriptor)) - ev.events |= POLLPRI; - interrupter_.interrupt(); - } - } - - // Start a new exception operation. The handler object will be invoked when - // the given descriptor has exception information, or an error has occurred. - template - void start_except_op(socket_type descriptor, - per_descriptor_data&, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (except_op_queue_.enqueue_operation(descriptor, handler)) - { - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLPRI | POLLERR | POLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= POLLIN; - if (write_op_queue_.has_operation(descriptor)) + if (op_type == write_op + || op_queue_[write_op].has_operation(descriptor)) ev.events |= POLLOUT; - interrupter_.interrupt(); - } - } - - // Start a new write operation. The handler object will be invoked when the - // information available, or an error has occurred. - template - void start_connect_op(socket_type descriptor, - per_descriptor_data&, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLOUT | POLLERR | POLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= POLLIN; - if (except_op_queue_.has_operation(descriptor)) + if (op_type == except_op + || op_queue_[except_op].has_operation(descriptor)) ev.events |= POLLPRI; interrupter_.interrupt(); } @@ -267,7 +165,7 @@ public: void cancel_ops(socket_type descriptor, per_descriptor_data&) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); } // Cancel any operations that are running against the descriptor and remove @@ -282,7 +180,7 @@ public: interrupter_.interrupt(); // Cancel any outstanding operations associated with the descriptor. - cancel_ops_unlocked(descriptor); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); } // Add a new timer queue to the reactor. @@ -290,7 +188,7 @@ public: void add_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.push_back(&timer_queue); + timer_queues_.insert(&timer_queue); } // Remove a timer queue from the reactor. @@ -298,71 +196,48 @@ public: void remove_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - if (timer_queues_[i] == &timer_queue) - { - timer_queues_.erase(timer_queues_.begin() + i); - return; - } - } + timer_queues_.erase(&timer_queue); } - // Schedule a timer in the given timer queue to expire at the specified - // absolute time. The handler object will be invoked when the timer expires. - template + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, Handler handler, void* token) + const typename Time_Traits::time_type& time, timer_op* op, void* token) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (!shutdown_) - if (timer_queue.enqueue_timer(time, handler, token)) + { + bool earliest = timer_queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) interrupter_.interrupt(); + } } - // Cancel the timer associated with the given token. Returns the number of - // handlers that have been posted or dispatched. + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& timer_queue, void* token) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); + op_queue ops; + std::size_t n = timer_queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); return n; } -private: - friend class task_io_service >; - // Run /dev/poll once until interrupted or events are ready to be dispatched. - void run(bool block) + void run(bool block, op_queue& ops) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - // Dispatch any operation cancellations that were made while the select - // loop was not running. - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); - - // Check if the thread is supposed to stop. - if (stop_thread_) - { - complete_operations_and_timers(lock); - return; - } - // We can return immediately if there's no work to do and the reactor is // not supposed to block. - if (!block && read_op_queue_.empty() && write_op_queue_.empty() - && except_op_queue_.empty() && all_timer_queues_are_empty()) - { - complete_operations_and_timers(lock); + if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty() + && op_queue_[except_op].empty() && timer_queues_.all_empty()) return; - } // Write the pending event registration changes to the /dev/poll descriptor. std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); @@ -373,14 +248,13 @@ private: &pending_event_changes_[0], events_size); if (result != static_cast(events_size)) { + boost::system::error_code ec = boost::system::error_code( + errno, boost::asio::error::get_system_category()); for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) { int descriptor = pending_event_changes_[i].fd; - boost::system::error_code ec = boost::system::error_code( - errno, boost::asio::error::get_system_category()); - read_op_queue_.perform_all_operations(descriptor, ec); - write_op_queue_.perform_all_operations(descriptor, ec); - except_op_queue_.perform_all_operations(descriptor, ec); + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); } } pending_event_changes_.clear(); @@ -388,7 +262,6 @@ private: } int timeout = block ? get_timeout() : 0; - wait_in_progress_ = true; lock.unlock(); // Block on the /dev/poll descriptor. @@ -400,7 +273,6 @@ private: int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); lock.lock(); - wait_in_progress_ = false; // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) @@ -415,24 +287,24 @@ private: bool more_reads = false; bool more_writes = false; bool more_except = false; - boost::system::error_code ec; // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. if (events[i].events & (POLLPRI | POLLERR | POLLHUP)) - more_except = except_op_queue_.perform_operation(descriptor, ec); + more_except = + op_queue_[except_op].perform_operations(descriptor, ops); else - more_except = except_op_queue_.has_operation(descriptor); + more_except = op_queue_[except_op].has_operation(descriptor); if (events[i].events & (POLLIN | POLLERR | POLLHUP)) - more_reads = read_op_queue_.perform_operation(descriptor, ec); + more_reads = op_queue_[read_op].perform_operations(descriptor, ops); else - more_reads = read_op_queue_.has_operation(descriptor); + more_reads = op_queue_[read_op].has_operation(descriptor); if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) - more_writes = write_op_queue_.perform_operation(descriptor, ec); + more_writes = op_queue_[write_op].perform_operations(descriptor, ops); else - more_writes = write_op_queue_.has_operation(descriptor); + more_writes = op_queue_[write_op].has_operation(descriptor); if ((events[i].events & (POLLERR | POLLHUP)) != 0 && !more_except && !more_reads && !more_writes) @@ -463,48 +335,15 @@ private: int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); if (result != sizeof(ev)) { - ec = boost::system::error_code(errno, + boost::system::error_code ec(errno, boost::asio::error::get_system_category()); - read_op_queue_.perform_all_operations(descriptor, ec); - write_op_queue_.perform_all_operations(descriptor, ec); - except_op_queue_.perform_all_operations(descriptor, ec); + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); } } } } - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); - } - - // Issue any pending cancellations. - for (size_t i = 0; i < pending_cancellations_.size(); ++i) - cancel_ops_unlocked(pending_cancellations_[i]); - pending_cancellations_.clear(); - - complete_operations_and_timers(lock); - } - - // Run the select loop in the thread. - void run_thread() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) - { - lock.unlock(); - run(true); - lock.lock(); - } - } - - // Entry point for the select loop thread. - static void call_run_thread(dev_poll_reactor* reactor) - { - reactor->run_thread(); + timer_queues_.get_ready_timers(ops); } // Interrupt the select loop. @@ -513,6 +352,7 @@ private: interrupter_.interrupt(); } +private: // Create the /dev/poll file descriptor. Throws an exception if the descriptor // cannot be created. static int do_dev_poll_create() @@ -529,75 +369,32 @@ private: return fd; } - // Check if all timer queues are empty. - bool all_timer_queues_are_empty() const - { - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - if (!timer_queues_[i]->empty()) - return false; - return true; - } - // Get the timeout value for the /dev/poll DP_POLL operation. The timeout // value is returned as a number of milliseconds. A return value of -1 // indicates that the poll should block indefinitely. int get_timeout() { - if (all_timer_queues_are_empty()) - return -1; - // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. - boost::posix_time::time_duration minimum_wait_duration - = boost::posix_time::minutes(5); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - boost::posix_time::time_duration wait_duration - = timer_queues_[i]->wait_duration(); - if (wait_duration < minimum_wait_duration) - minimum_wait_duration = wait_duration; - } - - if (minimum_wait_duration > boost::posix_time::time_duration()) - { - int milliseconds = minimum_wait_duration.total_milliseconds(); - return milliseconds > 0 ? milliseconds : 1; - } - else - { - return 0; - } + return timer_queues_.wait_duration_msec(5 * 60 * 1000); } // Cancel all operations associated with the given descriptor. The do_cancel // function of the handler objects will be invoked. This function does not // acquire the dev_poll_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor) + void cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) { - bool interrupt = read_op_queue_.cancel_operations(descriptor); - interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; - interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; - if (interrupt) + bool need_interrupt = false; + op_queue ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + io_service_.post_deferred_completions(ops); + if (need_interrupt) interrupter_.interrupt(); } - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void complete_operations_and_timers( - boost::asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.complete_operations(); - write_op_queue_.complete_operations(); - except_op_queue_.complete_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->complete_timers(); - } - // Add a pending event entry for the given descriptor. ::pollfd& add_pending_event_change(int descriptor) { @@ -619,6 +416,9 @@ private: } } + // The io_service implementation used to post completions. + io_service_impl& io_service_; + // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; @@ -631,36 +431,14 @@ private: // Hash map to associate a descriptor with a pending event change index. hash_map pending_event_change_index_; - // Whether the DP_POLL operation is currently in progress - bool wait_in_progress_; - // The interrupter is used to break a blocking DP_POLL operation. select_interrupter interrupter_; - // The queue of read operations. - reactor_op_queue read_op_queue_; - - // The queue of write operations. - reactor_op_queue write_op_queue_; - - // The queue of except operations. - reactor_op_queue except_op_queue_; + // The queues of read, write and except operations. + reactor_op_queue op_queue_[max_ops]; // The timer queues. - std::vector timer_queues_; - - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - - // The descriptors that are pending cancellation. - std::vector pending_cancellations_; - - // Does the reactor loop thread need to stop. - bool stop_thread_; - - // The thread that is running the reactor loop. - boost::asio::detail::thread* thread_; + timer_queue_set timer_queues_; // Whether the service has been shut down. bool shutdown_; diff --git a/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor_fwd.hpp index d890fa8..238cee5 100644 --- a/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor_fwd.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor_fwd.hpp @@ -27,7 +27,6 @@ namespace boost { namespace asio { namespace detail { -template class dev_poll_reactor; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/epoll_reactor.hpp b/3rdParty/Boost/src/boost/asio/detail/epoll_reactor.hpp index 6c6bfe3..4684944 100644 --- a/3rdParty/Boost/src/boost/asio/detail/epoll_reactor.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/epoll_reactor.hpp @@ -23,115 +23,126 @@ #include #include -#include #include #include -#include #include #include #include #include #include -#include #include #include -#include -#include -#include +#include +#include #include #include -#include #include -#include +#include +#include +#include +#include + +#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define BOOST_ASIO_HAS_TIMERFD 1 +#endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) + +#if defined(BOOST_ASIO_HAS_TIMERFD) +# include +# include +# include +#endif // defined(BOOST_ASIO_HAS_TIMERFD) namespace boost { namespace asio { namespace detail { -template class epoll_reactor - : public boost::asio::detail::service_base > + : public boost::asio::detail::service_base { public: - // Per-descriptor data. - struct per_descriptor_data + enum { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor queues. + struct descriptor_state { - bool allow_speculative_read; - bool allow_speculative_write; + descriptor_state() {} + descriptor_state(const descriptor_state&) {} + void operator=(const descriptor_state&) {} + + mutex mutex_; + op_queue op_queue_[max_ops]; + bool shutdown_; }; + // Per-descriptor data. + typedef descriptor_state* per_descriptor_data; + // Constructor. epoll_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base >(io_service), + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), mutex_(), epoll_fd_(do_epoll_create()), - wait_in_progress_(false), +#if defined(BOOST_ASIO_HAS_TIMERFD) + timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), +#else // defined(BOOST_ASIO_HAS_TIMERFD) + timer_fd_(-1), +#endif // defined(BOOST_ASIO_HAS_TIMERFD) interrupter_(), - read_op_queue_(), - write_op_queue_(), - except_op_queue_(), - pending_cancellations_(), - stop_thread_(false), - thread_(0), - shutdown_(false), - need_epoll_wait_(true) + shutdown_(false) { - // Start the reactor's internal thread only if needed. - if (Own_Thread) - { - boost::asio::detail::signal_blocker sb; - thread_ = new boost::asio::detail::thread( - bind_handler(&epoll_reactor::call_run_thread, this)); - } - // Add the interrupter's descriptor to epoll. epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR; - ev.data.fd = interrupter_.read_descriptor(); + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); + interrupter_.interrupt(); + + // Add the timer descriptor to epoll. + if (timer_fd_ != -1) + { + ev.events = EPOLLIN | EPOLLERR; + ev.data.ptr = &timer_fd_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); + } } // Destructor. ~epoll_reactor() { - shutdown_service(); close(epoll_fd_); + if (timer_fd_ != -1) + close(timer_fd_); } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); shutdown_ = true; - stop_thread_ = true; lock.unlock(); - if (thread_) + op_queue ops; + + descriptor_map::iterator iter = registered_descriptors_.begin(); + descriptor_map::iterator end = registered_descriptors_.end(); + while (iter != end) { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; + for (int i = 0; i < max_ops; ++i) + ops.push(iter->second.op_queue_[i]); + iter->second.shutdown_ = true; + ++iter; } - read_op_queue_.destroy_operations(); - write_op_queue_.destroy_operations(); - except_op_queue_.destroy_operations(); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->destroy_timers(); - timer_queues_.clear(); + timer_queues_.get_all_timers(ops); } - // Initialise the task, but only if the reactor is not in its own thread. + // Initialise the task. void init_task() { - if (!Own_Thread) - { - typedef task_io_service > task_io_service_type; - use_service(this->get_io_service()).init_task(); - } + io_service_.init_task(); } // Register a socket with the reactor. Returns 0 on success, system error @@ -139,454 +150,274 @@ public: int register_descriptor(socket_type descriptor, per_descriptor_data& descriptor_data) { - // No need to lock according to epoll documentation. + mutex::scoped_lock lock(registered_descriptors_mutex_); - descriptor_data.allow_speculative_read = true; - descriptor_data.allow_speculative_write = true; + descriptor_map::iterator new_entry = registered_descriptors_.insert( + std::make_pair(descriptor, descriptor_state())).first; + descriptor_data = &new_entry->second; epoll_event ev = { 0, { 0 } }; - ev.events = 0; - ev.data.fd = descriptor; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET; + ev.data.ptr = descriptor_data; int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); if (result != 0) return errno; + + descriptor_data->shutdown_ = false; + return 0; } - // Start a new read operation. The handler object will be invoked when the - // given descriptor is ready to be read, or an error has occurred. - template - void start_read_op(socket_type descriptor, + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, - Handler handler, bool allow_speculative_read = true) + reactor_op* op, bool allow_speculative) { - if (allow_speculative_read && descriptor_data.allow_speculative_read) - { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - - // We only get one shot at a speculative read in this function. - allow_speculative_read = false; - } - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + if (descriptor_data->shutdown_) return; - if (!allow_speculative_read) - need_epoll_wait_ = true; - else if (!read_op_queue_.has_operation(descriptor)) + if (descriptor_data->op_queue_[op_type].empty()) { - // Speculative reads are ok as there are no queued read operations. - descriptor_data.allow_speculative_read = true; - - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) { - handler.complete(ec, bytes_transferred); - return; + if (op->perform()) + { + descriptor_lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } } - } - - // Speculative reads are not ok as there will be queued read operations. - descriptor_data.allow_speculative_read = false; - - if (read_op_queue_.enqueue_operation(descriptor, handler)) - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; - if (write_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLOUT; - if (except_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLPRI; - ev.data.fd = descriptor; - - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0 && errno == ENOENT) - result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) + else { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - read_op_queue_.perform_all_operations(descriptor, ec); + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP + | EPOLLOUT | EPOLLPRI | EPOLLET; + ev.data.ptr = descriptor_data; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); } } + + descriptor_data->op_queue_[op_type].push(op); + io_service_.work_started(); } - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready to be written, or an error has occurred. - template - void start_write_op(socket_type descriptor, - per_descriptor_data& descriptor_data, - Handler handler, bool allow_speculative_write = true) + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data) { - if (allow_speculative_write && descriptor_data.allow_speculative_write) - { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - - // We only get one shot at a speculative write in this function. - allow_speculative_write = false; - } - - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - if (shutdown_) - return; - - if (!allow_speculative_write) - need_epoll_wait_ = true; - else if (!write_op_queue_.has_operation(descriptor)) + op_queue ops; + for (int i = 0; i < max_ops; ++i) { - // Speculative writes are ok as there are no queued write operations. - descriptor_data.allow_speculative_write = true; - - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) + while (reactor_op* op = descriptor_data->op_queue_[i].front()) { - handler.complete(ec, bytes_transferred); - return; + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); } } - // Speculative writes are not ok as there will be queued write operations. - descriptor_data.allow_speculative_write = false; + descriptor_lock.unlock(); - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLIN; - if (except_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLPRI; - ev.data.fd = descriptor; - - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0 && errno == ENOENT) - result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, ec); - } - } + io_service_.post_deferred_completions(ops); } - // Start a new exception operation. The handler object will be invoked when - // the given descriptor has exception information, or an error has occurred. - template - void start_except_op(socket_type descriptor, - per_descriptor_data&, Handler handler) + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. + void close_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - if (shutdown_) - return; + // Remove the descriptor from the set of known descriptors. The descriptor + // will be automatically removed from the epoll set when it is closed. + descriptor_data->shutdown_ = true; - if (except_op_queue_.enqueue_operation(descriptor, handler)) + op_queue ops; + for (int i = 0; i < max_ops; ++i) { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLPRI | EPOLLERR | EPOLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLIN; - if (write_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLOUT; - ev.data.fd = descriptor; - - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0 && errno == ENOENT) - result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) + while (reactor_op* op = descriptor_data->op_queue_[i].front()) { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - except_op_queue_.perform_all_operations(descriptor, ec); + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); } } - } - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready for writing or an error has occurred. Speculative - // writes are not allowed. - template - void start_connect_op(socket_type descriptor, - per_descriptor_data& descriptor_data, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + descriptor_lock.unlock(); - if (shutdown_) - return; + registered_descriptors_.erase(descriptor); - // Speculative writes are not ok as there will be queued write operations. - descriptor_data.allow_speculative_write = false; - - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLIN; - if (except_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLPRI; - ev.data.fd = descriptor; - - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0 && errno == ENOENT) - result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, ec); - } - } - } + descriptors_lock.unlock(); - // Cancel all operations associated with the given descriptor. The - // handlers associated with the descriptor will be invoked with the - // operation_aborted error. - void cancel_ops(socket_type descriptor, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor); - } - - // Cancel any operations that are running against the descriptor and remove - // its registration from the reactor. - void close_descriptor(socket_type descriptor, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Remove the descriptor from epoll. - epoll_event ev = { 0, { 0 } }; - epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); - - // Cancel any outstanding operations associated with the descriptor. - cancel_ops_unlocked(descriptor); + io_service_.post_deferred_completions(ops); } // Add a new timer queue to the reactor. template void add_timer_queue(timer_queue& timer_queue) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.push_back(&timer_queue); + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&timer_queue); } // Remove a timer queue from the reactor. template void remove_timer_queue(timer_queue& timer_queue) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - if (timer_queues_[i] == &timer_queue) - { - timer_queues_.erase(timer_queues_.begin() + i); - return; - } - } + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&timer_queue); } - // Schedule a timer in the given timer queue to expire at the specified - // absolute time. The handler object will be invoked when the timer expires. - template + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, Handler handler, void* token) + const typename Time_Traits::time_type& time, timer_op* op, void* token) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); if (!shutdown_) - if (timer_queue.enqueue_timer(time, handler, token)) + { + bool earliest = timer_queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) + { +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + return; + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) interrupter_.interrupt(); + } + } } - // Cancel the timer associated with the given token. Returns the number of - // handlers that have been posted or dispatched. + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& timer_queue, void* token) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); + mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = timer_queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); return n; } -private: - friend class task_io_service >; - // Run epoll once until interrupted or events are ready to be dispatched. - void run(bool block) + void run(bool block, op_queue& ops) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Dispatch any operation cancellations that were made while the select - // loop was not running. - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); - - // Check if the thread is supposed to stop. - if (stop_thread_) - { - complete_operations_and_timers(lock); - return; - } - - // We can return immediately if there's no work to do and the reactor is - // not supposed to block. - if (!block && read_op_queue_.empty() && write_op_queue_.empty() - && except_op_queue_.empty() && all_timer_queues_are_empty()) + // Calculate a timeout only if timerfd is not used. + int timeout; + if (timer_fd_ != -1) + timeout = block ? -1 : 0; + else { - complete_operations_and_timers(lock); - return; + mutex::scoped_lock lock(mutex_); + timeout = block ? get_timeout() : 0; } - int timeout = block ? get_timeout() : 0; - wait_in_progress_ = true; - lock.unlock(); - // Block on the epoll descriptor. epoll_event events[128]; - int num_events = (block || need_epoll_wait_) - ? epoll_wait(epoll_fd_, events, 128, timeout) - : 0; + int num_events = epoll_wait(epoll_fd_, events, 128, timeout); - lock.lock(); - wait_in_progress_ = false; +#if defined(BOOST_ASIO_HAS_TIMERFD) + bool check_timers = (timer_fd_ == -1); +#else // defined(BOOST_ASIO_HAS_TIMERFD) + bool check_timers = true; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) { - int descriptor = events[i].data.fd; - if (descriptor == interrupter_.read_descriptor()) + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) { - interrupter_.reset(); + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on edge-triggered notifications + // to make it so that we only get woken up when the descriptor's epoll + // registration is updated. + +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ == -1) + check_timers = true; +#else // defined(BOOST_ASIO_HAS_TIMERFD) + check_timers = true; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) } +#if defined(BOOST_ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + check_timers = true; + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) else { - bool more_reads = false; - bool more_writes = false; - bool more_except = false; - boost::system::error_code ec; + descriptor_state* descriptor_data = static_cast(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. - if (events[i].events & (EPOLLPRI | EPOLLERR | EPOLLHUP)) - more_except = except_op_queue_.perform_operation(descriptor, ec); - else - more_except = except_op_queue_.has_operation(descriptor); - - if (events[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) - more_reads = read_op_queue_.perform_operation(descriptor, ec); - else - more_reads = read_op_queue_.has_operation(descriptor); - - if (events[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) - more_writes = write_op_queue_.perform_operation(descriptor, ec); - else - more_writes = write_op_queue_.has_operation(descriptor); - - if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0 - && (events[i].events & ~(EPOLLERR | EPOLLHUP)) == 0 - && !more_except && !more_reads && !more_writes) + static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; + for (int j = max_ops - 1; j >= 0; --j) { - // If we have an event and no operations associated with the - // descriptor then we need to delete the descriptor from epoll. The - // epoll_wait system call can produce EPOLLHUP or EPOLLERR events - // when there is no operation pending, so if we do not remove the - // descriptor we can end up in a tight loop of repeated - // calls to epoll_wait. - epoll_event ev = { 0, { 0 } }; - epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); - } - else - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLERR | EPOLLHUP; - if (more_reads) - ev.events |= EPOLLIN; - if (more_writes) - ev.events |= EPOLLOUT; - if (more_except) - ev.events |= EPOLLPRI; - ev.data.fd = descriptor; - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0 && errno == ENOENT) - result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) + if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP)) { - ec = boost::system::error_code(errno, - boost::asio::error::get_system_category()); - read_op_queue_.perform_all_operations(descriptor, ec); - write_op_queue_.perform_all_operations(descriptor, ec); - except_op_queue_.perform_all_operations(descriptor, ec); + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } } } } } - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); - } - - // Issue any pending cancellations. - for (size_t i = 0; i < pending_cancellations_.size(); ++i) - cancel_ops_unlocked(pending_cancellations_[i]); - pending_cancellations_.clear(); - - // Determine whether epoll_wait should be called when the reactor next runs. - need_epoll_wait_ = !read_op_queue_.empty() - || !write_op_queue_.empty() || !except_op_queue_.empty(); - - complete_operations_and_timers(lock); - } - // Run the select loop in the thread. - void run_thread() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) + if (check_timers) { - lock.unlock(); - run(true); - lock.lock(); - } - } + mutex::scoped_lock common_lock(mutex_); + timer_queues_.get_ready_timers(ops); - // Entry point for the select loop thread. - static void call_run_thread(epoll_reactor* reactor) - { - reactor->run_thread(); +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + } } // Interrupt the select loop. void interrupt() { - interrupter_.interrupt(); + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); } +private: // The hint to pass to epoll_create to size its data structures. enum { epoll_size = 20000 }; @@ -606,117 +437,65 @@ private: return fd; } - // Check if all timer queues are empty. - bool all_timer_queues_are_empty() const - { - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - if (!timer_queues_[i]->empty()) - return false; - return true; - } - // Get the timeout value for the epoll_wait call. The timeout value is // returned as a number of milliseconds. A return value of -1 indicates // that epoll_wait should block indefinitely. int get_timeout() { - if (all_timer_queues_are_empty()) - return -1; - // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. - boost::posix_time::time_duration minimum_wait_duration - = boost::posix_time::minutes(5); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - boost::posix_time::time_duration wait_duration - = timer_queues_[i]->wait_duration(); - if (wait_duration < minimum_wait_duration) - minimum_wait_duration = wait_duration; - } - - if (minimum_wait_duration > boost::posix_time::time_duration()) - { - int milliseconds = minimum_wait_duration.total_milliseconds(); - return milliseconds > 0 ? milliseconds : 1; - } - else - { - return 0; - } + return timer_queues_.wait_duration_msec(5 * 60 * 1000); } - // Cancel all operations associated with the given descriptor. The do_cancel - // function of the handler objects will be invoked. This function does not - // acquire the epoll_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor) +#if defined(BOOST_ASIO_HAS_TIMERFD) + // Get the timeout value for the timer descriptor. The return value is the + // flag argument to be used when calling timerfd_settime. + int get_timeout(itimerspec& ts) { - bool interrupt = read_op_queue_.cancel_operations(descriptor); - interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; - interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; - if (interrupt) - interrupter_.interrupt(); - } + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void complete_operations_and_timers( - boost::asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.complete_operations(); - write_op_queue_.complete_operations(); - except_op_queue_.complete_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->complete_timers(); + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.it_value.tv_sec = usec / 1000000; + ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; + + return usec ? 0 : TFD_TIMER_ABSTIME; } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + + // The io_service implementation used to post completions. + io_service_impl& io_service_; // Mutex to protect access to internal data. - boost::asio::detail::mutex mutex_; + mutex mutex_; // The epoll file descriptor. int epoll_fd_; - // Whether the epoll_wait call is currently in progress - bool wait_in_progress_; + // The timer file descriptor. + int timer_fd_; // The interrupter is used to break a blocking epoll_wait call. select_interrupter interrupter_; - // The queue of read operations. - reactor_op_queue read_op_queue_; - - // The queue of write operations. - reactor_op_queue write_op_queue_; - - // The queue of except operations. - reactor_op_queue except_op_queue_; - // The timer queues. - std::vector timer_queues_; - - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - - // The descriptors that are pending cancellation. - std::vector pending_cancellations_; - - // Does the reactor loop thread need to stop. - bool stop_thread_; - - // The thread that is running the reactor loop. - boost::asio::detail::thread* thread_; + timer_queue_set timer_queues_; // Whether the service has been shut down. bool shutdown_; - // Whether we need to call epoll_wait the next time the reactor is run. - bool need_epoll_wait_; + // Mutex to protect access to the registered descriptors. + mutex registered_descriptors_mutex_; + + // Keep track of all registered descriptors. This code relies on the fact that + // the hash_map implementation pools deleted nodes, meaning that we can assume + // our descriptor_state pointer remains valid even after the entry is removed. + // Technically this is not true for C++98, as that standard says that spliced + // elements in a list are invalidated. However, C++0x fixes this shortcoming + // so we'll just assume that C++98 std::list implementations will do the right + // thing anyway. + typedef detail::hash_map descriptor_map; + descriptor_map registered_descriptors_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/epoll_reactor_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/epoll_reactor_fwd.hpp index 9659dd4..214cee5 100644 --- a/3rdParty/Boost/src/boost/asio/detail/epoll_reactor_fwd.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/epoll_reactor_fwd.hpp @@ -33,7 +33,6 @@ namespace boost { namespace asio { namespace detail { -template class epoll_reactor; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/event.hpp b/3rdParty/Boost/src/boost/asio/detail/event.hpp index 89f9896..e8d185f 100644 --- a/3rdParty/Boost/src/boost/asio/detail/event.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/event.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(BOOST_WINDOWS) # include @@ -35,7 +35,7 @@ namespace boost { namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) typedef null_event event; #elif defined(BOOST_WINDOWS) typedef win_event event; diff --git a/3rdParty/Boost/src/boost/asio/detail/fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/fenced_block.hpp new file mode 100644 index 0000000..c80161f --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/fenced_block.hpp @@ -0,0 +1,72 @@ +// +// fenced_block.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) +# include +#elif defined(__MACH__) && defined(__APPLE__) +# include +#elif defined(__sun) +# include +#elif defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) +# include +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# include +#elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) +# include +#else +# include +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) +typedef null_fenced_block fenced_block; +#elif defined(__MACH__) && defined(__APPLE__) +typedef macos_fenced_block fenced_block; +#elif defined(__sun) +typedef solaris_fenced_block fenced_block; +#elif defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) +typedef gcc_fenced_block fenced_block; +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +typedef gcc_x86_fenced_block fenced_block; +#elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) +typedef win_fenced_block fenced_block; +#else +typedef null_fenced_block fenced_block; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/gcc_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/gcc_fenced_block.hpp new file mode 100644 index 0000000..0c086a6 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/gcc_fenced_block.hpp @@ -0,0 +1,65 @@ +// +// gcc_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_GCC_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_GCC_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + +namespace boost { +namespace asio { +namespace detail { + +class gcc_fenced_block + : private noncopyable +{ +public: + // Constructor. + gcc_fenced_block() + : value_(0) + { + __sync_lock_test_and_set(&value_, 1); + } + + // Destructor. + ~gcc_fenced_block() + { + __sync_lock_release(&value_); + } + +private: + int value_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(__GNUC__) + // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + // && !defined(__INTEL_COMPILER) && !defined(__ICL) + // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + +#include + +#endif // BOOST_ASIO_DETAIL_GCC_FENCED_BLOCK_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/gcc_x86_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/gcc_x86_fenced_block.hpp new file mode 100644 index 0000000..fc23d66 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/gcc_x86_fenced_block.hpp @@ -0,0 +1,63 @@ +// +// gcc_x86_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_GCC_X86_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +namespace boost { +namespace asio { +namespace detail { + +class gcc_x86_fenced_block + : private noncopyable +{ +public: + // Constructor. + gcc_x86_fenced_block() + { + barrier(); + } + + // Destructor. + ~gcc_x86_fenced_block() + { + barrier(); + } + +private: + static int barrier() + { + int r = 0; + __asm__ __volatile__ ("xchgl %%eax, %0" : "=m" (r) : : "memory", "cc"); + return r; + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#include + +#endif // BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/handler_base_from_member.hpp b/3rdParty/Boost/src/boost/asio/detail/handler_base_from_member.hpp deleted file mode 100644 index 4e471e3..0000000 --- a/3rdParty/Boost/src/boost/asio/detail/handler_base_from_member.hpp +++ /dev/null @@ -1,78 +0,0 @@ -// -// handler_base_from_member.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_HANDLER_BASE_FROM_MEMBER_HPP -#define BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include - -namespace boost { -namespace asio { -namespace detail { - -// Base class for classes that need a handler data member. Forwards the custom -// allocation and invocation hooks to the contained handler. -template -class handler_base_from_member -{ -public: - handler_base_from_member(Handler handler) - : handler_(handler) - { - } - -//protected: - Handler handler_; - -protected: - // Protected destructor to prevent deletion through this type. - ~handler_base_from_member() - { - } -}; - -template -inline void* asio_handler_allocate(std::size_t size, - handler_base_from_member* this_handler) -{ - return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); -} - -template -inline void asio_handler_deallocate(void* pointer, std::size_t size, - handler_base_from_member* this_handler) -{ - boost_asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); -} - -template -inline void asio_handler_invoke(const Function& function, - handler_base_from_member* this_handler) -{ - boost_asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); -} - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/handler_queue.hpp b/3rdParty/Boost/src/boost/asio/detail/handler_queue.hpp deleted file mode 100644 index c1fb988..0000000 --- a/3rdParty/Boost/src/boost/asio/detail/handler_queue.hpp +++ /dev/null @@ -1,231 +0,0 @@ -// -// handler_queue.hpp -// ~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_HANDLER_QUEUE_HPP -#define BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include - -namespace boost { -namespace asio { -namespace detail { - -class handler_queue - : private noncopyable -{ -public: - // Base class for handlers in the queue. - class handler - : private noncopyable - { - public: - void invoke() - { - invoke_func_(this); - } - - void destroy() - { - destroy_func_(this); - } - - protected: - typedef void (*invoke_func_type)(handler*); - typedef void (*destroy_func_type)(handler*); - - handler(invoke_func_type invoke_func, - destroy_func_type destroy_func) - : next_(0), - invoke_func_(invoke_func), - destroy_func_(destroy_func) - { - } - - ~handler() - { - } - - private: - friend class handler_queue; - handler* next_; - invoke_func_type invoke_func_; - destroy_func_type destroy_func_; - }; - - // Smart point to manager handler lifetimes. - class scoped_ptr - : private noncopyable - { - public: - explicit scoped_ptr(handler* h) - : handler_(h) - { - } - - ~scoped_ptr() - { - if (handler_) - handler_->destroy(); - } - - handler* get() const - { - return handler_; - } - - handler* release() - { - handler* tmp = handler_; - handler_ = 0; - return tmp; - } - - private: - handler* handler_; - }; - - // Constructor. - handler_queue() - : front_(0), - back_(0) - { - } - - // Wrap a handler to be pushed into the queue. - template - static handler* wrap(Handler h) - { - // Allocate and construct an object to wrap the handler. - typedef handler_wrapper value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(h); - handler_ptr ptr(raw_ptr, h); - return ptr.release(); - } - - // Get the handler at the front of the queue. - handler* front() - { - return front_; - } - - // Pop a handler from the front of the queue. - void pop() - { - if (front_) - { - handler* tmp = front_; - front_ = front_->next_; - if (front_ == 0) - back_ = 0; - tmp->next_= 0; - } - } - - // Push a handler on to the back of the queue. - void push(handler* h) - { - h->next_ = 0; - if (back_) - { - back_->next_ = h; - back_ = h; - } - else - { - front_ = back_ = h; - } - } - - // Whether the queue is empty. - bool empty() const - { - return front_ == 0; - } - -private: - // Template wrapper for handlers. - template - class handler_wrapper - : public handler - { - public: - handler_wrapper(Handler h) - : handler( - &handler_wrapper::do_call, - &handler_wrapper::do_destroy), - handler_(h) - { - } - - static void do_call(handler* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(h->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - - static void do_destroy(handler* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr 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_; - }; - - // The front of the queue. - handler* front_; - - // The back of the queue. - handler* back_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/hash_map.hpp b/3rdParty/Boost/src/boost/asio/detail/hash_map.hpp index c620da7..36c9a99 100644 --- a/3rdParty/Boost/src/boost/asio/detail/hash_map.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/hash_map.hpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -62,9 +61,16 @@ public: // Constructor. hash_map() - : size_(0) + : size_(0), + buckets_(0), + num_buckets_(0) { - rehash(hash_size(0)); + } + + // Destructor. + ~hash_map() + { + delete[] buckets_; } // Get an iterator for the beginning of the map. @@ -100,17 +106,20 @@ public: // Find an entry in the map. iterator find(const K& k) { - size_t bucket = calculate_hash_value(k) % buckets_.size(); - iterator it = buckets_[bucket].first; - if (it == values_.end()) - return values_.end(); - iterator end = buckets_[bucket].last; - ++end; - while (it != end) + if (num_buckets_) { - if (it->first == k) - return it; - ++it; + size_t bucket = calculate_hash_value(k) % num_buckets_; + iterator it = buckets_[bucket].first; + if (it == values_.end()) + return values_.end(); + iterator end = buckets_[bucket].last; + ++end; + while (it != end) + { + if (it->first == k) + return it; + ++it; + } } return values_.end(); } @@ -118,17 +127,20 @@ public: // Find an entry in the map. const_iterator find(const K& k) const { - size_t bucket = calculate_hash_value(k) % buckets_.size(); - const_iterator it = buckets_[bucket].first; - if (it == values_.end()) - return it; - const_iterator end = buckets_[bucket].last; - ++end; - while (it != end) + if (num_buckets_) { - if (it->first == k) + size_t bucket = calculate_hash_value(k) % num_buckets_; + const_iterator it = buckets_[bucket].first; + if (it == values_.end()) return it; - ++it; + const_iterator end = buckets_[bucket].last; + ++end; + while (it != end) + { + if (it->first == k) + return it; + ++it; + } } return values_.end(); } @@ -136,9 +148,9 @@ public: // Insert a new entry into the map. std::pair insert(const value_type& v) { - if (size_ + 1 >= buckets_.size()) + if (size_ + 1 >= num_buckets_) rehash(hash_size(size_ + 1)); - size_t bucket = calculate_hash_value(v.first) % buckets_.size(); + size_t bucket = calculate_hash_value(v.first) % num_buckets_; iterator it = buckets_[bucket].first; if (it == values_.end()) { @@ -165,7 +177,7 @@ public: { assert(it != values_.end()); - size_t bucket = calculate_hash_value(it->first) % buckets_.size(); + size_t bucket = calculate_hash_value(it->first) % num_buckets_; bool is_first = (it == buckets_[bucket].first); bool is_last = (it == buckets_[bucket].last); if (is_first && is_last) @@ -179,6 +191,14 @@ public: --size_; } + // Erase a key from the map. + void erase(const K& k) + { + iterator it = find(k); + if (it != values_.end()) + erase(it); + } + // Remove all entries from the map. void clear() { @@ -187,8 +207,9 @@ public: size_ = 0; // Initialise all buckets to empty. - for (size_t i = 0; i < buckets_.size(); ++i) - buckets_[i].first = buckets_[i].last = values_.end(); + iterator end = values_.end(); + for (size_t i = 0; i < num_buckets_; ++i) + buckets_[i].first = buckets_[i].last = end; } private: @@ -215,21 +236,24 @@ private: // Re-initialise the hash from the values already contained in the list. void rehash(std::size_t num_buckets) { - if (num_buckets == buckets_.size()) + if (num_buckets == num_buckets_) return; + num_buckets_ = num_buckets; iterator end = values_.end(); // Update number of buckets and initialise all buckets to empty. - buckets_.resize(num_buckets); - for (std::size_t i = 0; i < buckets_.size(); ++i) + bucket_type* tmp = new bucket_type[num_buckets_]; + delete[] buckets_; + buckets_ = tmp; + for (std::size_t i = 0; i < num_buckets_; ++i) buckets_[i].first = buckets_[i].last = end; // Put all values back into the hash. iterator iter = values_.begin(); while (iter != end) { - std::size_t bucket = calculate_hash_value(iter->first) % buckets_.size(); + std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_; if (buckets_[bucket].last == end) { buckets_[bucket].first = buckets_[bucket].last = iter++; @@ -282,14 +306,15 @@ private: // The type for a bucket in the hash table. struct bucket_type { - bucket_type() {} - bucket_type(const bucket_type&) { /* noop */ } iterator first; iterator last; }; // The buckets in the hash. - std::vector buckets_; + bucket_type* buckets_; + + // The number of buckets in the hash. + std::size_t num_buckets_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/indirect_handler_queue.hpp b/3rdParty/Boost/src/boost/asio/detail/indirect_handler_queue.hpp deleted file mode 100644 index 72b1030..0000000 --- a/3rdParty/Boost/src/boost/asio/detail/indirect_handler_queue.hpp +++ /dev/null @@ -1,293 +0,0 @@ -// -// indirect_handler_queue.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_INDIRECT_HANDLER_QUEUE_HPP -#define BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include - -#if defined(_MSC_VER) && (_MSC_VER >= 1310) -extern "C" void _ReadWriteBarrier(); -# pragma intrinsic(_ReadWriteBarrier) -#endif // defined(_MSC_VER) && (_MSC_VER >= 1310) - -namespace boost { -namespace asio { -namespace detail { - -class indirect_handler_queue - : private noncopyable -{ -public: - class handler; - - // Element for a node in the queue. - class node - { - public: - node() - : version_(0), - handler_(0), - next_(0) - { - } - - private: - friend class indirect_handler_queue; - unsigned long version_; - handler* handler_; - node* next_; - }; - - // Base class for handlers in the queue. - class handler - : private noncopyable - { - public: - void invoke() - { - invoke_func_(this); - } - - void destroy() - { - destroy_func_(this); - } - - protected: - typedef void (*invoke_func_type)(handler*); - typedef void (*destroy_func_type)(handler*); - - handler(invoke_func_type invoke_func, - destroy_func_type destroy_func) - : node_(new node), - invoke_func_(invoke_func), - destroy_func_(destroy_func) - { - } - - ~handler() - { - if (node_) - delete node_; - } - - private: - friend class indirect_handler_queue; - node* node_; - invoke_func_type invoke_func_; - destroy_func_type destroy_func_; - }; - - // Smart point to manager handler lifetimes. - class scoped_ptr - : private noncopyable - { - public: - explicit scoped_ptr(handler* h) - : handler_(h) - { - } - - ~scoped_ptr() - { - if (handler_) - handler_->destroy(); - } - - handler* get() const - { - return handler_; - } - - handler* release() - { - handler* tmp = handler_; - handler_ = 0; - return tmp; - } - - private: - handler* handler_; - }; - - // Constructor. - indirect_handler_queue() - : front_(new node), - back_(front_), - next_version_(1) - { - } - - // Destructor. - ~indirect_handler_queue() - { - while (front_) - { - node* tmp = front_; - front_ = front_->next_; - delete tmp; - } - } - - // Wrap a handler to be pushed into the queue. - template - static handler* wrap(Handler h) - { - // Allocate and construct an object to wrap the handler. - typedef handler_wrapper value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(h); - handler_ptr ptr(raw_ptr, h); - return ptr.release(); - } - - // Determine whether the queue has something ready to pop. - bool poppable() - { - return front_->next_ != 0; - } - - // The version number at the front of the queue. - unsigned long front_version() - { - return front_->version_; - } - - // The version number at the back of the queue. - unsigned long back_version() - { - return back_->version_; - } - - // Pop a handler from the front of the queue. - handler* pop() - { - node* n = front_; - node* new_front = n->next_; - if (new_front) - { - handler* h = new_front->handler_; - h->node_ = n; - new_front->handler_ = 0; - front_ = new_front; - return h; - } - return 0; - } - - // Push a handler on to the back of the queue. - void push(handler* h) - { - node* n = h->node_; - h->node_ = 0; - n->version_ = next_version_; - next_version_ += 2; - n->handler_ = h; - n->next_ = 0; - memory_barrier(); - back_->next_ = n; - back_ = n; - } - -private: - // Template wrapper for handlers. - template - class handler_wrapper - : public handler - { - public: - handler_wrapper(Handler h) - : handler( - &handler_wrapper::do_call, - &handler_wrapper::do_destroy), - handler_(h) - { - } - - static void do_call(handler* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(h->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - - static void do_destroy(handler* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr 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_; - }; - - // Helper function to create a memory barrier. - static void memory_barrier() - { -#if defined(_GLIBCXX_WRITE_MEM_BARRIER) - _GLIBCXX_WRITE_MEM_BARRIER; -#elif defined(_MSC_VER) && (_MSC_VER >= 1310) - _ReadWriteBarrier(); -#else -# error memory barrier required -#endif - } - - // The front of the queue. - node* front_; - - // The back of the queue. - node* back_; - - // The next version counter to be assigned to a node. - unsigned long next_version_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor.hpp b/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor.hpp index ea8e285..c1a6705 100644 --- a/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor.hpp @@ -24,28 +24,27 @@ #include #include -#include #include #include #include #include -#include #include #include #include #include #include -#include +#include #include -#include -#include -#include +#include +#include #include #include -#include #include -#include +#include +#include +#include +#include // Older versions of Mac OS X may not define EV_OOBAND. #if !defined(EV_OOBAND) @@ -56,520 +55,368 @@ namespace boost { namespace asio { namespace detail { -template class kqueue_reactor - : public boost::asio::detail::service_base > + : public boost::asio::detail::service_base { public: - // Per-descriptor data. - struct per_descriptor_data + enum op_types { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor queues. + struct descriptor_state { - bool allow_speculative_read; - bool allow_speculative_write; + descriptor_state() {} + descriptor_state(const descriptor_state&) {} + void operator=(const descriptor_state&) {} + + mutex mutex_; + op_queue op_queue_[max_ops]; + bool shutdown_; }; + // Per-descriptor data. + typedef descriptor_state* per_descriptor_data; + // Constructor. kqueue_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - kqueue_reactor >(io_service), + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), mutex_(), kqueue_fd_(do_kqueue_create()), - wait_in_progress_(false), interrupter_(), - read_op_queue_(), - write_op_queue_(), - except_op_queue_(), - pending_cancellations_(), - stop_thread_(false), - thread_(0), - shutdown_(false), - need_kqueue_wait_(true) + shutdown_(false) { - // Start the reactor's internal thread only if needed. - if (Own_Thread) - { - boost::asio::detail::signal_blocker sb; - thread_ = new boost::asio::detail::thread( - bind_handler(&kqueue_reactor::call_run_thread, this)); - } - - // Add the interrupter's descriptor to the kqueue. - struct kevent event; - EV_SET(&event, interrupter_.read_descriptor(), - EVFILT_READ, EV_ADD, 0, 0, 0); - ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); + // The interrupter is put into a permanently readable state. Whenever we + // want to interrupt the blocked kevent call we register a one-shot read + // operation against the descriptor. + interrupter_.interrupt(); } // Destructor. ~kqueue_reactor() { - shutdown_service(); close(kqueue_fd_); } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); shutdown_ = true; - stop_thread_ = true; lock.unlock(); - if (thread_) + op_queue ops; + + descriptor_map::iterator iter = registered_descriptors_.begin(); + descriptor_map::iterator end = registered_descriptors_.end(); + while (iter != end) { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; + for (int i = 0; i < max_ops; ++i) + ops.push(iter->second.op_queue_[i]); + iter->second.shutdown_ = true; + ++iter; } - read_op_queue_.destroy_operations(); - write_op_queue_.destroy_operations(); - except_op_queue_.destroy_operations(); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->destroy_timers(); - timer_queues_.clear(); + timer_queues_.get_all_timers(ops); } - // Initialise the task, but only if the reactor is not in its own thread. + // Initialise the task. void init_task() { - if (!Own_Thread) - { - typedef task_io_service > task_io_service_type; - use_service(this->get_io_service()).init_task(); - } + io_service_.init_task(); } // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type, per_descriptor_data& descriptor_data) + int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data) { - descriptor_data.allow_speculative_read = true; - descriptor_data.allow_speculative_write = true; + mutex::scoped_lock lock(registered_descriptors_mutex_); + + descriptor_map::iterator new_entry = registered_descriptors_.insert( + std::make_pair(descriptor, descriptor_state())).first; + descriptor_data = &new_entry->second; + + descriptor_data->shutdown_ = false; return 0; } - // Start a new read operation. The handler object will be invoked when the - // given descriptor is ready to be read, or an error has occurred. - template - void start_read_op(socket_type descriptor, - per_descriptor_data& descriptor_data, Handler handler, - bool allow_speculative_read = true) + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, + reactor_op* op, bool allow_speculative) { - if (allow_speculative_read && descriptor_data.allow_speculative_read) - { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - - // We only get one shot at a speculative read in this function. - allow_speculative_read = false; - } - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + if (descriptor_data->shutdown_) return; - if (!allow_speculative_read) - need_kqueue_wait_ = true; - else if (!read_op_queue_.has_operation(descriptor)) + bool first = descriptor_data->op_queue_[op_type].empty(); + if (first) { - // Speculative reads are ok as there are no queued read operations. - descriptor_data.allow_speculative_read = true; - - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) + if (allow_speculative) { - handler.complete(ec, bytes_transferred); - return; + if (op_type != read_op || descriptor_data->op_queue_[except_op].empty()) + { + if (op->perform()) + { + descriptor_lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } } } - // Speculative reads are not ok as there will be queued read operations. - descriptor_data.allow_speculative_read = false; + descriptor_data->op_queue_[op_type].push(op); + io_service_.work_started(); - if (read_op_queue_.enqueue_operation(descriptor, handler)) + if (first) { struct kevent event; - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); + switch (op_type) + { + case read_op: + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + break; + case write_op: + EV_SET(&event, descriptor, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + break; + case except_op: + if (!descriptor_data->op_queue_[read_op].empty()) + return; // Already registered for read events. + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); + break; + } + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - boost::system::error_code ec(errno, + op->ec_ = boost::system::error_code(errno, boost::asio::error::get_system_category()); - read_op_queue_.perform_all_operations(descriptor, ec); + descriptor_data->op_queue_[op_type].pop(); + io_service_.post_deferred_completion(op); } } } - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready to be written, or an error has occurred. - template - void start_write_op(socket_type descriptor, - per_descriptor_data& descriptor_data, Handler handler, - bool allow_speculative_write = true) + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data) { - if (allow_speculative_write && descriptor_data.allow_speculative_write) - { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - - // We only get one shot at a speculative write in this function. - allow_speculative_write = false; - } + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (!allow_speculative_write) - need_kqueue_wait_ = true; - else if (!write_op_queue_.has_operation(descriptor)) + op_queue ops; + for (int i = 0; i < max_ops; ++i) { - // Speculative writes are ok as there are no queued write operations. - descriptor_data.allow_speculative_write = true; - - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) + while (reactor_op* op = descriptor_data->op_queue_[i].front()) { - handler.complete(ec, bytes_transferred); - return; + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); } } - // Speculative writes are not ok as there will be queued write operations. - descriptor_data.allow_speculative_write = false; + descriptor_lock.unlock(); - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - struct kevent event; - EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, ec); - } - } + io_service_.post_deferred_completions(ops); } - // Start a new exception operation. The handler object will be invoked when - // the given descriptor has exception information, or an error has occurred. - template - void start_except_op(socket_type descriptor, - per_descriptor_data&, Handler handler) + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. + void close_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - if (shutdown_) - return; + // Remove the descriptor from the set of known descriptors. The descriptor + // will be automatically removed from the kqueue set when it is closed. + descriptor_data->shutdown_ = true; - if (except_op_queue_.enqueue_operation(descriptor, handler)) + op_queue ops; + for (int i = 0; i < max_ops; ++i) { - struct kevent event; - if (read_op_queue_.has_operation(descriptor)) - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); - else - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0); - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + while (reactor_op* op = descriptor_data->op_queue_[i].front()) { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - except_op_queue_.perform_all_operations(descriptor, ec); + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); } } - } - - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready to be written, or an error has occurred. - template - void start_connect_op(socket_type descriptor, - per_descriptor_data& descriptor_data, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - // Speculative writes are not ok as there will be queued write operations. - descriptor_data.allow_speculative_write = false; + descriptor_lock.unlock(); - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - struct kevent event; - EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, ec); - } - } - } + registered_descriptors_.erase(descriptor); - // Cancel all operations associated with the given descriptor. The - // handlers associated with the descriptor will be invoked with the - // operation_aborted error. - void cancel_ops(socket_type descriptor, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor); - } + descriptors_lock.unlock(); - // Cancel any operations that are running against the descriptor and remove - // its registration from the reactor. - void close_descriptor(socket_type descriptor, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Remove the descriptor from kqueue. - struct kevent event[2]; - EV_SET(&event[0], descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0); - EV_SET(&event[1], descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0); - ::kevent(kqueue_fd_, event, 2, 0, 0, 0); - - // Cancel any outstanding operations associated with the descriptor. - cancel_ops_unlocked(descriptor); + io_service_.post_deferred_completions(ops); } // Add a new timer queue to the reactor. template void add_timer_queue(timer_queue& timer_queue) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.push_back(&timer_queue); + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&timer_queue); } // Remove a timer queue from the reactor. template void remove_timer_queue(timer_queue& timer_queue) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - if (timer_queues_[i] == &timer_queue) - { - timer_queues_.erase(timer_queues_.begin() + i); - return; - } - } + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&timer_queue); } - // Schedule a timer in the given timer queue to expire at the specified - // absolute time. The handler object will be invoked when the timer expires. - template + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, Handler handler, void* token) + const typename Time_Traits::time_type& time, timer_op* op, void* token) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); if (!shutdown_) - if (timer_queue.enqueue_timer(time, handler, token)) - interrupter_.interrupt(); + { + bool earliest = timer_queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) + interrupt(); + } } - // Cancel the timer associated with the given token. Returns the number of - // handlers that have been posted or dispatched. + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& timer_queue, void* token) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); + mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = timer_queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); return n; } -private: - friend class task_io_service >; - // Run the kqueue loop. - void run(bool block) + void run(bool block, op_queue& ops) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Dispatch any operation cancellations that were made while the select - // loop was not running. - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); - - // Check if the thread is supposed to stop. - if (stop_thread_) - { - complete_operations_and_timers(lock); - return; - } - - // We can return immediately if there's no work to do and the reactor is - // not supposed to block. - if (!block && read_op_queue_.empty() && write_op_queue_.empty() - && except_op_queue_.empty() && all_timer_queues_are_empty()) - { - complete_operations_and_timers(lock); - return; - } + mutex::scoped_lock lock(mutex_); // Determine how long to block while waiting for events. timespec timeout_buf = { 0, 0 }; timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf; - wait_in_progress_ = true; lock.unlock(); // Block on the kqueue descriptor. struct kevent events[128]; - int num_events = (block || need_kqueue_wait_) - ? kevent(kqueue_fd_, 0, 0, events, 128, timeout) - : 0; - - lock.lock(); - wait_in_progress_ = false; + int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) { int descriptor = events[i].ident; - if (descriptor == interrupter_.read_descriptor()) + void* ptr = events[i].udata; + if (ptr == &interrupter_) { - interrupter_.reset(); + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on one-shot notifications. } - else if (events[i].filter == EVFILT_READ) + else { - // Dispatch operations associated with the descriptor. - bool more_reads = false; - bool more_except = false; - if (events[i].flags & EV_ERROR) + descriptor_state* descriptor_data = static_cast(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + static const int filter[max_ops] = + { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; + for (int j = max_ops - 1; j >= 0; --j) { - boost::system::error_code error( - events[i].data, boost::asio::error::get_system_category()); - except_op_queue_.perform_all_operations(descriptor, error); - read_op_queue_.perform_all_operations(descriptor, error); - } - else if (events[i].flags & EV_OOBAND) - { - boost::system::error_code error; - more_except = except_op_queue_.perform_operation(descriptor, error); - if (events[i].data > 0) - more_reads = read_op_queue_.perform_operation(descriptor, error); - else - more_reads = read_op_queue_.has_operation(descriptor); - } - else - { - boost::system::error_code error; - more_reads = read_op_queue_.perform_operation(descriptor, error); - more_except = except_op_queue_.has_operation(descriptor); + if (events[i].filter == filter[j]) + { + if (j != except_op || events[i].flags & EV_OOBAND) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (events[i].flags & EV_ERROR) + { + op->ec_ = boost::system::error_code(events[i].data, + boost::asio::error::get_system_category()); + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } + } + } } - // Update the descriptor in the kqueue. + // Renew registration for event notifications. struct kevent event; - if (more_reads) - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); - else if (more_except) - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0); - else - EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0); - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - boost::system::error_code error(errno, - boost::asio::error::get_system_category()); - except_op_queue_.perform_all_operations(descriptor, error); - read_op_queue_.perform_all_operations(descriptor, error); - } - } - else if (events[i].filter == EVFILT_WRITE) - { - // Dispatch operations associated with the descriptor. - bool more_writes = false; - if (events[i].flags & EV_ERROR) - { - boost::system::error_code error( - events[i].data, boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, error); - } - else + switch (events[i].filter) { - boost::system::error_code error; - more_writes = write_op_queue_.perform_operation(descriptor, error); + case EVFILT_READ: + if (!descriptor_data->op_queue_[read_op].empty()) + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + else if (!descriptor_data->op_queue_[except_op].empty()) + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); + else + continue; + case EVFILT_WRITE: + if (!descriptor_data->op_queue_[write_op].empty()) + EV_SET(&event, descriptor, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + else + continue; + default: + break; } - - // Update the descriptor in the kqueue. - struct kevent event; - if (more_writes) - EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); - else - EV_SET(&event, descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { boost::system::error_code error(errno, boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, error); + for (int j = 0; j < max_ops; ++j) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + op->ec_ = error; + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + } } } } - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); - } - - // Issue any pending cancellations. - for (std::size_t i = 0; i < pending_cancellations_.size(); ++i) - cancel_ops_unlocked(pending_cancellations_[i]); - pending_cancellations_.clear(); - - // Determine whether kqueue needs to be called next time the reactor is run. - need_kqueue_wait_ = !read_op_queue_.empty() - || !write_op_queue_.empty() || !except_op_queue_.empty(); - - complete_operations_and_timers(lock); - } - - // Run the select loop in the thread. - void run_thread() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) - { - lock.unlock(); - run(true); - lock.lock(); - } - } - - // Entry point for the select loop thread. - static void call_run_thread(kqueue_reactor* reactor) - { - reactor->run_thread(); + lock.lock(); + timer_queues_.get_ready_timers(ops); } - // Interrupt the select loop. + // Interrupt the kqueue loop. void interrupt() { - interrupter_.interrupt(); + struct kevent event; + EV_SET(&event, interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_); + ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); } +private: // Create the kqueue file descriptor. Throws an exception if the descriptor // cannot be created. static int do_kqueue_create() @@ -586,118 +433,47 @@ private: return fd; } - // Check if all timer queues are empty. - bool all_timer_queues_are_empty() const - { - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - if (!timer_queues_[i]->empty()) - return false; - return true; - } - // Get the timeout value for the kevent call. timespec* get_timeout(timespec& ts) { - if (all_timer_queues_are_empty()) - return 0; - // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. - boost::posix_time::time_duration minimum_wait_duration - = boost::posix_time::minutes(5); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - boost::posix_time::time_duration wait_duration - = timer_queues_[i]->wait_duration(); - if (wait_duration < minimum_wait_duration) - minimum_wait_duration = wait_duration; - } - - if (minimum_wait_duration > boost::posix_time::time_duration()) - { - ts.tv_sec = minimum_wait_duration.total_seconds(); - ts.tv_nsec = minimum_wait_duration.total_nanoseconds() % 1000000000; - } - else - { - ts.tv_sec = 0; - ts.tv_nsec = 0; - } - + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; return &ts; } - // Cancel all operations associated with the given descriptor. The do_cancel - // function of the handler objects will be invoked. This function does not - // acquire the kqueue_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor) - { - bool interrupt = read_op_queue_.cancel_operations(descriptor); - interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; - interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; - if (interrupt) - interrupter_.interrupt(); - } - - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void complete_operations_and_timers( - boost::asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.complete_operations(); - write_op_queue_.complete_operations(); - except_op_queue_.complete_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->complete_timers(); - } + // The io_service implementation used to post completions. + io_service_impl& io_service_; // Mutex to protect access to internal data. - boost::asio::detail::mutex mutex_; + mutex mutex_; // The kqueue file descriptor. int kqueue_fd_; - // Whether the kqueue wait call is currently in progress - bool wait_in_progress_; - // The interrupter is used to break a blocking kevent call. select_interrupter interrupter_; - // The queue of read operations. - reactor_op_queue read_op_queue_; - - // The queue of write operations. - reactor_op_queue write_op_queue_; - - // The queue of except operations. - reactor_op_queue except_op_queue_; - // The timer queues. - std::vector timer_queues_; - - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - - // The descriptors that are pending cancellation. - std::vector pending_cancellations_; - - // Does the reactor loop thread need to stop. - bool stop_thread_; - - // The thread that is running the reactor loop. - boost::asio::detail::thread* thread_; + timer_queue_set timer_queues_; // Whether the service has been shut down. bool shutdown_; - // Whether we need to call kqueue the next time the reactor is run. - bool need_kqueue_wait_; + // Mutex to protect access to the registered descriptors. + mutex registered_descriptors_mutex_; + + // Keep track of all registered descriptors. This code relies on the fact that + // the hash_map implementation pools deleted nodes, meaning that we can assume + // our descriptor_state pointer remains valid even after the entry is removed. + // Technically this is not true for C++98, as that standard says that spliced + // elements in a list are invalidated. However, C++0x fixes this shortcoming + // so we'll just assume that C++98 std::list implementations will do the right + // thing anyway. + typedef detail::hash_map descriptor_map; + descriptor_map registered_descriptors_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor_fwd.hpp index b2751bf..0471c39 100644 --- a/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor_fwd.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor_fwd.hpp @@ -30,7 +30,6 @@ namespace boost { namespace asio { namespace detail { -template class kqueue_reactor; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/macos_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/macos_fenced_block.hpp new file mode 100644 index 0000000..496d7f0 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/macos_fenced_block.hpp @@ -0,0 +1,59 @@ +// +// macos_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_MACOS_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(__MACH__) && defined(__APPLE__) + +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class macos_fenced_block + : private noncopyable +{ +public: + // Constructor. + macos_fenced_block() + { + OSMemoryBarrier(); + } + + // Destructor. + ~macos_fenced_block() + { + OSMemoryBarrier(); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(__MACH__) && defined(__APPLE__) + +#include + +#endif // BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/mutex.hpp b/3rdParty/Boost/src/boost/asio/detail/mutex.hpp index fc7ed83..e804ec2 100644 --- a/3rdParty/Boost/src/boost/asio/detail/mutex.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/mutex.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(BOOST_WINDOWS) # include @@ -35,7 +35,7 @@ namespace boost { namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) typedef null_mutex mutex; #elif defined(BOOST_WINDOWS) typedef win_mutex mutex; diff --git a/3rdParty/Boost/src/boost/asio/detail/null_buffers_op.hpp b/3rdParty/Boost/src/boost/asio/detail/null_buffers_op.hpp new file mode 100644 index 0000000..02160af --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/null_buffers_op.hpp @@ -0,0 +1,79 @@ +// +// null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_NULL_BUFFERS_OP_HPP +#define BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class null_buffers_op : public reactor_op +{ +public: + null_buffers_op(Handler handler) + : reactor_op(&null_buffers_op::do_perform, &null_buffers_op::do_complete), + handler_(handler) + { + } + + static bool do_perform(reactor_op*) + { + return true; + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + null_buffers_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an upcall, + // 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/null_event.hpp b/3rdParty/Boost/src/boost/asio/detail/null_event.hpp index 184f753..2dc0bf6 100644 --- a/3rdParty/Boost/src/boost/asio/detail/null_event.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/null_event.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include @@ -49,6 +49,12 @@ public: { } + // Signal the event and unlock the mutex. + template + void signal_and_unlock(Lock&) + { + } + // Reset the event. template void clear(Lock&) @@ -66,7 +72,7 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include diff --git a/3rdParty/Boost/src/boost/asio/detail/null_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/null_fenced_block.hpp new file mode 100644 index 0000000..ea8e0fc --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/null_fenced_block.hpp @@ -0,0 +1,45 @@ +// +// null_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_NULL_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_fenced_block + : private noncopyable +{ +public: + // Constructor. + null_fenced_block() + { + } + + // Destructor. + ~null_fenced_block() + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/null_mutex.hpp b/3rdParty/Boost/src/boost/asio/detail/null_mutex.hpp index bdf5617..edc1358 100644 --- a/3rdParty/Boost/src/boost/asio/detail/null_mutex.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/null_mutex.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include #include @@ -61,7 +61,7 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include diff --git a/3rdParty/Boost/src/boost/asio/detail/null_signal_blocker.hpp b/3rdParty/Boost/src/boost/asio/detail/null_signal_blocker.hpp index 7fe5c10..65b55e9 100644 --- a/3rdParty/Boost/src/boost/asio/detail/null_signal_blocker.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/null_signal_blocker.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include @@ -58,7 +58,7 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include diff --git a/3rdParty/Boost/src/boost/asio/detail/null_thread.hpp b/3rdParty/Boost/src/boost/asio/detail/null_thread.hpp index 0a508f3..ba16311 100644 --- a/3rdParty/Boost/src/boost/asio/detail/null_thread.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/null_thread.hpp @@ -22,7 +22,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include #include @@ -63,7 +63,7 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include diff --git a/3rdParty/Boost/src/boost/asio/detail/null_tss_ptr.hpp b/3rdParty/Boost/src/boost/asio/detail/null_tss_ptr.hpp index 7c35b15..bd83e7e 100644 --- a/3rdParty/Boost/src/boost/asio/detail/null_tss_ptr.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/null_tss_ptr.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include @@ -65,7 +65,7 @@ private: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include diff --git a/3rdParty/Boost/src/boost/asio/detail/op_queue.hpp b/3rdParty/Boost/src/boost/asio/detail/op_queue.hpp new file mode 100644 index 0000000..ddf3e18 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/op_queue.hpp @@ -0,0 +1,158 @@ +// +// op_queue.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_OP_QUEUE_HPP +#define BOOST_ASIO_DETAIL_OP_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class op_queue; + +class op_queue_access +{ +public: + template + static Operation* next(Operation* o) + { + return static_cast(o->next_); + } + + template + static void next(Operation1*& o1, Operation2* o2) + { + o1->next_ = o2; + } + + template + static void destroy(Operation* o) + { + o->destroy(); + } + + template + static Operation*& front(op_queue& q) + { + return q.front_; + } + + template + static Operation*& back(op_queue& q) + { + return q.back_; + } +}; + +template +class op_queue + : private noncopyable +{ +public: + // Constructor. + op_queue() + : front_(0), + back_(0) + { + } + + // Destructor destroys all operations. + ~op_queue() + { + while (Operation* op = front_) + { + pop(); + op_queue_access::destroy(op); + } + } + + // Get the operation at the front of the queue. + Operation* front() + { + return front_; + } + + // Pop an operation from the front of the queue. + void pop() + { + if (front_) + { + Operation* tmp = front_; + front_ = op_queue_access::next(front_); + if (front_ == 0) + back_ = 0; + op_queue_access::next(tmp, static_cast(0)); + } + } + + // Push an operation on to the back of the queue. + void push(Operation* h) + { + op_queue_access::next(h, static_cast(0)); + if (back_) + { + op_queue_access::next(back_, h); + back_ = h; + } + else + { + front_ = back_ = h; + } + } + + // Push all operations from another queue on to the back of the queue. The + // source queue may contain operations of a derived type. + template + void push(op_queue& q) + { + if (Operation* other_front = op_queue_access::front(q)) + { + if (back_) + op_queue_access::next(back_, other_front); + else + front_ = other_front; + back_ = op_queue_access::back(q); + op_queue_access::front(q) = 0; + op_queue_access::back(q) = 0; + } + } + + // Whether the queue is empty. + bool empty() const + { + return front_ == 0; + } + +private: + friend class op_queue_access; + + // The front of the queue. + Operation* front_; + + // The back of the queue. + Operation* back_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_OP_QUEUE_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/operation.hpp b/3rdParty/Boost/src/boost/asio/detail/operation.hpp new file mode 100644 index 0000000..579b6b5 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/operation.hpp @@ -0,0 +1,45 @@ +// +// operation.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_OPERATION_HPP +#define BOOST_ASIO_DETAIL_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +# include +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_IOCP) +typedef win_iocp_operation operation; +#else +typedef task_io_service_operation operation; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_OPERATION_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/posix_event.hpp b/3rdParty/Boost/src/boost/asio/detail/posix_event.hpp index 20c0fe3..b2938cf 100644 --- a/3rdParty/Boost/src/boost/asio/detail/posix_event.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/posix_event.hpp @@ -72,6 +72,16 @@ public: ::pthread_cond_signal(&cond_); // Ignore EINVAL. } + // Signal the event and unlock the mutex. + template + void signal_and_unlock(Lock& lock) + { + BOOST_ASSERT(lock.locked()); + signalled_ = true; + lock.unlock(); + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + } + // Reset the event. template void clear(Lock& lock) diff --git a/3rdParty/Boost/src/boost/asio/detail/posix_mutex.hpp b/3rdParty/Boost/src/boost/asio/detail/posix_mutex.hpp index e7209c1..6d9a44f 100644 --- a/3rdParty/Boost/src/boost/asio/detail/posix_mutex.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/posix_mutex.hpp @@ -62,35 +62,19 @@ public: // Destructor. ~posix_mutex() { - ::pthread_mutex_destroy(&mutex_); + ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY. } // Lock the mutex. void lock() { - int error = ::pthread_mutex_lock(&mutex_); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } + (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL. } // Unlock the mutex. void unlock() { - int error = ::pthread_mutex_unlock(&mutex_); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } + (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL. } private: diff --git a/3rdParty/Boost/src/boost/asio/detail/reactive_descriptor_service.hpp b/3rdParty/Boost/src/boost/asio/detail/reactive_descriptor_service.hpp index 61f676b..536b96a 100644 --- a/3rdParty/Boost/src/boost/asio/detail/reactive_descriptor_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/reactive_descriptor_service.hpp @@ -21,10 +21,13 @@ #include #include #include -#include -#include -#include +#include #include +#include +#include +#include +#include +#include #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) @@ -32,10 +35,7 @@ namespace boost { namespace asio { namespace detail { -template class reactive_descriptor_service - : public boost::asio::detail::service_base< - reactive_descriptor_service > { public: // The native type of a descriptor. @@ -55,22 +55,28 @@ public: private: // Only this service will have access to the internal values. - friend class reactive_descriptor_service; + friend class reactive_descriptor_service; // The native descriptor representation. int descriptor_; enum { - user_set_non_blocking = 1, // The user wants a non-blocking descriptor. - internal_non_blocking = 2 // The descriptor has been set non-blocking. + // The user wants a non-blocking descriptor. + user_set_non_blocking = 1, + + // The descriptor has been set non-blocking. + internal_non_blocking = 2, + + // Helper "flag" used to determine whether the descriptor is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking }; // Flags indicating the current state of the descriptor. unsigned char flags_; // Per-descriptor data used by the reactor. - typename Reactor::per_descriptor_data reactor_data_; + reactor::per_descriptor_data reactor_data_; }; // The maximum number of buffers to support in a single operation. @@ -78,9 +84,8 @@ public: // Constructor. reactive_descriptor_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - reactive_descriptor_service >(io_service), - reactor_(boost::asio::use_service(io_service)) + : io_service_impl_(boost::asio::use_service(io_service)), + reactor_(boost::asio::use_service(io_service)) { reactor_.init_task(); } @@ -209,19 +214,31 @@ public: return ec; } - if (command.name() == static_cast(FIONBIO)) + descriptor_ops::ioctl(impl.descriptor_, command.name(), + static_cast(command.data()), ec); + + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the descriptor is + // already in the correct state. This ensures that the underlying + // descriptor is put into the state that has been requested by the user. If + // the ioctl syscall was successful then we need to update the flags to + // match. + if (!ec && command.name() == static_cast(FIONBIO)) { - if (command.get()) + if (*static_cast(command.data())) + { impl.flags_ |= implementation_type::user_set_non_blocking; + } else - impl.flags_ &= ~implementation_type::user_set_non_blocking; - ec = boost::system::error_code(); - } - else - { - descriptor_ops::ioctl(impl.descriptor_, command.name(), - static_cast(command.data()), ec); + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + impl.flags_ &= ~(implementation_type::user_set_non_blocking + | implementation_type::internal_non_blocking); + } } + return ec; } @@ -236,47 +253,22 @@ public: return 0; } - // Copy buffers into array. - descriptor_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - descriptor_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to read_some 0 bytes on a stream is a no-op. - if (total_buffer_size == 0) + if (bufs.all_empty()) { ec = boost::system::error_code(); return 0; } - // Make descriptor non-blocking if user wants non-blocking. - if (impl.flags_ & implementation_type::user_set_non_blocking) - { - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - if (descriptor_ops::ioctl(impl.descriptor_, - FIONBIO, &non_blocking, ec)) - return 0; - impl.flags_ |= implementation_type::internal_non_blocking; - } - } - // Send the data. for (;;) { // Try to complete the operation without blocking. int bytes_sent = descriptor_ops::gather_write( - impl.descriptor_, bufs, i, ec); + impl.descriptor_, bufs.buffers(), bufs.count(), ec); // Check if operation succeeded. if (bytes_sent >= 0) @@ -310,48 +302,31 @@ public: return 0; } - template - class write_operation : - public handler_base_from_member + template + class write_op_base : public reactor_op { public: - write_operation(int descriptor, boost::asio::io_service& io_service, - const ConstBufferSequence& buffers, Handler handler) - : handler_base_from_member(handler), + write_op_base(int descriptor, + const ConstBufferSequence& buffers, func_type complete_func) + : reactor_op(&write_op_base::do_perform, complete_func), descriptor_(descriptor), - io_service_(io_service), - work_(io_service), buffers_(buffers) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + write_op_base* o(static_cast(base)); - // Copy buffers into array. - descriptor_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers_.begin(); - typename ConstBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - descriptor_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Write the data. - int bytes = descriptor_ops::gather_write(descriptor_, bufs, i, ec); + boost::system::error_code ec; + int bytes = descriptor_ops::gather_write( + o->descriptor_, bufs.buffers(), bufs.count(), ec); // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) @@ -362,120 +337,89 @@ public: || ec == boost::asio::error::try_again) return false; - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); - } - private: int descriptor_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; ConstBufferSequence buffers_; }; - // Start an asynchronous write. The data being sent must be valid for the - // lifetime of the asynchronous operation. template - void async_write_some(implementation_type& impl, - const ConstBufferSequence& buffers, Handler handler) - { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Determine total size of buffers. - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - total_buffer_size += boost::asio::buffer_size(buffer); - } - - // A request to read_some 0 bytes on a stream is a no-op. - if (total_buffer_size == 0) - { - this->get_io_service().post(bind_handler(handler, - boost::system::error_code(), 0)); - return; - } - - // Make descriptor non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - impl.flags_ |= implementation_type::internal_non_blocking; - } - - reactor_.start_write_op(impl.descriptor_, impl.reactor_data_, - write_operation( - impl.descriptor_, this->get_io_service(), buffers, handler)); - } - } - - template - class null_buffers_operation : - public handler_base_from_member + class write_op : public write_op_base { public: - null_buffers_operation(boost::asio::io_service& io_service, Handler handler) - : handler_base_from_member(handler), - work_(io_service) + write_op(int descriptor, + const ConstBufferSequence& buffers, Handler handler) + : write_op_base( + descriptor, buffers, &write_op::do_complete), + handler_(handler) { } - bool perform(boost::system::error_code&, - std::size_t& bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - bytes_transferred = 0; - return true; - } + // Take ownership of the handler object. + write_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - work_.get_io_service().post(bind_handler( - this->handler_, ec, bytes_transferred)); + // Make the upcall if required. + if (owner) + { + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } private: - boost::asio::io_service::work work_; + Handler handler_; }; + // Start an asynchronous write. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef write_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, impl.descriptor_, buffers, handler); + + start_op(impl, reactor::write_op, ptr.get(), true, + buffer_sequence_adapter::all_empty(buffers)); + ptr.release(); + } + // Start an asynchronous wait until data can be written without blocking. template void async_write_some(implementation_type& impl, const null_buffers&, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - reactor_.start_write_op(impl.descriptor_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + start_op(impl, reactor::write_op, ptr.get(), false, false); + ptr.release(); } // Read some data from the stream. Returns the number of bytes read. @@ -489,46 +433,22 @@ public: return 0; } - // Copy buffers into array. - descriptor_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - descriptor_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to read_some 0 bytes on a stream is a no-op. - if (total_buffer_size == 0) + if (bufs.all_empty()) { ec = boost::system::error_code(); return 0; } - // Make descriptor non-blocking if user wants non-blocking. - if (impl.flags_ & implementation_type::user_set_non_blocking) - { - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) - return 0; - impl.flags_ |= implementation_type::internal_non_blocking; - } - } - // Read some data. for (;;) { // Try to complete the operation without blocking. int bytes_read = descriptor_ops::scatter_read( - impl.descriptor_, bufs, i, ec); + impl.descriptor_, bufs.buffers(), bufs.count(), ec); // Check if operation succeeded. if (bytes_read > 0) @@ -569,48 +489,31 @@ public: return 0; } - template - class read_operation : - public handler_base_from_member + template + class read_op_base : public reactor_op { public: - read_operation(int descriptor, boost::asio::io_service& io_service, - const MutableBufferSequence& buffers, Handler handler) - : handler_base_from_member(handler), + read_op_base(int descriptor, + const MutableBufferSequence& buffers, func_type complete_func) + : reactor_op(&read_op_base::do_perform, complete_func), descriptor_(descriptor), - io_service_(io_service), - work_(io_service), buffers_(buffers) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + read_op_base* o(static_cast(base)); - // Copy buffers into array. - descriptor_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers_.begin(); - typename MutableBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - descriptor_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Read some data. - int bytes = descriptor_ops::scatter_read(descriptor_, bufs, i, ec); + boost::system::error_code ec; + int bytes = descriptor_ops::scatter_read( + o->descriptor_, bufs.buffers(), bufs.count(), ec); if (bytes == 0) ec = boost::asio::error::eof; @@ -623,73 +526,75 @@ public: || ec == boost::asio::error::try_again) return false; - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); - } - private: int descriptor_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; MutableBufferSequence buffers_; }; - // Start an asynchronous read. The buffer for the data being read must be - // valid for the lifetime of the asynchronous operation. template - void async_read_some(implementation_type& impl, - const MutableBufferSequence& buffers, Handler handler) + class read_op : public read_op_base { - if (!is_open(impl)) + public: + read_op(int descriptor, + const MutableBufferSequence& buffers, Handler handler) + : read_op_base( + descriptor, buffers, &read_op::do_complete), + handler_(handler) { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); } - else + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - // Determine total size of buffers. - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - total_buffer_size += boost::asio::buffer_size(buffer); - } + // Take ownership of the handler object. + read_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); - // A request to read_some 0 bytes on a stream is a no-op. - if (total_buffer_size == 0) + // Make the upcall if required. + if (owner) { - this->get_io_service().post(bind_handler(handler, - boost::system::error_code(), 0)); - return; + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } + } - // Make descriptor non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - impl.flags_ |= implementation_type::internal_non_blocking; - } + private: + Handler handler_; + }; - reactor_.start_read_op(impl.descriptor_, impl.reactor_data_, - read_operation( - impl.descriptor_, this->get_io_service(), buffers, handler)); - } + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef read_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, + impl.descriptor_, buffers, handler); + + start_op(impl, reactor::read_op, ptr.get(), true, + buffer_sequence_adapter::all_empty(buffers)); + ptr.release(); } // Wait until data can be read without blocking. @@ -697,22 +602,61 @@ public: void async_read_some(implementation_type& impl, const null_buffers&, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + start_op(impl, reactor::read_op, ptr.get(), false, false); + ptr.release(); + } + +private: + // Start the asynchronous operation. + void start_op(implementation_type& impl, int op_type, + reactor_op* op, bool non_blocking, bool noop) + { + if (!noop) { - reactor_.start_read_op(impl.descriptor_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); + if (is_open(impl)) + { + if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_)) + { + reactor_.start_op(op_type, impl.descriptor_, + impl.reactor_data_, op, non_blocking); + return; + } + } + else + op->ec_ = boost::asio::error::bad_descriptor; } + + io_service_impl_.post_immediate_completion(op); } -private: + // Determine whether the descriptor has been set non-blocking. + bool is_non_blocking(implementation_type& impl) const + { + return (impl.flags_ & implementation_type::non_blocking); + } + + // Set the internal non-blocking flag. + bool set_non_blocking(implementation_type& impl, + boost::system::error_code& ec) + { + ioctl_arg_type non_blocking = 1; + if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) + return false; + impl.flags_ |= implementation_type::internal_non_blocking; + return true; + } + + // The io_service implementation used to post completions. + io_service_impl& io_service_impl_; + // The selector that performs event demultiplexing for the service. - Reactor& reactor_; + reactor& reactor_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/reactive_serial_port_service.hpp b/3rdParty/Boost/src/boost/asio/detail/reactive_serial_port_service.hpp index cd163e9..faa2149 100644 --- a/3rdParty/Boost/src/boost/asio/detail/reactive_serial_port_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/reactive_serial_port_service.hpp @@ -38,31 +38,24 @@ namespace asio { namespace detail { // Extend reactive_descriptor_service to provide serial port support. -template class reactive_serial_port_service - : public boost::asio::detail::service_base< - reactive_serial_port_service > { public: - // The native type of a stream handle. - typedef typename reactive_descriptor_service::native_type - native_type; + // The native type of a serial port. + typedef reactive_descriptor_service::native_type native_type; - // The implementation type of the stream handle. - typedef typename reactive_descriptor_service::implementation_type - implementation_type; + // The implementation type of the serial port. + typedef reactive_descriptor_service::implementation_type implementation_type; reactive_serial_port_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - reactive_serial_port_service>(io_service), - descriptor_service_(boost::asio::use_service< - reactive_descriptor_service >(io_service)) + : descriptor_service_(io_service) { } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { + descriptor_service_.shutdown_service(); } // Construct a new handle implementation. @@ -254,8 +247,8 @@ public: } private: - // The handle service used for initiating asynchronous operations. - reactive_descriptor_service& descriptor_service_; + // The implementation used for initiating asynchronous operations. + reactive_descriptor_service descriptor_service_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/reactive_socket_service.hpp b/3rdParty/Boost/src/boost/asio/detail/reactive_socket_service.hpp index 95d39dd..5f7bbf5 100644 --- a/3rdParty/Boost/src/boost/asio/detail/reactive_socket_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/reactive_socket_service.hpp @@ -17,18 +17,17 @@ #include -#include -#include -#include - #include #include #include #include #include -#include +#include +#include #include -#include +#include +#include +#include #include #include #include @@ -37,10 +36,8 @@ namespace boost { namespace asio { namespace detail { -template +template class reactive_socket_service - : public boost::asio::detail::service_base< - reactive_socket_service > { public: // The protocol type. @@ -67,7 +64,7 @@ public: private: // Only this service will have access to the internal values. - friend class reactive_socket_service; + friend class reactive_socket_service; // The native socket representation. socket_type socket_; @@ -87,7 +84,7 @@ public: // User wants connection_aborted errors, which are disabled by default. enable_connection_aborted = 4, - // The user set the linger option. Needs to be checked when closing. + // The user set the linger option. Needs to be checked when closing. user_set_linger = 8 }; @@ -98,17 +95,13 @@ public: protocol_type protocol_; // Per-descriptor data used by the reactor. - typename Reactor::per_descriptor_data reactor_data_; + reactor::per_descriptor_data reactor_data_; }; - // The maximum number of buffers to support in a single operation. - enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; - // Constructor. reactive_socket_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - reactive_socket_service >(io_service), - reactor_(boost::asio::use_service(io_service)) + : io_service_impl_(use_service(io_service)), + reactor_(use_service(io_service)) { reactor_.init_task(); } @@ -452,43 +445,30 @@ public: return ec; } - if (command.name() == static_cast(FIONBIO)) + socket_ops::ioctl(impl.socket_, command.name(), + static_cast(command.data()), ec); + + // When updating the non-blocking mode we always perform the ioctl + // syscall, even if the flags would otherwise indicate that the socket is + // already in the correct state. This ensures that the underlying socket + // is put into the state that has been requested by the user. If the ioctl + // syscall was successful then we need to update the flags to match. + if (!ec && command.name() == static_cast(FIONBIO)) { - // Flags are manipulated in a temporary variable so that the socket - // implementation is not updated unless the ioctl operation succeeds. - unsigned char new_flags = impl.flags_; if (*static_cast(command.data())) - new_flags |= implementation_type::user_set_non_blocking; - else - new_flags &= ~implementation_type::user_set_non_blocking; - - // Perform ioctl on socket if the non-blocking state has changed. - if (!(impl.flags_ & implementation_type::non_blocking) - && (new_flags & implementation_type::non_blocking)) { - ioctl_arg_type non_blocking = 1; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec); - } - else if ((impl.flags_ & implementation_type::non_blocking) - && !(new_flags & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 0; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec); + impl.flags_ |= implementation_type::user_set_non_blocking; } else { - ec = boost::system::error_code(); + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + impl.flags_ &= ~(implementation_type::user_set_non_blocking + | implementation_type::internal_non_blocking); } - - // Update socket implementation's flags only if successful. - if (!ec) - impl.flags_ = new_flags; - } - else - { - socket_ops::ioctl(impl.socket_, command.name(), - static_cast(command.data()), ec); } + return ec; } @@ -553,23 +533,11 @@ public: return 0; } - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) + if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) { ec = boost::system::error_code(); return 0; @@ -579,7 +547,8 @@ public: for (;;) { // Try to complete the operation without blocking. - int bytes_sent = socket_ops::send(impl.socket_, bufs, i, flags, ec); + int bytes_sent = socket_ops::send(impl.socket_, + bufs.buffers(), bufs.count(), flags, ec); // Check if operation succeeded. if (bytes_sent >= 0) @@ -613,50 +582,32 @@ public: return 0; } - template - class send_operation : - public handler_base_from_member + template + class send_op_base : public reactor_op { public: - send_operation(socket_type socket, boost::asio::io_service& io_service, - const ConstBufferSequence& buffers, socket_base::message_flags flags, - Handler handler) - : handler_base_from_member(handler), + send_op_base(socket_type socket, const ConstBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&send_op_base::do_perform, complete_func), socket_(socket), - io_service_(io_service), - work_(io_service), buffers_(buffers), flags_(flags) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + send_op_base* o(static_cast(base)); - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers_.begin(); - typename ConstBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Send the data. - int bytes = socket_ops::send(socket_, bufs, i, flags_, ec); + boost::system::error_code ec; + int bytes = socket_ops::send(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, ec); // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) @@ -667,127 +618,92 @@ public: || ec == boost::asio::error::try_again) return false; - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); - } - private: socket_type socket_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; ConstBufferSequence buffers_; socket_base::message_flags flags_; }; - // Start an asynchronous send. The data being sent must be valid for the - // lifetime of the asynchronous operation. template - void async_send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - if (impl.protocol_.type() == SOCK_STREAM) - { - // Determine total size of buffers. - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - total_buffer_size += boost::asio::buffer_size(buffer); - } - - // A request to receive 0 bytes on a stream socket is a no-op. - if (total_buffer_size == 0) - { - this->get_io_service().post(bind_handler(handler, - boost::system::error_code(), 0)); - return; - } - } - - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; - } - - reactor_.start_write_op(impl.socket_, impl.reactor_data_, - send_operation( - impl.socket_, this->get_io_service(), buffers, flags, handler)); - } - } - - template - class null_buffers_operation : - public handler_base_from_member + class send_op : public send_op_base { public: - null_buffers_operation(boost::asio::io_service& io_service, Handler handler) - : handler_base_from_member(handler), - work_(io_service) + send_op(socket_type socket, const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : send_op_base(socket, + buffers, flags, &send_op::do_complete), + handler_(handler) { } - bool perform(boost::system::error_code&, - std::size_t& bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - bytes_transferred = 0; - return true; - } + // Take ownership of the handler object. + send_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - work_.get_io_service().post(bind_handler( - this->handler_, ec, bytes_transferred)); + // Make the upcall if required. + if (owner) + { + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } private: - boost::asio::io_service::work work_; + Handler handler_; }; + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(implementation_type& impl, const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef send_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, + impl.socket_, buffers, flags, handler); + + start_op(impl, reactor::write_op, ptr.get(), true, + (impl.protocol_.type() == SOCK_STREAM + && buffer_sequence_adapter::all_empty(buffers))); + ptr.release(); + } + // Start an asynchronous wait until data can be sent without blocking. template void async_send(implementation_type& impl, const null_buffers&, socket_base::message_flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - reactor_.start_write_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + start_op(impl, reactor::write_op, ptr.get(), false, false); + ptr.release(); } // Send a datagram to the specified endpoint. Returns the number of bytes @@ -803,25 +719,15 @@ public: return 0; } - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(buffers); // Send the data. for (;;) { // Try to complete the operation without blocking. - int bytes_sent = socket_ops::sendto(impl.socket_, bufs, i, flags, - destination.data(), destination.size(), ec); + int bytes_sent = socket_ops::sendto(impl.socket_, bufs.buffers(), + bufs.count(), flags, destination.data(), destination.size(), ec); // Check if operation succeeded. if (bytes_sent >= 0) @@ -856,52 +762,34 @@ public: return 0; } - template - class send_to_operation : - public handler_base_from_member + template + class send_to_op_base : public reactor_op { public: - send_to_operation(socket_type socket, boost::asio::io_service& io_service, - const ConstBufferSequence& buffers, const endpoint_type& endpoint, - socket_base::message_flags flags, Handler handler) - : handler_base_from_member(handler), + send_to_op_base(socket_type socket, const ConstBufferSequence& buffers, + const endpoint_type& endpoint, socket_base::message_flags flags, + func_type complete_func) + : reactor_op(&send_to_op_base::do_perform, complete_func), socket_(socket), - io_service_(io_service), - work_(io_service), buffers_(buffers), destination_(endpoint), flags_(flags) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + send_to_op_base* o(static_cast(base)); - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers_.begin(); - typename ConstBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Send the data. - int bytes = socket_ops::sendto(socket_, bufs, i, flags_, - destination_.data(), destination_.size(), ec); + boost::system::error_code ec; + int bytes = socket_ops::sendto(o->socket_, bufs.buffers(), bufs.count(), + o->flags_, o->destination_.data(), o->destination_.size(), ec); // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) @@ -912,62 +800,78 @@ public: || ec == boost::asio::error::try_again) return false; - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); - } - private: socket_type socket_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; ConstBufferSequence buffers_; endpoint_type destination_; socket_base::message_flags flags_; }; - // Start an asynchronous send. The data being sent must be valid for the - // lifetime of the asynchronous operation. template - void async_send_to(implementation_type& impl, - const ConstBufferSequence& buffers, - const endpoint_type& destination, socket_base::message_flags flags, - Handler handler) + class send_to_op : public send_to_op_base { - if (!is_open(impl)) + public: + send_to_op(socket_type socket, const ConstBufferSequence& buffers, + const endpoint_type& endpoint, socket_base::message_flags flags, + Handler handler) + : send_to_op_base(socket, + buffers, endpoint, flags, &send_to_op::do_complete), + handler_(handler) { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); } - else + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) + // Take ownership of the handler object. + send_to_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - - reactor_.start_write_op(impl.socket_, impl.reactor_data_, - send_to_operation( - impl.socket_, this->get_io_service(), buffers, - destination, flags, handler)); } + + private: + Handler handler_; + }; + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef send_to_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, impl.socket_, + buffers, destination, flags, handler); + + start_op(impl, reactor::write_op, ptr.get(), true, false); + ptr.release(); } // Start an asynchronous wait until data can be sent without blocking. @@ -975,17 +879,14 @@ public: void async_send_to(implementation_type& impl, const null_buffers&, socket_base::message_flags, const endpoint_type&, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - reactor_.start_write_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + start_op(impl, reactor::write_op, ptr.get(), false, false); + ptr.release(); } // Receive some data from the peer. Returns the number of bytes received. @@ -1000,23 +901,11 @@ public: return 0; } - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) + if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) { ec = boost::system::error_code(); return 0; @@ -1026,7 +915,8 @@ public: for (;;) { // Try to complete the operation without blocking. - int bytes_recvd = socket_ops::recv(impl.socket_, bufs, i, flags, ec); + int bytes_recvd = socket_ops::recv(impl.socket_, + bufs.buffers(), bufs.count(), flags, ec); // Check if operation succeeded. if (bytes_recvd > 0) @@ -1067,53 +957,35 @@ public: return 0; } - template - class receive_operation : - public handler_base_from_member + template + class receive_op_base : public reactor_op { public: - receive_operation(socket_type socket, int protocol_type, - boost::asio::io_service& io_service, + receive_op_base(socket_type socket, int protocol_type, const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - : handler_base_from_member(handler), + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&receive_op_base::do_perform, complete_func), socket_(socket), protocol_type_(protocol_type), - io_service_(io_service), - work_(io_service), buffers_(buffers), flags_(flags) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + receive_op_base* o(static_cast(base)); - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers_.begin(); - typename MutableBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Receive some data. - int bytes = socket_ops::recv(socket_, bufs, i, flags_, ec); - if (bytes == 0 && protocol_type_ == SOCK_STREAM) + boost::system::error_code ec; + int bytes = socket_ops::recv(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, ec); + if (bytes == 0 && o->protocol_type_ == SOCK_STREAM) ec = boost::asio::error::eof; // Retry operation if interrupted by signal. @@ -1125,93 +997,84 @@ public: || ec == boost::asio::error::try_again) return false; - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); - } - private: socket_type socket_; int protocol_type_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; MutableBufferSequence buffers_; socket_base::message_flags flags_; }; - // Start an asynchronous receive. The buffer for the data being received - // must be valid for the lifetime of the asynchronous operation. template - void async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) + class receive_op : public receive_op_base { - if (!is_open(impl)) + public: + receive_op(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : receive_op_base(socket, + protocol_type, buffers, flags, &receive_op::do_complete), + handler_(handler) { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); } - else - { - if (impl.protocol_.type() == SOCK_STREAM) - { - // Determine total size of buffers. - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - total_buffer_size += boost::asio::buffer_size(buffer); - } - - // A request to receive 0 bytes on a stream socket is a no-op. - if (total_buffer_size == 0) - { - this->get_io_service().post(bind_handler(handler, - boost::system::error_code(), 0)); - return; - } - } - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; - } + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + receive_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); - if (flags & socket_base::message_out_of_band) + // Make the upcall if required. + if (owner) { - reactor_.start_except_op(impl.socket_, impl.reactor_data_, - receive_operation( - impl.socket_, impl.protocol_.type(), - this->get_io_service(), buffers, flags, handler)); - } - else - { - reactor_.start_read_op(impl.socket_, impl.reactor_data_, - receive_operation( - impl.socket_, impl.protocol_.type(), - this->get_io_service(), buffers, flags, handler)); + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } } + + private: + Handler handler_; + }; + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef receive_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + int protocol_type = impl.protocol_.type(); + handler_ptr ptr(raw_ptr, impl.socket_, + protocol_type, buffers, flags, handler); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get(), (flags & socket_base::message_out_of_band) == 0, + (impl.protocol_.type() == SOCK_STREAM + && buffer_sequence_adapter::all_empty(buffers))); + ptr.release(); } // Wait until data can be received without blocking. @@ -1219,22 +1082,17 @@ public: void async_receive(implementation_type& impl, const null_buffers&, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else if (flags & socket_base::message_out_of_band) - { - reactor_.start_except_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler)); - } - else - { - reactor_.start_read_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get(), false, false); + ptr.release(); } // Receive a datagram with the endpoint of the sender. Returns the number of @@ -1251,26 +1109,16 @@ public: return 0; } - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(buffers); // Receive some data. for (;;) { // Try to complete the operation without blocking. std::size_t addr_len = sender_endpoint.capacity(); - int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs, i, flags, - sender_endpoint.data(), &addr_len, ec); + int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs.buffers(), + bufs.count(), flags, sender_endpoint.data(), &addr_len, ec); // Check if operation succeeded. if (bytes_recvd > 0) @@ -1318,56 +1166,37 @@ public: return 0; } - template - class receive_from_operation : - public handler_base_from_member + template + class receive_from_op_base : public reactor_op { public: - receive_from_operation(socket_type socket, int protocol_type, - boost::asio::io_service& io_service, + receive_from_op_base(socket_type socket, int protocol_type, const MutableBufferSequence& buffers, endpoint_type& endpoint, - socket_base::message_flags flags, Handler handler) - : handler_base_from_member(handler), + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&receive_from_op_base::do_perform, complete_func), socket_(socket), protocol_type_(protocol_type), - io_service_(io_service), - work_(io_service), buffers_(buffers), sender_endpoint_(endpoint), flags_(flags) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + receive_from_op_base* o(static_cast(base)); - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers_.begin(); - typename MutableBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Receive some data. - std::size_t addr_len = sender_endpoint_.capacity(); - int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_, - sender_endpoint_.data(), &addr_len, ec); - if (bytes == 0 && protocol_type_ == SOCK_STREAM) + boost::system::error_code ec; + std::size_t addr_len = o->sender_endpoint_.capacity(); + int bytes = socket_ops::recvfrom(o->socket_, bufs.buffers(), + bufs.count(), o->flags_, o->sender_endpoint_.data(), &addr_len, ec); + if (bytes == 0 && o->protocol_type_ == SOCK_STREAM) ec = boost::asio::error::eof; // Retry operation if interrupted by signal. @@ -1379,64 +1208,84 @@ public: || ec == boost::asio::error::try_again) return false; - sender_endpoint_.resize(addr_len); - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->sender_endpoint_.resize(addr_len); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); - } - private: socket_type socket_; int protocol_type_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; MutableBufferSequence buffers_; endpoint_type& sender_endpoint_; socket_base::message_flags flags_; }; - // Start an asynchronous receive. The buffer for the data being received and - // the sender_endpoint object must both be valid for the lifetime of the - // asynchronous operation. template - void async_receive_from(implementation_type& impl, - const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, - socket_base::message_flags flags, Handler handler) + class receive_from_op : public receive_from_op_base { - if (!is_open(impl)) + public: + receive_from_op(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, endpoint_type& endpoint, + socket_base::message_flags flags, Handler handler) + : receive_from_op_base(socket, protocol_type, + buffers, endpoint, flags, &receive_from_op::do_complete), + handler_(handler) { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); } - else + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) + // Take ownership of the handler object. + receive_from_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - - reactor_.start_read_op(impl.socket_, impl.reactor_data_, - receive_from_operation( - impl.socket_, impl.protocol_.type(), this->get_io_service(), - buffers, sender_endpoint, flags, handler)); } + + private: + Handler handler_; + }; + + // Start an asynchronous receive. The buffer for the data being received and + // the sender_endpoint object must both be valid for the lifetime of the + // asynchronous operation. + template + void async_receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef receive_from_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + int protocol_type = impl.protocol_.type(); + handler_ptr ptr(raw_ptr, impl.socket_, + protocol_type, buffers, sender_endpoint, flags, handler); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get(), true, false); + ptr.release(); } // Wait until data can be received without blocking. @@ -1445,28 +1294,20 @@ public: const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Reset endpoint since it can be given no sensible value at this time. - sender_endpoint = endpoint_type(); + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - if (flags & socket_base::message_out_of_band) - { - reactor_.start_except_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler)); - } - else - { - reactor_.start_read_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } - } + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get(), false, false); + ptr.release(); } // Accept a new connection. @@ -1546,19 +1387,15 @@ public: } } - template - class accept_operation : - public handler_base_from_member + template + class accept_op_base : public reactor_op { public: - accept_operation(socket_type socket, boost::asio::io_service& io_service, - Socket& peer, const protocol_type& protocol, - endpoint_type* peer_endpoint, bool enable_connection_aborted, - Handler handler) - : handler_base_from_member(handler), + accept_op_base(socket_type socket, Socket& peer, + const protocol_type& protocol, endpoint_type* peer_endpoint, + bool enable_connection_aborted, func_type complete_func) + : reactor_op(&accept_op_base::do_perform, complete_func), socket_(socket), - io_service_(io_service), - work_(io_service), peer_(peer), protocol_(protocol), peer_endpoint_(peer_endpoint), @@ -1566,27 +1403,25 @@ public: { } - bool perform(boost::system::error_code& ec, std::size_t&) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - return true; + accept_op_base* o(static_cast(base)); for (;;) { // Accept the waiting connection. + boost::system::error_code ec; socket_holder new_socket; std::size_t addr_len = 0; - if (peer_endpoint_) - { - addr_len = peer_endpoint_->capacity(); - new_socket.reset(socket_ops::accept(socket_, - peer_endpoint_->data(), &addr_len, ec)); - } - else + std::size_t* addr_len_p = 0; + socket_addr_type* addr = 0; + if (o->peer_endpoint_) { - new_socket.reset(socket_ops::accept(socket_, 0, 0, ec)); + addr_len = o->peer_endpoint_->capacity(); + addr_len_p = &addr_len; + addr = o->peer_endpoint_->data(); } + new_socket.reset(socket_ops::accept(o->socket_, addr, addr_len_p, ec)); // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) @@ -1597,83 +1432,95 @@ public: || ec == boost::asio::error::try_again) return false; if (ec == boost::asio::error::connection_aborted - && !enable_connection_aborted_) + && !o->enable_connection_aborted_) return false; #if defined(EPROTO) - if (ec.value() == EPROTO && !enable_connection_aborted_) + if (ec.value() == EPROTO && !o->enable_connection_aborted_) return false; #endif // defined(EPROTO) // Transfer ownership of the new socket to the peer object. if (!ec) { - if (peer_endpoint_) - peer_endpoint_->resize(addr_len); - peer_.assign(protocol_, new_socket.get(), ec); + if (o->peer_endpoint_) + o->peer_endpoint_->resize(addr_len); + o->peer_.assign(o->protocol_, new_socket.get(), ec); if (!ec) new_socket.release(); } + o->ec_ = ec; return true; } } - void complete(const boost::system::error_code& ec, std::size_t) - { - io_service_.post(bind_handler(this->handler_, ec)); - } - private: socket_type socket_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; Socket& peer_; protocol_type protocol_; endpoint_type* peer_endpoint_; bool enable_connection_aborted_; }; - // Start an asynchronous accept. The peer and peer_endpoint objects - // must be valid until the accept's handler is invoked. template - void async_accept(implementation_type& impl, Socket& peer, - endpoint_type* peer_endpoint, Handler handler) + class accept_op : public accept_op_base { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor)); - } - else if (peer.is_open()) + public: + accept_op(socket_type socket, Socket& peer, const protocol_type& protocol, + endpoint_type* peer_endpoint, bool enable_connection_aborted, + Handler handler) + : accept_op_base(socket, peer, protocol, peer_endpoint, + enable_connection_aborted, &accept_op::do_complete), + handler_(handler) { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::already_open)); } - else + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) + // Take ownership of the handler object. + accept_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder1 + handler(o->handler_, o->ec_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - - reactor_.start_read_op(impl.socket_, impl.reactor_data_, - accept_operation( - impl.socket_, this->get_io_service(), - peer, impl.protocol_, peer_endpoint, - (impl.flags_ & implementation_type::enable_connection_aborted) != 0, - handler)); } + + private: + Handler handler_; + }; + + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef accept_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + bool enable_connection_aborted = + (impl.flags_ & implementation_type::enable_connection_aborted) != 0; + handler_ptr ptr(raw_ptr, impl.socket_, peer, + impl.protocol_, peer_endpoint, enable_connection_aborted, handler); + + start_accept_op(impl, ptr.get(), peer.is_open()); + ptr.release(); } // Connect the socket to the specified endpoint. @@ -1713,53 +1560,77 @@ public: return ec; } - template - class connect_operation : - public handler_base_from_member + class connect_op_base : public reactor_op { public: - connect_operation(socket_type socket, - boost::asio::io_service& io_service, Handler handler) - : handler_base_from_member(handler), - socket_(socket), - io_service_(io_service), - work_(io_service) + connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&connect_op_base::do_perform, complete_func), + socket_(socket) { } - bool perform(boost::system::error_code& ec, std::size_t&) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - return true; + connect_op_base* o(static_cast(base)); // Get the error code from the connect operation. int connect_error = 0; size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, ec) == socket_error_retval) + if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, o->ec_) == socket_error_retval) return true; // The connection failed so the handler will be posted with an error code. if (connect_error) { - ec = boost::system::error_code(connect_error, + o->ec_ = boost::system::error_code(connect_error, boost::asio::error::get_system_category()); - return true; } return true; } - void complete(const boost::system::error_code& ec, std::size_t) + private: + socket_type socket_; + }; + + template + class connect_op : public connect_op_base + { + public: + connect_op(socket_type socket, Handler handler) + : connect_op_base(socket, &connect_op::do_complete), + handler_(handler) { - io_service_.post(bind_handler(this->handler_, ec)); + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + connect_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder1 + handler(o->handler_, o->ec_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } private: - socket_type socket_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; + Handler handler_; }; // Start an asynchronous connect. @@ -1767,59 +1638,103 @@ public: void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor)); - return; - } + // Allocate and construct an operation to wrap the handler. + typedef connect_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, impl.socket_, handler); + + start_connect_op(impl, ptr.get(), peer_endpoint); + ptr.release(); + } - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) +private: + // Start the asynchronous read or write operation. + void start_op(implementation_type& impl, int op_type, + reactor_op* op, bool non_blocking, bool noop) + { + if (!noop) { - if (!(impl.flags_ & implementation_type::non_blocking)) + if (is_open(impl)) { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + if (!non_blocking || is_non_blocking(impl) + || set_non_blocking(impl, op->ec_)) { - this->get_io_service().post(bind_handler(handler, ec)); + reactor_.start_op(op_type, impl.socket_, + impl.reactor_data_, op, non_blocking); return; } } - impl.flags_ |= implementation_type::internal_non_blocking; + else + op->ec_ = boost::asio::error::bad_descriptor; } - // Start the connect operation. The socket is already marked as non-blocking - // so the connection will take place asynchronously. - boost::system::error_code ec; - if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size(), ec) == 0) + io_service_impl_.post_immediate_completion(op); + } + + // Start the asynchronous accept operation. + void start_accept_op(implementation_type& impl, + reactor_op* op, bool peer_is_open) + { + if (!peer_is_open) + start_op(impl, reactor::read_op, op, true, false); + else { - // The connect operation has finished successfully so we need to post the - // handler immediately. - this->get_io_service().post(bind_handler(handler, - boost::system::error_code())); + op->ec_ = boost::asio::error::already_open; + io_service_impl_.post_immediate_completion(op); } - else if (ec == boost::asio::error::in_progress - || ec == boost::asio::error::would_block) + } + + // Start the asynchronous connect operation. + void start_connect_op(implementation_type& impl, + reactor_op* op, const endpoint_type& peer_endpoint) + { + if (is_open(impl)) { - // The connection is happening in the background, and we need to wait - // until the socket becomes writeable. - reactor_.start_connect_op(impl.socket_, impl.reactor_data_, - connect_operation(impl.socket_, - this->get_io_service(), handler)); + if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_)) + { + if (socket_ops::connect(impl.socket_, peer_endpoint.data(), + peer_endpoint.size(), op->ec_) != 0) + { + if (op->ec_ == boost::asio::error::in_progress + || op->ec_ == boost::asio::error::would_block) + { + op->ec_ = boost::system::error_code(); + reactor_.start_op(reactor::connect_op, + impl.socket_, impl.reactor_data_, op, false); + return; + } + } + } } else - { - // The connect operation has failed, so post the handler immediately. - this->get_io_service().post(bind_handler(handler, ec)); - } + op->ec_ = boost::asio::error::bad_descriptor; + + io_service_impl_.post_immediate_completion(op); } -private: + // Determine whether the socket has been set non-blocking. + bool is_non_blocking(implementation_type& impl) const + { + return (impl.flags_ & implementation_type::non_blocking); + } + + // Set the internal non-blocking flag. + bool set_non_blocking(implementation_type& impl, + boost::system::error_code& ec) + { + ioctl_arg_type non_blocking = 1; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + return false; + impl.flags_ |= implementation_type::internal_non_blocking; + return true; + } + + // The io_service implementation used to post completions. + io_service_impl& io_service_impl_; + // The selector that performs event demultiplexing for the service. - Reactor& reactor_; + reactor& reactor_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/reactor.hpp b/3rdParty/Boost/src/boost/asio/detail/reactor.hpp new file mode 100644 index 0000000..43e432b --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/reactor.hpp @@ -0,0 +1,34 @@ +// +// reactor.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_REACTOR_HPP +#define BOOST_ASIO_DETAIL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_EPOLL) +# include +#elif defined(BOOST_ASIO_HAS_KQUEUE) +# include +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +# include +#else +# include +#endif + +#include + +#endif // BOOST_ASIO_DETAIL_REACTOR_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/reactor_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/reactor_fwd.hpp new file mode 100644 index 0000000..9ff05eb --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/reactor_fwd.hpp @@ -0,0 +1,48 @@ +// +// reactor_fwd.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_REACTOR_FWD_HPP +#define BOOST_ASIO_DETAIL_REACTOR_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_IOCP) +typedef select_reactor reactor; +#elif defined(BOOST_ASIO_HAS_EPOLL) +typedef epoll_reactor reactor; +#elif defined(BOOST_ASIO_HAS_KQUEUE) +typedef kqueue_reactor reactor; +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +typedef dev_poll_reactor reactor; +#else +typedef select_reactor reactor; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTOR_FWD_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/reactor_op.hpp b/3rdParty/Boost/src/boost/asio/detail/reactor_op.hpp new file mode 100644 index 0000000..40647ec --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/reactor_op.hpp @@ -0,0 +1,62 @@ +// +// reactor_op.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_REACTOR_OP_HPP +#define BOOST_ASIO_DETAIL_REACTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class reactor_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + boost::system::error_code ec_; + + // The number of bytes transferred, to be passed to the completion handler. + std::size_t bytes_transferred_; + + // Perform the operation. Returns true if it is finished. + bool perform() + { + return perform_func_(this); + } + +protected: + typedef bool (*perform_func_type)(reactor_op*); + + reactor_op(perform_func_type perform_func, func_type complete_func) + : operation(complete_func), + bytes_transferred_(0), + perform_func_(perform_func) + { + } + +private: + perform_func_type perform_func_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTOR_OP_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/reactor_op_queue.hpp b/3rdParty/Boost/src/boost/asio/detail/reactor_op_queue.hpp index 46f0c10..0dd5654 100644 --- a/3rdParty/Boost/src/boost/asio/detail/reactor_op_queue.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/reactor_op_queue.hpp @@ -17,14 +17,11 @@ #include -#include -#include -#include - #include -#include #include #include +#include +#include namespace boost { namespace asio { @@ -37,39 +34,21 @@ class reactor_op_queue public: // Constructor. reactor_op_queue() - : operations_(), - cancelled_operations_(0), - complete_operations_(0) + : operations_() { } // Add a new operation to the queue. Returns true if this is the only // operation for the given descriptor, in which case the reactor's event // demultiplexing function call may need to be interrupted and restarted. - template - bool enqueue_operation(Descriptor descriptor, Operation operation) + bool enqueue_operation(Descriptor descriptor, reactor_op* op) { - // Allocate and construct an object to wrap the handler. - typedef handler_alloc_traits > alloc_traits; - raw_handler_ptr raw_ptr(operation); - handler_ptr ptr(raw_ptr, descriptor, operation); - - typedef typename operation_map::iterator iterator; - typedef typename operation_map::value_type value_type; + typedef typename operations_map::iterator iterator; + typedef typename operations_map::value_type value_type; std::pair entry = - operations_.insert(value_type(descriptor, ptr.get())); - if (entry.second) - { - ptr.release(); - return true; - } - - op_base* current_op = entry.first->second; - while (current_op->next_) - current_op = current_op->next_; - current_op->next_ = ptr.release(); - - return false; + operations_.insert(value_type(descriptor, operations())); + entry.first->second.op_queue_.push(op); + return entry.second; } // Cancel all operations associated with the descriptor. Any operations @@ -77,16 +56,19 @@ public: // next time perform_cancellations is called. Returns true if any operations // were cancelled, in which case the reactor's event demultiplexing function // may need to be interrupted and restarted. - bool cancel_operations(Descriptor descriptor) + bool cancel_operations(Descriptor descriptor, op_queue& ops, + const boost::system::error_code& ec = + boost::asio::error::operation_aborted) { - typename operation_map::iterator i = operations_.find(descriptor); + typename operations_map::iterator i = operations_.find(descriptor); if (i != operations_.end()) { - op_base* last_op = i->second; - while (last_op->next_) - last_op = last_op->next_; - last_op->next_ = cancelled_operations_; - cancelled_operations_ = i->second; + while (reactor_op* op = i->second.op_queue_.front()) + { + op->ec_ = ec; + i->second.op_queue_.pop(); + ops.push(op); + } operations_.erase(i); return true; } @@ -106,79 +88,37 @@ public: return operations_.find(descriptor) != operations_.end(); } - // Perform the first operation corresponding to the descriptor. Returns true - // if there are more operations queued for the descriptor. - bool perform_operation(Descriptor descriptor, - const boost::system::error_code& result) + // Perform the operations corresponding to the descriptor. Returns true if + // there are still unfinished operations queued for the descriptor. + bool perform_operations(Descriptor descriptor, op_queue& ops) { - typename operation_map::iterator i = operations_.find(descriptor); + typename operations_map::iterator i = operations_.find(descriptor); if (i != operations_.end()) { - op_base* this_op = i->second; - i->second = this_op->next_; - this_op->next_ = complete_operations_; - complete_operations_ = this_op; - bool done = this_op->perform(result); - if (done) + while (reactor_op* op = i->second.op_queue_.front()) { - // Operation has finished. - if (i->second) + if (op->perform()) { - return true; + i->second.op_queue_.pop(); + ops.push(op); } else { - operations_.erase(i); - return false; - } - } - else - { - // Operation wants to be called again. Leave it at the front of the - // queue for this descriptor, and remove from the completed list. - complete_operations_ = this_op->next_; - this_op->next_ = i->second; - i->second = this_op; - return true; - } - } - return false; - } - - // Perform all operations corresponding to the descriptor. - void perform_all_operations(Descriptor descriptor, - const boost::system::error_code& result) - { - typename operation_map::iterator i = operations_.find(descriptor); - if (i != operations_.end()) - { - while (i->second) - { - op_base* this_op = i->second; - i->second = this_op->next_; - this_op->next_ = complete_operations_; - complete_operations_ = this_op; - bool done = this_op->perform(result); - if (!done) - { - // Operation has not finished yet, so leave at front of queue, and - // remove from the completed list. - complete_operations_ = this_op->next_; - this_op->next_ = i->second; - i->second = this_op; - return; + return true; } } operations_.erase(i); } + return false; } // Fill a descriptor set with the descriptors corresponding to each active - // operation. + // operation. The op_queue is used only when descriptors fail to be added to + // the descriptor set. template - void get_descriptors(Descriptor_Set& descriptors) + void get_descriptors(Descriptor_Set& descriptors, op_queue& ops) { - typename operation_map::iterator i = operations_.begin(); + typename operations_map::iterator i = operations_.begin(); while (i != operations_.end()) { Descriptor descriptor = i->first; @@ -186,7 +126,7 @@ public: if (!descriptors.set(descriptor)) { boost::system::error_code ec(error::fd_set_failure); - perform_all_operations(descriptor, ec); + cancel_operations(descriptor, ops, ec); } } } @@ -194,257 +134,62 @@ public: // Perform the operations corresponding to the ready file descriptors // contained in the given descriptor set. template - void perform_operations_for_descriptors(const Descriptor_Set& descriptors, - const boost::system::error_code& result) + void perform_operations_for_descriptors( + const Descriptor_Set& descriptors, op_queue& ops) { - typename operation_map::iterator i = operations_.begin(); + typename operations_map::iterator i = operations_.begin(); while (i != operations_.end()) { - typename operation_map::iterator op_iter = i++; + typename operations_map::iterator op_iter = i++; if (descriptors.is_set(op_iter->first)) { - op_base* this_op = op_iter->second; - op_iter->second = this_op->next_; - this_op->next_ = complete_operations_; - complete_operations_ = this_op; - bool done = this_op->perform(result); - if (done) - { - if (!op_iter->second) - operations_.erase(op_iter); - } - else + while (reactor_op* op = op_iter->second.op_queue_.front()) { - // Operation has not finished yet, so leave at front of queue, and - // remove from the completed list. - complete_operations_ = this_op->next_; - this_op->next_ = op_iter->second; - op_iter->second = this_op; + if (op->perform()) + { + op_iter->second.op_queue_.pop(); + ops.push(op); + } + else + { + break; + } } - } - } - } - - // Perform any pending cancels for operations. - void perform_cancellations() - { - while (cancelled_operations_) - { - op_base* this_op = cancelled_operations_; - cancelled_operations_ = this_op->next_; - this_op->next_ = complete_operations_; - complete_operations_ = this_op; - this_op->perform(boost::asio::error::operation_aborted); - } - } - // Complete all operations that are waiting to be completed. - void complete_operations() - { - while (complete_operations_) - { - op_base* next_op = complete_operations_->next_; - complete_operations_->next_ = 0; - complete_operations_->complete(); - complete_operations_ = next_op; + if (op_iter->second.op_queue_.empty()) + operations_.erase(op_iter); + } } } - // Destroy all operations owned by the queue. - void destroy_operations() + // Get all operations owned by the queue. + void get_all_operations(op_queue& ops) { - while (cancelled_operations_) - { - op_base* next_op = cancelled_operations_->next_; - cancelled_operations_->next_ = 0; - cancelled_operations_->destroy(); - cancelled_operations_ = next_op; - } - - while (complete_operations_) - { - op_base* next_op = complete_operations_->next_; - complete_operations_->next_ = 0; - complete_operations_->destroy(); - complete_operations_ = next_op; - } - - typename operation_map::iterator i = operations_.begin(); + typename operations_map::iterator i = operations_.begin(); while (i != operations_.end()) { - typename operation_map::iterator op_iter = i++; - op_base* curr_op = op_iter->second; + typename operations_map::iterator op_iter = i++; + ops.push(op_iter->second.op_queue_); operations_.erase(op_iter); - while (curr_op) - { - op_base* next_op = curr_op->next_; - curr_op->next_ = 0; - curr_op->destroy(); - curr_op = next_op; - } } } private: - // Base class for reactor operations. A function pointer is used instead of - // virtual functions to avoid the associated overhead. - class op_base - { - public: - // Get the descriptor associated with the operation. - Descriptor descriptor() const - { - return descriptor_; - } - - // Perform the operation. - bool perform(const boost::system::error_code& result) - { - result_ = result; - return perform_func_(this, result_, bytes_transferred_); - } - - // Destroy the operation and post the handler. - void complete() - { - complete_func_(this, result_, bytes_transferred_); - } - - // Destroy the operation. - void destroy() - { - destroy_func_(this); - } - - protected: - typedef bool (*perform_func_type)(op_base*, - boost::system::error_code&, std::size_t&); - typedef void (*complete_func_type)(op_base*, - const boost::system::error_code&, std::size_t); - typedef void (*destroy_func_type)(op_base*); - - // Construct an operation for the given descriptor. - op_base(perform_func_type perform_func, complete_func_type complete_func, - destroy_func_type destroy_func, Descriptor descriptor) - : perform_func_(perform_func), - complete_func_(complete_func), - destroy_func_(destroy_func), - descriptor_(descriptor), - result_(), - bytes_transferred_(0), - next_(0) - { - } - - // Prevent deletion through this type. - ~op_base() - { - } - - private: - friend class reactor_op_queue; - - // The function to be called to perform the operation. - perform_func_type perform_func_; - - // The function to be called to delete the operation and post the handler. - complete_func_type complete_func_; - - // The function to be called to delete the operation. - destroy_func_type destroy_func_; - - // The descriptor associated with the operation. - Descriptor descriptor_; - - // The result of the operation. - boost::system::error_code result_; - - // The number of bytes transferred in the operation. - std::size_t bytes_transferred_; - - // The next operation for the same file descriptor. - op_base* next_; - }; - - // Adaptor class template for operations. - template - class op - : public op_base + struct operations { - public: - // Constructor. - op(Descriptor descriptor, Operation operation) - : op_base(&op::do_perform, &op::do_complete, - &op::do_destroy, descriptor), - operation_(operation) - { - } - - // Perform the operation. - static bool do_perform(op_base* base, - boost::system::error_code& result, std::size_t& bytes_transferred) - { - return static_cast*>(base)->operation_.perform( - result, bytes_transferred); - } - - // Destroy the operation and post the handler. - static void do_complete(op_base* base, - const boost::system::error_code& result, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - typedef op this_type; - this_type* this_op(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(this_op->operation_, this_op); - - // Make a copy of the error_code and the operation so that the memory can - // be deallocated before the upcall is made. - boost::system::error_code ec(result); - Operation operation(this_op->operation_); - - // Free the memory associated with the operation. - ptr.reset(); - - // Make the upcall. - operation.complete(ec, bytes_transferred); - } - - // Destroy the operation. - static void do_destroy(op_base* base) - { - // Take ownership of the operation object. - typedef op this_type; - this_type* this_op(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(this_op->operation_, this_op); - - // A sub-object of the operation may be the true owner of the memory - // associated with the operation. Consequently, a local copy of the - // operation is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - Operation operation(this_op->operation_); - (void)operation; - - // Free the memory associated with the operation. - ptr.reset(); - } + operations() {} + operations(const operations&) {} + void operator=(const operations&) {} - private: - Operation operation_; + // The operations waiting on the desccriptor. + op_queue op_queue_; }; // The type for a map of operations. - typedef hash_map operation_map; + typedef hash_map operations_map; // The operations that are currently executing asynchronously. - operation_map operations_; - - // The list of operations that have been cancelled. - op_base* cancelled_operations_; - - // The list of operations waiting to be completed. - op_base* complete_operations_; + operations_map operations_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/resolver_service.hpp b/3rdParty/Boost/src/boost/asio/detail/resolver_service.hpp index 3270cd6..f9b7a98 100644 --- a/3rdParty/Boost/src/boost/asio/detail/resolver_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/resolver_service.hpp @@ -26,9 +26,13 @@ #include #include +#include +#include #include +#include #include #include +#include #include #include #include @@ -79,17 +83,20 @@ public: typedef typename Protocol::endpoint endpoint_type; // The query type. - typedef typename Protocol::resolver_query query_type; + typedef boost::asio::ip::basic_resolver_query query_type; // The iterator type. - typedef typename Protocol::resolver_iterator iterator_type; + typedef boost::asio::ip::basic_resolver_iterator iterator_type; // Constructor. resolver_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< resolver_service >(io_service), mutex_(), + io_service_impl_(boost::asio::use_service(io_service)), work_io_service_(new boost::asio::io_service), + work_io_service_impl_(boost::asio::use_service< + io_service_impl>(*work_io_service_)), work_(new boost::asio::io_service::work(*work_io_service_)), work_thread_(0) { @@ -143,7 +150,7 @@ public: std::string service_name = query.service_name(); boost::asio::detail::addrinfo_type hints = query.hints(); - socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0, + socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0, service_name.c_str(), &hints, &address_info, ec); auto_addrinfo auto_address_info(address_info); @@ -154,54 +161,84 @@ public: } template - class resolve_query_handler + class resolve_op + : public operation { public: - resolve_query_handler(implementation_type impl, const query_type& query, - boost::asio::io_service& io_service, Handler handler) - : impl_(impl), + resolve_op(implementation_type impl, const query_type& query, + io_service_impl& io_service_impl, Handler handler) + : operation(&resolve_op::do_complete), + impl_(impl), query_(query), - io_service_(io_service), - work_(io_service), + io_service_impl_(io_service_impl), handler_(handler) { } - void operator()() + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - // Check if the operation has been cancelled. - if (impl_.expired()) + // Take ownership of the operation object. + resolve_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + if (owner) { - iterator_type iterator; - io_service_.post(boost::asio::detail::bind_handler(handler_, - boost::asio::error::operation_aborted, iterator)); - return; + if (owner != &o->io_service_impl_) + { + // The operation is being run on the worker io_service. Time to + // perform the resolver operation. + + if (o->impl_.expired()) + { + // THe operation has been cancelled. + o->ec_ = boost::asio::error::operation_aborted; + } + else + { + // Perform the blocking host resolution operation. + boost::asio::detail::addrinfo_type* address_info = 0; + std::string host_name = o->query_.host_name(); + std::string service_name = o->query_.service_name(); + boost::asio::detail::addrinfo_type hints = o->query_.hints(); + socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0, + service_name.c_str(), &hints, &address_info, o->ec_); + auto_addrinfo auto_address_info(address_info); + o->iter_ = iterator_type::create( + address_info, host_name, service_name); + } + + o->io_service_impl_.post_deferred_completion(o); + ptr.release(); + } + else + { + // The operation has been returned to the main io_serice. The + // completion handler is ready to be delivered. + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->iter_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } - - // Perform the blocking host resolution operation. - boost::asio::detail::addrinfo_type* address_info = 0; - std::string host_name = query_.host_name(); - std::string service_name = query_.service_name(); - boost::asio::detail::addrinfo_type hints = query_.hints(); - boost::system::error_code ec; - socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0, - service_name.c_str(), &hints, &address_info, ec); - auto_addrinfo auto_address_info(address_info); - - // Invoke the handler and pass the result. - iterator_type iterator; - if (!ec) - iterator = iterator_type::create(address_info, host_name, service_name); - io_service_.post(boost::asio::detail::bind_handler( - handler_, ec, iterator)); } private: boost::weak_ptr impl_; query_type query_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; + io_service_impl& io_service_impl_; Handler handler_; + boost::system::error_code ec_; + iterator_type iter_; }; // Asynchronously resolve a query to a list of entries. @@ -209,12 +246,19 @@ public: void async_resolve(implementation_type& impl, const query_type& query, Handler handler) { + // Allocate and construct an operation to wrap the handler. + typedef resolve_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, + impl, query, io_service_impl_, handler); + if (work_io_service_) { start_work_thread(); - work_io_service_->post( - resolve_query_handler( - impl, query, this->get_io_service(), handler)); + io_service_impl_.work_started(); + work_io_service_impl_.post_immediate_completion(ptr.get()); + ptr.release(); } } @@ -243,61 +287,89 @@ public: } template - class resolve_endpoint_handler + class resolve_endpoint_op + : public operation { public: - resolve_endpoint_handler(implementation_type impl, - const endpoint_type& endpoint, boost::asio::io_service& io_service, - Handler handler) - : impl_(impl), - endpoint_(endpoint), - io_service_(io_service), - work_(io_service), + resolve_endpoint_op(implementation_type impl, const endpoint_type& ep, + io_service_impl& io_service_impl, Handler handler) + : operation(&resolve_endpoint_op::do_complete), + impl_(impl), + ep_(ep), + io_service_impl_(io_service_impl), handler_(handler) { } - void operator()() + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - // Check if the operation has been cancelled. - if (impl_.expired()) - { - iterator_type iterator; - io_service_.post(boost::asio::detail::bind_handler(handler_, - boost::asio::error::operation_aborted, iterator)); - return; - } - + // Take ownership of the operation object. + resolve_endpoint_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); - // First try resolving with the service name. If that fails try resolving - // but allow the service to be returned as a number. - char host_name[NI_MAXHOST]; - char service_name[NI_MAXSERV]; - int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; - boost::system::error_code ec; - socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); - if (ec) + if (owner) { - flags |= NI_NUMERICSERV; - socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); + if (owner != &o->io_service_impl_) + { + // The operation is being run on the worker io_service. Time to + // perform the resolver operation. + + if (o->impl_.expired()) + { + // THe operation has been cancelled. + o->ec_ = boost::asio::error::operation_aborted; + } + else + { + // Perform the blocking endoint resolution operation. + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + int flags = o->ep_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; + socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(), + host_name, NI_MAXHOST, service_name, + NI_MAXSERV, flags, o->ec_); + if (o->ec_) + { + flags |= NI_NUMERICSERV; + socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(), + host_name, NI_MAXHOST, service_name, + NI_MAXSERV, flags, o->ec_); + } + o->iter_ = iterator_type::create(o->ep_, host_name, service_name); + } + + o->io_service_impl_.post_deferred_completion(o); + ptr.release(); + } + else + { + // The operation has been returned to the main io_serice. The + // completion handler is ready to be delivered. + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, o->ec_, o->iter_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } - - // Invoke the handler and pass the result. - iterator_type iterator; - if (!ec) - iterator = iterator_type::create(endpoint_, host_name, service_name); - io_service_.post(boost::asio::detail::bind_handler( - handler_, ec, iterator)); } private: boost::weak_ptr impl_; - endpoint_type endpoint_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; + endpoint_type ep_; + io_service_impl& io_service_impl_; Handler handler_; + boost::system::error_code ec_; + iterator_type iter_; }; // Asynchronously resolve an endpoint to a list of entries. @@ -305,12 +377,19 @@ public: void async_resolve(implementation_type& impl, const endpoint_type& endpoint, Handler handler) { + // Allocate and construct an operation to wrap the handler. + typedef resolve_endpoint_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, + impl, endpoint, io_service_impl_, handler); + if (work_io_service_) { start_work_thread(); - work_io_service_->post( - resolve_endpoint_handler( - impl, endpoint, this->get_io_service(), handler)); + io_service_impl_.work_started(); + work_io_service_impl_.post_immediate_completion(ptr.get()); + ptr.release(); } } @@ -340,9 +419,15 @@ private: // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; + // The io_service implementation used to post completions. + io_service_impl& io_service_impl_; + // Private io_service used for performing asynchronous host resolution. boost::scoped_ptr work_io_service_; + // The work io_service implementation used to post completions. + io_service_impl& work_io_service_impl_; + // Work for the private io_service to perform. boost::scoped_ptr work_; diff --git a/3rdParty/Boost/src/boost/asio/detail/select_reactor.hpp b/3rdParty/Boost/src/boost/asio/detail/select_reactor.hpp index ba8b5d3..91030e9 100644 --- a/3rdParty/Boost/src/boost/asio/detail/select_reactor.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/select_reactor.hpp @@ -22,9 +22,6 @@ #include #include #include -#include -#include -#include #include #include @@ -32,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -39,9 +38,11 @@ #include #include #include -#include #include -#include +#include +#include +#include +#include namespace boost { namespace asio { @@ -52,6 +53,14 @@ class select_reactor : public boost::asio::detail::service_base > { public: +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + enum { read_op = 0, write_op = 1, except_op = 2, + max_select_ops = 3, connect_op = 3, max_ops = 4 }; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + enum { read_op = 0, write_op = 1, except_op = 2, + max_select_ops = 3, connect_op = 1, max_ops = 3 }; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Per-descriptor data. struct per_descriptor_data { @@ -61,13 +70,9 @@ public: select_reactor(boost::asio::io_service& io_service) : boost::asio::detail::service_base< select_reactor >(io_service), + io_service_(use_service(io_service)), mutex_(), - select_in_progress_(false), interrupter_(), - read_op_queue_(), - write_op_queue_(), - except_op_queue_(), - pending_cancellations_(), stop_thread_(false), thread_(0), shutdown_(false) @@ -94,31 +99,29 @@ public: stop_thread_ = true; lock.unlock(); - if (thread_) + if (Own_Thread) { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } } - read_op_queue_.destroy_operations(); - write_op_queue_.destroy_operations(); - except_op_queue_.destroy_operations(); + op_queue ops; - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->destroy_timers(); - timer_queues_.clear(); + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); } // Initialise the task, but only if the reactor is not in its own thread. void init_task() { - if (!Own_Thread) - { - typedef task_io_service > task_io_service_type; - use_service(this->get_io_service()).init_task(); - } + io_service_.init_task(); } // Register a socket with the reactor. Returns 0 on success, system error @@ -128,111 +131,17 @@ public: return 0; } - // Start a new read operation. The handler object will be invoked when the - // given descriptor is ready to be read, or an error has occurred. - template - void start_read_op(socket_type descriptor, per_descriptor_data&, - Handler handler, bool /*allow_speculative_read*/ = true) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - if (read_op_queue_.enqueue_operation(descriptor, handler)) - interrupter_.interrupt(); - } - - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready to be written, or an error has occurred. - template - void start_write_op(socket_type descriptor, per_descriptor_data&, - Handler handler, bool /*allow_speculative_write*/ = true) + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (!shutdown_) - if (write_op_queue_.enqueue_operation(descriptor, handler)) - interrupter_.interrupt(); - } - - // Start a new exception operation. The handler object will be invoked when - // the given descriptor has exception information, or an error has occurred. - template - void start_except_op(socket_type descriptor, - per_descriptor_data&, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - if (except_op_queue_.enqueue_operation(descriptor, handler)) - interrupter_.interrupt(); - } - - // Wrapper for connect handlers to enable the handler object to be placed - // in both the write and the except operation queues, but ensure that only - // one of the handlers is called. - template - class connect_handler_wrapper - { - public: - connect_handler_wrapper(socket_type descriptor, - boost::shared_ptr completed, - select_reactor& reactor, Handler handler) - : descriptor_(descriptor), - completed_(completed), - reactor_(reactor), - handler_(handler) { - } - - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) - { - // Check whether one of the handlers has already been called. If it has, - // then we don't want to do anything in this handler. - if (*completed_) - { - completed_.reset(); // Indicate that this handler should not complete. - return true; - } - - // Cancel the other reactor operation for the connection. - *completed_ = true; - reactor_.enqueue_cancel_ops_unlocked(descriptor_); - - // Call the contained handler. - return handler_.perform(ec, bytes_transferred); - } - - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - if (completed_.get()) - handler_.complete(ec, bytes_transferred); - } - - private: - socket_type descriptor_; - boost::shared_ptr completed_; - select_reactor& reactor_; - Handler handler_; - }; - - // Start new write and exception operations. The handler object will be - // invoked when the given descriptor is ready for writing or has exception - // information available, or an error has occurred. The handler will be called - // only once. - template - void start_connect_op(socket_type descriptor, - per_descriptor_data&, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - boost::shared_ptr completed(new bool(false)); - connect_handler_wrapper wrapped_handler( - descriptor, completed, *this, handler); - bool interrupt = write_op_queue_.enqueue_operation( - descriptor, wrapped_handler); - interrupt = except_op_queue_.enqueue_operation( - descriptor, wrapped_handler) || interrupt; - if (interrupt) + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) interrupter_.interrupt(); } } @@ -243,17 +152,7 @@ public: void cancel_ops(socket_type descriptor, per_descriptor_data&) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor); - } - - // Enqueue cancellation of all operations associated with the given - // descriptor. The handlers associated with the descriptor will be invoked - // with the operation_aborted error. This function does not acquire the - // select_reactor's mutex, and so should only be used when the reactor lock is - // already held. - void enqueue_cancel_ops_unlocked(socket_type descriptor) - { - pending_cancellations_.push_back(descriptor); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); } // Cancel any operations that are running against the descriptor and remove @@ -261,7 +160,7 @@ public: void close_descriptor(socket_type descriptor, per_descriptor_data&) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); } // Add a new timer queue to the reactor. @@ -269,7 +168,7 @@ public: void add_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.push_back(&timer_queue); + timer_queues_.insert(&timer_queue); } // Remove a timer queue from the reactor. @@ -277,252 +176,186 @@ public: void remove_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - if (timer_queues_[i] == &timer_queue) - { - timer_queues_.erase(timer_queues_.begin() + i); - return; - } - } + timer_queues_.erase(&timer_queue); } - // Schedule a timer in the given timer queue to expire at the specified - // absolute time. The handler object will be invoked when the timer expires. - template + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, Handler handler, void* token) + const typename Time_Traits::time_type& time, timer_op* op, void* token) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (!shutdown_) - if (timer_queue.enqueue_timer(time, handler, token)) + { + bool earliest = timer_queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) interrupter_.interrupt(); + } } - // Cancel the timer associated with the given token. Returns the number of - // handlers that have been posted or dispatched. + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& timer_queue, void* token) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); + op_queue ops; + std::size_t n = timer_queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); return n; } -private: - friend class task_io_service >; - // Run select once until interrupted or events are ready to be dispatched. - void run(bool block) + void run(bool block, op_queue& ops) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - // Dispatch any operation cancellations that were made while the select - // loop was not running. - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); - // Check if the thread is supposed to stop. - if (stop_thread_) + if (Own_Thread) + if (stop_thread_) + return; + + // Set up the descriptor sets. + fd_set_adapter fds[max_select_ops]; + fds[read_op].set(interrupter_.read_descriptor()); + socket_type max_fd = 0; + bool have_work_to_do = !timer_queues_.all_empty(); + for (int i = 0; i < max_select_ops; ++i) { - complete_operations_and_timers(lock); - return; + have_work_to_do = have_work_to_do || !op_queue_[i].empty(); + op_queue_[i].get_descriptors(fds[i], ops); + if (fds[i].max_descriptor() > max_fd) + max_fd = fds[i].max_descriptor(); } +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); + op_queue_[connect_op].get_descriptors(fds[write_op], ops); + if (fds[write_op].max_descriptor() > max_fd) + max_fd = fds[write_op].max_descriptor(); + op_queue_[connect_op].get_descriptors(fds[except_op], ops); + if (fds[except_op].max_descriptor() > max_fd) + max_fd = fds[except_op].max_descriptor(); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // We can return immediately if there's no work to do and the reactor is // not supposed to block. - if (!block && read_op_queue_.empty() && write_op_queue_.empty() - && except_op_queue_.empty() && all_timer_queues_are_empty()) - { - complete_operations_and_timers(lock); + if (!block && !have_work_to_do) return; - } - // Set up the descriptor sets. - fd_set_adapter read_fds; - read_fds.set(interrupter_.read_descriptor()); - read_op_queue_.get_descriptors(read_fds); - fd_set_adapter write_fds; - write_op_queue_.get_descriptors(write_fds); - fd_set_adapter except_fds; - except_op_queue_.get_descriptors(except_fds); - socket_type max_fd = read_fds.max_descriptor(); - if (write_fds.max_descriptor() > max_fd) - max_fd = write_fds.max_descriptor(); - if (except_fds.max_descriptor() > max_fd) - max_fd = except_fds.max_descriptor(); - - // Block on the select call without holding the lock so that new - // operations can be started while the call is executing. + // Determine how long to block while waiting for events. timeval tv_buf = { 0, 0 }; timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; - select_in_progress_ = true; + lock.unlock(); + + // Block on the select call until descriptors become ready. boost::system::error_code ec; int retval = socket_ops::select(static_cast(max_fd + 1), - read_fds, write_fds, except_fds, tv, ec); - lock.lock(); - select_in_progress_ = false; + fds[read_op], fds[write_op], fds[except_op], tv, ec); // Reset the interrupter. - if (retval > 0 && read_fds.is_set(interrupter_.read_descriptor())) + if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor())) interrupter_.reset(); + lock.lock(); + // Dispatch all ready operations. if (retval > 0) { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + op_queue_[connect_op].perform_operations_for_descriptors( + fds[except_op], ops); + op_queue_[connect_op].perform_operations_for_descriptors( + fds[write_op], ops); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. - except_op_queue_.perform_operations_for_descriptors( - except_fds, boost::system::error_code()); - read_op_queue_.perform_operations_for_descriptors( - read_fds, boost::system::error_code()); - write_op_queue_.perform_operations_for_descriptors( - write_fds, boost::system::error_code()); - except_op_queue_.perform_cancellations(); - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); + for (int i = max_select_ops - 1; i >= 0; --i) + op_queue_[i].perform_operations_for_descriptors(fds[i], ops); } - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); - } - - // Issue any pending cancellations. - for (size_t i = 0; i < pending_cancellations_.size(); ++i) - cancel_ops_unlocked(pending_cancellations_[i]); - pending_cancellations_.clear(); + timer_queues_.get_ready_timers(ops); + } - complete_operations_and_timers(lock); + // Interrupt the select loop. + void interrupt() + { + interrupter_.interrupt(); } +private: // Run the select loop in the thread. void run_thread() { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) + if (Own_Thread) { - lock.unlock(); - run(true); - lock.lock(); + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + op_queue ops; + run(true, ops); + io_service_.post_deferred_completions(ops); + lock.lock(); + } } } // Entry point for the select loop thread. static void call_run_thread(select_reactor* reactor) { - reactor->run_thread(); - } - - // Interrupt the select loop. - void interrupt() - { - interrupter_.interrupt(); - } - - // Check if all timer queues are empty. - bool all_timer_queues_are_empty() const - { - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - if (!timer_queues_[i]->empty()) - return false; - return true; + if (Own_Thread) + { + reactor->run_thread(); + } } // Get the timeout value for the select call. timeval* get_timeout(timeval& tv) { - if (all_timer_queues_are_empty()) - return 0; - // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. - boost::posix_time::time_duration minimum_wait_duration - = boost::posix_time::minutes(5); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - boost::posix_time::time_duration wait_duration - = timer_queues_[i]->wait_duration(); - if (wait_duration < minimum_wait_duration) - minimum_wait_duration = wait_duration; - } - - if (minimum_wait_duration > boost::posix_time::time_duration()) - { - tv.tv_sec = minimum_wait_duration.total_seconds(); - tv.tv_usec = minimum_wait_duration.total_microseconds() % 1000000; - } - else - { - tv.tv_sec = 0; - tv.tv_usec = 0; - } - + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; return &tv; } - // Cancel all operations associated with the given descriptor. The do_cancel - // function of the handler objects will be invoked. This function does not - // acquire the select_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor) + // Cancel all operations associated with the given descriptor. This function + // does not acquire the select_reactor's mutex. + void cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) { - bool interrupt = read_op_queue_.cancel_operations(descriptor); - interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; - interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; - if (interrupt) + bool need_interrupt = false; + op_queue ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + io_service_.post_deferred_completions(ops); + if (need_interrupt) interrupter_.interrupt(); } - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void complete_operations_and_timers( - boost::asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.complete_operations(); - write_op_queue_.complete_operations(); - except_op_queue_.complete_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->complete_timers(); - } + // The io_service implementation used to post completions. + io_service_impl& io_service_; // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; - // Whether the select loop is currently running or not. - bool select_in_progress_; - // The interrupter is used to break a blocking select call. select_interrupter interrupter_; - // The queue of read operations. - reactor_op_queue read_op_queue_; - - // The queue of write operations. - reactor_op_queue write_op_queue_; - - // The queue of exception operations. - reactor_op_queue except_op_queue_; + // The queues of read, write and except operations. + reactor_op_queue op_queue_[max_ops]; // The timer queues. - std::vector timer_queues_; - - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - - // The descriptors that are pending cancellation. - std::vector pending_cancellations_; + timer_queue_set timer_queues_; // Does the reactor loop thread need to stop. bool stop_thread_; diff --git a/3rdParty/Boost/src/boost/asio/detail/service_registry.hpp b/3rdParty/Boost/src/boost/asio/detail/service_registry.hpp index b648939..e640ec8 100644 --- a/3rdParty/Boost/src/boost/asio/detail/service_registry.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/service_registry.hpp @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -80,7 +79,7 @@ public: while (first_service_) { boost::asio::io_service::service* next_service = first_service_->next_; - delete first_service_; + destroy(first_service_); first_service_ = next_service; } } @@ -91,14 +90,105 @@ public: template Service& use_service() { + boost::asio::io_service::service::key key; + init_key(key, Service::id); + factory_type factory = &service_registry::create; + return *static_cast(do_use_service(key, factory)); + } + + // Add a service object. Returns false on error, in which case ownership of + // the object is retained by the caller. + template + bool add_service(Service* new_service) + { + boost::asio::io_service::service::key key; + init_key(key, Service::id); + return do_add_service(key, new_service); + } + + // Check whether a service object of the specified type already exists. + template + bool has_service() const + { + boost::asio::io_service::service::key key; + init_key(key, Service::id); + return do_has_service(key); + } + +private: + // Initialise a service's key based on its id. + void init_key(boost::asio::io_service::service::key& key, + const boost::asio::io_service::id& id) + { + key.type_info_ = 0; + key.id_ = &id; + } + +#if !defined(BOOST_ASIO_NO_TYPEID) + // Initialise a service's key based on its id. + template + void init_key(boost::asio::io_service::service::key& key, + const boost::asio::detail::service_id& /*id*/) + { + key.type_info_ = &typeid(typeid_wrapper); + key.id_ = 0; + } +#endif // !defined(BOOST_ASIO_NO_TYPEID) + + // Check if a service matches the given id. + static bool keys_match( + const boost::asio::io_service::service::key& key1, + const boost::asio::io_service::service::key& key2) + { + if (key1.id_ && key2.id_) + if (key1.id_ == key2.id_) + return true; + if (key1.type_info_ && key2.type_info_) + if (*key1.type_info_ == *key2.type_info_) + return true; + return false; + } + + // The type of a factory function used for creating a service instance. + typedef boost::asio::io_service::service* + (*factory_type)(boost::asio::io_service&); + + // Factory function for creating a service instance. + template + static boost::asio::io_service::service* create( + boost::asio::io_service& owner) + { + return new Service(owner); + } + + // Destroy a service instance. + static void destroy(boost::asio::io_service::service* service) + { + delete service; + } + + // Helper class to manage service pointers. + struct auto_service_ptr + { + boost::asio::io_service::service* ptr_; + ~auto_service_ptr() { destroy(ptr_); } + }; + + // Get the service object corresponding to the specified service key. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. + boost::asio::io_service::service* do_use_service( + const boost::asio::io_service::service::key& key, + factory_type factory) + { boost::asio::detail::mutex::scoped_lock lock(mutex_); - // First see if there is an existing service object for the given type. + // First see if there is an existing service object with the given key. boost::asio::io_service::service* service = first_service_; while (service) { - if (service_id_matches(*service, Service::id)) - return *static_cast(service); + if (keys_match(service->key_, key)) + return service; service = service->next_; } @@ -106,9 +196,8 @@ public: // at this time to allow for nested calls into this function from the new // service's constructor. lock.unlock(); - std::auto_ptr new_service(new Service(owner_)); - init_service_id(*new_service, Service::id); - Service& new_service_ref = *new_service; + auto_service_ptr new_service = { factory(owner_) }; + new_service.ptr_->key_ = key; lock.lock(); // Check that nobody else created another service object of the same type @@ -116,52 +205,52 @@ public: service = first_service_; while (service) { - if (service_id_matches(*service, Service::id)) - return *static_cast(service); + if (keys_match(service->key_, key)) + return service; service = service->next_; } // Service was successfully initialised, pass ownership to registry. - new_service->next_ = first_service_; - first_service_ = new_service.release(); - - return new_service_ref; + new_service.ptr_->next_ = first_service_; + first_service_ = new_service.ptr_; + new_service.ptr_ = 0; + return first_service_; } // Add a service object. Returns false on error, in which case ownership of // the object is retained by the caller. - template - bool add_service(Service* new_service) + bool do_add_service( + const boost::asio::io_service::service::key& key, + boost::asio::io_service::service* new_service) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - // Check if there is an existing service object for the given type. + // Check if there is an existing service object with the given key. boost::asio::io_service::service* service = first_service_; while (service) { - if (service_id_matches(*service, Service::id)) + if (keys_match(service->key_, key)) return false; service = service->next_; } // Take ownership of the service object. - init_service_id(*new_service, Service::id); + new_service->key_ = key; new_service->next_ = first_service_; first_service_ = new_service; return true; } - // Check whether a service object of the specified type already exists. - template - bool has_service() const + // Check whether a service object with the specified key already exists. + bool do_has_service(const boost::asio::io_service::service::key& key) const { boost::asio::detail::mutex::scoped_lock lock(mutex_); boost::asio::io_service::service* service = first_service_; while (service) { - if (service_id_matches(*service, Service::id)) + if (keys_match(service->key_, key)) return true; service = service->next_; } @@ -169,46 +258,6 @@ public: return false; } -private: - // Set a service's id. - void init_service_id(boost::asio::io_service::service& service, - const boost::asio::io_service::id& id) - { - service.type_info_ = 0; - service.id_ = &id; - } - -#if !defined(BOOST_ASIO_NO_TYPEID) - // Set a service's id. - template - void init_service_id(boost::asio::io_service::service& service, - const boost::asio::detail::service_id& /*id*/) - { - service.type_info_ = &typeid(typeid_wrapper); - service.id_ = 0; - } -#endif // !defined(BOOST_ASIO_NO_TYPEID) - - // Check if a service matches the given id. - static bool service_id_matches( - const boost::asio::io_service::service& service, - const boost::asio::io_service::id& id) - { - return service.id_ == &id; - } - -#if !defined(BOOST_ASIO_NO_TYPEID) - // Check if a service matches the given id. - template - static bool service_id_matches( - const boost::asio::io_service::service& service, - const boost::asio::detail::service_id& /*id*/) - { - return service.type_info_ != 0 - && *service.type_info_ == typeid(typeid_wrapper); - } -#endif // !defined(BOOST_ASIO_NO_TYPEID) - // Mutex to protect access to internal data. mutable boost::asio::detail::mutex mutex_; diff --git a/3rdParty/Boost/src/boost/asio/detail/signal_blocker.hpp b/3rdParty/Boost/src/boost/asio/detail/signal_blocker.hpp index db11fe4..0197e04 100644 --- a/3rdParty/Boost/src/boost/asio/detail/signal_blocker.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/signal_blocker.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) # include @@ -35,7 +35,7 @@ namespace boost { namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) typedef null_signal_blocker signal_blocker; #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef win_signal_blocker signal_blocker; diff --git a/3rdParty/Boost/src/boost/asio/detail/socket_types.hpp b/3rdParty/Boost/src/boost/asio/detail/socket_types.hpp index 7395ee4..1009164 100644 --- a/3rdParty/Boost/src/boost/asio/detail/socket_types.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/socket_types.hpp @@ -68,13 +68,15 @@ # define WIN32_LEAN_AND_MEAN # endif // !defined(WIN32_LEAN_AND_MEAN) # endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(BOOST_ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(BOOST_ASIO_NO_NOMINMAX) # if defined(__CYGWIN__) # if !defined(__USE_W32_SOCKETS) # error You must add -D__USE_W32_SOCKETS to your compiler options. # endif // !defined(__USE_W32_SOCKETS) -# if !defined(NOMINMAX) -# define NOMINMAX 1 -# endif // !defined(NOMINMAX) # endif // defined(__CYGWIN__) # include # include diff --git a/3rdParty/Boost/src/boost/asio/detail/solaris_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/solaris_fenced_block.hpp new file mode 100644 index 0000000..be9803e --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/solaris_fenced_block.hpp @@ -0,0 +1,59 @@ +// +// solaris_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOLARIS_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(__sun) + +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class solaris_fenced_block + : private noncopyable +{ +public: + // Constructor. + solaris_fenced_block() + { + membar_consumer(); + } + + // Destructor. + ~solaris_fenced_block() + { + membar_producer(); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(__sun) + +#include + +#endif // BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/strand_service.hpp b/3rdParty/Boost/src/boost/asio/detail/strand_service.hpp index b228cec..d6b45b1 100644 --- a/3rdParty/Boost/src/boost/asio/detail/strand_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/strand_service.hpp @@ -18,19 +18,19 @@ #include #include -#include -#include #include #include #include #include -#include #include +#include +#include #include #include #include -#include +#include +#include #include namespace boost { @@ -41,252 +41,45 @@ namespace detail { class strand_service : public boost::asio::detail::service_base { +private: + struct on_do_complete_exit; + struct on_dispatch_exit; + public: - class handler_base; - class invoke_current_handler; - class post_next_waiter_on_exit; // The underlying implementation of a strand. class strand_impl + : public operation { public: strand_impl() - : current_handler_(0), - first_waiter_(0), - last_waiter_(0) + : operation(&strand_service::do_complete), + count_(0) { } 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; + friend struct on_do_complete_exit; + friend struct on_dispatch_exit; // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; - // 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 - }; - - friend class strand_impl; - - typedef 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; - } + // The count of handlers in the strand, including the upcall (if any). + std::size_t count_; - private: - strand_service& service_impl_; - implementation_type& impl_; - bool cancelled_; + // The handlers waiting on the strand. + op_queue queue_; }; - // Class template for a waiter. - template - class handler_wrapper - : public handler_base - { - public: - handler_wrapper(Handler handler) - : handler_base(&handler_wrapper::do_invoke, - &handler_wrapper::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 this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr 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::context ctx(impl); - - // 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 this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr 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_; - }; + typedef strand_impl* implementation_type; // Construct a new strand service for the specified io_service. explicit strand_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base(io_service), + io_service_(boost::asio::use_service(io_service)), mutex_(), salt_(0) { @@ -295,37 +88,13 @@ public: // Destroy all user-defined handler objects owned by the service. void shutdown_service() { - // Construct a list of all handlers to be destroyed. + op_queue ops; + boost::asio::detail::mutex::scoped_lock lock(mutex_); - handler_base* first_handler = 0; + for (std::size_t i = 0; i < num_implementations; ++i) - { if (strand_impl* impl = implementations_[i].get()) - { - 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; - } - } - } - - // Destroy all handlers without holding the lock. - lock.unlock(); - while (first_handler) - { - handler_base* next = first_handler->next_; - first_handler->destroy(); - first_handler = next; - } + ops.push(impl->queue_); } // Construct a new strand implementation. @@ -352,45 +121,54 @@ public: template void dispatch(implementation_type& impl, Handler handler) { + // If we are already in the strand then the handler can run immediately. if (call_stack::contains(impl)) { + boost::asio::detail::fenced_block b; boost_asio_handler_invoke_helpers::invoke(handler, handler); + return; } - else + + // Allocate and construct an object to wrap the handler. + typedef completion_handler value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + // If we are running inside the io_service, and no other handler is queued + // or running, then the handler can run immediately. + bool can_dispatch = call_stack::contains(&io_service_); + impl->mutex_.lock(); + bool first = (++impl->count_ == 1); + if (can_dispatch && first) { - // Allocate and construct an object to wrap the handler. - typedef handler_wrapper value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr 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(); - } + // Immediate invocation is allowed. + impl->mutex_.unlock(); + + // Memory must be releaesed before any upcall is made. + ptr.reset(); + + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_dispatch_exit on_exit = { &io_service_, impl }; + (void)on_exit; + + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + return; } + + // Immediate invocation is not allowed, so enqueue for later. + impl->queue_.push(ptr.get()); + impl->mutex_.unlock(); + ptr.release(); + + // The first handler to be enqueued is responsible for scheduling the + // strand. + if (first) + io_service_.post_immediate_completion(impl); } // Request the io_service to invoke the given handler and return immediately. @@ -398,40 +176,85 @@ public: void post(implementation_type& impl, Handler handler) { // Allocate and construct an object to wrap the handler. - typedef handler_wrapper value_type; + typedef completion_handler value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, handler); - boost::asio::detail::mutex::scoped_lock lock(impl->mutex_); + // Add the handler to the queue. + impl->mutex_.lock(); + bool first = (++impl->count_ == 1); + impl->queue_.push(ptr.get()); + impl->mutex_.unlock(); + ptr.release(); + + // The first handler to be enqueue is responsible for scheduling the strand. + if (first) + io_service_.post_immediate_completion(impl); + } + +private: + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + if (owner) + { + strand_impl* impl = static_cast(base); + + // Get the next handler to be executed. + impl->mutex_.lock(); + operation* o = impl->queue_.front(); + impl->queue_.pop(); + impl->mutex_.unlock(); + + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_do_complete_exit on_exit = { owner, impl }; + (void)on_exit; + + o->complete(*owner); + } + } + + // Helper class to re-post the strand on exit. + struct on_do_complete_exit + { + io_service_impl* owner_; + strand_impl* impl_; - if (impl->current_handler_ == 0) + ~on_do_complete_exit() { - // 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)); + impl_->mutex_.lock(); + bool more_handlers = (--impl_->count_ > 0); + impl_->mutex_.unlock(); + + if (more_handlers) + owner_->post_immediate_completion(impl_); } - else + }; + + // Helper class to re-post the strand on exit. + struct on_dispatch_exit + { + io_service_impl* io_service_; + strand_impl* impl_; + + ~on_dispatch_exit() { - // 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(); + impl_->mutex_.lock(); + bool more_handlers = (--impl_->count_ > 0); + impl_->mutex_.unlock(); + + if (more_handlers) + io_service_->post_immediate_completion(impl_); } - } + }; + + // The io_service implementation used to post completions. + io_service_impl& io_service_; -private: // Mutex to protect access to the array of implementations. boost::asio::detail::mutex mutex_; diff --git a/3rdParty/Boost/src/boost/asio/detail/task_io_service.hpp b/3rdParty/Boost/src/boost/asio/detail/task_io_service.hpp index ddfea72..f6de370 100644 --- a/3rdParty/Boost/src/boost/asio/detail/task_io_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/task_io_service.hpp @@ -15,21 +15,25 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#if defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE) -#include -#else // defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE) - #include #include #include +#include #include +#include #include #include -#include #include +#include #include #include +#include + +#include +#include +#include +#include namespace boost { namespace asio { @@ -40,6 +44,8 @@ class task_io_service : public boost::asio::detail::service_base > { public: + typedef task_io_service_operation operation; + // Constructor. task_io_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base >(io_service), @@ -65,12 +71,12 @@ public: lock.unlock(); // Destroy handler objects. - while (!handler_queue_.empty()) + while (!op_queue_.empty()) { - handler_queue::handler* h = handler_queue_.front(); - handler_queue_.pop(); - if (h != &task_handler_) - h->destroy(); + operation* o = op_queue_.front(); + op_queue_.pop(); + if (o != &task_operation_) + o->destroy(); } // Reset to initial state. @@ -84,14 +90,21 @@ public: if (!shutdown_ && !task_) { task_ = &use_service(this->get_io_service()); - handler_queue_.push(&task_handler_); - interrupt_one_idle_thread(lock); + op_queue_.push(&task_operation_); + wake_one_thread_and_unlock(lock); } } // Run the event loop until interrupted or no more work. size_t run(boost::system::error_code& ec) { + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + typename call_stack::context ctx(this); idle_thread_info this_idle_thread; @@ -100,7 +113,7 @@ public: boost::asio::detail::mutex::scoped_lock lock(mutex_); size_t n = 0; - while (do_one(lock, &this_idle_thread, ec)) + for (; do_one(lock, &this_idle_thread); lock.lock()) if (n != (std::numeric_limits::max)()) ++n; return n; @@ -109,6 +122,13 @@ public: // Run until interrupted or one operation is performed. size_t run_one(boost::system::error_code& ec) { + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + typename call_stack::context ctx(this); idle_thread_info this_idle_thread; @@ -116,18 +136,25 @@ public: boost::asio::detail::mutex::scoped_lock lock(mutex_); - return do_one(lock, &this_idle_thread, ec); + return do_one(lock, &this_idle_thread); } // Poll for operations without blocking. size_t poll(boost::system::error_code& ec) { + if (outstanding_work_ == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + typename call_stack::context ctx(this); boost::asio::detail::mutex::scoped_lock lock(mutex_); size_t n = 0; - while (do_one(lock, 0, ec)) + for (; do_one(lock, 0); lock.lock()) if (n != (std::numeric_limits::max)()) ++n; return n; @@ -136,11 +163,18 @@ public: // Poll for one operation without blocking. size_t poll_one(boost::system::error_code& ec) { + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + typename call_stack::context ctx(this); boost::asio::detail::mutex::scoped_lock lock(mutex_); - return do_one(lock, 0, ec); + return do_one(lock, 0); } // Interrupt the event processing loop. @@ -160,16 +194,14 @@ public: // Notify that some work has started. void work_started() { - boost::asio::detail::mutex::scoped_lock lock(mutex_); ++outstanding_work_; } // Notify that some work has finished. void work_finished() { - boost::asio::detail::mutex::scoped_lock lock(mutex_); if (--outstanding_work_ == 0) - stop_all_threads(lock); + stop(); } // Request invocation of the given handler. @@ -177,7 +209,10 @@ public: void dispatch(Handler handler) { if (call_stack::contains(this)) + { + boost::asio::detail::fenced_block b; boost_asio_handler_invoke_helpers::invoke(handler, handler); + } else post(handler); } @@ -187,29 +222,41 @@ public: void post(Handler handler) { // Allocate and construct an operation to wrap the handler. - handler_queue::scoped_ptr ptr(handler_queue::wrap(handler)); - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // If the service has been shut down we silently discard the handler. - if (shutdown_) - return; + typedef completion_handler value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - // Add the handler to the end of the queue. - handler_queue_.push(ptr.get()); + post_immediate_completion(ptr.get()); ptr.release(); + } - // An undelivered handler is treated as unfinished work. - ++outstanding_work_; + // Request invocation of the given operation and return immediately. Assumes + // that work_started() has not yet been called for the operation. + void post_immediate_completion(operation* op) + { + work_started(); + post_deferred_completion(op); + } + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operation. + void post_deferred_completion(operation* op) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); + } - // Wake up a thread to execute the handler. - if (!interrupt_one_idle_thread(lock)) + // Request invocation of the given operations and return immediately. Assumes + // that work_started() was previously called for each operation. + void post_deferred_completions(op_queue& ops) + { + if (!ops.empty()) { - if (!task_interrupted_ && task_) - { - task_interrupted_ = true; - task_->interrupt(); - } + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue_.push(ops); + wake_one_thread_and_unlock(lock); } } @@ -217,57 +264,58 @@ private: struct idle_thread_info; size_t do_one(boost::asio::detail::mutex::scoped_lock& lock, - idle_thread_info* this_idle_thread, boost::system::error_code& ec) + idle_thread_info* this_idle_thread) { - if (outstanding_work_ == 0 && !stopped_) - { - stop_all_threads(lock); - ec = boost::system::error_code(); - return 0; - } - bool polling = !this_idle_thread; bool task_has_run = false; while (!stopped_) { - if (!handler_queue_.empty()) + if (!op_queue_.empty()) { // Prepare to execute first handler from queue. - handler_queue::handler* h = handler_queue_.front(); - handler_queue_.pop(); + operation* o = op_queue_.front(); + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); - if (h == &task_handler_) + if (o == &task_operation_) { - bool more_handlers = (!handler_queue_.empty()); task_interrupted_ = more_handlers || polling; // If the task has already run and we're polling then we're done. if (task_has_run && polling) { task_interrupted_ = true; - handler_queue_.push(&task_handler_); - ec = boost::system::error_code(); + op_queue_.push(&task_operation_); return 0; } task_has_run = true; - lock.unlock(); - task_cleanup c(lock, *this); + if (!more_handlers || !wake_one_idle_thread_and_unlock(lock)) + lock.unlock(); - // Run the task. May throw an exception. Only block if the handler - // queue is empty and we have an idle_thread_info object, otherwise - // we want to return as soon as possible. - task_->run(!more_handlers && !polling); + op_queue completed_ops; + task_cleanup c = { this, &lock, &completed_ops }; + (void)c; + + // Run the task. May throw an exception. Only block if the operation + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_->run(!more_handlers && !polling, completed_ops); } else { - lock.unlock(); - handler_cleanup c(lock, *this); + if (more_handlers) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; - // Invoke the handler. May throw an exception. - h->invoke(); // invoke() deletes the handler object + // Complete the operation. May throw an exception. + o->complete(*this); // deletes the operation object - ec = boost::system::error_code(); return 1; } } @@ -281,12 +329,10 @@ private: } else { - ec = boost::system::error_code(); return 0; } } - ec = boost::system::error_code(); return 0; } @@ -295,7 +341,15 @@ private: boost::asio::detail::mutex::scoped_lock& lock) { stopped_ = true; - interrupt_all_idle_threads(lock); + + while (first_idle_thread_) + { + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(lock); + } + if (!task_interrupted_ && task_) { task_interrupted_ = true; @@ -303,9 +357,10 @@ private: } } - // Interrupt a single idle thread. Returns true if a thread was interrupted, - // false if no running thread could be found to interrupt. - bool interrupt_one_idle_thread( + // Wakes a single idle thread and unlocks the mutex. Returns true if an idle + // thread was found. If there is no idle thread, returns false and leaves the + // mutex locked. + bool wake_one_idle_thread_and_unlock( boost::asio::detail::mutex::scoped_lock& lock) { if (first_idle_thread_) @@ -313,74 +368,56 @@ private: idle_thread_info* idle_thread = first_idle_thread_; first_idle_thread_ = idle_thread->next; idle_thread->next = 0; - idle_thread->wakeup_event.signal(lock); + idle_thread->wakeup_event.signal_and_unlock(lock); return true; } return false; } - // Interrupt all idle threads. - void interrupt_all_idle_threads( + // Wake a single idle thread, or the task, and always unlock the mutex. + void wake_one_thread_and_unlock( boost::asio::detail::mutex::scoped_lock& lock) { - while (first_idle_thread_) + if (!wake_one_idle_thread_and_unlock(lock)) { - idle_thread_info* idle_thread = first_idle_thread_; - first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(lock); + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + lock.unlock(); } } // Helper class to perform task-related operations on block exit. - class task_cleanup; - friend class task_cleanup; - class task_cleanup + struct task_cleanup; + friend struct task_cleanup; + struct task_cleanup { - public: - task_cleanup(boost::asio::detail::mutex::scoped_lock& lock, - task_io_service& task_io_svc) - : lock_(lock), - task_io_service_(task_io_svc) - { - } - ~task_cleanup() { - // Reinsert the task at the end of the handler queue. - lock_.lock(); - task_io_service_.task_interrupted_ = true; - task_io_service_.handler_queue_.push(&task_io_service_.task_handler_); + // Enqueue the completed operations and reinsert the task at the end of + // the operation queue. + lock_->lock(); + task_io_service_->task_interrupted_ = true; + task_io_service_->op_queue_.push(*ops_); + task_io_service_->op_queue_.push(&task_io_service_->task_operation_); } - private: - boost::asio::detail::mutex::scoped_lock& lock_; - task_io_service& task_io_service_; + task_io_service* task_io_service_; + boost::asio::detail::mutex::scoped_lock* lock_; + op_queue* ops_; }; - // Helper class to perform handler-related operations on block exit. - class handler_cleanup; - friend class handler_cleanup; - class handler_cleanup + // Helper class to call work_finished() on block exit. + struct work_finished_on_block_exit { - public: - handler_cleanup(boost::asio::detail::mutex::scoped_lock& lock, - task_io_service& task_io_svc) - : lock_(lock), - task_io_service_(task_io_svc) - { - } - - ~handler_cleanup() + ~work_finished_on_block_exit() { - lock_.lock(); - if (--task_io_service_.outstanding_work_ == 0) - task_io_service_.stop_all_threads(lock_); + task_io_service_->work_finished(); } - private: - boost::asio::detail::mutex::scoped_lock& lock_; - task_io_service& task_io_service_; + task_io_service* task_io_service_; }; // Mutex to protect access to internal data. @@ -389,25 +426,20 @@ private: // The task to be run by this service. Task* task_; - // Handler object to represent the position of the task in the queue. - class task_handler - : public handler_queue::handler + // Operation object to represent the position of the task in the queue. + struct task_operation : public operation { - public: - task_handler() - : handler_queue::handler(0, 0) - { - } - } task_handler_; + task_operation() : operation(0) {} + } task_operation_; // Whether the task has been interrupted. bool task_interrupted_; // The count of unfinished work. - int outstanding_work_; + boost::detail::atomic_count outstanding_work_; // The queue of handlers that are ready to be delivered. - handler_queue handler_queue_; + op_queue op_queue_; // Flag to indicate that the dispatcher has been stopped. bool stopped_; @@ -422,7 +454,7 @@ private: idle_thread_info* next; }; - // The number of threads that are currently idle. + // The threads that are currently idle. idle_thread_info* first_idle_thread_; }; @@ -430,9 +462,6 @@ private: } // namespace asio } // namespace boost -#include #include -#endif // defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE) - #endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/task_io_service_2lock.hpp b/3rdParty/Boost/src/boost/asio/detail/task_io_service_2lock.hpp deleted file mode 100644 index 71bceef..0000000 --- a/3rdParty/Boost/src/boost/asio/detail/task_io_service_2lock.hpp +++ /dev/null @@ -1,475 +0,0 @@ -// -// task_io_service_2lock.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_TASK_IO_SERVICE_2LOCK_HPP -#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace boost { -namespace asio { -namespace detail { - -// An alternative task_io_service implementation based on a two-lock queue. - -template -class task_io_service - : public boost::asio::detail::service_base > -{ -public: - typedef indirect_handler_queue handler_queue; - - // Constructor. - task_io_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base >(io_service), - front_mutex_(), - back_mutex_(), - task_(0), - outstanding_work_(0), - front_stopped_(false), - back_stopped_(false), - back_shutdown_(false), - back_first_idle_thread_(0), - back_task_thread_(0) - { - } - - void init(size_t /*concurrency_hint*/) - { - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - back_shutdown_ = true; - back_lock.unlock(); - - // Destroy handler objects. - while (handler_queue::handler* h = handler_queue_.pop()) - if (h != &task_handler_) - h->destroy(); - - // Reset to initial state. - task_ = 0; - } - - // Initialise the task, if required. - void init_task() - { - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - if (!back_shutdown_ && !task_) - { - task_ = &use_service(this->get_io_service()); - handler_queue_.push(&task_handler_); - interrupt_one_idle_thread(back_lock); - } - } - - // Run the event loop until interrupted or no more work. - size_t run(boost::system::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - typename call_stack::context ctx(this); - - idle_thread_info this_idle_thread; - this_idle_thread.next = 0; - - size_t n = 0; - while (do_one(&this_idle_thread, ec)) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } - - // Run until interrupted or one operation is performed. - size_t run_one(boost::system::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - typename call_stack::context ctx(this); - - idle_thread_info this_idle_thread; - this_idle_thread.next = 0; - - return do_one(&this_idle_thread, ec); - } - - // Poll for operations without blocking. - size_t poll(boost::system::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - typename call_stack::context ctx(this); - - size_t n = 0; - while (do_one(0, ec)) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } - - // Poll for one operation without blocking. - size_t poll_one(boost::system::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - typename call_stack::context ctx(this); - - return do_one(0, ec); - } - - // Interrupt the event processing loop. - void stop() - { - boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_); - front_stopped_ = true; - front_lock.unlock(); - - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - back_stopped_ = true; - interrupt_all_idle_threads(back_lock); - } - - // Reset in preparation for a subsequent run invocation. - void reset() - { - boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_); - front_stopped_ = false; - front_lock.unlock(); - - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - back_stopped_ = false; - } - - // Notify that some work has started. - void work_started() - { - ++outstanding_work_; - } - - // Notify that some work has finished. - void work_finished() - { - if (--outstanding_work_ == 0) - stop(); - } - - // Request invocation of the given handler. - template - void dispatch(Handler handler) - { - if (call_stack::contains(this)) - boost_asio_handler_invoke_helpers::invoke(handler, handler); - else - post(handler); - } - - // Request invocation of the given handler and return immediately. - template - void post(Handler handler) - { - // Allocate and construct an operation to wrap the handler. - handler_queue::scoped_ptr ptr(handler_queue::wrap(handler)); - - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - - // If the service has been shut down we silently discard the handler. - if (back_shutdown_) - return; - - // Add the handler to the end of the queue. - handler_queue_.push(ptr.get()); - ptr.release(); - - // An undelivered handler is treated as unfinished work. - ++outstanding_work_; - - // Wake up a thread to execute the handler. - interrupt_one_idle_thread(back_lock); - } - -private: - struct idle_thread_info; - - size_t do_one(idle_thread_info* this_idle_thread, - boost::system::error_code& ec) - { - bool task_has_run = false; - for (;;) - { - // The front lock must be held before we can pop items from the queue. - boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_); - if (front_stopped_) - { - ec = boost::system::error_code(); - return 0; - } - - if (handler_queue::handler* h = handler_queue_.pop()) - { - if (h == &task_handler_) - { - bool more_handlers = handler_queue_.poppable(); - unsigned long front_version = handler_queue_.front_version(); - front_lock.unlock(); - - // The task is always added to the back of the queue when we exit - // this block. - task_cleanup c(*this); - - // If we're polling and the task has already run then we're done. - bool polling = !this_idle_thread; - if (task_has_run && polling) - { - ec = boost::system::error_code(); - return 0; - } - - // If we're considering going idle we need to check whether the queue - // is still empty. If it is, add the thread to the list of idle - // threads. - if (!more_handlers && !polling) - { - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - if (back_stopped_) - { - ec = boost::system::error_code(); - return 0; - } - else if (front_version == handler_queue_.back_version()) - { - back_task_thread_ = this_idle_thread; - } - else - { - more_handlers = true; - } - } - - // Run the task. May throw an exception. Only block if the handler - // queue is empty and we're not polling, otherwise we want to return - // as soon as possible. - task_has_run = true; - task_->run(!more_handlers && !polling); - } - else - { - front_lock.unlock(); - handler_cleanup c(*this); - - // Invoke the handler. May throw an exception. - h->invoke(); // invoke() deletes the handler object - - ec = boost::system::error_code(); - return 1; - } - } - else if (this_idle_thread) - { - unsigned long front_version = handler_queue_.front_version(); - front_lock.unlock(); - - // If we're considering going idle we need to check whether the queue - // is still empty. If it is, add the thread to the list of idle - // threads. - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - if (back_stopped_) - { - ec = boost::system::error_code(); - return 0; - } - else if (front_version == handler_queue_.back_version()) - { - this_idle_thread->next = back_first_idle_thread_; - back_first_idle_thread_ = this_idle_thread; - this_idle_thread->wakeup_event.clear(back_lock); - this_idle_thread->wakeup_event.wait(back_lock); - } - } - else - { - ec = boost::system::error_code(); - return 0; - } - } - } - - // Interrupt a single idle thread. - void interrupt_one_idle_thread( - boost::asio::detail::mutex::scoped_lock& back_lock) - { - if (back_first_idle_thread_) - { - idle_thread_info* idle_thread = back_first_idle_thread_; - back_first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(back_lock); - } - else if (back_task_thread_ && task_) - { - back_task_thread_ = 0; - task_->interrupt(); - } - } - - // Interrupt all idle threads. - void interrupt_all_idle_threads( - boost::asio::detail::mutex::scoped_lock& back_lock) - { - while (back_first_idle_thread_) - { - idle_thread_info* idle_thread = back_first_idle_thread_; - back_first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(back_lock); - } - - if (back_task_thread_ && task_) - { - back_task_thread_ = 0; - task_->interrupt(); - } - } - - // Helper class to perform task-related operations on block exit. - class task_cleanup; - friend class task_cleanup; - class task_cleanup - { - public: - task_cleanup(task_io_service& task_io_svc) - : task_io_service_(task_io_svc) - { - } - - ~task_cleanup() - { - // Reinsert the task at the end of the handler queue. - boost::asio::detail::mutex::scoped_lock back_lock( - task_io_service_.back_mutex_); - task_io_service_.back_task_thread_ = 0; - task_io_service_.handler_queue_.push(&task_io_service_.task_handler_); - } - - private: - task_io_service& task_io_service_; - }; - - // Helper class to perform handler-related operations on block exit. - class handler_cleanup - { - public: - handler_cleanup(task_io_service& task_io_svc) - : task_io_service_(task_io_svc) - { - } - - ~handler_cleanup() - { - task_io_service_.work_finished(); - } - - private: - task_io_service& task_io_service_; - }; - - // Mutexes to protect access to internal data. - boost::asio::detail::mutex front_mutex_; - boost::asio::detail::mutex back_mutex_; - - // The task to be run by this service. - Task* task_; - - // Handler object to represent the position of the task in the queue. - class task_handler - : public handler_queue::handler - { - public: - task_handler() - : handler_queue::handler(0, 0) - { - } - } task_handler_; - - // The count of unfinished work. - boost::detail::atomic_count outstanding_work_; - - // The queue of handlers that are ready to be delivered. - handler_queue handler_queue_; - - // Flag to indicate that the dispatcher has been stopped. - bool front_stopped_; - bool back_stopped_; - - // Flag to indicate that the dispatcher has been shut down. - bool back_shutdown_; - - // Structure containing information about an idle thread. - struct idle_thread_info - { - event wakeup_event; - idle_thread_info* next; - }; - - // The number of threads that are currently idle. - idle_thread_info* back_first_idle_thread_; - - // The thread that is currently blocked on the task. - idle_thread_info* back_task_thread_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/task_io_service_operation.hpp b/3rdParty/Boost/src/boost/asio/detail/task_io_service_operation.hpp new file mode 100644 index 0000000..557f673 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/task_io_service_operation.hpp @@ -0,0 +1,71 @@ +// +// task_io_service_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TASK_IO_SERVICE_OPERATION_HPP +#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// Base class for all operations. A function pointer is used instead of virtual +// functions to avoid the associated overhead. +template +class task_io_service_operation +{ +public: + void complete(task_io_service& owner) + { + func_(&owner, this, boost::system::error_code(), 0); + } + + void destroy() + { + func_(0, this, boost::system::error_code(), 0); + } + +protected: + typedef void (*func_type)(task_io_service*, + task_io_service_operation*, boost::system::error_code, std::size_t); + + task_io_service_operation(func_type func) + : next_(0), + func_(func) + { + } + + // Prevents deletion through this type. + ~task_io_service_operation() + { + } + +private: + friend class op_queue_access; + task_io_service_operation* next_; + func_type func_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include +#include + +#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/thread.hpp b/3rdParty/Boost/src/boost/asio/detail/thread.hpp index 24a7a8c..3e2e215 100644 --- a/3rdParty/Boost/src/boost/asio/detail/thread.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/thread.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(BOOST_WINDOWS) # if defined(UNDER_CE) @@ -39,7 +39,7 @@ namespace boost { namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) typedef null_thread thread; #elif defined(BOOST_WINDOWS) # if defined(UNDER_CE) diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_op.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_op.hpp new file mode 100644 index 0000000..9973d89 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/timer_op.hpp @@ -0,0 +1,46 @@ +// +// timer_op.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_OP_HPP +#define BOOST_ASIO_DETAIL_TIMER_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class timer_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + boost::system::error_code ec_; + +protected: + timer_op(func_type func) + : operation(func) + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_OP_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_queue.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_queue.hpp index 35c8a77..164b342 100644 --- a/3rdParty/Boost/src/boost/asio/detail/timer_queue.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/timer_queue.hpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -27,9 +26,9 @@ #include #include -#include #include -#include +#include +#include #include namespace boost { @@ -50,50 +49,36 @@ public: // Constructor. timer_queue() : timers_(), - heap_(), - cancelled_timers_(0), - complete_timers_(0) + heap_() { } // Add a new timer to the queue. Returns true if this is the timer that is // earliest in the queue, in which case the reactor's event demultiplexing // function call may need to be interrupted and restarted. - template - bool enqueue_timer(const time_type& time, Handler handler, void* token) + bool enqueue_timer(const time_type& time, timer_op* op, void* token) { // Ensure that there is space for the timer in the heap. We reserve here so // that the push_back below will not throw due to a reallocation failure. heap_.reserve(heap_.size() + 1); - // Create a new timer object. - typedef timer timer_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr new_timer(raw_ptr, time, handler, token); - // Insert the new timer into the hash. - typedef typename hash_map::iterator iterator; - typedef typename hash_map::value_type value_type; + typedef typename hash_map::iterator iterator; + typedef typename hash_map::value_type value_type; std::pair result = - timers_.insert(value_type(token, new_timer.get())); - if (!result.second) + timers_.insert(value_type(token, timer())); + result.first->second.op_queue_.push(op); + if (result.second) { - result.first->second->prev_ = new_timer.get(); - new_timer.get()->next_ = result.first->second; - result.first->second = new_timer.get(); + // Put the new timer at the correct position in the heap. + result.first->second.time_ = time; + result.first->second.heap_index_ = heap_.size(); + result.first->second.token_ = token; + heap_.push_back(&result.first->second); + up_heap(heap_.size() - 1); } - // Put the timer at the correct position in the heap. - new_timer.get()->heap_index_ = heap_.size(); - heap_.push_back(new_timer.get()); - up_heap(heap_.size() - 1); - bool is_first = (heap_[0] == new_timer.get()); - - // Ownership of the timer is transferred to the timer queue. - new_timer.release(); - - return is_first; + return (heap_[0] == &result.first->second); } // Whether there are no timers in the queue. @@ -103,226 +88,106 @@ public: } // Get the time for the timer that is earliest in the queue. - virtual boost::posix_time::time_duration wait_duration() const + virtual long wait_duration_msec(long max_duration) const { if (heap_.empty()) - return boost::posix_time::pos_infin; - return Time_Traits::to_posix_duration( + return max_duration; + + boost::posix_time::time_duration duration = Time_Traits::to_posix_duration( Time_Traits::subtract(heap_[0]->time_, Time_Traits::now())); - } - // Dispatch the timers that are earlier than the specified time. - virtual void dispatch_timers() - { - const time_type now = Time_Traits::now(); - while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_)) - { - timer_base* t = heap_[0]; - remove_timer(t); - t->result_ = boost::system::error_code(); - t->prev_ = 0; - t->next_ = complete_timers_; - complete_timers_ = t; - } - } + if (duration > boost::posix_time::milliseconds(max_duration)) + duration = boost::posix_time::milliseconds(max_duration); + else if (duration < boost::posix_time::milliseconds(0)) + duration = boost::posix_time::milliseconds(0); - // Cancel the timers with the given token. Any timers pending for the token - // will be notified that they have been cancelled next time - // dispatch_cancellations is called. Returns the number of timers that were - // cancelled. - std::size_t cancel_timer(void* timer_token) - { - std::size_t num_cancelled = 0; - typedef typename hash_map::iterator iterator; - iterator it = timers_.find(timer_token); - if (it != timers_.end()) - { - timer_base* t = it->second; - while (t) - { - timer_base* next = t->next_; - remove_timer(t); - t->prev_ = 0; - t->next_ = cancelled_timers_; - cancelled_timers_ = t; - t = next; - ++num_cancelled; - } - } - return num_cancelled; + return duration.total_milliseconds(); } - // Dispatch any pending cancels for timers. - virtual void dispatch_cancellations() + // Get the time for the timer that is earliest in the queue. + virtual long wait_duration_usec(long max_duration) const { - while (cancelled_timers_) - { - timer_base* this_timer = cancelled_timers_; - this_timer->result_ = boost::asio::error::operation_aborted; - cancelled_timers_ = this_timer->next_; - this_timer->next_ = complete_timers_; - complete_timers_ = this_timer; - } + if (heap_.empty()) + return max_duration; + + boost::posix_time::time_duration duration = Time_Traits::to_posix_duration( + Time_Traits::subtract(heap_[0]->time_, Time_Traits::now())); + + if (duration > boost::posix_time::microseconds(max_duration)) + duration = boost::posix_time::microseconds(max_duration); + else if (duration < boost::posix_time::microseconds(0)) + duration = boost::posix_time::microseconds(0); + + return duration.total_microseconds(); } - // Complete any timers that are waiting to be completed. - virtual void complete_timers() + // Dequeue all timers not later than the current time. + virtual void get_ready_timers(op_queue& ops) { - while (complete_timers_) + const time_type now = Time_Traits::now(); + while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_)) { - timer_base* this_timer = complete_timers_; - complete_timers_ = this_timer->next_; - this_timer->next_ = 0; - this_timer->complete(); + timer* t = heap_[0]; + ops.push(t->op_queue_); + remove_timer(t); } } - // Destroy all timers. - virtual void destroy_timers() + // Dequeue all timers. + virtual void get_all_timers(op_queue& ops) { - typename hash_map::iterator i = timers_.begin(); - typename hash_map::iterator end = timers_.end(); + typename hash_map::iterator i = timers_.begin(); + typename hash_map::iterator end = timers_.end(); while (i != end) { - timer_base* t = i->second; - typename hash_map::iterator old_i = i++; + ops.push(i->second.op_queue_); + typename hash_map::iterator old_i = i++; timers_.erase(old_i); - destroy_timer_list(t); } + heap_.clear(); timers_.clear(); - destroy_timer_list(cancelled_timers_); - destroy_timer_list(complete_timers_); } -private: - // Base class for timer operations. Function pointers are used instead of - // virtual functions to avoid the associated overhead. - class timer_base + // Cancel and dequeue the timers with the given token. + std::size_t cancel_timer(void* timer_token, op_queue& ops) { - public: - // Delete the timer and post the handler. - void complete() - { - complete_func_(this, result_); - } - - // Delete the timer. - void destroy() - { - destroy_func_(this); - } - - protected: - typedef void (*complete_func_type)(timer_base*, - const boost::system::error_code&); - typedef void (*destroy_func_type)(timer_base*); - - // Constructor. - timer_base(complete_func_type complete_func, destroy_func_type destroy_func, - const time_type& time, void* token) - : complete_func_(complete_func), - destroy_func_(destroy_func), - time_(time), - token_(token), - next_(0), - prev_(0), - heap_index_( - std::numeric_limits::max BOOST_PREVENT_MACRO_SUBSTITUTION()) - { - } - - // Prevent deletion through this type. - ~timer_base() + std::size_t num_cancelled = 0; + typedef typename hash_map::iterator iterator; + iterator it = timers_.find(timer_token); + if (it != timers_.end()) { + while (timer_op* op = it->second.op_queue_.front()) + { + op->ec_ = boost::asio::error::operation_aborted; + it->second.op_queue_.pop(); + ops.push(op); + ++num_cancelled; + } + remove_timer(&it->second); } + return num_cancelled; + } - private: - friend class timer_queue; - - // The function to be called to delete the timer and post the handler. - complete_func_type complete_func_; - - // The function to be called to delete the timer. - destroy_func_type destroy_func_; - - // The result of the timer operation. - boost::system::error_code result_; +private: + // Structure representing a single outstanding timer. + struct timer + { + timer() {} + timer(const timer&) {} + void operator=(const timer&) {} // The time when the timer should fire. time_type time_; - // The token associated with the timer. - void* token_; - - // The next timer known to the queue. - timer_base* next_; - - // The previous timer known to the queue. - timer_base* prev_; + // The operations waiting on the timer. + op_queue op_queue_; // The index of the timer in the heap. size_t heap_index_; - }; - // Adaptor class template for using handlers in timers. - template - class timer - : public timer_base - { - public: - // Constructor. - timer(const time_type& time, Handler handler, void* token) - : timer_base(&timer::complete_handler, - &timer::destroy_handler, time, token), - handler_(handler) - { - } - - // Delete the timer and post the handler. - static void complete_handler(timer_base* base, - const boost::system::error_code& result) - { - // Take ownership of the timer object. - typedef timer this_type; - this_type* this_timer(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(this_timer->handler_, this_timer); - - // Make a copy of the error_code and the handler so that the memory can - // be deallocated before the upcall is made. - boost::system::error_code ec(result); - Handler handler(this_timer->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - handler(ec); - } - - // Delete the timer. - static void destroy_handler(timer_base* base) - { - // Take ownership of the timer object. - typedef timer this_type; - this_type* this_timer(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(this_timer->handler_, this_timer); - - // 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(this_timer->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - private: - Handler handler_; + // The token associated with the timer. + void* token_; }; // Move the item at the given index up the heap to its correct position. @@ -359,7 +224,7 @@ private: // Swap two entries in the heap. void swap_heap(size_t index1, size_t index2) { - timer_base* tmp = heap_[index1]; + timer* tmp = heap_[index1]; heap_[index1] = heap_[index2]; heap_[index2] = tmp; heap_[index1]->heap_index_ = index1; @@ -367,7 +232,7 @@ private: } // Remove a timer from the heap and list of timers. - void remove_timer(timer_base* t) + void remove_timer(timer* t) { // Remove the timer from the heap. size_t index = t->heap_index_; @@ -391,44 +256,17 @@ private: } // Remove the timer from the hash. - typedef typename hash_map::iterator iterator; + typedef typename hash_map::iterator iterator; iterator it = timers_.find(t->token_); if (it != timers_.end()) - { - if (it->second == t) - it->second = t->next_; - if (t->prev_) - t->prev_->next_ = t->next_; - if (t->next_) - t->next_->prev_ = t->prev_; - if (it->second == 0) - timers_.erase(it); - } - } - - // Destroy all timers in a linked list. - void destroy_timer_list(timer_base*& t) - { - while (t) - { - timer_base* next = t->next_; - t->next_ = 0; - t->destroy(); - t = next; - } + timers_.erase(it); } // A hash of timer token to linked lists of timers. - hash_map timers_; + hash_map timers_; // The heap of timers, with the earliest timer at the front. - std::vector heap_; - - // The list of timers to be cancelled. - timer_base* cancelled_timers_; - - // The list of timers waiting to be completed. - timer_base* complete_timers_; + std::vector heap_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_queue_base.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_queue_base.hpp index cd6a0d3..074c2e1 100644 --- a/3rdParty/Boost/src/boost/asio/detail/timer_queue_base.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/timer_queue_base.hpp @@ -17,13 +17,9 @@ #include -#include // Must come before posix_time. - -#include -#include -#include - #include +#include +#include namespace boost { namespace asio { @@ -33,6 +29,9 @@ class timer_queue_base : private noncopyable { public: + // Constructor. + timer_queue_base() : next_(0) {} + // Destructor. virtual ~timer_queue_base() {} @@ -40,19 +39,22 @@ public: virtual bool empty() const = 0; // Get the time to wait until the next timer. - virtual boost::posix_time::time_duration wait_duration() const = 0; + virtual long wait_duration_msec(long max_duration) const = 0; + + // Get the time to wait until the next timer. + virtual long wait_duration_usec(long max_duration) const = 0; - // Dispatch all ready timers. - virtual void dispatch_timers() = 0; + // Dequeue all ready timers. + virtual void get_ready_timers(op_queue& ops) = 0; - // Dispatch any pending cancels for timers. - virtual void dispatch_cancellations() = 0; + // Dequeue all timers. + virtual void get_all_timers(op_queue& ops) = 0; - // Complete all timers that are waiting to be completed. - virtual void complete_timers() = 0; +private: + friend class timer_queue_set; - // Destroy all timers. - virtual void destroy_timers() = 0; + // Next timer queue in the set. + timer_queue_base* next_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_queue_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_queue_fwd.hpp new file mode 100644 index 0000000..b8bc5f2 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/timer_queue_fwd.hpp @@ -0,0 +1,33 @@ +// +// timer_queue_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_QUEUE_FWD_HPP +#define BOOST_ASIO_DETAIL_TIMER_QUEUE_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class timer_queue; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_FWD_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_queue_set.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_queue_set.hpp new file mode 100644 index 0000000..a92a6b9 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/timer_queue_set.hpp @@ -0,0 +1,117 @@ +// +// timer_queue_set.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_QUEUE_SET_HPP +#define BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class timer_queue_set +{ +public: + // Constructor. + timer_queue_set() + : first_(0) + { + } + + // Add a timer queue to the set. + void insert(timer_queue_base* q) + { + q->next_ = first_; + first_ = q; + } + + // Remove a timer queue from the set. + void erase(timer_queue_base* q) + { + if (first_) + { + if (q == first_) + { + first_ = q->next_; + q->next_ = 0; + return; + } + + for (timer_queue_base* p = first_; p->next_; p = p->next_) + { + if (p->next_ == q) + { + p->next_ = q->next_; + q->next_ = 0; + return; + } + } + } + } + + // Determine whether all queues are empty. + bool all_empty() const + { + for (timer_queue_base* p = first_; p; p = p->next_) + if (!p->empty()) + return false; + return true; + } + + // Get the wait duration in milliseconds. + long wait_duration_msec(long max_duration) const + { + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_msec(min_duration); + return min_duration; + } + + // Get the wait duration in microseconds. + long wait_duration_usec(long max_duration) const + { + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_usec(min_duration); + return min_duration; + } + + // Dequeue all ready timers. + void get_ready_timers(op_queue& ops) + { + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_ready_timers(ops); + } + + // Dequeue all timers. + void get_all_timers(op_queue& ops) + { + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_all_timers(ops); + } + +private: + timer_queue_base* first_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_scheduler.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_scheduler.hpp new file mode 100644 index 0000000..bc837ee --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/timer_scheduler.hpp @@ -0,0 +1,36 @@ +// +// timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_SCHEDULER_HPP +#define BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#elif defined(BOOST_ASIO_HAS_EPOLL) +# include +#elif defined(BOOST_ASIO_HAS_KQUEUE) +# include +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +# include +#else +# include +#endif + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_scheduler_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_scheduler_fwd.hpp new file mode 100644 index 0000000..9d0b1e6 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/timer_scheduler_fwd.hpp @@ -0,0 +1,48 @@ +// +// timer_scheduler_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_SCHEDULER_FWD_HPP +#define BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_IOCP) +typedef win_iocp_io_service timer_scheduler; +#elif defined(BOOST_ASIO_HAS_EPOLL) +typedef epoll_reactor timer_scheduler; +#elif defined(BOOST_ASIO_HAS_KQUEUE) +typedef kqueue_reactor timer_scheduler; +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +typedef dev_poll_reactor timer_scheduler; +#else +typedef select_reactor timer_scheduler; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/tss_ptr.hpp b/3rdParty/Boost/src/boost/asio/detail/tss_ptr.hpp index 9af4965..7ccfcf3 100644 --- a/3rdParty/Boost/src/boost/asio/detail/tss_ptr.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/tss_ptr.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(BOOST_WINDOWS) # include @@ -37,7 +37,7 @@ namespace detail { template class tss_ptr -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) : public null_tss_ptr #elif defined(BOOST_WINDOWS) : public win_tss_ptr @@ -48,7 +48,7 @@ class tss_ptr public: void operator=(T* value) { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) null_tss_ptr::operator=(value); #elif defined(BOOST_WINDOWS) win_tss_ptr::operator=(value); diff --git a/3rdParty/Boost/src/boost/asio/detail/win_event.hpp b/3rdParty/Boost/src/boost/asio/detail/win_event.hpp index 637b580..bddf09d 100644 --- a/3rdParty/Boost/src/boost/asio/detail/win_event.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/win_event.hpp @@ -71,6 +71,15 @@ public: ::SetEvent(event_); } + // Signal the event and unlock the mutex. + template + void signal_and_unlock(Lock& lock) + { + BOOST_ASSERT(lock.locked()); + lock.unlock(); + ::SetEvent(event_); + } + // Reset the event. template void clear(Lock& lock) diff --git a/3rdParty/Boost/src/boost/asio/detail/win_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/win_fenced_block.hpp new file mode 100644 index 0000000..ff4a21c --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/win_fenced_block.hpp @@ -0,0 +1,77 @@ +// +// win_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WIN_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(BOOST_WINDOWS) && !defined(UNDER_CE) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_fenced_block + : private noncopyable +{ +public: + // Constructor. + win_fenced_block() + { +#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400) +# if defined(_M_IX86) +# pragma warning(push) +# pragma warning(disable:4793) + LONG barrier; + __asm { xchg barrier, eax } +# pragma warning(pop) +# endif // defined(_M_IX86) +#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) + MemoryBarrier(); +#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) + } + + // Destructor. + ~win_fenced_block() + { +#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400) +# if defined(_M_IX86) +# pragma warning(push) +# pragma warning(disable:4793) + LONG barrier; + __asm { xchg barrier, eax } +# pragma warning(pop) +# endif // defined(_M_IX86) +#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) + MemoryBarrier(); +#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) + +#include + +#endif // BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_handle_service.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_handle_service.hpp index 6998d57..a6d6599 100644 --- a/3rdParty/Boost/src/boost/asio/detail/win_iocp_handle_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_handle_service.hpp @@ -26,13 +26,14 @@ #include #include -#include #include #include #include +#include #include #include #include +#include #include namespace boost { @@ -40,12 +41,8 @@ namespace asio { namespace detail { class win_iocp_handle_service - : public boost::asio::detail::service_base { public: - // Base class for all operations. - typedef win_iocp_io_service::operation operation; - // The native type of a stream handle. typedef HANDLE native_type; @@ -81,8 +78,7 @@ public: }; win_iocp_handle_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - iocp_service_(boost::asio::use_service(io_service)), + : iocp_service_(boost::asio::use_service(io_service)), mutex_(), impl_list_(0) { @@ -307,16 +303,9 @@ public: return 0; } - // Find first buffer of non-zero length. - boost::asio::const_buffer buffer; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - for (DWORD i = 0; iter != end; ++iter, ++i) - { - buffer = boost::asio::const_buffer(*iter); - if (boost::asio::buffer_size(buffer) != 0) - break; - } + boost::asio::const_buffer buffer = + buffer_sequence_adapter::first(buffers); // A request to write 0 bytes on a handle is a no-op. if (boost::asio::buffer_size(buffer) == 0) @@ -365,79 +354,48 @@ public: } template - class write_operation - : public operation + class write_op : public operation { public: - write_operation(win_iocp_io_service& io_service, - const ConstBufferSequence& buffers, Handler handler) - : operation(io_service, - &write_operation::do_completion_impl, - &write_operation::destroy_impl), - work_(io_service.get_io_service()), + write_op(const ConstBufferSequence& buffers, Handler handler) + : operation(&write_op::do_complete), buffers_(buffers), handler_(handler) { } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef write_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + write_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename ConstBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename ConstBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::const_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // 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. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - boost_asio_handler_invoke_helpers::invoke( - bind_handler(handler, ec, bytes_transferred), handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef write_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } - boost::asio::io_service::work work_; + private: ConstBufferSequence buffers_; Handler handler_; }; @@ -457,65 +415,16 @@ public: void async_write_some_at(implementation_type& impl, boost::uint64_t offset, const ConstBufferSequence& buffers, Handler handler) { - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); - // Allocate and construct an operation to wrap the handler. - typedef write_operation value_type; + typedef write_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, iocp_service_, buffers, handler); - - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } - - // Find first buffer of non-zero length. - boost::asio::const_buffer buffer; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - for (DWORD i = 0; iter != end; ++iter, ++i) - { - buffer = boost::asio::const_buffer(*iter); - if (boost::asio::buffer_size(buffer) != 0) - break; - } - - // A request to write 0 bytes on a handle is a no-op. - if (boost::asio::buffer_size(buffer) == 0) - { - ptr.get()->on_immediate_completion(0, 0); - ptr.release(); - return; - } - - // Write the data. - DWORD bytes_transferred = 0; - ptr.get()->Offset = offset & 0xFFFFFFFF; - ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::WriteFile(impl.handle_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), - &bytes_transferred, ptr.get()); - DWORD last_error = ::GetLastError(); + handler_ptr ptr(raw_ptr, buffers, handler); - // Check if the operation completed immediately. - if (!ok && last_error != ERROR_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_write_op(impl, offset, + buffer_sequence_adapter::first(buffers), ptr.get()); + ptr.release(); } // Read some data. Returns the number of bytes received. @@ -537,16 +446,9 @@ public: return 0; } - // Find first buffer of non-zero length. - boost::asio::mutable_buffer buffer; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - for (DWORD i = 0; iter != end; ++iter, ++i) - { - buffer = boost::asio::mutable_buffer(*iter); - if (boost::asio::buffer_size(buffer) != 0) - break; - } + boost::asio::mutable_buffer buffer = + buffer_sequence_adapter::first(buffers); // A request to read 0 bytes on a stream handle is a no-op. if (boost::asio::buffer_size(buffer) == 0) @@ -609,89 +511,54 @@ public: } template - class read_operation - : public operation + class read_op : public operation { public: - read_operation(win_iocp_io_service& io_service, - const MutableBufferSequence& buffers, Handler handler) - : operation(io_service, - &read_operation< - MutableBufferSequence, Handler>::do_completion_impl, - &read_operation< - MutableBufferSequence, Handler>::destroy_impl), - work_(io_service.get_io_service()), + read_op(const MutableBufferSequence& buffers, Handler handler) + : operation(&read_op::do_complete), buffers_(buffers), handler_(handler) { } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef read_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + read_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename MutableBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename MutableBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::mutable_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check for the end-of-file condition. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - if (!ec && bytes_transferred == 0 || last_error == ERROR_HANDLE_EOF) - { - ec = boost::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. - boost_asio_handler_invoke_helpers::invoke( - bind_handler(handler, ec, bytes_transferred), handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef read_operation op_type; - op_type* handler_op(static_cast(op)); - typedef boost::asio::detail::handler_alloc_traits< - Handler, op_type> alloc_traits; - boost::asio::detail::handler_ptr ptr( - handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_HANDLE_EOF) + { + ec = boost::asio::error::eof; + } - // Free the memory associated with the handler. - ptr.reset(); + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } - boost::asio::io_service::work work_; + private: MutableBufferSequence buffers_; Handler handler_; }; @@ -712,63 +579,16 @@ public: void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, Handler handler) { - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); - // Allocate and construct an operation to wrap the handler. - typedef read_operation value_type; + typedef read_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, iocp_service_, buffers, handler); + handler_ptr ptr(raw_ptr, buffers, handler); - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } - - // Find first buffer of non-zero length. - boost::asio::mutable_buffer buffer; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - for (DWORD i = 0; iter != end; ++iter, ++i) - { - buffer = boost::asio::mutable_buffer(*iter); - if (boost::asio::buffer_size(buffer) != 0) - break; - } - - // A request to receive 0 bytes on a stream handle is a no-op. - if (boost::asio::buffer_size(buffer) == 0) - { - ptr.get()->on_immediate_completion(0, 0); - ptr.release(); - return; - } - - // Read some data. - DWORD bytes_transferred = 0; - ptr.get()->Offset = offset & 0xFFFFFFFF; - ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::ReadFile(impl.handle_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), - &bytes_transferred, ptr.get()); - DWORD last_error = ::GetLastError(); - if (!ok && last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_read_op(impl, offset, + buffer_sequence_adapter::first(buffers), ptr.get()); + ptr.release(); } private: @@ -794,6 +614,95 @@ private: void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, Handler handler); + // Helper function to start a write operation. + void start_write_op(implementation_type& impl, boost::uint64_t offset, + const boost::asio::const_buffer& buffer, operation* op) + { + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + } + else if (boost::asio::buffer_size(buffer) == 0) + { + // A request to write 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } + } + + // Helper function to start a read operation. + void start_read_op(implementation_type& impl, boost::uint64_t offset, + const boost::asio::mutable_buffer& buffer, operation* op) + { + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + } + else if (boost::asio::buffer_size(buffer) == 0) + { + // A request to read 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } + } + + // Update the ID of the thread from which cancellation is safe. + void update_cancellation_thread_id(implementation_type& impl) + { +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +#else // defined(BOOST_ASIO_ENABLE_CANCELIO) + (void)impl; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + } + // Helper function to close a handle when the associated object is being // destroyed. void close_for_destruction(implementation_type& impl) diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_io_service.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_io_service.hpp index 1dfb9a1..83b16bf 100644 --- a/3rdParty/Boost/src/boost/asio/detail/win_iocp_io_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_io_service.hpp @@ -29,122 +29,37 @@ #include #include +#include +#include #include #include +#include +#include #include #include -#include -#include +#include +#include +#include +#include +#include namespace boost { namespace asio { namespace detail { +class timer_op; + class win_iocp_io_service : public boost::asio::detail::service_base { public: - // Base class for all operations. A function pointer is used instead of - // virtual functions to avoid the associated overhead. - // - // This class inherits from OVERLAPPED so that we can downcast to get back to - // the operation pointer from the LPOVERLAPPED out parameter of - // GetQueuedCompletionStatus. - class operation; - friend class operation; - class operation - : public OVERLAPPED - { - public: - typedef void (*invoke_func_type)(operation*, DWORD, size_t); - typedef void (*destroy_func_type)(operation*); - - operation(win_iocp_io_service& iocp_service, - invoke_func_type invoke_func, destroy_func_type destroy_func) - : iocp_service_(iocp_service), - ready_(0), - last_error_(~DWORD(0)), - bytes_transferred_(0), - invoke_func_(invoke_func), - destroy_func_(destroy_func) - { - Internal = 0; - InternalHigh = 0; - Offset = 0; - OffsetHigh = 0; - hEvent = 0; - - ::InterlockedIncrement(&iocp_service_.outstanding_operations_); - } - - void reset() - { - Internal = 0; - InternalHigh = 0; - Offset = 0; - OffsetHigh = 0; - hEvent = 0; - ready_ = 0; - last_error_ = ~DWORD(0); - bytes_transferred_ = 0; - } - - void on_pending() - { - if (::InterlockedCompareExchange(&ready_, 1, 0) == 1) - iocp_service_.post_completion(this, last_error_, bytes_transferred_); - } - - void on_immediate_completion(DWORD last_error, DWORD bytes_transferred) - { - ready_ = 1; - iocp_service_.post_completion(this, last_error, bytes_transferred); - } - - bool on_completion(DWORD last_error, DWORD bytes_transferred) - { - if (last_error_ == ~DWORD(0)) - { - last_error_ = last_error; - bytes_transferred_ = bytes_transferred; - } - - if (::InterlockedCompareExchange(&ready_, 1, 0) == 1) - { - invoke_func_(this, last_error_, bytes_transferred_); - return true; - } - - return false; - } - - void destroy() - { - destroy_func_(this); - } - - protected: - // Prevent deletion through this type. - ~operation() - { - ::InterlockedDecrement(&iocp_service_.outstanding_operations_); - } - - private: - win_iocp_io_service& iocp_service_; - long ready_; - DWORD last_error_; - DWORD bytes_transferred_; - invoke_func_type invoke_func_; - destroy_func_type destroy_func_; - }; + typedef win_iocp_operation operation; // Constructor. win_iocp_io_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base(io_service), iocp_(), outstanding_work_(0), - outstanding_operations_(0), stopped_(0), shutdown_(0), timer_thread_(0), @@ -172,24 +87,34 @@ public: { ::InterlockedExchange(&shutdown_, 1); - while (::InterlockedExchangeAdd(&outstanding_operations_, 0) > 0) + while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) { - DWORD bytes_transferred = 0; -#if defined(WINVER) && (WINVER < 0x0500) - DWORD completion_key = 0; -#else - DWORD_PTR completion_key = 0; -#endif - LPOVERLAPPED overlapped = 0; - ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, INFINITE); - if (overlapped) - static_cast(overlapped)->destroy(); + op_queue ops; + timer_queues_.get_all_timers(ops); + ops.push(completed_ops_); + if (!ops.empty()) + { + while (operation* op = ops.front()) + { + ops.pop(); + ::InterlockedDecrement(&outstanding_work_); + op->destroy(); + } + } + else + { + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, + &completion_key, &overlapped, max_timeout); + if (overlapped) + { + ::InterlockedDecrement(&outstanding_work_); + static_cast(overlapped)->destroy(); + } + } } - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->destroy_timers(); - timer_queues_.clear(); } // Initialise the task. Nothing to do here. @@ -219,6 +144,7 @@ public: { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { + stop(); ec = boost::system::error_code(); return 0; } @@ -237,6 +163,7 @@ public: { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { + stop(); ec = boost::system::error_code(); return 0; } @@ -251,6 +178,7 @@ public: { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { + stop(); ec = boost::system::error_code(); return 0; } @@ -269,6 +197,7 @@ public: { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { + stop(); ec = boost::system::error_code(); return 0; } @@ -319,7 +248,10 @@ public: void dispatch(Handler handler) { if (call_stack::contains(this)) + { + boost::asio::detail::fenced_block b; boost_asio_handler_invoke_helpers::invoke(handler, handler); + } else post(handler); } @@ -328,37 +260,128 @@ public: template void post(Handler handler) { - // If the service has been shut down we silently discard the handler. - if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) - return; - // Allocate and construct an operation to wrap the handler. - typedef handler_operation value_type; + typedef completion_handler value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, *this, handler); + handler_ptr ptr(raw_ptr, handler); + + post_immediate_completion(ptr.get()); + ptr.release(); + } + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() has not yet been called for the operation. + void post_immediate_completion(operation* op) + { + work_started(); + post_deferred_completion(op); + } + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operation. + void post_deferred_completion(operation* op) + { + // Flag the operation as ready. + op->ready_ = 1; // Enqueue the operation on the I/O completion port. - ptr.get()->on_immediate_completion(0, 0); + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + completed_ops_.push(op); + } + } - // Operation has been successfully posted. - ptr.release(); + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operations. + void post_deferred_completions(op_queue& ops) + { + while (operation* op = ops.front()) + { + ops.pop(); + + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + completed_ops_.push(op); + completed_ops_.push(ops); + } + } } - // Request invocation of the given OVERLAPPED-derived operation. - void post_completion(operation* op, DWORD op_last_error, - DWORD bytes_transferred) + // Called after starting an overlapped I/O operation that did not complete + // immediately. The caller must have already called work_started() prior to + // starting the operation. + void on_pending(operation* op) { + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + completed_ops_.push(op); + } + } + } + + // Called after starting an overlapped I/O operation that completed + // immediately. The caller must have already called work_started() prior to + // starting the operation. + void on_completion(operation* op, + DWORD last_error = 0, DWORD bytes_transferred = 0) + { + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast( + &boost::asio::error::get_system_category()); + op->Offset = last_error; + op->OffsetHigh = bytes_transferred; + // Enqueue the operation on the I/O completion port. if (!::PostQueuedCompletionStatus(iocp_.handle, - bytes_transferred, op_last_error, op)) + 0, overlapped_contains_result, op)) { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "pqcs"); - boost::throw_exception(e); + // Out of resources. Put on completed queue instead. + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + completed_ops_.push(op); + } + } + + // Called after starting an overlapped I/O operation that completed + // immediately. The caller must have already called work_started() prior to + // starting the operation. + void on_completion(operation* op, + const boost::system::error_code& ec, DWORD bytes_transferred = 0) + { + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast(&ec.category()); + op->Offset = ec.value(); + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + completed_ops_.push(op); } } @@ -367,7 +390,7 @@ public: void add_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_queues_.push_back(&timer_queue); + timer_queues_.insert(&timer_queue); } // Remove a timer queue from the service. @@ -375,36 +398,28 @@ public: void remove_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - if (timer_queues_[i] == &timer_queue) - { - timer_queues_.erase(timer_queues_.begin() + i); - return; - } - } + timer_queues_.erase(&timer_queue); } - // Schedule a timer in the given timer queue to expire at the specified - // absolute time. The handler object will be invoked when the timer expires. - template + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, Handler handler, void* token) + const typename Time_Traits::time_type& time, timer_op* op, void* token) { // If the service has been shut down we silently discard the timer. if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) return; boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - if (timer_queue.enqueue_timer(time, handler, token)) + bool interrupt = timer_queue.enqueue_timer(time, op, token); + work_started(); + if (interrupt && !timer_interrupt_issued_) { - if (!timer_interrupt_issued_) - { - timer_interrupt_issued_ = true; - lock.unlock(); - ::PostQueuedCompletionStatus(iocp_.handle, - 0, steal_timer_dispatching, 0); - } + timer_interrupt_issued_ = true; + lock.unlock(); + ::PostQueuedCompletionStatus(iocp_.handle, + 0, steal_timer_dispatching, 0); } } @@ -418,7 +433,9 @@ public: return 0; boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - std::size_t n = timer_queue.cancel_timer(token); + op_queue ops; + std::size_t n = timer_queue.cancel_timer(token, ops); + post_deferred_completions(ops); if (n > 0 && !timer_interrupt_issued_) { timer_interrupt_issued_ = true; @@ -430,6 +447,14 @@ public: } private: +#if defined(WINVER) && (WINVER < 0x0500) + typedef DWORD dword_ptr_t; + typedef ULONG ulong_ptr_t; +#else // defined(WINVER) && (WINVER < 0x0500) + typedef DWORD_PTR dword_ptr_t; + typedef ULONG_PTR ulong_ptr_t; +#endif // defined(WINVER) && (WINVER < 0x0500) + // Dequeues at most one operation from the I/O completion port, and then // executes it. Returns the number of operations that were dequeued (i.e. // either 0 or 1). @@ -454,11 +479,7 @@ private: // Get the next operation from the queue. DWORD bytes_transferred = 0; -#if defined(WINVER) && (WINVER < 0x0500) - DWORD completion_key = 0; -#else - DWORD_PTR completion_key = 0; -#endif + dword_ptr_t completion_key = 0; LPOVERLAPPED overlapped = 0; ::SetLastError(0); BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, @@ -468,32 +489,11 @@ private: // Dispatch any pending timers. if (dispatching_timers) { - try - { - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - if (!timer_queues_.empty()) - { - timer_queues_copy_ = timer_queues_; - for (std::size_t i = 0; i < timer_queues_copy_.size(); ++i) - { - timer_queues_copy_[i]->dispatch_timers(); - timer_queues_copy_[i]->dispatch_cancellations(); - timer_queues_copy_[i]->complete_timers(); - } - } - } - catch (...) - { - // Transfer responsibility for dispatching timers to another thread. - if (::InterlockedCompareExchange(&timer_thread_, - 0, this_thread_id) == this_thread_id) - { - ::PostQueuedCompletionStatus(iocp_.handle, - 0, transfer_timer_dispatching, 0); - } - - throw; - } + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + op_queue ops; + ops.push(completed_ops_); + timer_queues_.get_ready_timers(ops); + post_deferred_completions(ops); } if (!ok && overlapped == 0) @@ -522,11 +522,9 @@ private: } else if (overlapped) { - // We may have been passed a last_error value in the completion_key. - if (last_error == 0) - { - last_error = completion_key; - } + operation* op = static_cast(overlapped); + boost::system::error_code result_ec(last_error, + boost::asio::error::get_system_category()); // Transfer responsibility for dispatching timers to another thread. if (dispatching_timers && ::InterlockedCompareExchange( @@ -536,14 +534,35 @@ private: 0, transfer_timer_dispatching, 0); } - // Ensure that the io_service does not exit due to running out of work - // while we make the upcall. - auto_work work(*this); + // We may have been passed the last_error and bytes_transferred in the + // OVERLAPPED structure itself. + if (completion_key == overlapped_contains_result) + { + result_ec = boost::system::error_code(static_cast(op->Offset), + *reinterpret_cast(op->Internal)); + bytes_transferred = op->OffsetHigh; + } - // Dispatch the operation. - operation* op = static_cast(overlapped); - if (op->on_completion(last_error, bytes_transferred)) + // Otherwise ensure any result has been saved into the OVERLAPPED + // structure. + else { + op->Internal = reinterpret_cast(&result_ec.category()); + op->Offset = result_ec.value(); + op->OffsetHigh = bytes_transferred; + } + + // Dispatch the operation only if ready. The operation may not be ready + // if the initiating function (e.g. a call to WSARecv) has not yet + // returned. This is because the initiating function still wants access + // to the operation's OVERLAPPED structure. + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + op->complete(*this, result_ec, bytes_transferred); ec = boost::system::error_code(); return 1; } @@ -588,126 +607,23 @@ private: } } - // Check if all timer queues are empty. - bool all_timer_queues_are_empty() const - { - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - if (!timer_queues_[i]->empty()) - return false; - return true; - } - // Get the timeout value for the GetQueuedCompletionStatus call. The timeout // value is returned as a number of milliseconds. We will wait no longer than // 1000 milliseconds. DWORD get_timeout() { - if (all_timer_queues_are_empty()) - return max_timeout; - - boost::posix_time::time_duration minimum_wait_duration - = boost::posix_time::milliseconds(max_timeout); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - boost::posix_time::time_duration wait_duration - = timer_queues_[i]->wait_duration(); - if (wait_duration < minimum_wait_duration) - minimum_wait_duration = wait_duration; - } - - if (minimum_wait_duration > boost::posix_time::time_duration()) - { - int milliseconds = minimum_wait_duration.total_milliseconds(); - return static_cast(milliseconds > 0 ? milliseconds : 1); - } - else - { - return 0; - } + return timer_queues_.wait_duration_msec(max_timeout); } - struct auto_work + // Helper class to call work_finished() on block exit. + struct work_finished_on_block_exit { - auto_work(win_iocp_io_service& io_service) - : io_service_(io_service) + ~work_finished_on_block_exit() { - io_service_.work_started(); + io_service_->work_finished(); } - ~auto_work() - { - io_service_.work_finished(); - } - - private: - win_iocp_io_service& io_service_; - }; - - template - struct handler_operation - : public operation - { - handler_operation(win_iocp_io_service& io_service, - Handler handler) - : operation(io_service, &handler_operation::do_completion_impl, - &handler_operation::destroy_impl), - io_service_(io_service), - handler_(handler) - { - io_service_.work_started(); - } - - ~handler_operation() - { - io_service_.work_finished(); - } - - private: - // Prevent copying and assignment. - handler_operation(const handler_operation&); - void operator=(const handler_operation&); - - static void do_completion_impl(operation* op, DWORD, size_t) - { - // Take ownership of the operation object. - typedef handler_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, 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. - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef handler_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - win_iocp_io_service& io_service_; - Handler handler_; + win_iocp_io_service* io_service_; }; // The IO completion port used for queueing operations. @@ -721,10 +637,6 @@ private: // The count of unfinished work. long outstanding_work_; - // The count of unfinished operations. - long outstanding_operations_; - friend class operation; - // Flag to indicate whether the event loop has been stopped. long stopped_; @@ -742,7 +654,12 @@ private: // Completion key value to indicate that responsibility for dispatching // timers should be stolen from another thread. - steal_timer_dispatching = 2 + steal_timer_dispatching = 2, + + // Completion key value to indicate that an operation has posted with the + // original last_error and bytes_transferred values stored in the fields of + // the OVERLAPPED structure. + overlapped_contains_result = 3 }; // The thread that's currently in charge of dispatching timers. @@ -755,12 +672,10 @@ private: bool timer_interrupt_issued_; // The timer queues. - std::vector timer_queues_; + timer_queue_set timer_queues_; - // A copy of the timer queues, used when dispatching, cancelling and cleaning - // up timers. The copy is stored as a class data member to avoid unnecessary - // memory allocation. - std::vector timer_queues_copy_; + // The operations that are ready to dispatch. + op_queue completed_ops_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_operation.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_operation.hpp new file mode 100644 index 0000000..d7d5723 --- /dev/null +++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_operation.hpp @@ -0,0 +1,91 @@ +// +// win_iocp_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WIN_IOCP_OPERATION_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Base class for all operations. A function pointer is used instead of virtual +// functions to avoid the associated overhead. +class win_iocp_operation + : public OVERLAPPED +{ +public: + void complete(win_iocp_io_service& owner, + const boost::system::error_code& ec = boost::system::error_code(), + std::size_t bytes_transferred = 0) + { + func_(&owner, this, ec, bytes_transferred); + } + + void destroy() + { + func_(0, this, boost::system::error_code(), 0); + } + +protected: + typedef void (*func_type)(win_iocp_io_service*, + win_iocp_operation*, boost::system::error_code, std::size_t); + + win_iocp_operation(func_type func) + : next_(0), + func_(func) + { + reset(); + } + + // Prevents deletion through this type. + ~win_iocp_operation() + { + } + + void reset() + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + hEvent = 0; + ready_ = 0; + } + +private: + friend class op_queue_access; + friend class win_iocp_io_service; + win_iocp_operation* next_; + func_type func_; + long ready_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include +#include + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_overlapped_ptr.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_overlapped_ptr.hpp index bb64014..082a5b1 100644 --- a/3rdParty/Boost/src/boost/asio/detail/win_iocp_overlapped_ptr.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_overlapped_ptr.hpp @@ -21,8 +21,10 @@ #if defined(BOOST_ASIO_HAS_IOCP) +#include #include #include +#include namespace boost { namespace asio { @@ -35,7 +37,8 @@ class win_iocp_overlapped_ptr public: // Construct an empty win_iocp_overlapped_ptr. win_iocp_overlapped_ptr() - : ptr_(0) + : ptr_(0), + iocp_service_(0) { } @@ -43,7 +46,8 @@ public: template explicit win_iocp_overlapped_ptr( boost::asio::io_service& io_service, Handler handler) - : ptr_(0) + : ptr_(0), + iocp_service_(0) { this->reset(io_service, handler); } @@ -61,6 +65,8 @@ public: { ptr_->destroy(); ptr_ = 0; + iocp_service_->work_finished(); + iocp_service_ = 0; } } @@ -69,12 +75,14 @@ public: template void reset(boost::asio::io_service& io_service, Handler handler) { - typedef overlapped_operation value_type; + typedef overlapped_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, io_service.impl_, handler); + handler_ptr ptr(raw_ptr, handler); + io_service.impl_.work_started(); reset(); ptr_ = ptr.release(); + iocp_service_ = &io_service.impl_; } // Get the contained OVERLAPPED object. @@ -93,10 +101,11 @@ public: OVERLAPPED* release() { if (ptr_) - ptr_->on_pending(); + iocp_service_->on_pending(ptr_); OVERLAPPED* tmp = ptr_; ptr_ = 0; + iocp_service_ = 0; return tmp; } @@ -106,99 +115,54 @@ public: { if (ptr_) { - ptr_->ec_ = ec; - ptr_->on_immediate_completion(0, static_cast(bytes_transferred)); + iocp_service_->on_completion(ptr_, ec, + static_cast(bytes_transferred)); ptr_ = 0; + iocp_service_ = 0; } } private: - struct overlapped_operation_base - : public win_iocp_io_service::operation - { - overlapped_operation_base(win_iocp_io_service& io_service, - invoke_func_type invoke_func, destroy_func_type destroy_func) - : win_iocp_io_service::operation(io_service, invoke_func, destroy_func), - io_service_(io_service) - { - io_service_.work_started(); - } - - ~overlapped_operation_base() - { - io_service_.work_finished(); - } - - win_iocp_io_service& io_service_; - boost::system::error_code ec_; - }; - template - struct overlapped_operation - : public overlapped_operation_base + struct overlapped_op : public win_iocp_operation { - overlapped_operation(win_iocp_io_service& io_service, - Handler handler) - : overlapped_operation_base(io_service, - &overlapped_operation::do_completion_impl, - &overlapped_operation::destroy_impl), + overlapped_op(Handler handler) + : win_iocp_operation(&overlapped_op::do_complete), handler_(handler) { } - private: - // Prevent copying and assignment. - overlapped_operation(const overlapped_operation&); - void operator=(const overlapped_operation&); - - static void do_completion_impl(win_iocp_io_service::operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef overlapped_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // Make a copy of the handler and error_code so that the memory can be - // deallocated before the upcall is made. - Handler handler(handler_op->handler_); - boost::system::error_code ec(handler_op->ec_); - if (last_error) - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - boost_asio_handler_invoke_helpers::invoke( - bind_handler(handler, ec, bytes_transferred), handler); - } - - static void destroy_impl(win_iocp_io_service::operation* op) - { - // Take ownership of the operation object. - typedef overlapped_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); + overlapped_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } + private: Handler handler_; }; - overlapped_operation_base* ptr_; + win_iocp_operation* ptr_; + win_iocp_io_service* iocp_service_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_serial_port_service.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_serial_port_service.hpp index 4d6d2e9..288287c 100644 --- a/3rdParty/Boost/src/boost/asio/detail/win_iocp_serial_port_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_serial_port_service.hpp @@ -37,7 +37,6 @@ namespace detail { // Extend win_iocp_handle_service to provide serial port support. class win_iocp_serial_port_service - : public boost::asio::detail::service_base { public: // The native type of a stream handle. @@ -47,10 +46,7 @@ public: typedef win_iocp_handle_service::implementation_type implementation_type; win_iocp_serial_port_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - win_iocp_serial_port_service>(io_service), - handle_service_( - boost::asio::use_service(io_service)) + : handle_service_(io_service) { } @@ -279,8 +275,8 @@ public: } private: - // The handle service used for initiating asynchronous operations. - win_iocp_handle_service& handle_service_; + // The implementation used for initiating asynchronous operations. + win_iocp_handle_service handle_service_; }; } // namespace detail diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_socket_service.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_socket_service.hpp index e0c0806..5d545a8 100644 --- a/3rdParty/Boost/src/boost/asio/detail/win_iocp_socket_service.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_socket_service.hpp @@ -28,15 +28,19 @@ #include #include -#include #include #include #include #include +#include +#include #include #include #include -#include +#include +#include +#include +#include #include #include #include @@ -48,7 +52,6 @@ namespace detail { template class win_iocp_socket_service - : public boost::asio::detail::service_base > { public: // The protocol type. @@ -57,9 +60,6 @@ public: // The endpoint type. typedef typename Protocol::endpoint endpoint_type; - // Base class for all operations. - typedef win_iocp_io_service::operation operation; - struct noop_deleter { void operator()(void*) {} }; typedef boost::shared_ptr shared_cancel_token_type; typedef boost::weak_ptr weak_cancel_token_type; @@ -114,9 +114,6 @@ public: endpoint_type remote_endpoint_; }; - // The type of the reactor used for connect operations. - typedef detail::select_reactor reactor_type; - // The implementation type of the socket. class implementation_type { @@ -161,7 +158,7 @@ public: protocol_type protocol_; // Per-descriptor data used by the reactor. - reactor_type::per_descriptor_data reactor_data_; + reactor::per_descriptor_data reactor_data_; #if defined(BOOST_ASIO_ENABLE_CANCELIO) // The ID of the thread from which it is safe to cancel asynchronous @@ -176,14 +173,10 @@ public: implementation_type* prev_; }; - // The maximum number of buffers to support in a single operation. - enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; - // Constructor. win_iocp_socket_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - win_iocp_socket_service >(io_service), - iocp_service_(boost::asio::use_service(io_service)), + : io_service_(io_service), + iocp_service_(use_service(io_service)), reactor_(0), mutex_(), impl_list_(0) @@ -304,11 +297,11 @@ public: // Check if the reactor was created, in which case we need to close the // socket on the reactor as well to cancel any operations that might be // running there. - reactor_type* reactor = static_cast( + reactor* r = static_cast( interlocked_compare_exchange_pointer( reinterpret_cast(&reactor_), 0, 0)); - if (reactor) - reactor->close_descriptor(impl.socket_, impl.reactor_data_); + if (r) + r->close_descriptor(impl.socket_, impl.reactor_data_); if (socket_ops::close(impl.socket_, ec) == socket_error_retval) return ec; @@ -665,23 +658,11 @@ public: return 0; } - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = const_cast( - boost::asio::buffer_cast(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) + if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) { ec = boost::system::error_code(); return 0; @@ -689,8 +670,8 @@ public: // Send the data. DWORD bytes_transferred = 0; - int result = ::WSASend(impl.socket_, bufs, - i, &bytes_transferred, flags, 0, 0); + int result = ::WSASend(impl.socket_, bufs.buffers(), + bufs.count(), &bytes_transferred, flags, 0, 0); if (result != 0) { DWORD last_error = ::WSAGetLastError(); @@ -724,94 +705,63 @@ public: } template - class send_operation - : public operation + class send_op : public operation { public: - send_operation(win_iocp_io_service& io_service, - weak_cancel_token_type cancel_token, + send_op(weak_cancel_token_type cancel_token, const ConstBufferSequence& buffers, Handler handler) - : operation(io_service, - &send_operation::do_completion_impl, - &send_operation::destroy_impl), - work_(io_service.get_io_service()), + : operation(&send_op::do_complete), cancel_token_(cancel_token), buffers_(buffers), handler_(handler) { } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef send_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + send_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename ConstBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename ConstBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::const_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Map non-portable errors to their portable counterparts. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - if (ec.value() == ERROR_NETNAME_DELETED) - { - if (handler_op->cancel_token_.expired()) - ec = boost::asio::error::operation_aborted; - else - ec = boost::asio::error::connection_reset; - } - else if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; - } - - // 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. - boost_asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, ec, bytes_transferred), handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef send_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } - // Free the memory associated with the handler. - ptr.reset(); + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } - boost::asio::io_service::work work_; + private: weak_cancel_token_type cancel_token_; ConstBufferSequence buffers_; Handler handler_; @@ -823,127 +773,34 @@ public: void async_send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - // Allocate and construct an operation to wrap the handler. - typedef send_operation value_type; + typedef send_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, iocp_service_, + handler_ptr ptr(raw_ptr, impl.cancel_token_, buffers, handler); - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } - - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = const_cast( - boost::asio::buffer_cast(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) - { - ptr.get()->on_immediate_completion(0, 0); - ptr.release(); - return; - } - - // Send the data. - DWORD bytes_transferred = 0; - int result = ::WSASend(impl.socket_, bufs, i, - &bytes_transferred, flags, ptr.get(), 0); - DWORD last_error = ::WSAGetLastError(); + buffer_sequence_adapter bufs(buffers); - // Check if the operation completed immediately. - if (result != 0 && last_error != WSA_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_send_op(impl, bufs.buffers(), bufs.count(), flags, + impl.protocol_.type() == SOCK_STREAM && bufs.all_empty(), ptr.get()); + ptr.release(); } - template - class null_buffers_operation - { - public: - null_buffers_operation(boost::asio::io_service& io_service, Handler handler) - : work_(io_service), - handler_(handler) - { - } - - bool perform(boost::system::error_code&, - std::size_t& bytes_transferred) - { - bytes_transferred = 0; - return true; - } - - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - work_.get_io_service().post(bind_handler( - handler_, ec, bytes_transferred)); - } - - private: - boost::asio::io_service::work work_; - Handler handler_; - }; - // Start an asynchronous wait until data can be sent without blocking. template void async_send(implementation_type& impl, const null_buffers&, socket_base::message_flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Check if the reactor was already obtained from the io_service. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!reactor) - { - reactor = &(boost::asio::use_service( - this->get_io_service())); - interlocked_exchange_pointer( - reinterpret_cast(&reactor_), reactor); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - reactor->start_write_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + start_reactor_op(impl, reactor::write_op, ptr.get()); + ptr.release(); } // Send a datagram to the specified endpoint. Returns the number of bytes @@ -959,23 +816,14 @@ public: return 0; } - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = const_cast( - boost::asio::buffer_cast(buffer)); - } + buffer_sequence_adapter bufs(buffers); // Send the data. DWORD bytes_transferred = 0; - int result = ::WSASendTo(impl.socket_, bufs, i, &bytes_transferred, - flags, destination.data(), static_cast(destination.size()), 0, 0); + int result = ::WSASendTo(impl.socket_, bufs.buffers(), bufs.count(), + &bytes_transferred, flags, destination.data(), + static_cast(destination.size()), 0, 0); if (result != 0) { DWORD last_error = ::WSAGetLastError(); @@ -1008,85 +856,57 @@ public: } template - class send_to_operation - : public operation + class send_to_op : public operation { public: - send_to_operation(win_iocp_io_service& io_service, + send_to_op(weak_cancel_token_type cancel_token, const ConstBufferSequence& buffers, Handler handler) - : operation(io_service, - &send_to_operation::do_completion_impl, - &send_to_operation::destroy_impl), - work_(io_service.get_io_service()), + : operation(&send_to_op::do_complete), + cancel_token_(cancel_token), buffers_(buffers), handler_(handler) { } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef send_to_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + send_to_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename ConstBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename ConstBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::const_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Map non-portable errors to their portable counterparts. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; - } - - // 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. - boost_asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, ec, bytes_transferred), handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef send_to_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } - // Free the memory associated with the handler. - ptr.reset(); + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } - boost::asio::io_service::work work_; + private: + weak_cancel_token_type cancel_token_; ConstBufferSequence buffers_; Handler handler_; }; @@ -1098,57 +918,19 @@ public: const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, Handler handler) { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - // Allocate and construct an operation to wrap the handler. - typedef send_to_operation value_type; + typedef send_to_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, iocp_service_, buffers, handler); - - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } - - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = const_cast( - boost::asio::buffer_cast(buffer)); - } + handler_ptr ptr(raw_ptr, + impl.cancel_token_, buffers, handler); - // Send the data. - DWORD bytes_transferred = 0; - int result = ::WSASendTo(impl.socket_, bufs, i, &bytes_transferred, flags, - destination.data(), static_cast(destination.size()), ptr.get(), 0); - DWORD last_error = ::WSAGetLastError(); + buffer_sequence_adapter bufs(buffers); - // Check if the operation completed immediately. - if (result != 0 && last_error != WSA_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_send_to_op(impl, bufs.buffers(), + bufs.count(), destination, flags, ptr.get()); + ptr.release(); } // Start an asynchronous wait until data can be sent without blocking. @@ -1156,29 +938,14 @@ public: void async_send_to(implementation_type& impl, const null_buffers&, socket_base::message_flags, const endpoint_type&, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Check if the reactor was already obtained from the io_service. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!reactor) - { - reactor = &(boost::asio::use_service( - this->get_io_service())); - interlocked_exchange_pointer( - reinterpret_cast(&reactor_), reactor); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - reactor->start_write_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + start_reactor_op(impl, reactor::write_op, ptr.get()); + ptr.release(); } // Receive some data from the peer. Returns the number of bytes received. @@ -1193,22 +960,11 @@ public: return 0; } - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = boost::asio::buffer_cast(buffer); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) + if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) { ec = boost::system::error_code(); return 0; @@ -1217,8 +973,8 @@ public: // Receive some data. DWORD bytes_transferred = 0; DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, bufs, i, - &bytes_transferred, &recv_flags, 0, 0); + int result = ::WSARecv(impl.socket_, bufs.buffers(), + bufs.count(), &bytes_transferred, &recv_flags, 0, 0); if (result != 0) { DWORD last_error = ::WSAGetLastError(); @@ -1257,106 +1013,75 @@ public: } template - class receive_operation - : public operation + class receive_op : public operation { public: - receive_operation(int protocol_type, win_iocp_io_service& io_service, - weak_cancel_token_type cancel_token, + receive_op(int protocol_type, weak_cancel_token_type cancel_token, const MutableBufferSequence& buffers, Handler handler) - : operation(io_service, - &receive_operation< - MutableBufferSequence, Handler>::do_completion_impl, - &receive_operation< - MutableBufferSequence, Handler>::destroy_impl), + : operation(&receive_op::do_complete), protocol_type_(protocol_type), - work_(io_service.get_io_service()), cancel_token_(cancel_token), buffers_(buffers), handler_(handler) { } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef receive_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + receive_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename MutableBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename MutableBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::mutable_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Map non-portable errors to their portable counterparts. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - if (ec.value() == ERROR_NETNAME_DELETED) - { - if (handler_op->cancel_token_.expired()) - ec = boost::asio::error::operation_aborted; - else - ec = boost::asio::error::connection_reset; - } - else if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; - } - - // Check for connection closed. - else if (!ec && bytes_transferred == 0 - && handler_op->protocol_type_ == SOCK_STREAM - && !boost::is_same::value) - { - ec = boost::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. - boost_asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, ec, bytes_transferred), handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef receive_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } - // 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(handler_op->handler_); - (void)handler; + // Check for connection closed. + else if (!ec && bytes_transferred == 0 + && o->protocol_type_ == SOCK_STREAM + && !buffer_sequence_adapter::all_empty(o->buffers_) + && !boost::is_same::value) + { + ec = boost::asio::error::eof; + } - // Free the memory associated with the handler. - ptr.reset(); + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } + private: int protocol_type_; - boost::asio::io_service::work work_; weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; @@ -1369,67 +1094,20 @@ public: const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - // Allocate and construct an operation to wrap the handler. - typedef receive_operation value_type; + typedef receive_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); int protocol_type = impl.protocol_.type(); handler_ptr ptr(raw_ptr, protocol_type, - iocp_service_, impl.cancel_token_, buffers, handler); - - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } - - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = boost::asio::buffer_cast(buffer); - total_buffer_size += boost::asio::buffer_size(buffer); - } + impl.cancel_token_, buffers, handler); - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) - { - ptr.get()->on_immediate_completion(0, 0); - ptr.release(); - return; - } + buffer_sequence_adapter bufs(buffers); - // Receive some data. - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, bufs, i, - &bytes_transferred, &recv_flags, ptr.get(), 0); - DWORD last_error = ::WSAGetLastError(); - if (result != 0 && last_error != WSA_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_receive_op(impl, bufs.buffers(), bufs.count(), flags, + protocol_type == SOCK_STREAM && bufs.all_empty(), ptr.get()); + ptr.release(); } // Wait until data can be received without blocking. @@ -1437,75 +1115,36 @@ public: void async_receive(implementation_type& impl, const null_buffers& buffers, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else if (impl.protocol_.type() == SOCK_STREAM) + if (impl.protocol_.type() == SOCK_STREAM) { // For stream sockets on Windows, we may issue a 0-byte overlapped // WSARecv to wait until there is data available on the socket. -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - // Allocate and construct an operation to wrap the handler. - typedef receive_operation value_type; + typedef receive_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); int protocol_type = impl.protocol_.type(); handler_ptr ptr(raw_ptr, protocol_type, - iocp_service_, impl.cancel_token_, buffers, handler); + impl.cancel_token_, buffers, handler); - // Issue a receive operation with an empty buffer. ::WSABUF buf = { 0, 0 }; - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, &buf, 1, - &bytes_transferred, &recv_flags, ptr.get(), 0); - DWORD last_error = ::WSAGetLastError(); - if (result != 0 && last_error != WSA_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_receive_op(impl, &buf, 1, flags, false, ptr.get()); + ptr.release(); } else { - // Check if the reactor was already obtained from the io_service. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!reactor) - { - reactor = &(boost::asio::use_service( - this->get_io_service())); - interlocked_exchange_pointer( - reinterpret_cast(&reactor_), reactor); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - if (flags & socket_base::message_out_of_band) - { - reactor->start_except_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler)); - } - else - { - reactor->start_read_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + start_reactor_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get()); + ptr.release(); } } @@ -1523,24 +1162,16 @@ public: return 0; } - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = boost::asio::buffer_cast(buffer); - } + buffer_sequence_adapter bufs(buffers); // Receive some data. DWORD bytes_transferred = 0; DWORD recv_flags = flags; int endpoint_size = static_cast(sender_endpoint.capacity()); - int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred, - &recv_flags, sender_endpoint.data(), &endpoint_size, 0, 0); + int result = ::WSARecvFrom(impl.socket_, bufs.buffers(), + bufs.count(), &bytes_transferred, &recv_flags, + sender_endpoint.data(), &endpoint_size, 0, 0); if (result != 0) { DWORD last_error = ::WSAGetLastError(); @@ -1583,22 +1214,15 @@ public: } template - class receive_from_operation - : public operation + class receive_from_op : public operation { public: - receive_from_operation(int protocol_type, win_iocp_io_service& io_service, - endpoint_type& endpoint, const MutableBufferSequence& buffers, - Handler handler) - : operation(io_service, - &receive_from_operation< - MutableBufferSequence, Handler>::do_completion_impl, - &receive_from_operation< - MutableBufferSequence, Handler>::destroy_impl), + receive_from_op(int protocol_type, endpoint_type& endpoint, + const MutableBufferSequence& buffers, Handler handler) + : operation(&receive_from_op::do_complete), protocol_type_(protocol_type), endpoint_(endpoint), endpoint_size_(static_cast(endpoint.capacity())), - work_(io_service.get_io_service()), buffers_(buffers), handler_(handler) { @@ -1609,83 +1233,51 @@ public: return endpoint_size_; } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef receive_from_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + receive_from_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename MutableBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename MutableBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::mutable_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Map non-portable errors to their portable counterparts. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; - } + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } - // Check for connection closed. - if (!ec && bytes_transferred == 0 - && handler_op->protocol_type_ == SOCK_STREAM) - { - ec = boost::asio::error::eof; + // Record the size of the endpoint returned by the operation. + o->endpoint_.resize(o->endpoint_size_); + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - - // Record the size of the endpoint returned by the operation. - handler_op->endpoint_.resize(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. - boost_asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, ec, bytes_transferred), handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef receive_from_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); } + private: int protocol_type_; endpoint_type& endpoint_; int endpoint_size_; - boost::asio::io_service::work work_; + weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; }; @@ -1698,58 +1290,20 @@ public: const MutableBufferSequence& buffers, endpoint_type& sender_endp, socket_base::message_flags flags, Handler handler) { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - // Allocate and construct an operation to wrap the handler. - typedef receive_from_operation value_type; + typedef receive_from_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, protocol_type, - iocp_service_, sender_endp, buffers, handler); - - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } + handler_ptr ptr(raw_ptr, + protocol_type, sender_endp, buffers, handler); - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = boost::asio::buffer_cast(buffer); - } + buffer_sequence_adapter bufs(buffers); - // Receive some data. - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred, - &recv_flags, sender_endp.data(), &ptr.get()->endpoint_size(), - ptr.get(), 0); - DWORD last_error = ::WSAGetLastError(); - if (result != 0 && last_error != WSA_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_receive_from_op(impl, bufs.buffers(), bufs.count(), + sender_endp, flags, &ptr.get()->endpoint_size(), ptr.get()); + ptr.release(); } // Wait until data can be received without blocking. @@ -1758,40 +1312,20 @@ public: const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Check if the reactor was already obtained from the io_service. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!reactor) - { - reactor = &(boost::asio::use_service( - this->get_io_service())); - interlocked_exchange_pointer( - reinterpret_cast(&reactor_), reactor); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - // Reset endpoint since it can be given no sensible value at this time. - sender_endpoint = endpoint_type(); + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); - if (flags & socket_base::message_out_of_band) - { - reactor->start_except_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler)); - } - else - { - reactor->start_read_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } - } + start_reactor_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get()); + ptr.release(); } // Accept a new connection. @@ -1852,32 +1386,27 @@ public: } template - class accept_operation - : public operation + class accept_op : public operation { public: - accept_operation(win_iocp_io_service& io_service, - socket_type socket, socket_type new_socket, Socket& peer, - const protocol_type& protocol, endpoint_type* peer_endpoint, - bool enable_connection_aborted, Handler handler) - : operation(io_service, - &accept_operation::do_completion_impl, - &accept_operation::destroy_impl), - io_service_(io_service), + accept_op(win_iocp_io_service& iocp_service, socket_type socket, + Socket& peer, const protocol_type& protocol, + endpoint_type* peer_endpoint, bool enable_connection_aborted, + Handler handler) + : operation(&accept_op::do_complete), + iocp_service_(iocp_service), socket_(socket), - new_socket_(new_socket), peer_(peer), protocol_(protocol), peer_endpoint_(peer_endpoint), - work_(io_service.get_io_service()), enable_connection_aborted_(enable_connection_aborted), handler_(handler) { } - socket_type new_socket() + socket_holder& new_socket() { - return new_socket_.get(); + return new_socket_; } void* output_buffer() @@ -1890,166 +1419,145 @@ public: return sizeof(sockaddr_storage_type) + 16; } - private: - static void do_completion_impl(operation* op, DWORD last_error, size_t) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t /*bytes_transferred*/) { - // Take ownership of the operation object. - typedef accept_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + // Take ownership of the handler object. + accept_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); - // Map Windows error ERROR_NETNAME_DELETED to connection_aborted. - if (last_error == ERROR_NETNAME_DELETED) + // Make the upcall if required. + if (owner) { - last_error = WSAECONNABORTED; - } + // Map Windows error ERROR_NETNAME_DELETED to connection_aborted. + if (ec.value() == ERROR_NETNAME_DELETED) + { + ec = boost::asio::error::connection_aborted; + } - // Restart the accept operation if we got the connection_aborted error - // and the enable_connection_aborted socket option is not set. - if (last_error == WSAECONNABORTED - && !ptr.get()->enable_connection_aborted_) - { - // Reset OVERLAPPED structure. - ptr.get()->reset(); - - // Create a new socket for the next connection, since the AcceptEx call - // fails with WSAEINVAL if we try to reuse the same socket. - boost::system::error_code ec; - ptr.get()->new_socket_.reset(); - ptr.get()->new_socket_.reset(socket_ops::socket( - ptr.get()->protocol_.family(), ptr.get()->protocol_.type(), - ptr.get()->protocol_.protocol(), ec)); - if (ptr.get()->new_socket() != invalid_socket) + // Restart the accept operation if we got the connection_aborted error + // and the enable_connection_aborted socket option is not set. + if (ec == boost::asio::error::connection_aborted + && !o->enable_connection_aborted_) { - // Accept a connection. - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(ptr.get()->socket_, ptr.get()->new_socket(), - ptr.get()->output_buffer(), 0, ptr.get()->address_length(), - ptr.get()->address_length(), &bytes_read, ptr.get()); - last_error = ::WSAGetLastError(); - - // Check if the operation completed immediately. - if (!result && last_error != WSA_IO_PENDING) + // Reset OVERLAPPED structure. + o->reset(); + + // Create a new socket for the next connection, since the AcceptEx + // call fails with WSAEINVAL if we try to reuse the same socket. + o->new_socket_.reset(); + o->new_socket_.reset(socket_ops::socket(o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), ec)); + if (o->new_socket_.get() != invalid_socket) { - if (last_error == ERROR_NETNAME_DELETED - || last_error == WSAECONNABORTED) + // Accept a connection. + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(o->socket_, o->new_socket_.get(), + o->output_buffer(), 0, o->address_length(), + o->address_length(), &bytes_read, o); + DWORD last_error = ::WSAGetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + + // Check if the operation completed immediately. + if (!result && last_error != WSA_IO_PENDING) { - // Post this handler so that operation will be restarted again. - ptr.get()->on_immediate_completion(last_error, 0); - ptr.release(); - return; + if (last_error == ERROR_NETNAME_DELETED + || last_error == WSAECONNABORTED) + { + // Post this handler so that operation will be restarted again. + o->iocp_service_.work_started(); + o->iocp_service_.on_completion(o, ec); + ptr.release(); + return; + } + else + { + // Operation already complete. Continue with rest of this + // handler. + } } else { - // Operation already complete. Continue with rest of this handler. + // Asynchronous operation has been successfully restarted. + o->iocp_service_.work_started(); + o->iocp_service_.on_pending(o); + ptr.release(); + return; } } + } + + // Get the address of the peer. + endpoint_type peer_endpoint; + if (!ec) + { + LPSOCKADDR local_addr = 0; + int local_addr_length = 0; + LPSOCKADDR remote_addr = 0; + int remote_addr_length = 0; + GetAcceptExSockaddrs(o->output_buffer(), 0, o->address_length(), + o->address_length(), &local_addr, &local_addr_length, + &remote_addr, &remote_addr_length); + if (static_cast(remote_addr_length) + > peer_endpoint.capacity()) + { + ec = boost::asio::error::invalid_argument; + } else { - // Asynchronous operation has been successfully restarted. - ptr.get()->on_pending(); - ptr.release(); - return; + using namespace std; // For memcpy. + memcpy(peer_endpoint.data(), remote_addr, remote_addr_length); + peer_endpoint.resize(static_cast(remote_addr_length)); } } - } - // Get the address of the peer. - endpoint_type peer_endpoint; - if (last_error == 0) - { - 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 (static_cast(remote_addr_length) - > peer_endpoint.capacity()) + // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname + // and getpeername will work on the accepted socket. + if (!ec) { - last_error = WSAEINVAL; + SOCKET update_ctx_param = o->socket_; + socket_ops::setsockopt(o->new_socket_.get(), + SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + &update_ctx_param, sizeof(SOCKET), ec); } - else - { - using namespace std; // For memcpy. - memcpy(peer_endpoint.data(), remote_addr, remote_addr_length); - peer_endpoint.resize(static_cast(remote_addr_length)); - } - } - // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname - // and getpeername will work on the accepted socket. - if (last_error == 0) - { - SOCKET update_ctx_param = handler_op->socket_; - boost::system::error_code ec; - if (socket_ops::setsockopt(handler_op->new_socket_.get(), - SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - &update_ctx_param, sizeof(SOCKET), ec) != 0) + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) { - last_error = ec.value(); + o->peer_.assign(o->protocol_, + native_type(o->new_socket_.get(), peer_endpoint), ec); + if (!ec) + o->new_socket_.release(); } - } - // If the socket was successfully accepted, transfer ownership of the - // socket to the peer object. - if (last_error == 0) - { - boost::system::error_code ec; - handler_op->peer_.assign(handler_op->protocol_, - native_type(handler_op->new_socket_.get(), peer_endpoint), ec); - if (ec) - last_error = ec.value(); - else - handler_op->new_socket_.release(); + // Pass endpoint back to caller. + if (o->peer_endpoint_) + *o->peer_endpoint_ = peer_endpoint; + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder1 + handler(o->handler_, ec); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - - // Pass endpoint back to caller. - if (handler_op->peer_endpoint_) - *handler_op->peer_endpoint_ = peer_endpoint; - - // 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. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - boost_asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, ec), handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef accept_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); } - win_iocp_io_service& io_service_; + private: + win_iocp_io_service& iocp_service_; socket_type socket_; socket_holder new_socket_; Socket& peer_; protocol_type protocol_; endpoint_type* peer_endpoint_; - boost::asio::io_service::work work_; unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; bool enable_connection_aborted_; Handler handler_; @@ -2061,86 +1569,18 @@ public: void async_accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, Handler handler) { - // Check whether acceptor has been initialised. - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor)); - return; - } - - // Check that peer socket has not already been opened. - if (peer.is_open()) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::already_open)); - return; - } - -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - - // Create a new socket for the connection. - boost::system::error_code ec; - socket_holder sock(socket_ops::socket(impl.protocol_.family(), - impl.protocol_.type(), impl.protocol_.protocol(), ec)); - if (sock.get() == invalid_socket) - { - this->get_io_service().post(bind_handler(handler, ec)); - return; - } - // Allocate and construct an operation to wrap the handler. - typedef accept_operation value_type; + typedef accept_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - socket_type new_socket = sock.get(); bool enable_connection_aborted = (impl.flags_ & implementation_type::enable_connection_aborted); - handler_ptr ptr(raw_ptr, - iocp_service_, impl.socket_, new_socket, peer, impl.protocol_, - peer_endpoint, enable_connection_aborted, handler); - sock.release(); - - // Accept a connection. - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(impl.socket_, 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) - { - if (!enable_connection_aborted - && (last_error == ERROR_NETNAME_DELETED - || last_error == WSAECONNABORTED)) - { - // Post handler so that operation will be restarted again. We do not - // perform the AcceptEx again here to avoid the possibility of starving - // other handlers. - ptr.get()->on_immediate_completion(last_error, 0); - ptr.release(); - } - else - { - boost::asio::io_service::work work(this->get_io_service()); - ptr.reset(); - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - iocp_service_.post(bind_handler(handler, ec)); - } - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + handler_ptr ptr(raw_ptr, iocp_service_, impl.socket_, peer, + impl.protocol_, peer_endpoint, enable_connection_aborted, handler); + + start_accept_op(impl, peer.is_open(), ptr.get()->new_socket(), + ptr.get()->output_buffer(), ptr.get()->address_length(), ptr.get()); + ptr.release(); } // Connect the socket to the specified endpoint. @@ -2159,67 +1599,76 @@ public: return ec; } - template - class connect_operation + class connect_op_base : public reactor_op { public: - connect_operation(socket_type socket, bool user_set_non_blocking, - boost::asio::io_service& io_service, Handler handler) - : socket_(socket), - user_set_non_blocking_(user_set_non_blocking), - io_service_(io_service), - work_(io_service), - handler_(handler) + connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&connect_op_base::do_perform, complete_func), + socket_(socket) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - bytes_transferred = 0; - - // Check whether the operation was successful. - if (ec) - return true; + connect_op_base* o(static_cast(base)); // Get the error code from the connect operation. int connect_error = 0; size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, ec) == socket_error_retval) + if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, o->ec_) == socket_error_retval) return true; - // If connection failed then post the handler with the error code. + // The connection failed so the handler will be posted with an error code. if (connect_error) { - ec = boost::system::error_code(connect_error, + o->ec_ = boost::system::error_code(connect_error, boost::asio::error::get_system_category()); - return true; } - // Revert socket to blocking mode unless the user requested otherwise. - if (!user_set_non_blocking_) - { - ioctl_arg_type non_blocking = 0; - if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking, ec)) - return true; - } - - // Post the result of the successful connection operation. - ec = boost::system::error_code(); return true; } - void complete(const boost::system::error_code& ec, std::size_t) + private: + socket_type socket_; + }; + + template + class connect_op : public connect_op_base + { + public: + connect_op(socket_type socket, Handler handler) + : connect_op_base(socket, &connect_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - io_service_.post(bind_handler(handler_, ec)); + // Take ownership of the handler object. + connect_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an + // upcall, 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. + detail::binder1 + handler(o->handler_, o->ec_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } private: - socket_type socket_; - bool user_set_non_blocking_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; Handler handler_; }; @@ -2228,86 +1677,216 @@ public: void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { + // Allocate and construct an operation to wrap the handler. + typedef connect_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, impl.socket_, handler); + + start_connect_op(impl, ptr.get(), peer_endpoint); + ptr.release(); + } + +private: + // Helper function to start an asynchronous send operation. + void start_send_op(implementation_type& impl, WSABUF* buffers, + std::size_t buffer_count, socket_base::message_flags flags, + bool noop, operation* op) + { + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASend(impl.socket_, buffers, + buffer_count, &bytes_transferred, flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } + } + + // Helper function to start an asynchronous send_to operation. + void start_send_to_op(implementation_type& impl, WSABUF* buffers, + std::size_t buffer_count, const endpoint_type& destination, + socket_base::message_flags flags, operation* op) + { + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor)); - return; + DWORD bytes_transferred = 0; + int result = ::WSASendTo(impl.socket_, buffers, buffer_count, + &bytes_transferred, flags, destination.data(), + static_cast(destination.size()), op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); } + } -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + // Helper function to start an asynchronous receive operation. + void start_receive_op(implementation_type& impl, WSABUF* buffers, + std::size_t buffer_count, socket_base::message_flags flags, + bool noop, operation* op) + { + update_cancellation_thread_id(impl); + iocp_service_.work_started(); - // Check if the reactor was already obtained from the io_service. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!reactor) + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else { - reactor = &(boost::asio::use_service( - this->get_io_service())); - interlocked_exchange_pointer( - reinterpret_cast(&reactor_), reactor); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(impl.socket_, buffers, buffer_count, + &bytes_transferred, &recv_flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_NETNAME_DELETED) + last_error = WSAECONNRESET; + else if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); } + } + + // Helper function to start an asynchronous receive_from operation. + void start_receive_from_op(implementation_type& impl, WSABUF* buffers, + std::size_t buffer_count, endpoint_type& sender_endpoint, + socket_base::message_flags flags, int* endpoint_size, operation* op) + { + update_cancellation_thread_id(impl); + iocp_service_.work_started(); - // Mark the socket as non-blocking so that the connection will take place - // asynchronously. - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else { - this->get_io_service().post(bind_handler(handler, ec)); - return; + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecvFrom(impl.socket_, buffers, + buffer_count, &bytes_transferred, &recv_flags, + sender_endpoint.data(), endpoint_size, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); } + } + + // Helper function to start an asynchronous receive_from operation. + void start_accept_op(implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, + void* output_buffer, DWORD address_length, operation* op) + { + update_cancellation_thread_id(impl); + iocp_service_.work_started(); - // Start the connect operation. - if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size(), ec) == 0) + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else if (peer_is_open) + iocp_service_.on_completion(op, boost::asio::error::already_open); + else { - // Revert socket to blocking mode unless the user requested otherwise. - if (!(impl.flags_ & implementation_type::user_set_non_blocking)) + boost::system::error_code ec; + new_socket.reset(socket_ops::socket(impl.protocol_.family(), + impl.protocol_.type(), impl.protocol_.protocol(), ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else { - non_blocking = 0; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec); + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); } - - // The connect operation has finished successfully so we need to post the - // handler immediately. - this->get_io_service().post(bind_handler(handler, ec)); } - else if (ec == boost::asio::error::in_progress - || ec == boost::asio::error::would_block) + } + + // Start an asynchronous read or write operation using the the reactor. + void start_reactor_op(implementation_type& impl, int op_type, reactor_op* op) + { + reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if (is_open(impl)) { - // The connection is happening in the background, and we need to wait - // until the socket becomes writeable. - boost::shared_ptr completed(new bool(false)); - reactor->start_connect_op(impl.socket_, impl.reactor_data_, - connect_operation( - impl.socket_, - (impl.flags_ & implementation_type::user_set_non_blocking) != 0, - this->get_io_service(), handler)); + r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false); + return; } else + op->ec_ = boost::asio::error::bad_descriptor; + + iocp_service_.post_immediate_completion(op); + } + + // Start the asynchronous connect operation using the reactor. + void start_connect_op(implementation_type& impl, + reactor_op* op, const endpoint_type& peer_endpoint) + { + reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if (is_open(impl)) { - // Revert socket to blocking mode unless the user requested otherwise. - if (!(impl.flags_ & implementation_type::user_set_non_blocking)) + ioctl_arg_type non_blocking = 1; + if (!socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_)) { - non_blocking = 0; - boost::system::error_code ignored_ec; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); - } + if (socket_ops::connect(impl.socket_, peer_endpoint.data(), + peer_endpoint.size(), op->ec_) != 0) + { + if (!op->ec_ + && !(impl.flags_ & implementation_type::user_set_non_blocking)) + { + non_blocking = 0; + socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_); + } - // The connect operation has failed, so post the handler immediately. - this->get_io_service().post(bind_handler(handler, ec)); + if (op->ec_ == boost::asio::error::in_progress + || op->ec_ == boost::asio::error::would_block) + { + op->ec_ = boost::system::error_code(); + r.start_op(reactor::connect_op, impl.socket_, + impl.reactor_data_, op, true); + return; + } + } + } } + else + op->ec_ = boost::asio::error::bad_descriptor; + + iocp_service_.post_immediate_completion(op); } -private: // Helper function to close a socket when the associated object is being // destroyed. void close_for_destruction(implementation_type& impl) @@ -2317,11 +1896,11 @@ private: // Check if the reactor was created, in which case we need to close the // socket on the reactor as well to cancel any operations that might be // running there. - reactor_type* reactor = static_cast( + reactor* r = static_cast( interlocked_compare_exchange_pointer( reinterpret_cast(&reactor_), 0, 0)); - if (reactor) - reactor->close_descriptor(impl.socket_, impl.reactor_data_); + if (r) + r->close_descriptor(impl.socket_, impl.reactor_data_); // The socket destructor must not block. If the user has changed the // linger option to block in the foreground, we will change it back to the @@ -2347,6 +1926,35 @@ private: } } + // Update the ID of the thread from which cancellation is safe. + void update_cancellation_thread_id(implementation_type& impl) + { +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +#else // defined(BOOST_ASIO_ENABLE_CANCELIO) + (void)impl; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + } + + // Helper function to get the reactor. If no reactor has been created yet, a + // new one is obtained from the io_service and a pointer to it is cached in + // this service. + reactor& get_reactor() + { + reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (!r) + { + r = &(use_service(io_service_)); + interlocked_exchange_pointer(reinterpret_cast(&reactor_), r); + } + return *r; + } + // Helper function to emulate InterlockedCompareExchangePointer functionality // for: // - very old Platform SDKs; and @@ -2375,13 +1983,16 @@ private: #endif } + // The io_service used to obtain the reactor, if required. + boost::asio::io_service& io_service_; + // The IOCP service used for running asynchronous operations and dispatching // handlers. win_iocp_io_service& iocp_service_; // The reactor used for performing connect operations. This object is created // only if needed. - reactor_type* reactor_; + reactor* reactor_; // Mutex to protect access to the linked list of implementations. boost::asio::detail::mutex mutex_; diff --git a/3rdParty/Boost/src/boost/asio/detail/win_mutex.hpp b/3rdParty/Boost/src/boost/asio/detail/win_mutex.hpp index 107d707..176a5fd 100644 --- a/3rdParty/Boost/src/boost/asio/detail/win_mutex.hpp +++ b/3rdParty/Boost/src/boost/asio/detail/win_mutex.hpp @@ -66,15 +66,7 @@ public: // Lock the mutex. void lock() { - int error = do_lock(); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } + ::EnterCriticalSection(&crit_section_); } // Unlock the mutex. @@ -92,12 +84,20 @@ private: #if defined(__MINGW32__) // Not sure if MinGW supports structured exception handling, so for now // we'll just call the Windows API and hope. +# if defined(UNDER_CE) ::InitializeCriticalSection(&crit_section_); +# else + ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); +# endif return 0; #else __try { +# if defined(UNDER_CE) ::InitializeCriticalSection(&crit_section_); +# else + ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); +# endif } __except(GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) @@ -109,34 +109,6 @@ private: #endif } - // Locking must be performed in a separate function to lock() since the - // compiler does not support the use of structured exceptions and C++ - // exceptions in the same function. - int do_lock() - { -#if defined(__MINGW32__) - // Not sure if MinGW supports structured exception handling, so for now - // we'll just call the Windows API and hope. - ::EnterCriticalSection(&crit_section_); - return 0; -#else - __try - { - ::EnterCriticalSection(&crit_section_); - } - __except(GetExceptionCode() == STATUS_INVALID_HANDLE - || GetExceptionCode() == STATUS_NO_MEMORY - ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - if (GetExceptionCode() == STATUS_NO_MEMORY) - return ERROR_OUTOFMEMORY; - return ERROR_INVALID_HANDLE; - } - - return 0; -#endif - } - ::CRITICAL_SECTION crit_section_; }; diff --git a/3rdParty/Boost/src/boost/asio/impl/io_service.ipp b/3rdParty/Boost/src/boost/asio/impl/io_service.ipp index 9234dc4..20f868d 100644 --- a/3rdParty/Boost/src/boost/asio/impl/io_service.ipp +++ b/3rdParty/Boost/src/boost/asio/impl/io_service.ipp @@ -26,18 +26,9 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include #else -# include # include +# include #endif namespace boost { @@ -176,7 +167,6 @@ inline boost::asio::io_service& io_service::work::get_io_service() inline io_service::service::service(boost::asio::io_service& owner) : owner_(owner), - type_info_(0), next_(0) { } diff --git a/3rdParty/Boost/src/boost/asio/impl/read.ipp b/3rdParty/Boost/src/boost/asio/impl/read.ipp index 05ea960..772c06b 100644 --- a/3rdParty/Boost/src/boost/asio/impl/read.ipp +++ b/3rdParty/Boost/src/boost/asio/impl/read.ipp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -42,14 +43,14 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, boost::asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = s.read_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; @@ -130,51 +131,111 @@ namespace detail { template - class read_handler + class read_op + : detail::base_from_completion_cond { public: - typedef boost::asio::detail::consuming_buffers< - mutable_buffer, MutableBufferSequence> buffers_type; - - read_handler(AsyncReadStream& stream, const buffers_type& buffers, + read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) - : stream_(stream), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), buffers_(buffers), total_transferred_(0), - completion_condition_(completion_condition), - handler_(handler) + handler_(handler), + start_(true) { } void operator()(const boost::system::error_code& ec, std::size_t bytes_transferred) { - total_transferred_ += bytes_transferred; - buffers_.consume(bytes_transferred); - buffers_.set_max_size(detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_))); - if (buffers_.begin() == buffers_.end()) + switch (start_) { + case true: start_ = false; + buffers_.prepare(this->check(ec, total_transferred_)); + for (;;) + { + stream_.async_read_some(buffers_, *this); + return; default: + total_transferred_ += bytes_transferred; + buffers_.consume(bytes_transferred); + buffers_.prepare(this->check(ec, total_transferred_)); + if ((!ec && bytes_transferred == 0) + || buffers_.begin() == buffers_.end()) + break; + } + handler_(ec, total_transferred_); } - else + } + + //private: + AsyncReadStream& stream_; + boost::asio::detail::consuming_buffers< + mutable_buffer, MutableBufferSequence> buffers_; + std::size_t total_transferred_; + ReadHandler handler_; + bool start_; + }; + + template + class read_op + : detail::base_from_completion_cond + { + public: + read_op(AsyncReadStream& stream, + const boost::asio::mutable_buffers_1& buffers, + CompletionCondition completion_condition, + ReadHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffer_(buffers), + total_transferred_(0), + handler_(handler), + start_(true) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + std::size_t n = 0; + switch (start_) { - stream_.async_read_some(buffers_, *this); + case true: start_ = false; + n = this->check(ec, total_transferred_); + for (;;) + { + stream_.async_read_some(boost::asio::buffer( + buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check(ec, total_transferred_)) == 0 + || total_transferred_ == boost::asio::buffer_size(buffer_)) + break; + } + + handler_(ec, total_transferred_); } } //private: AsyncReadStream& stream_; - buffers_type buffers_; + boost::asio::mutable_buffer buffer_; std::size_t total_transferred_; - CompletionCondition completion_condition_; ReadHandler handler_; + bool start_; }; template inline void* asio_handler_allocate(std::size_t size, - read_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -184,7 +245,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -195,7 +256,7 @@ namespace detail typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -208,24 +269,10 @@ template tmp(buffers); - - boost::system::error_code ec; - std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - if (tmp.begin() == tmp.end()) - { - s.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - s.async_read_some(tmp, - detail::read_handler( - s, tmp, completion_condition, handler)); + detail::read_op( + s, buffers, completion_condition, handler)( + boost::system::error_code(), 0); } template - class read_streambuf_handler + class read_streambuf_op + : detail::base_from_completion_cond { public: - read_streambuf_handler(AsyncReadStream& stream, + read_streambuf_op(AsyncReadStream& stream, basic_streambuf& streambuf, CompletionCondition completion_condition, ReadHandler handler) - : stream_(stream), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), streambuf_(streambuf), total_transferred_(0), - completion_condition_(completion_condition), - handler_(handler) + handler_(handler), + start_(true) { } void operator()(const boost::system::error_code& ec, std::size_t bytes_transferred) { - total_transferred_ += bytes_transferred; - streambuf_.commit(bytes_transferred); - std::size_t max_size = detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_)); - std::size_t bytes_available = std::min(512, - std::min(max_size, - streambuf_.max_size() - streambuf_.size())); - if (bytes_available == 0) + std::size_t max_size, bytes_available; + switch (start_) { + case true: start_ = false; + max_size = this->check(ec, total_transferred_); + bytes_available = std::min(512, + std::min(max_size, + streambuf_.max_size() - streambuf_.size())); + for (;;) + { + stream_.async_read_some(streambuf_.prepare(bytes_available), *this); + return; default: + total_transferred_ += bytes_transferred; + streambuf_.commit(bytes_transferred); + max_size = this->check(ec, total_transferred_); + bytes_available = std::min(512, + std::min(max_size, + streambuf_.max_size() - streambuf_.size())); + if ((!ec && bytes_transferred == 0) || bytes_available == 0) + break; + } + handler_(ec, total_transferred_); } - else - { - stream_.async_read_some(streambuf_.prepare(bytes_available), *this); - } } //private: AsyncReadStream& stream_; boost::asio::basic_streambuf& streambuf_; std::size_t total_transferred_; - CompletionCondition completion_condition_; ReadHandler handler_; + bool start_; }; template inline void* asio_handler_allocate(std::size_t size, - read_streambuf_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -297,7 +356,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_streambuf_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -307,7 +366,7 @@ namespace detail template inline void asio_handler_invoke(const Function& function, - read_streambuf_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -321,23 +380,10 @@ inline void async_read(AsyncReadStream& s, boost::asio::basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler) { - boost::system::error_code ec; - std::size_t total_transferred = 0; - std::size_t max_size = detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred)); - std::size_t bytes_available = std::min(512, - std::min(max_size, b.max_size() - b.size())); - if (bytes_available == 0) - { - s.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - s.async_read_some(b.prepare(bytes_available), - detail::read_streambuf_handler( - s, b, completion_condition, handler)); + detail::read_streambuf_op( + s, b, completion_condition, handler)( + boost::system::error_code(), 0); } template diff --git a/3rdParty/Boost/src/boost/asio/impl/read_at.ipp b/3rdParty/Boost/src/boost/asio/impl/read_at.ipp index 91fd014..eb3c3f8 100644 --- a/3rdParty/Boost/src/boost/asio/impl/read_at.ipp +++ b/3rdParty/Boost/src/boost/asio/impl/read_at.ipp @@ -43,7 +43,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, boost::asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { @@ -51,7 +51,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, offset + total_transferred, tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; @@ -158,7 +158,7 @@ namespace detail { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.set_max_size(detail::adapt_completion_condition_result( + buffers_.prepare(detail::adapt_completion_condition_result( completion_condition_(ec, total_transferred_))); if (buffers_.begin() == buffers_.end()) { @@ -225,7 +225,7 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::system::error_code ec; std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); if (tmp.begin() == tmp.end()) { diff --git a/3rdParty/Boost/src/boost/asio/impl/write.ipp b/3rdParty/Boost/src/boost/asio/impl/write.ipp index 76bace3..28a5273 100644 --- a/3rdParty/Boost/src/boost/asio/impl/write.ipp +++ b/3rdParty/Boost/src/boost/asio/impl/write.ipp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -37,14 +38,14 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, boost::asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> tmp(buffers); std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = s.write_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; @@ -111,51 +112,164 @@ namespace detail { template - class write_handler + class write_op + : detail::base_from_completion_cond { public: - typedef boost::asio::detail::consuming_buffers< - const_buffer, ConstBufferSequence> buffers_type; - - write_handler(AsyncWriteStream& stream, const buffers_type& buffers, + write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) - : stream_(stream), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), buffers_(buffers), total_transferred_(0), - completion_condition_(completion_condition), - handler_(handler) + handler_(handler), + start_(true) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + switch (start_) + { + case true: start_ = false; + buffers_.prepare(this->check(ec, total_transferred_)); + for (;;) + { + stream_.async_write_some(buffers_, *this); + return; default: + total_transferred_ += bytes_transferred; + buffers_.consume(bytes_transferred); + buffers_.prepare(this->check(ec, total_transferred_)); + if ((!ec && bytes_transferred == 0) + || buffers_.begin() == buffers_.end()) + break; + } + + handler_(ec, total_transferred_); + } + } + + //private: + AsyncWriteStream& stream_; + boost::asio::detail::consuming_buffers< + const_buffer, ConstBufferSequence> buffers_; + std::size_t total_transferred_; + WriteHandler handler_; + bool start_; + }; + + template + class write_op + : detail::base_from_completion_cond + { + public: + write_op(AsyncWriteStream& stream, + const boost::asio::mutable_buffers_1& buffers, + CompletionCondition completion_condition, + WriteHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffer_(buffers), + total_transferred_(0), + handler_(handler), + start_(true) { } void operator()(const boost::system::error_code& ec, std::size_t bytes_transferred) { - total_transferred_ += bytes_transferred; - buffers_.consume(bytes_transferred); - buffers_.set_max_size(detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_))); - if (buffers_.begin() == buffers_.end()) + std::size_t n = 0; + switch (start_) { + case true: start_ = false; + n = this->check(ec, total_transferred_); + for (;;) + { + stream_.async_write_some(boost::asio::buffer( + buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check(ec, total_transferred_)) == 0 + || total_transferred_ == boost::asio::buffer_size(buffer_)) + break; + } + handler_(ec, total_transferred_); } - else + } + + //private: + AsyncWriteStream& stream_; + boost::asio::mutable_buffer buffer_; + std::size_t total_transferred_; + WriteHandler handler_; + bool start_; + }; + + template + class write_op + : detail::base_from_completion_cond + { + public: + write_op(AsyncWriteStream& stream, + const boost::asio::const_buffers_1& buffers, + CompletionCondition completion_condition, + WriteHandler handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffer_(buffers), + total_transferred_(0), + handler_(handler), + start_(true) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + std::size_t n = 0; + switch (start_) { - stream_.async_write_some(buffers_, *this); + case true: start_ = false; + n = this->check(ec, total_transferred_); + for (;;) + { + stream_.async_write_some(boost::asio::buffer( + buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check(ec, total_transferred_)) == 0 + || total_transferred_ == boost::asio::buffer_size(buffer_)) + break; + } + + handler_(ec, total_transferred_); } } //private: AsyncWriteStream& stream_; - buffers_type buffers_; + boost::asio::const_buffer buffer_; std::size_t total_transferred_; - CompletionCondition completion_condition_; WriteHandler handler_; + bool start_; }; template inline void* asio_handler_allocate(std::size_t size, - write_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -165,7 +279,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -176,7 +290,7 @@ namespace detail typename ConstBufferSequence, typename CompletionCondition, typename WriteHandler> inline void asio_handler_invoke(const Function& function, - write_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -189,24 +303,10 @@ template tmp(buffers); - - boost::system::error_code ec; - std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - if (tmp.begin() == tmp.end()) - { - s.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - s.async_write_some(tmp, - detail::write_handler( - s, tmp, completion_condition, handler)); + detail::write_op( + s, buffers, completion_condition, handler)( + boost::system::error_code(), 0); } template tmp(buffers); std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { @@ -46,7 +46,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, offset + total_transferred, tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; @@ -142,7 +142,7 @@ namespace detail { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.set_max_size(detail::adapt_completion_condition_result( + buffers_.prepare(detail::adapt_completion_condition_result( completion_condition_(ec, total_transferred_))); if (buffers_.begin() == buffers_.end()) { @@ -207,7 +207,7 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::system::error_code ec; std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); if (tmp.begin() == tmp.end()) { diff --git a/3rdParty/Boost/src/boost/asio/io_service.hpp b/3rdParty/Boost/src/boost/asio/io_service.hpp index a34d874..3863e96 100644 --- a/3rdParty/Boost/src/boost/asio/io_service.hpp +++ b/3rdParty/Boost/src/boost/asio/io_service.hpp @@ -26,11 +26,8 @@ #include #include -#include -#include -#include #include -#include +#include #include #include #include @@ -46,6 +43,12 @@ template Service& use_service(io_service& ios); template void add_service(io_service& ios, Service* svc); template bool has_service(io_service& ios); +#if defined(BOOST_ASIO_HAS_IOCP) +namespace detail { typedef win_iocp_io_service io_service_impl; } +#else +namespace detail { typedef task_io_service io_service_impl; } +#endif + /// Provides core I/O functionality. /** * The io_service class provides the core I/O functionality for users of the @@ -178,18 +181,9 @@ class io_service : private noncopyable { private: - // The type of the platform-specific implementation. + typedef detail::io_service_impl impl_type; #if defined(BOOST_ASIO_HAS_IOCP) - typedef detail::win_iocp_io_service impl_type; friend class detail::win_iocp_overlapped_ptr; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::task_io_service > impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::task_io_service > impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::task_io_service > impl_type; -#else - typedef detail::task_io_service > impl_type; #endif public: @@ -406,6 +400,14 @@ public: * @param handler The handler to be called. The io_service will make * a copy of the handler object as required. The function signature of the * handler must be: @code void handler(); @endcode + * + * @note This function throws an exception only if: + * + * @li the handler's @c asio_handler_allocate function; or + * + * @li the handler's copy constructor + * + * throws an exception. */ template void dispatch(CompletionHandler handler); @@ -423,6 +425,14 @@ public: * @param handler The handler to be called. The io_service will make * a copy of the handler object as required. The function signature of the * handler must be: @code void handler(); @endcode + * + * @note This function throws an exception only if: + * + * @li the handler's @c asio_handler_allocate function; or + * + * @li the handler's copy constructor + * + * throws an exception. */ template void post(CompletionHandler handler); @@ -606,9 +616,14 @@ private: virtual void shutdown_service() = 0; friend class boost::asio::detail::service_registry; + struct key + { + key() : type_info_(0), id_(0) {} + const std::type_info* type_info_; + const boost::asio::io_service::id* id_; + } key_; + boost::asio::io_service& owner_; - const std::type_info* type_info_; - const boost::asio::io_service::id* id_; service* next_; }; diff --git a/3rdParty/Boost/src/boost/asio/ip/address_v4.hpp b/3rdParty/Boost/src/boost/asio/ip/address_v4.hpp index e0088dc..47d36b5 100644 --- a/3rdParty/Boost/src/boost/asio/ip/address_v4.hpp +++ b/3rdParty/Boost/src/boost/asio/ip/address_v4.hpp @@ -102,7 +102,7 @@ public: return *this; } - /// Get the address in bytes. + /// Get the address in bytes, in network byte order. bytes_type to_bytes() const { using namespace std; // For memcpy. diff --git a/3rdParty/Boost/src/boost/asio/ip/address_v6.hpp b/3rdParty/Boost/src/boost/asio/ip/address_v6.hpp index 4105c8d..5685f08 100644 --- a/3rdParty/Boost/src/boost/asio/ip/address_v6.hpp +++ b/3rdParty/Boost/src/boost/asio/ip/address_v6.hpp @@ -115,7 +115,7 @@ public: scope_id_ = id; } - /// Get the address in bytes. + /// Get the address in bytes, in network byte order. bytes_type to_bytes() const { using namespace std; // For memcpy. diff --git a/3rdParty/Boost/src/boost/asio/ip/basic_resolver.hpp b/3rdParty/Boost/src/boost/asio/ip/basic_resolver.hpp index c4f13ab..0660ce5 100644 --- a/3rdParty/Boost/src/boost/asio/ip/basic_resolver.hpp +++ b/3rdParty/Boost/src/boost/asio/ip/basic_resolver.hpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include @@ -48,10 +50,10 @@ public: typedef typename InternetProtocol::endpoint endpoint_type; /// The query type. - typedef typename InternetProtocol::resolver_query query; + typedef basic_resolver_query query; /// The iterator type. - typedef typename InternetProtocol::resolver_iterator iterator; + typedef basic_resolver_iterator iterator; /// Constructor. /** diff --git a/3rdParty/Boost/src/boost/asio/ip/basic_resolver_iterator.hpp b/3rdParty/Boost/src/boost/asio/ip/basic_resolver_iterator.hpp index 90644a2..5f4937b 100644 --- a/3rdParty/Boost/src/boost/asio/ip/basic_resolver_iterator.hpp +++ b/3rdParty/Boost/src/boost/asio/ip/basic_resolver_iterator.hpp @@ -18,8 +18,7 @@ #include #include -#include -#include +#include #include #include #include @@ -48,14 +47,18 @@ namespace ip { */ template class basic_resolver_iterator - : public boost::iterator_facade< - basic_resolver_iterator, - const basic_resolver_entry, - boost::forward_traversal_tag> +#if defined(GENERATING_DOCUMENTATION) + : public std::iterator< +#else // defined(GENERATING_DOCUMENTATION) + : public boost::iterator< +#endif // defined(GENERATING_DOCUMENTATION) + std::forward_iterator_tag, + const basic_resolver_entry > { public: /// Default constructor creates an end iterator. basic_resolver_iterator() + : index_(0) { } @@ -91,11 +94,6 @@ public: address_info = address_info->ai_next; } - if (iter.values_->size()) - iter.iter_ = iter.values_->begin(); - else - iter.values_.reset(); - return iter; } @@ -109,21 +107,58 @@ public: iter.values_->push_back( basic_resolver_entry( endpoint, host_name, service_name)); - iter.iter_ = iter.values_->begin(); return iter; } -private: - friend class boost::iterator_core_access; + /// Dereference an iterator. + const basic_resolver_entry& operator*() const + { + return dereference(); + } + + /// Dereference an iterator. + const basic_resolver_entry* operator->() const + { + return &dereference(); + } + + /// Increment operator (prefix). + basic_resolver_iterator& operator++() + { + increment(); + return *this; + } + /// Increment operator (postfix). + basic_resolver_iterator operator++(int) + { + basic_resolver_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Test two iterators for equality. + friend bool operator==(const basic_resolver_iterator& a, + const basic_resolver_iterator& b) + { + return a.equal(b); + } + + /// Test two iterators for inequality. + friend bool operator!=(const basic_resolver_iterator& a, + const basic_resolver_iterator& b) + { + return !a.equal(b); + } + +private: void increment() { - if (++*iter_ == values_->end()) + if (++index_ == values_->size()) { // Reset state to match a default constructed end iterator. values_.reset(); - typedef typename values_type::const_iterator values_iterator_type; - iter_.reset(); + index_ = 0; } } @@ -133,18 +168,17 @@ private: return true; if (values_ != other.values_) return false; - return *iter_ == *other.iter_; + return index_ == other.index_; } const basic_resolver_entry& dereference() const { - return **iter_; + return (*values_)[index_]; } typedef std::vector > values_type; - typedef typename values_type::const_iterator values_iter_type; boost::shared_ptr values_; - boost::optional iter_; + std::size_t index_; }; } // namespace ip diff --git a/3rdParty/Boost/src/boost/asio/ip/basic_resolver_query.hpp b/3rdParty/Boost/src/boost/asio/ip/basic_resolver_query.hpp index e95362b..75d3c47 100644 --- a/3rdParty/Boost/src/boost/asio/ip/basic_resolver_query.hpp +++ b/3rdParty/Boost/src/boost/asio/ip/basic_resolver_query.hpp @@ -47,14 +47,30 @@ public: typedef InternetProtocol protocol_type; /// Construct with specified service name for any protocol. + /** + * This constructor is typically used to perform name resolution for local + * service binding. + * + * @param service_name A string identifying the requested service. This may + * be a descriptive name or a numeric string corresponding to a port number. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for local service + * binding. + * + * @note On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ basic_resolver_query(const std::string& service_name, - int flags = passive | address_configured) + resolver_query_base::flags resolve_flags = passive | address_configured) : hints_(), host_name_(), service_name_(service_name) { typename InternetProtocol::endpoint endpoint; - hints_.ai_flags = flags; + hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = PF_UNSPEC; hints_.ai_socktype = endpoint.protocol().type(); hints_.ai_protocol = endpoint.protocol().protocol(); @@ -65,14 +81,33 @@ public: } /// Construct with specified service name for a given protocol. + /** + * This constructor is typically used to perform name resolution for local + * service binding with a specific protocol version. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param service_name A string identifying the requested service. This may + * be a descriptive name or a numeric string corresponding to a port number. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for local service + * binding. + * + * @note On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ basic_resolver_query(const protocol_type& protocol, const std::string& service_name, - int flags = passive | address_configured) + resolver_query_base::flags resolve_flags = passive | address_configured) : hints_(), host_name_(), service_name_(service_name) { - hints_.ai_flags = flags; + hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = protocol.family(); hints_.ai_socktype = protocol.type(); hints_.ai_protocol = protocol.protocol(); @@ -83,14 +118,45 @@ public: } /// Construct with specified host name and service name for any protocol. + /** + * This constructor is typically used to perform name resolution for + * communication with remote hosts. + * + * @param host_name A string identifying a location. May be a descriptive name + * or a numeric address string. If an empty string and the passive flag has + * been specified, the resolved endpoints are suitable for local service + * binding. If an empty string and passive is not specified, the resolved + * endpoints will use the loopback address. + * + * @param service_name A string identifying the requested service. This may + * be a descriptive name or a numeric string corresponding to a port number. + * May be an empty string, in which case all resolved endpoints will have a + * port number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ basic_resolver_query(const std::string& host_name, - const std::string& service_name, int flags = address_configured) + const std::string& service_name, + resolver_query_base::flags resolve_flags = address_configured) : hints_(), host_name_(host_name), service_name_(service_name) { typename InternetProtocol::endpoint endpoint; - hints_.ai_flags = flags; + hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = PF_UNSPEC; hints_.ai_socktype = endpoint.protocol().type(); hints_.ai_protocol = endpoint.protocol().protocol(); @@ -101,14 +167,47 @@ public: } /// Construct with specified host name and service name for a given protocol. + /** + * This constructor is typically used to perform name resolution for + * communication with remote hosts. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host_name A string identifying a location. May be a descriptive name + * or a numeric address string. If an empty string and the passive flag has + * been specified, the resolved endpoints are suitable for local service + * binding. If an empty string and passive is not specified, the resolved + * endpoints will use the loopback address. + * + * @param service_name A string identifying the requested service. This may + * be a descriptive name or a numeric string corresponding to a port number. + * May be an empty string, in which case all resolved endpoints will have a + * port number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ basic_resolver_query(const protocol_type& protocol, const std::string& host_name, const std::string& service_name, - int flags = address_configured) + resolver_query_base::flags resolve_flags = address_configured) : hints_(), host_name_(host_name), service_name_(service_name) { - hints_.ai_flags = flags; + hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = protocol.family(); hints_.ai_socktype = protocol.type(); hints_.ai_protocol = protocol.protocol(); diff --git a/3rdParty/Boost/src/boost/asio/ip/icmp.hpp b/3rdParty/Boost/src/boost/asio/ip/icmp.hpp index b70d87d..5d2fcab 100644 --- a/3rdParty/Boost/src/boost/asio/ip/icmp.hpp +++ b/3rdParty/Boost/src/boost/asio/ip/icmp.hpp @@ -45,10 +45,10 @@ public: /// The type of a ICMP endpoint. typedef basic_endpoint endpoint; - /// The type of a resolver query. + /// (Deprecated: use resolver::query.) The type of a resolver query. typedef basic_resolver_query resolver_query; - /// The type of a resolver iterator. + /// (Deprecated: use resolver::iterator.) The type of a resolver iterator. typedef basic_resolver_iterator resolver_iterator; /// Construct to represent the IPv4 ICMP protocol. diff --git a/3rdParty/Boost/src/boost/asio/ip/resolver_query_base.hpp b/3rdParty/Boost/src/boost/asio/ip/resolver_query_base.hpp index d21b462..7fe1650 100644 --- a/3rdParty/Boost/src/boost/asio/ip/resolver_query_base.hpp +++ b/3rdParty/Boost/src/boost/asio/ip/resolver_query_base.hpp @@ -35,58 +35,107 @@ class resolver_query_base { public: #if defined(GENERATING_DOCUMENTATION) + /// A bitmask type (C++ Std [lib.bitmask.types]). + typedef unspecified flags; + /// Determine the canonical name of the host specified in the query. - static const int canonical_name = implementation_defined; + static const flags canonical_name = implementation_defined; /// Indicate that returned endpoint is intended for use as a locally bound /// socket endpoint. - static const int passive = implementation_defined; + static const flags passive = implementation_defined; /// Host name should be treated as a numeric string defining an IPv4 or IPv6 /// address and no name resolution should be attempted. - static const int numeric_host = implementation_defined; + static const flags numeric_host = implementation_defined; /// Service name should be treated as a numeric string defining a port number /// and no name resolution should be attempted. - static const int numeric_service = implementation_defined; + static const flags numeric_service = implementation_defined; /// If the query protocol family is specified as IPv6, return IPv4-mapped /// IPv6 addresses on finding no IPv6 addresses. - static const int v4_mapped = implementation_defined; + static const flags v4_mapped = implementation_defined; /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses. - static const int all_matching = implementation_defined; + static const flags all_matching = implementation_defined; /// Only return IPv4 addresses if a non-loopback IPv4 address is configured /// for the system. Only return IPv6 addresses if a non-loopback IPv6 address /// is configured for the system. - static const int address_configured = implementation_defined; + static const flags address_configured = implementation_defined; #else - BOOST_STATIC_CONSTANT(int, canonical_name = AI_CANONNAME); - BOOST_STATIC_CONSTANT(int, passive = AI_PASSIVE); - BOOST_STATIC_CONSTANT(int, numeric_host = AI_NUMERICHOST); + enum flags + { + canonical_name = AI_CANONNAME, + passive = AI_PASSIVE, + numeric_host = AI_NUMERICHOST, # if defined(AI_NUMERICSERV) - BOOST_STATIC_CONSTANT(int, numeric_service = AI_NUMERICSERV); + numeric_service = AI_NUMERICSERV, # else - BOOST_STATIC_CONSTANT(int, numeric_service = 0); + numeric_service = 0, # endif - // Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but - // does not implement them. Therefore they are specifically excluded here. + // Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but + // does not implement them. Therefore they are specifically excluded here. # if defined(AI_V4MAPPED) && !defined(__QNXNTO__) - BOOST_STATIC_CONSTANT(int, v4_mapped = AI_V4MAPPED); + v4_mapped = AI_V4MAPPED, # else - BOOST_STATIC_CONSTANT(int, v4_mapped = 0); + v4_mapped = 0, # endif # if defined(AI_ALL) && !defined(__QNXNTO__) - BOOST_STATIC_CONSTANT(int, all_matching = AI_ALL); + all_matching = AI_ALL, # else - BOOST_STATIC_CONSTANT(int, all_matching = 0); + all_matching = 0, # endif # if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__) - BOOST_STATIC_CONSTANT(int, address_configured = AI_ADDRCONFIG); + address_configured = AI_ADDRCONFIG # else - BOOST_STATIC_CONSTANT(int, address_configured = 0); + address_configured = 0 # endif + }; + + // Implement bitmask operations as shown in C++ Std [lib.bitmask.types]. + + friend flags operator&(flags x, flags y) + { + return static_cast( + static_cast(x) & static_cast(y)); + } + + friend flags operator|(flags x, flags y) + { + return static_cast( + static_cast(x) | static_cast(y)); + } + + friend flags operator^(flags x, flags y) + { + return static_cast( + static_cast(x) ^ static_cast(y)); + } + + friend flags operator~(flags x) + { + return static_cast(static_cast(~x)); + } + + friend flags& operator&=(flags& x, flags y) + { + x = x & y; + return x; + } + + friend flags& operator|=(flags& x, flags y) + { + x = x | y; + return x; + } + + friend flags& operator^=(flags& x, flags y) + { + x = x ^ y; + return x; + } #endif protected: diff --git a/3rdParty/Boost/src/boost/asio/ip/resolver_service.hpp b/3rdParty/Boost/src/boost/asio/ip/resolver_service.hpp index 1cd12b9..ba59f6d 100644 --- a/3rdParty/Boost/src/boost/asio/ip/resolver_service.hpp +++ b/3rdParty/Boost/src/boost/asio/ip/resolver_service.hpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include @@ -49,10 +51,10 @@ public: typedef typename InternetProtocol::endpoint endpoint_type; /// The query type. - typedef typename InternetProtocol::resolver_query query_type; + typedef basic_resolver_query query_type; /// The iterator type. - typedef typename InternetProtocol::resolver_iterator iterator_type; + typedef basic_resolver_iterator iterator_type; private: // The type of the platform-specific implementation. diff --git a/3rdParty/Boost/src/boost/asio/ip/tcp.hpp b/3rdParty/Boost/src/boost/asio/ip/tcp.hpp index a42c999..541c95c 100644 --- a/3rdParty/Boost/src/boost/asio/ip/tcp.hpp +++ b/3rdParty/Boost/src/boost/asio/ip/tcp.hpp @@ -48,10 +48,10 @@ public: /// The type of a TCP endpoint. typedef basic_endpoint endpoint; - /// The type of a resolver query. + /// (Deprecated: use resolver::query.) The type of a resolver query. typedef basic_resolver_query resolver_query; - /// The type of a resolver iterator. + /// (Deprecated: use resolver::iterator.) The type of a resolver iterator. typedef basic_resolver_iterator resolver_iterator; /// Construct to represent the IPv4 TCP protocol. diff --git a/3rdParty/Boost/src/boost/asio/ip/udp.hpp b/3rdParty/Boost/src/boost/asio/ip/udp.hpp index e1793c7..e592e06 100644 --- a/3rdParty/Boost/src/boost/asio/ip/udp.hpp +++ b/3rdParty/Boost/src/boost/asio/ip/udp.hpp @@ -45,10 +45,10 @@ public: /// The type of a UDP endpoint. typedef basic_endpoint endpoint; - /// The type of a resolver query. + /// (Deprecated: use resolver::query.) The type of a resolver query. typedef basic_resolver_query resolver_query; - /// The type of a resolver iterator. + /// (Deprecated: use resolver::iterator.) The type of a resolver iterator. typedef basic_resolver_iterator resolver_iterator; /// Construct to represent the IPv4 UDP protocol. diff --git a/3rdParty/Boost/src/boost/asio/posix/stream_descriptor_service.hpp b/3rdParty/Boost/src/boost/asio/posix/stream_descriptor_service.hpp index e64a617..89b9ef4 100644 --- a/3rdParty/Boost/src/boost/asio/posix/stream_descriptor_service.hpp +++ b/3rdParty/Boost/src/boost/asio/posix/stream_descriptor_service.hpp @@ -35,19 +35,7 @@ #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) -#if defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include -#else -# include -# include -#endif +#include namespace boost { namespace asio { @@ -69,19 +57,7 @@ public: private: // The type of the platform-specific implementation. -#if defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_descriptor_service< - detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_descriptor_service< - detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_descriptor_service< - detail::dev_poll_reactor > service_impl_type; -#else - typedef detail::reactive_descriptor_service< - detail::select_reactor > service_impl_type; -#endif + typedef detail::reactive_descriptor_service service_impl_type; public: /// The type of a stream descriptor implementation. @@ -101,13 +77,14 @@ public: /// Construct a new stream descriptor service for the specified io_service. explicit stream_descriptor_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined descriptorr objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new stream descriptor implementation. @@ -196,8 +173,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace posix diff --git a/3rdParty/Boost/src/boost/asio/raw_socket_service.hpp b/3rdParty/Boost/src/boost/asio/raw_socket_service.hpp index 1b5c03c..23427d7 100644 --- a/3rdParty/Boost/src/boost/asio/raw_socket_service.hpp +++ b/3rdParty/Boost/src/boost/asio/raw_socket_service.hpp @@ -28,17 +28,7 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include #else -# include # include #endif @@ -70,18 +60,8 @@ private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_socket_service< - Protocol, detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_socket_service< - Protocol, detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_socket_service< - Protocol, detail::dev_poll_reactor > service_impl_type; #else - typedef detail::reactive_socket_service< - Protocol, detail::select_reactor > service_impl_type; + typedef detail::reactive_socket_service service_impl_type; #endif public: @@ -103,13 +83,14 @@ public: explicit raw_socket_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< raw_socket_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new raw socket implementation. @@ -324,8 +305,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/3rdParty/Boost/src/boost/asio/read.hpp b/3rdParty/Boost/src/boost/asio/read.hpp index 8243d0f..40ccc00 100644 --- a/3rdParty/Boost/src/boost/asio/read.hpp +++ b/3rdParty/Boost/src/boost/asio/read.hpp @@ -301,7 +301,10 @@ std::size_t read(SyncReadStream& s, basic_streambuf& b, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. + * async_read_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. @@ -430,7 +433,10 @@ void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. + * async_read_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. @@ -477,7 +483,10 @@ void async_read(AsyncReadStream& s, basic_streambuf& b, * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. + * async_read_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. diff --git a/3rdParty/Boost/src/boost/asio/read_until.hpp b/3rdParty/Boost/src/boost/asio/read_until.hpp index 2f50072..ec6cb42 100644 --- a/3rdParty/Boost/src/boost/asio/read_until.hpp +++ b/3rdParty/Boost/src/boost/asio/read_until.hpp @@ -129,6 +129,16 @@ struct is_match_condition * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode + * After the @c read_until operation completes successfully, the buffer @c b + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. */ template std::size_t read_until(SyncReadStream& s, @@ -206,6 +216,16 @@ std::size_t read_until(SyncReadStream& s, * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode + * After the @c read_until operation completes successfully, the buffer @c b + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. */ template std::size_t read_until(SyncReadStream& s, @@ -285,6 +305,16 @@ std::size_t read_until(SyncReadStream& s, * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode + * After the @c read_until operation completes successfully, the buffer @c b + * contains the data which matched the regular expression: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * match, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. */ template std::size_t read_until(SyncReadStream& s, @@ -511,8 +541,12 @@ std::size_t read_until(SyncReadStream& s, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. If the streambuf's get area already contains the - * delimiter, the asynchronous operation completes immediately. + * async_read_some function, and is known as a composed operation. If + * the streambuf's get area already contains the delimiter, this asynchronous + * operation completes immediately. The program must ensure that the stream + * performs no other read operations (such as async_read, async_read_until, the + * stream's async_read_some function, or any other composed operations that + * perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. @@ -561,6 +595,16 @@ std::size_t read_until(SyncReadStream& s, * } * ... * boost::asio::async_read_until(s, b, '\n', handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c b contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. */ template void async_read_until(AsyncReadStream& s, @@ -580,8 +624,12 @@ void async_read_until(AsyncReadStream& s, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. If the streambuf's get area already contains the - * delimiter, the asynchronous operation completes immediately. + * async_read_some function, and is known as a composed operation. If + * the streambuf's get area already contains the delimiter, this asynchronous + * operation completes immediately. The program must ensure that the stream + * performs no other read operations (such as async_read, async_read_until, the + * stream's async_read_some function, or any other composed operations that + * perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. @@ -630,6 +678,16 @@ void async_read_until(AsyncReadStream& s, * } * ... * boost::asio::async_read_until(s, b, "\r\n", handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c b contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. */ template void async_read_until(AsyncReadStream& s, @@ -650,8 +708,13 @@ void async_read_until(AsyncReadStream& s, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. If the streambuf's get area already contains data - * that matches the regular expression, the function returns immediately. + * async_read_some function, and is known as a composed operation. If + * the streambuf's get area already contains data that matches the regular + * expression, this asynchronous operation completes immediately. The program + * must ensure that the stream performs no other read operations (such as + * async_read, async_read_until, the stream's async_read_some function, or any + * other composed operations that perform reads) until this operation + * completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. @@ -702,6 +765,16 @@ void async_read_until(AsyncReadStream& s, * } * ... * boost::asio::async_read_until(s, b, boost::regex("\r\n"), handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c b contains the data which matched the regular expression: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * match, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. */ template void async_read_until(AsyncReadStream& s, @@ -723,8 +796,12 @@ void async_read_until(AsyncReadStream& s, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. If the match condition function object already - * indicates a match, the operation completes immediately. + * async_read_some function, and is known as a composed operation. If + * the match condition function object already indicates a match, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. diff --git a/3rdParty/Boost/src/boost/asio/serial_port_service.hpp b/3rdParty/Boost/src/boost/asio/serial_port_service.hpp index 3abd244..f1a2344 100644 --- a/3rdParty/Boost/src/boost/asio/serial_port_service.hpp +++ b/3rdParty/Boost/src/boost/asio/serial_port_service.hpp @@ -54,18 +54,8 @@ private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_HAS_IOCP) typedef detail::win_iocp_serial_port_service service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_serial_port_service< - detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_serial_port_service< - detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_serial_port_service< - detail::dev_poll_reactor > service_impl_type; #else - typedef detail::reactive_serial_port_service< - detail::select_reactor > service_impl_type; + typedef detail::reactive_serial_port_service service_impl_type; #endif public: @@ -86,13 +76,14 @@ public: /// Construct a new serial port service for the specified io_service. explicit serial_port_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new serial port implementation. @@ -203,8 +194,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/3rdParty/Boost/src/boost/asio/socket_acceptor_service.hpp b/3rdParty/Boost/src/boost/asio/socket_acceptor_service.hpp index edca5b7..184580f 100644 --- a/3rdParty/Boost/src/boost/asio/socket_acceptor_service.hpp +++ b/3rdParty/Boost/src/boost/asio/socket_acceptor_service.hpp @@ -24,17 +24,7 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include #else -# include # include #endif @@ -66,18 +56,8 @@ private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_socket_service< - Protocol, detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_socket_service< - Protocol, detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_socket_service< - Protocol, detail::dev_poll_reactor > service_impl_type; #else - typedef detail::reactive_socket_service< - Protocol, detail::select_reactor > service_impl_type; + typedef detail::reactive_socket_service service_impl_type; #endif public: @@ -99,13 +79,14 @@ public: explicit socket_acceptor_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< socket_acceptor_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new socket acceptor implementation. @@ -226,8 +207,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/3rdParty/Boost/src/boost/asio/stream_socket_service.hpp b/3rdParty/Boost/src/boost/asio/stream_socket_service.hpp index 6a8dd36..15aa683 100644 --- a/3rdParty/Boost/src/boost/asio/stream_socket_service.hpp +++ b/3rdParty/Boost/src/boost/asio/stream_socket_service.hpp @@ -28,17 +28,7 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include #else -# include # include #endif @@ -70,18 +60,8 @@ private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_socket_service< - Protocol, detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_socket_service< - Protocol, detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_socket_service< - Protocol, detail::dev_poll_reactor > service_impl_type; #else - typedef detail::reactive_socket_service< - Protocol, detail::select_reactor > service_impl_type; + typedef detail::reactive_socket_service service_impl_type; #endif public: @@ -103,13 +83,14 @@ public: explicit stream_socket_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< stream_socket_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new stream socket implementation. @@ -287,8 +268,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/3rdParty/Boost/src/boost/asio/version.hpp b/3rdParty/Boost/src/boost/asio/version.hpp index 67e9171..0172f73 100644 --- a/3rdParty/Boost/src/boost/asio/version.hpp +++ b/3rdParty/Boost/src/boost/asio/version.hpp @@ -18,6 +18,6 @@ // BOOST_ASIO_VERSION % 100 is the sub-minor version // BOOST_ASIO_VERSION / 100 % 1000 is the minor version // BOOST_ASIO_VERSION / 100000 is the major version -#define BOOST_ASIO_VERSION 100404 // 1.4.4 +#define BOOST_ASIO_VERSION 100405 // 1.4.5 #endif // BOOST_ASIO_VERSION_HPP diff --git a/3rdParty/Boost/src/boost/asio/windows/random_access_handle_service.hpp b/3rdParty/Boost/src/boost/asio/windows/random_access_handle_service.hpp index fbbde67..1dcbee4 100644 --- a/3rdParty/Boost/src/boost/asio/windows/random_access_handle_service.hpp +++ b/3rdParty/Boost/src/boost/asio/windows/random_access_handle_service.hpp @@ -78,13 +78,14 @@ public: explicit random_access_handle_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< random_access_handle_service>(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new random-access handle implementation. @@ -165,8 +166,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace windows diff --git a/3rdParty/Boost/src/boost/asio/windows/stream_handle_service.hpp b/3rdParty/Boost/src/boost/asio/windows/stream_handle_service.hpp index c2224e4..cc6c6e8 100644 --- a/3rdParty/Boost/src/boost/asio/windows/stream_handle_service.hpp +++ b/3rdParty/Boost/src/boost/asio/windows/stream_handle_service.hpp @@ -76,13 +76,14 @@ public: /// Construct a new stream handle service for the specified io_service. explicit stream_handle_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new stream handle implementation. @@ -163,8 +164,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace windows diff --git a/3rdParty/Boost/src/boost/asio/write.hpp b/3rdParty/Boost/src/boost/asio/write.hpp index 2b9d4b7..2a95735 100644 --- a/3rdParty/Boost/src/boost/asio/write.hpp +++ b/3rdParty/Boost/src/boost/asio/write.hpp @@ -306,7 +306,10 @@ std::size_t write(SyncWriteStream& s, basic_streambuf& b, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_write_some function. + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. * * @param s The stream to which the data is to be written. The type must support * the AsyncWriteStream concept. @@ -360,7 +363,10 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's - * async_write_some function. + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. * * @param s The stream to which the data is to be written. The type must support * the AsyncWriteStream concept. @@ -430,7 +436,10 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_write_some function. + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. * * @param s The stream to which the data is to be written. The type must support * the AsyncWriteStream concept. @@ -472,7 +481,10 @@ void async_write(AsyncWriteStream& s, basic_streambuf& b, * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's - * async_write_some function. + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. * * @param s The stream to which the data is to be written. The type must support * the AsyncWriteStream concept. diff --git a/3rdParty/Boost/src/boost/concept/detail/has_constraints.hpp b/3rdParty/Boost/src/boost/concept/detail/has_constraints.hpp index 3112b55..9191181 100644 --- a/3rdParty/Boost/src/boost/concept/detail/has_constraints.hpp +++ b/3rdParty/Boost/src/boost/concept/detail/has_constraints.hpp @@ -19,7 +19,7 @@ namespace detail template struct wrap_constraints {}; -#if BOOST_WORKAROUND(__SUNPRO_CC, <= 0x580) +#if BOOST_WORKAROUND(__SUNPRO_CC, <= 0x580) || defined(__CUDACC__) // Work around the following bogus error in Sun Studio 11, by // turning off the has_constraints function entirely: // Error: complex expression not allowed in dependent template diff --git a/3rdParty/Boost/src/boost/concept_check.hpp b/3rdParty/Boost/src/boost/concept_check.hpp index 12ec2ad..7ee3036 100644 --- a/3rdParty/Boost/src/boost/concept_check.hpp +++ b/3rdParty/Boost/src/boost/concept_check.hpp @@ -330,7 +330,16 @@ namespace boost { f(arg); } - + +#if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ + && BOOST_WORKAROUND(__GNUC__, > 3))) + // Declare a dummy construktor to make gcc happy. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a refence type. + // (warning: non-static reference "const double& boost::UnaryFunction::arg" + // in class without a constructor [-Wuninitialized]) + UnaryFunction(); +#endif + Func f; Arg arg; }; diff --git a/3rdParty/Boost/src/boost/config/compiler/gcc.hpp b/3rdParty/Boost/src/boost/config/compiler/gcc.hpp index 6cae94c..fe2c52e 100644 --- a/3rdParty/Boost/src/boost/config/compiler/gcc.hpp +++ b/3rdParty/Boost/src/boost/config/compiler/gcc.hpp @@ -108,11 +108,8 @@ // #define BOOST_NO_CONSTEXPR #define BOOST_NO_EXTERN_TEMPLATE -#define BOOST_NO_LAMBDAS #define BOOST_NO_NULLPTR -#define BOOST_NO_RAW_LITERALS #define BOOST_NO_TEMPLATE_ALIASES -#define BOOST_NO_UNICODE_LITERALS // C++0x features in 4.3.n and later // @@ -168,6 +165,9 @@ // #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_NO_EXPLICIT_CONVERSION_OPERATORS +# define BOOST_NO_LAMBDAS +# define BOOST_NO_RAW_LITERALS +# define BOOST_NO_UNICODE_LITERALS #endif // ConceptGCC compiler: diff --git a/3rdParty/Boost/src/boost/config/compiler/nvcc.hpp b/3rdParty/Boost/src/boost/config/compiler/nvcc.hpp new file mode 100644 index 0000000..7d831af --- /dev/null +++ b/3rdParty/Boost/src/boost/config/compiler/nvcc.hpp @@ -0,0 +1,85 @@ +// (C) Copyright Eric Jourdanneau, Joel Falcou 2010 +// Use, modification and distribution are subject to 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) + +// See http://www.boost.org for most recent version. + +// NVIDIA CUDA C++ compiler setup + +#ifndef BOOST_COMPILER +# define BOOST_COMPILER "NVIDIA CUDA C++ Compiler" +#endif + +// NVIDIA Specific support +// BOOST_GPU_ENABLED : Flag a function or a method as being enabled on the host and device +#define BOOST_GPU_ENABLED __host__ __device__ + +// Boost support macro for NVCC +// NVCC Basically behaves like some flavor of MSVC6 + some specific quirks +#define BOOST_NO_INCLASS_MEMBER_INITIALIZATION +#define BOOST_MSVC6_MEMBER_TEMPLATES +#define BOOST_HAS_UNISTD_H +#define BOOST_HAS_STDINT_H +#define BOOST_HAS_SIGACTION +#define BOOST_HAS_SCHED_YIELD +#define BOOST_HAS_PTHREADS +#define BOOST_HAS_PTHREAD_YIELD +#define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +#define BOOST_HAS_PARTIAL_STD_ALLOCATOR +#define BOOST_HAS_NRVO +#define BOOST_HAS_NL_TYPES_H +#define BOOST_HAS_NANOSLEEP +#define BOOST_HAS_LONG_LONG +#define BOOST_HAS_LOG1P +#define BOOST_HAS_GETTIMEOFDAY +#define BOOST_HAS_EXPM1 +#define BOOST_HAS_DIRENT_H +#define BOOST_HAS_CLOCK_GETTIME +#define BOOST_NO_VARIADIC_TEMPLATES +#define BOOST_NO_UNICODE_LITERALS +#define BOOST_NO_TEMPLATE_ALIASES +#define BOOST_NO_STD_UNORDERED +#define BOOST_NO_STATIC_ASSERT +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_SCOPED_ENUMS +#define BOOST_NO_RVALUE_REFERENCES +#define BOOST_NO_RAW_LITERALS +#define BOOST_NO_NULLPTR +#define BOOST_NO_LAMBDAS +#define BOOST_NO_INITIALIZER_LISTS +#define BOOST_NO_MS_INT64_NUMERIC_LIMITS +#define BOOST_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS +#define BOOST_NO_EXTERN_TEMPLATE +#define BOOST_NO_EXPLICIT_CONVERSION_OPERATORS +#define BOOST_NO_DELETED_FUNCTIONS +#define BOOST_NO_DEFAULTED_FUNCTIONS +#define BOOST_NO_DECLTYPE +#define BOOST_NO_CONSTEXPR +#define BOOST_NO_CONCEPTS +#define BOOST_NO_CHAR32_T +#define BOOST_NO_CHAR16_T +#define BOOST_NO_AUTO_MULTIDECLARATIONS +#define BOOST_NO_AUTO_DECLARATIONS +#define BOOST_NO_0X_HDR_UNORDERED_SET +#define BOOST_NO_0X_HDR_UNORDERED_MAP +#define BOOST_NO_0X_HDR_TYPE_TRAITS +#define BOOST_NO_0X_HDR_TUPLE +#define BOOST_NO_0X_HDR_THREAD +#define BOOST_NO_0X_HDR_SYSTEM_ERROR +#define BOOST_NO_0X_HDR_REGEX +#define BOOST_NO_0X_HDR_RATIO +#define BOOST_NO_0X_HDR_RANDOM +#define BOOST_NO_0X_HDR_MUTEX +#define BOOST_NO_0X_HDR_MEMORY_CONCEPTS +#define BOOST_NO_0X_HDR_ITERATOR_CONCEPTS +#define BOOST_NO_0X_HDR_INITIALIZER_LIST +#define BOOST_NO_0X_HDR_FUTURE +#define BOOST_NO_0X_HDR_FORWARD_LIST +#define BOOST_NO_0X_HDR_CONTAINER_CONCEPTS +#define BOOST_NO_0X_HDR_CONDITION_VARIABLE +#define BOOST_NO_0X_HDR_CONCEPTS +#define BOOST_NO_0X_HDR_CODECVT +#define BOOST_NO_0X_HDR_CHRONO +#define BOOST_NO_0X_HDR_ARRAY + diff --git a/3rdParty/Boost/src/boost/config/compiler/pgi.hpp b/3rdParty/Boost/src/boost/config/compiler/pgi.hpp index e40553e..1c7c84b 100644 --- a/3rdParty/Boost/src/boost/config/compiler/pgi.hpp +++ b/3rdParty/Boost/src/boost/config/compiler/pgi.hpp @@ -16,11 +16,28 @@ // if no threading API is detected. // -#if (__PGIC__ >= 7) +// PGI 10.x doesn't seem to define __PGIC__ + +// versions earlier than 10.x do define __PGIC__ +#if __PGIC__ >= 10 + +// options requested by configure --enable-test +#define BOOST_HAS_PTHREADS +#define BOOST_HAS_NRVO +#define BOOST_HAS_LONG_LONG + +// options --enable-test wants undefined +#undef BOOST_NO_STDC_NAMESPACE +#undef BOOST_NO_EXCEPTION_STD_NAMESPACE +#undef BOOST_DEDUCED_TYPENAME + +#elif __PGIC__ >= 7 #define BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL #define BOOST_NO_TWO_PHASE_NAME_LOOKUP #define BOOST_NO_SWPRINTF +#define BOOST_NO_AUTO_MULTIDECLARATIONS +#define BOOST_NO_AUTO_DECLARATIONS #else @@ -32,8 +49,6 @@ // // See boost\config\suffix.hpp for BOOST_NO_LONG_LONG // -#define BOOST_NO_AUTO_DECLARATIONS -#define BOOST_NO_AUTO_MULTIDECLARATIONS #define BOOST_NO_CHAR16_T #define BOOST_NO_CHAR32_T #define BOOST_NO_CONCEPTS diff --git a/3rdParty/Boost/src/boost/config/compiler/visualc.hpp b/3rdParty/Boost/src/boost/config/compiler/visualc.hpp index 990901f..f8cc109 100644 --- a/3rdParty/Boost/src/boost/config/compiler/visualc.hpp +++ b/3rdParty/Boost/src/boost/config/compiler/visualc.hpp @@ -125,7 +125,7 @@ #if (_MSC_VER >= 1200) # define BOOST_HAS_MS_INT64 #endif -#if (_MSC_VER >= 1310) && (defined(_MSC_EXTENSIONS) || (_MSC_VER >= 1500)) +#if (_MSC_VER >= 1310) && (defined(_MSC_EXTENSIONS) || (_MSC_VER >= 1400)) # define BOOST_HAS_LONG_LONG #else # define BOOST_NO_LONG_LONG diff --git a/3rdParty/Boost/src/boost/config/platform/symbian.hpp b/3rdParty/Boost/src/boost/config/platform/symbian.hpp new file mode 100644 index 0000000..ad37943 --- /dev/null +++ b/3rdParty/Boost/src/boost/config/platform/symbian.hpp @@ -0,0 +1,94 @@ +// (C) Copyright Yuriy Krasnoschek 2009. +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2001 - 2003. +// Use, modification and distribution are subject to 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) + +// See http://www.boost.org for most recent version. + +// symbian specific config options: + + +#define BOOST_PLATFORM "Symbian" +#define BOOST_SYMBIAN 1 + + +#if defined(__S60_3X__) +// Open C / C++ plugin was introdused in this SDK, earlier versions don't have CRT / STL +# define BOOST_S60_3rd_EDITION_FP2_OR_LATER_SDK +// make sure we have __GLIBC_PREREQ if available at all +# include +// boilerplate code: +# define BOOST_HAS_UNISTD_H +# include +// S60 SDK defines _POSIX_VERSION as POSIX.1 +# ifndef BOOST_HAS_STDINT_H +# define BOOST_HAS_STDINT_H +# endif +# ifndef BOOST_HAS_GETTIMEOFDAY +# define BOOST_HAS_GETTIMEOFDAY +# endif +# ifndef BOOST_HAS_DIRENT_H +# define BOOST_HAS_DIRENT_H +# endif +# ifndef BOOST_HAS_SIGACTION +# define BOOST_HAS_SIGACTION +# endif +# ifndef BOOST_HAS_PTHREADS +# define BOOST_HAS_PTHREADS +# endif +# ifndef BOOST_HAS_NANOSLEEP +# define BOOST_HAS_NANOSLEEP +# endif +# ifndef BOOST_HAS_SCHED_YIELD +# define BOOST_HAS_SCHED_YIELD +# endif +# ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# endif +# ifndef BOOST_HAS_LOG1P +# define BOOST_HAS_LOG1P +# endif +# ifndef BOOST_HAS_EXPM1 +# define BOOST_HAS_EXPM1 +# endif +# ifndef BOOST_POSIX_API +# define BOOST_POSIX_API +# endif +// endianess support +# include +// Symbian SDK provides _BYTE_ORDER instead of __BYTE_ORDER +# ifndef __LITTLE_ENDIAN +# ifdef _LITTLE_ENDIAN +# define __LITTLE_ENDIAN _LITTLE_ENDIAN +# else +# define __LITTLE_ENDIAN 1234 +# endif +# endif +# ifndef __BIG_ENDIAN +# ifdef _BIG_ENDIAN +# define __BIG_ENDIAN _BIG_ENDIAN +# else +# define __BIG_ENDIAN 4321 +# endif +# endif +# ifndef __BYTE_ORDER +# define __BYTE_ORDER __LITTLE_ENDIAN // Symbian is LE +# endif +// Known limitations +# define BOOST_ASIO_DISABLE_SERIAL_PORT +# define BOOST_DATE_TIME_NO_LOCALE +# define BOOST_NO_STD_WSTRING +# define BOOST_EXCEPTION_DISABLE +# define BOOST_NO_EXCEPTIONS + +#else // TODO: More platform support e.g. UIQ +# error "Unsuppoted Symbian SDK" +#endif + +#if defined(__WINSCW__) && !defined(BOOST_DISABLE_WIN32) +# define BOOST_DISABLE_WIN32 // winscw defines WIN32 macro +#endif + + diff --git a/3rdParty/Boost/src/boost/config/select_compiler_config.hpp b/3rdParty/Boost/src/boost/config/select_compiler_config.hpp index 9141cd6..792963e 100644 --- a/3rdParty/Boost/src/boost/config/select_compiler_config.hpp +++ b/3rdParty/Boost/src/boost/config/select_compiler_config.hpp @@ -31,6 +31,7 @@ # define BOOST_CXX_IBMCPP 0 # define BOOST_CXX_MSVC 0 # define BOOST_CXX_PGI 0 +# define BOOST_CXX_NVCC 0 // locate which compiler we are using and define @@ -40,6 +41,10 @@ // GCC-XML emulates other compilers, it has to appear first here! # define BOOST_COMPILER_CONFIG "boost/config/compiler/gcc_xml.hpp" +#elif defined __CUDACC__ +// NVIDIA CUDA C++ compiler for GPU +# define BOOST_COMPILER_CONFIG "boost/config/compiler/nvcc.hpp" + #elif defined __COMO__ // Comeau C++ # define BOOST_COMPILER_CONFIG "boost/config/compiler/comeau.hpp" diff --git a/3rdParty/Boost/src/boost/config/select_platform_config.hpp b/3rdParty/Boost/src/boost/config/select_platform_config.hpp index 615bb06..8606e12 100644 --- a/3rdParty/Boost/src/boost/config/select_platform_config.hpp +++ b/3rdParty/Boost/src/boost/config/select_platform_config.hpp @@ -65,6 +65,10 @@ // vxWorks: # define BOOST_PLATFORM_CONFIG "boost/config/platform/vxworks.hpp" +#elif defined(__SYMBIAN32__) +// Symbian: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/symbian.hpp" + #else # if defined(unix) \ diff --git a/3rdParty/Boost/src/boost/config/suffix.hpp b/3rdParty/Boost/src/boost/config/suffix.hpp index fa44986..9e4d078 100644 --- a/3rdParty/Boost/src/boost/config/suffix.hpp +++ b/3rdParty/Boost/src/boost/config/suffix.hpp @@ -8,7 +8,7 @@ // Copyright (c) 2002-2003 David Abrahams // Copyright (c) 2003 Gennaro Prota // Copyright (c) 2003 Eric Friedman -// +// Copyright (c) 2010 Eric Jourdanneau, Joel Falcou // 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) @@ -596,6 +596,11 @@ namespace boost{ # endif # endif +// +// Set some default values GPU support +// +# ifndef BOOST_GPU_ENABLED +# define BOOST_GPU_ENABLED +# endif #endif - diff --git a/3rdParty/Boost/src/boost/cstdlib.hpp b/3rdParty/Boost/src/boost/cstdlib.hpp deleted file mode 100644 index 6322146..0000000 --- a/3rdParty/Boost/src/boost/cstdlib.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// boost/cstdlib.hpp header ------------------------------------------------// - -// Copyright Beman Dawes 2001. 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) - -// See http://www.boost.org/libs/utility/cstdlib.html for documentation. - -// Revision History -// 26 Feb 01 Initial version (Beman Dawes) - -#ifndef BOOST_CSTDLIB_HPP -#define BOOST_CSTDLIB_HPP - -#include - -namespace boost -{ - // The intent is to propose the following for addition to namespace std - // in the C++ Standard Library, and to then deprecate EXIT_SUCCESS and - // EXIT_FAILURE. As an implementation detail, this header defines the - // new constants in terms of EXIT_SUCCESS and EXIT_FAILURE. In a new - // standard, the constants would be implementation-defined, although it - // might be worthwhile to "suggest" (which a standard is allowed to do) - // values of 0 and 1 respectively. - - // Rationale for having multiple failure values: some environments may - // wish to distinguish between different classes of errors. - // Rationale for choice of values: programs often use values < 100 for - // their own error reporting. Values > 255 are sometimes reserved for - // system detected errors. 200/201 were suggested to minimize conflict. - - const int exit_success = EXIT_SUCCESS; // implementation-defined value - const int exit_failure = EXIT_FAILURE; // implementation-defined value - const int exit_exception_failure = 200; // otherwise uncaught exception - const int exit_test_failure = 201; // report_error or - // report_critical_error called. -} - -#endif - diff --git a/3rdParty/Boost/src/boost/date_time/gregorian/conversion.hpp b/3rdParty/Boost/src/boost/date_time/gregorian/conversion.hpp index 6d4b606..f35796e 100644 --- a/3rdParty/Boost/src/boost/date_time/gregorian/conversion.hpp +++ b/3rdParty/Boost/src/boost/date_time/gregorian/conversion.hpp @@ -15,7 +15,6 @@ #include #include #include -#include namespace boost { @@ -42,8 +41,7 @@ namespace gregorian { boost::throw_exception(std::out_of_range(s)); } - std::tm datetm; - memset(&datetm, 0, sizeof(std::tm)); + std::tm datetm = {}; // zero initialization is needed for extension members, like tm_zone boost::gregorian::date::ymd_type ymd = d.year_month_day(); datetm.tm_year = ymd.year - 1900; datetm.tm_mon = ymd.month - 1; diff --git a/3rdParty/Boost/src/boost/date_time/posix_time/conversion.hpp b/3rdParty/Boost/src/boost/date_time/posix_time/conversion.hpp index a7b1a80..9cdb864 100644 --- a/3rdParty/Boost/src/boost/date_time/posix_time/conversion.hpp +++ b/3rdParty/Boost/src/boost/date_time/posix_time/conversion.hpp @@ -15,7 +15,6 @@ #include #include // absolute_value #include -#include namespace boost { @@ -44,8 +43,7 @@ namespace posix_time { //! Convert a time_duration to a tm structure truncating any fractional seconds and zeroing fields for date components inline std::tm to_tm(const boost::posix_time::time_duration& td) { - std::tm timetm; - memset(&timetm, 0, sizeof(std::tm)); + std::tm timetm = {}; timetm.tm_hour = date_time::absolute_value(td.hours()); timetm.tm_min = date_time::absolute_value(td.minutes()); timetm.tm_sec = date_time::absolute_value(td.seconds()); diff --git a/3rdParty/Boost/src/boost/detail/binary_search.hpp b/3rdParty/Boost/src/boost/detail/binary_search.hpp deleted file mode 100644 index 3dca9b6..0000000 --- a/3rdParty/Boost/src/boost/detail/binary_search.hpp +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) 2000 David Abrahams. -// 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) -// -// Copyright (c) 1994 -// Hewlett-Packard Company -// -// Permission to use, copy, modify, distribute and sell this software -// and its documentation for any purpose is hereby granted without fee, -// provided that the above copyright notice appear in all copies and -// that both that copyright notice and this permission notice appear -// in supporting documentation. Hewlett-Packard Company makes no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied warranty. -// -// Copyright (c) 1996 -// Silicon Graphics Computer Systems, Inc. -// -// Permission to use, copy, modify, distribute and sell this software -// and its documentation for any purpose is hereby granted without fee, -// provided that the above copyright notice appear in all copies and -// that both that copyright notice and this permission notice appear -// in supporting documentation. Silicon Graphics makes no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied warranty. -// -#ifndef BINARY_SEARCH_DWA_122600_H_ -# define BINARY_SEARCH_DWA_122600_H_ - -# include -# include - -namespace boost { namespace detail { - -template -ForwardIter lower_bound(ForwardIter first, ForwardIter last, - const Tp& val) -{ - typedef detail::iterator_traits traits; - - typename traits::difference_type len = boost::detail::distance(first, last); - typename traits::difference_type half; - ForwardIter middle; - - while (len > 0) { - half = len >> 1; - middle = first; - std::advance(middle, half); - if (*middle < val) { - first = middle; - ++first; - len = len - half - 1; - } - else - len = half; - } - return first; -} - -template -ForwardIter lower_bound(ForwardIter first, ForwardIter last, - const Tp& val, Compare comp) -{ - typedef detail::iterator_traits traits; - - typename traits::difference_type len = boost::detail::distance(first, last); - typename traits::difference_type half; - ForwardIter middle; - - while (len > 0) { - half = len >> 1; - middle = first; - std::advance(middle, half); - if (comp(*middle, val)) { - first = middle; - ++first; - len = len - half - 1; - } - else - len = half; - } - return first; -} - -template -ForwardIter upper_bound(ForwardIter first, ForwardIter last, - const Tp& val) -{ - typedef detail::iterator_traits traits; - - typename traits::difference_type len = boost::detail::distance(first, last); - typename traits::difference_type half; - ForwardIter middle; - - while (len > 0) { - half = len >> 1; - middle = first; - std::advance(middle, half); - if (val < *middle) - len = half; - else { - first = middle; - ++first; - len = len - half - 1; - } - } - return first; -} - -template -ForwardIter upper_bound(ForwardIter first, ForwardIter last, - const Tp& val, Compare comp) -{ - typedef detail::iterator_traits traits; - - typename traits::difference_type len = boost::detail::distance(first, last); - typename traits::difference_type half; - ForwardIter middle; - - while (len > 0) { - half = len >> 1; - middle = first; - std::advance(middle, half); - if (comp(val, *middle)) - len = half; - else { - first = middle; - ++first; - len = len - half - 1; - } - } - return first; -} - -template -std::pair -equal_range(ForwardIter first, ForwardIter last, const Tp& val) -{ - typedef detail::iterator_traits traits; - - typename traits::difference_type len = boost::detail::distance(first, last); - typename traits::difference_type half; - ForwardIter middle, left, right; - - while (len > 0) { - half = len >> 1; - middle = first; - std::advance(middle, half); - if (*middle < val) { - first = middle; - ++first; - len = len - half - 1; - } - else if (val < *middle) - len = half; - else { - left = boost::detail::lower_bound(first, middle, val); - std::advance(first, len); - right = boost::detail::upper_bound(++middle, first, val); - return std::pair(left, right); - } - } - return std::pair(first, first); -} - -template -std::pair -equal_range(ForwardIter first, ForwardIter last, const Tp& val, - Compare comp) -{ - typedef detail::iterator_traits traits; - - typename traits::difference_type len = boost::detail::distance(first, last); - typename traits::difference_type half; - ForwardIter middle, left, right; - - while (len > 0) { - half = len >> 1; - middle = first; - std::advance(middle, half); - if (comp(*middle, val)) { - first = middle; - ++first; - len = len - half - 1; - } - else if (comp(val, *middle)) - len = half; - else { - left = boost::detail::lower_bound(first, middle, val, comp); - std::advance(first, len); - right = boost::detail::upper_bound(++middle, first, val, comp); - return std::pair(left, right); - } - } - return std::pair(first, first); -} - -template -bool binary_search(ForwardIter first, ForwardIter last, - const Tp& val) { - ForwardIter i = boost::detail::lower_bound(first, last, val); - return i != last && !(val < *i); -} - -template -bool binary_search(ForwardIter first, ForwardIter last, - const Tp& val, - Compare comp) { - ForwardIter i = boost::detail::lower_bound(first, last, val, comp); - return i != last && !comp(val, *i); -} - -}} // namespace boost::detail - -#endif // BINARY_SEARCH_DWA_122600_H_ diff --git a/3rdParty/Boost/src/boost/detail/container_fwd.hpp b/3rdParty/Boost/src/boost/detail/container_fwd.hpp index bc7f780..67c5a21 100644 --- a/3rdParty/Boost/src/boost/detail/container_fwd.hpp +++ b/3rdParty/Boost/src/boost/detail/container_fwd.hpp @@ -13,7 +13,9 @@ #include #include -#if ((defined(__GLIBCPP__) || defined(__GLIBCXX__)) && defined(_GLIBCXX_DEBUG)) \ +#if defined(BOOST_DETAIL_NO_CONTAINER_FWD) \ + || ((defined(__GLIBCPP__) || defined(__GLIBCXX__)) \ + && (defined(_GLIBCXX_DEBUG) || defined(_GLIBCXX_PARALLEL))) \ || BOOST_WORKAROUND(__BORLANDC__, > 0x551) \ || BOOST_WORKAROUND(__DMC__, BOOST_TESTED_AT(0x842)) \ || (defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) diff --git a/3rdParty/Boost/src/boost/detail/lcast_precision.hpp b/3rdParty/Boost/src/boost/detail/lcast_precision.hpp index d40ca21..93abce1 100644 --- a/3rdParty/Boost/src/boost/detail/lcast_precision.hpp +++ b/3rdParty/Boost/src/boost/detail/lcast_precision.hpp @@ -173,8 +173,8 @@ inline void lcast_set_precision(std::ios_base& stream, T*) template inline void lcast_set_precision(std::ios_base& stream, Source*, Target*) { - std::streamsize const s = lcast_get_precision((Source*)0); - std::streamsize const t = lcast_get_precision((Target*)0); + std::streamsize const s = lcast_get_precision(static_cast(0)); + std::streamsize const t = lcast_get_precision(static_cast(0)); stream.precision(s > t ? s : t); } diff --git a/3rdParty/Boost/src/boost/detail/scoped_enum_emulation.hpp b/3rdParty/Boost/src/boost/detail/scoped_enum_emulation.hpp index 644c138..e695a20 100644 --- a/3rdParty/Boost/src/boost/detail/scoped_enum_emulation.hpp +++ b/3rdParty/Boost/src/boost/detail/scoped_enum_emulation.hpp @@ -41,9 +41,9 @@ #ifdef BOOST_NO_SCOPED_ENUMS -# define BOOST_SCOPED_ENUM_START(name) struct name { enum enum_t +# define BOOST_SCOPED_ENUM_START(name) struct name { enum enum_type # define BOOST_SCOPED_ENUM_END }; -# define BOOST_SCOPED_ENUM(name) name::enum_t +# define BOOST_SCOPED_ENUM(name) name::enum_type #else diff --git a/3rdParty/Boost/src/boost/exception/detail/error_info_impl.hpp b/3rdParty/Boost/src/boost/exception/detail/error_info_impl.hpp index 32113b1..883d313 100644 --- a/3rdParty/Boost/src/boost/exception/detail/error_info_impl.hpp +++ b/3rdParty/Boost/src/boost/exception/detail/error_info_impl.hpp @@ -1,4 +1,4 @@ -//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. +//Copyright (c) 2006-2010 Emil Dotchevski and Reverge Studios, Inc. //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) @@ -25,7 +25,7 @@ boost { public: - virtual char const * tag_typeid_name() const = 0; + virtual std::string tag_typeid_name() const = 0; virtual std::string value_as_string() const = 0; protected: @@ -62,7 +62,7 @@ boost private: - char const * tag_typeid_name() const; + std::string tag_typeid_name() const; std::string value_as_string() const; value_type value_; diff --git a/3rdParty/Boost/src/boost/exception/detail/exception_ptr.hpp b/3rdParty/Boost/src/boost/exception/detail/exception_ptr.hpp index 78db17c..59686e9 100644 --- a/3rdParty/Boost/src/boost/exception/detail/exception_ptr.hpp +++ b/3rdParty/Boost/src/boost/exception/detail/exception_ptr.hpp @@ -28,6 +28,26 @@ namespace boost { + typedef shared_ptr exception_ptr; + + exception_ptr current_exception(); + + template + inline + exception_ptr + copy_exception( T const & e ) + { + try + { + throw enable_current_exception(e); + } + catch( + ... ) + { + return current_exception(); + } + } + #ifndef BOOST_NO_RTTI typedef error_info original_exception_type; @@ -39,91 +59,45 @@ boost } #endif - class exception_ptr; - exception_ptr current_exception(); - void rethrow_exception( exception_ptr const & ); - - class - exception_ptr + namespace + exception_detail { - typedef bool exception_ptr::*unspecified_bool_type; - friend exception_ptr current_exception(); - friend void rethrow_exception( exception_ptr const & ); - - shared_ptr c_; - bool bad_alloc_; - struct - bad_alloc_tag - { - }; - - explicit - exception_ptr( bad_alloc_tag ): - bad_alloc_(true) - { - } - - explicit - exception_ptr( shared_ptr const & c ): - c_(c), - bad_alloc_(false) - { - BOOST_ASSERT(c); - } - - void - rethrow() const - { - BOOST_ASSERT(*this); - if( bad_alloc_ ) - throw enable_current_exception(std::bad_alloc()); - else - c_->rethrow(); - } - - bool - empty() const - { - return !bad_alloc_ && !c_; - } - - public: - - exception_ptr(): - bad_alloc_(false) - { - } - - ~exception_ptr() throw() - { - } + bad_alloc_: + boost::exception, + std::bad_alloc + { + }; - operator unspecified_bool_type() const + template + exception_ptr + get_bad_alloc() { - return empty() ? 0 : &exception_ptr::bad_alloc_; + static exception_ptr e = boost::copy_exception( + bad_alloc_() << + throw_function("boost::current_exception()") << + throw_file(__FILE__) << + throw_line(__LINE__) ); + return e; } - friend - bool - operator==( exception_ptr const & a, exception_ptr const & b ) + template + struct + exception_ptr_bad_alloc { - return a.c_==b.c_ && a.bad_alloc_==b.bad_alloc_; - } + static exception_ptr const e; + }; - friend - bool - operator!=( exception_ptr const & a, exception_ptr const & b ) - { - return !(a==b); - } - }; + template + exception_ptr const + exception_ptr_bad_alloc:: + e = get_bad_alloc(); + } class unknown_exception: - public exception, - public std::exception, - public exception_detail::clone_base + public boost::exception, + public std::exception { public: @@ -150,18 +124,6 @@ boost private: - exception_detail::clone_base const * - clone() const - { - return new unknown_exception(*this); - } - - void - rethrow() const - { - throw*this; - } - template void add_original_type( E const & e ) @@ -179,8 +141,7 @@ boost class current_exception_std_exception_wrapper: public T, - public boost::exception, - public clone_base + public boost::exception { public: @@ -204,18 +165,6 @@ boost private: - clone_base const * - clone() const - { - return new current_exception_std_exception_wrapper(*this); - } - - void - rethrow() const - { - throw *this; - } - template void add_original_type( E const & e ) @@ -228,7 +177,7 @@ boost #ifdef BOOST_NO_RTTI template - exception const * + boost::exception const * get_boost_exception( T const * ) { try @@ -236,7 +185,7 @@ boost throw; } catch( - exception & x ) + boost::exception & x ) { return &x; } @@ -247,50 +196,50 @@ boost } #else template - exception const * + boost::exception const * get_boost_exception( T const * x ) { - return dynamic_cast(x); + return dynamic_cast(x); } #endif template inline - shared_ptr + exception_ptr current_exception_std_exception( T const & e1 ) { if( boost::exception const * e2 = get_boost_exception(&e1) ) - return shared_ptr const>(new current_exception_std_exception_wrapper(e1,*e2)); + return boost::copy_exception(current_exception_std_exception_wrapper(e1,*e2)); else - return shared_ptr const>(new current_exception_std_exception_wrapper(e1)); + return boost::copy_exception(current_exception_std_exception_wrapper(e1)); } inline - shared_ptr + exception_ptr current_exception_unknown_exception() { - return shared_ptr(new unknown_exception()); + return boost::copy_exception(unknown_exception()); } inline - shared_ptr + exception_ptr current_exception_unknown_boost_exception( boost::exception const & e ) { - return shared_ptr(new unknown_exception(e)); + return boost::copy_exception(unknown_exception(e)); } inline - shared_ptr + exception_ptr current_exception_unknown_std_exception( std::exception const & e ) { if( boost::exception const * be = get_boost_exception(&e) ) return current_exception_unknown_boost_exception(*be); else - return shared_ptr(new unknown_exception(e)); + return boost::copy_exception(unknown_exception(e)); } inline - shared_ptr + exception_ptr current_exception_impl() { try @@ -300,7 +249,7 @@ boost catch( exception_detail::clone_base & e ) { - return shared_ptr(e.clone()); + return exception_ptr(e.clone()); } catch( std::domain_error & e ) @@ -396,24 +345,28 @@ boost exception_ptr current_exception() { + exception_ptr ret; + BOOST_ASSERT(!ret); try { - return exception_ptr(exception_detail::current_exception_impl()); + ret=exception_detail::current_exception_impl(); } catch( std::bad_alloc & ) { + ret=exception_detail::exception_ptr_bad_alloc<42>::e; } catch( ... ) { try { - return exception_ptr(exception_detail::current_exception_std_exception(std::bad_exception())); + ret=exception_detail::current_exception_std_exception(std::bad_exception()); } catch( std::bad_alloc & ) { + ret=exception_detail::exception_ptr_bad_alloc<42>::e; } catch( ... ) @@ -421,30 +374,16 @@ boost BOOST_ASSERT(0); } } - return exception_ptr(exception_ptr::bad_alloc_tag()); - } - - template - inline - exception_ptr - copy_exception( T const & e ) - { - try - { - throw enable_current_exception(e); - } - catch( - ... ) - { - return current_exception(); - } + BOOST_ASSERT(ret); + return ret; } inline void rethrow_exception( exception_ptr const & p ) { - p.rethrow(); + BOOST_ASSERT(p); + p->rethrow(); } inline diff --git a/3rdParty/Boost/src/boost/exception/detail/is_output_streamable.hpp b/3rdParty/Boost/src/boost/exception/detail/is_output_streamable.hpp index 5eb1695..743313c 100644 --- a/3rdParty/Boost/src/boost/exception/detail/is_output_streamable.hpp +++ b/3rdParty/Boost/src/boost/exception/detail/is_output_streamable.hpp @@ -20,8 +20,21 @@ boost namespace to_string_detail { - template - char operator<<( std::basic_ostream &, T const & ); + struct + partial_ordering_helper1 + { + template + partial_ordering_helper1( std::basic_ostream & ); + }; + + struct + partial_ordering_helper2 + { + template + partial_ordering_helper2( T const & ); + }; + + char operator<<( partial_ordering_helper1, partial_ordering_helper2 ); template struct diff --git a/3rdParty/Boost/src/boost/exception/detail/type_info.hpp b/3rdParty/Boost/src/boost/exception/detail/type_info.hpp index 60709a1..9ab1c57 100644 --- a/3rdParty/Boost/src/boost/exception/detail/type_info.hpp +++ b/3rdParty/Boost/src/boost/exception/detail/type_info.hpp @@ -1,4 +1,4 @@ -//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. +//Copyright (c) 2006-2010 Emil Dotchevski and Reverge Studios, Inc. //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) @@ -15,31 +15,35 @@ #include #include #include +#ifndef BOOST_NO_TYPEID +#include +#endif +#include namespace boost { template inline - char const * + std::string tag_type_name() { #ifdef BOOST_NO_TYPEID return BOOST_CURRENT_FUNCTION; #else - return typeid(T*).name(); + return units::detail::demangle(typeid(T*).name()); #endif } template inline - char const * + std::string type_name() { #ifdef BOOST_NO_TYPEID return BOOST_CURRENT_FUNCTION; #else - return typeid(T).name(); + return units::detail::demangle(typeid(T).name()); #endif } diff --git a/3rdParty/Boost/src/boost/exception/diagnostic_information.hpp b/3rdParty/Boost/src/boost/exception/diagnostic_information.hpp index 632a5a3..1d6bc2c 100644 --- a/3rdParty/Boost/src/boost/exception/diagnostic_information.hpp +++ b/3rdParty/Boost/src/boost/exception/diagnostic_information.hpp @@ -1,4 +1,4 @@ -//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. +//Copyright (c) 2006-2010 Emil Dotchevski and Reverge Studios, Inc. //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) @@ -15,7 +15,9 @@ #include #include #include -#include +#ifndef BOOST_NO_RTTI +#include +#endif #include #include #include @@ -135,7 +137,7 @@ boost } #ifndef BOOST_NO_RTTI tmp << std::string("Dynamic exception type: ") << - (be?BOOST_EXCEPTION_DYNAMIC_TYPEID(*be):BOOST_EXCEPTION_DYNAMIC_TYPEID(*se)).type_.name() << '\n'; + units::detail::demangle((be?BOOST_EXCEPTION_DYNAMIC_TYPEID(*be):BOOST_EXCEPTION_DYNAMIC_TYPEID(*se)).type_.name()) << '\n'; #endif if( with_what && se ) tmp << "std::exception::what: " << wh << '\n'; diff --git a/3rdParty/Boost/src/boost/exception/exception.hpp b/3rdParty/Boost/src/boost/exception/exception.hpp index 79b2739..fd516dd 100644 --- a/3rdParty/Boost/src/boost/exception/exception.hpp +++ b/3rdParty/Boost/src/boost/exception/exception.hpp @@ -132,18 +132,6 @@ boost } }; - template - E const & operator<<( E const &, error_info const & ); - - template - E const & operator<<( E const &, throw_function const & ); - - template - E const & operator<<( E const &, throw_file const & ); - - template - E const & operator<<( E const &, throw_line const & ); - class exception; template @@ -163,6 +151,7 @@ boost virtual void set( shared_ptr const &, type_info_ const & ) = 0; virtual void add_ref() const = 0; virtual void release() const = 0; + virtual refcount_ptr clone() const = 0; protected: @@ -184,6 +173,20 @@ boost struct get_info; char const * get_diagnostic_information( exception const &, char const * ); + + void copy_boost_exception( exception *, exception const * ); + + template + E const & set_info( E const &, error_info const & ); + + template + E const & set_info( E const &, throw_function const & ); + + template + E const & set_info( E const &, throw_file const & ); + + template + E const & set_info( E const &, throw_line const & ); } class @@ -216,30 +219,31 @@ boost #endif ; -#if defined(__MWERKS__) && __MWERKS__<=0x3207 +#if (defined(__MWERKS__) && __MWERKS__<=0x3207) || (defined(_MSC_VER) && _MSC_VER<=1310) public: #else private: template - friend E const & operator<<( E const &, throw_function const & ); + friend E const & exception_detail::set_info( E const &, throw_function const & ); template - friend E const & operator<<( E const &, throw_file const & ); + friend E const & exception_detail::set_info( E const &, throw_file const & ); template - friend E const & operator<<( E const &, throw_line const & ); - - friend char const * exception_detail::get_diagnostic_information( exception const &, char const * ); + friend E const & exception_detail::set_info( E const &, throw_line const & ); template - friend E const & operator<<( E const &, error_info const & ); + friend E const & exception_detail::set_info( E const &, error_info const & ); + + friend char const * exception_detail::get_diagnostic_information( exception const &, char const * ); template friend struct exception_detail::get_info; friend struct exception_detail::get_info; friend struct exception_detail::get_info; friend struct exception_detail::get_info; + friend void exception_detail::copy_boost_exception( exception *, exception const * ); #endif mutable exception_detail::refcount_ptr data_; mutable char const * throw_function_; @@ -253,28 +257,32 @@ boost { } - template - E const & - operator<<( E const & x, throw_function const & y ) + namespace + exception_detail { - x.throw_function_=y.v_; - return x; - } + template + E const & + set_info( E const & x, throw_function const & y ) + { + x.throw_function_=y.v_; + return x; + } - template - E const & - operator<<( E const & x, throw_file const & y ) - { - x.throw_file_=y.v_; - return x; - } + template + E const & + set_info( E const & x, throw_file const & y ) + { + x.throw_file_=y.v_; + return x; + } - template - E const & - operator<<( E const & x, throw_line const & y ) - { - x.throw_line_=y.v_; - return x; + template + E const & + set_info( E const & x, throw_line const & y ) + { + x.throw_line_=y.v_; + return x; + } } //////////////////////////////////////////////////////////////////////// @@ -300,10 +308,10 @@ boost }; struct large_size { char c[256]; }; - large_size dispatch( exception * ); + large_size dispatch_boost_exception( exception const * ); struct small_size { }; - small_size dispatch( void * ); + small_size dispatch_boost_exception( void const * ); template struct enable_error_info_helper; @@ -326,7 +334,7 @@ boost struct enable_error_info_return_type { - typedef typename enable_error_info_helper::type type; + typedef typename enable_error_info_helper::type type; }; } @@ -363,7 +371,13 @@ boost void copy_boost_exception( exception * a, exception const * b ) { - *a = *b; + refcount_ptr data; + if( error_info_container * d=b->data_.get() ) + data = d->clone(); + a->throw_file_ = b->throw_file_; + a->throw_line_ = b->throw_line_; + a->throw_function_ = b->throw_function_; + a->data_ = data; } inline diff --git a/3rdParty/Boost/src/boost/exception/info.hpp b/3rdParty/Boost/src/boost/exception/info.hpp index cbbc2c0..7aeeee5 100644 --- a/3rdParty/Boost/src/boost/exception/info.hpp +++ b/3rdParty/Boost/src/boost/exception/info.hpp @@ -1,4 +1,4 @@ -//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. +//Copyright (c) 2006-2010 Emil Dotchevski and Reverge Studios, Inc. //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) @@ -47,7 +47,7 @@ boost template inline - char const * + std::string error_info:: tag_typeid_name() const { @@ -131,6 +131,9 @@ boost mutable std::string diagnostic_info_str_; mutable int count_; + error_info_container_impl( error_info_container_impl const & ); + error_info_container_impl & operator=( error_info_container const & ); + void add_ref() const { @@ -143,21 +146,46 @@ boost if( !--count_ ) delete this; } + + refcount_ptr + clone() const + { + refcount_ptr p; + error_info_container_impl * c=new error_info_container_impl; + p.adopt(c); + c->info_ = info_; + return p; + } + }; + + template + inline + E const & + set_info( E const & x, error_info const & v ) + { + typedef error_info error_info_tag_t; + shared_ptr p( new error_info_tag_t(v) ); + exception_detail::error_info_container * c=x.data_.get(); + if( !c ) + x.data_.adopt(c=new exception_detail::error_info_container_impl); + c->set(p,BOOST_EXCEPTION_STATIC_TYPEID(error_info_tag_t)); + return x; + } + + template + struct + derives_boost_exception + { + enum e { value = (sizeof(dispatch_boost_exception((T*)0))==sizeof(large_size)) }; }; } template inline - E const & + typename enable_if,E const &>::type operator<<( E const & x, error_info const & v ) { - typedef error_info error_info_tag_t; - shared_ptr p( new error_info_tag_t(v) ); - exception_detail::error_info_container * c=x.data_.get(); - if( !c ) - x.data_.adopt(c=new exception_detail::error_info_container_impl); - c->set(p,BOOST_EXCEPTION_STATIC_TYPEID(error_info_tag_t)); - return x; + return exception_detail::set_info(x,v); } } diff --git a/3rdParty/Boost/src/boost/functional/hash/detail/hash_float_generic.hpp b/3rdParty/Boost/src/boost/functional/hash/detail/hash_float_generic.hpp index f9acee9..fdbf53f 100644 --- a/3rdParty/Boost/src/boost/functional/hash/detail/hash_float_generic.hpp +++ b/3rdParty/Boost/src/boost/functional/hash/detail/hash_float_generic.hpp @@ -51,17 +51,15 @@ namespace boost limits::min_exponent; } - // The result of frexp is always between 0.5 and 1, so its - // top bit will always be 1. Subtract by 0.5 to remove that. - v -= T(0.5); - v = ldexp(v, limits::digits + 1); + v = ldexp(v, limits::digits); std::size_t seed = static_cast(v); v -= seed; // ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1; std::size_t const length = (limits::digits * - boost::static_log2::radix>::value - 1) + boost::static_log2::radix>::value + + limits::digits - 1) / limits::digits; for(std::size_t i = 0; i != length; ++i) diff --git a/3rdParty/Boost/src/boost/functional/hash/hash.hpp b/3rdParty/Boost/src/boost/functional/hash/hash.hpp index 1f33b9e..e85ca5a 100644 --- a/3rdParty/Boost/src/boost/functional/hash/hash.hpp +++ b/3rdParty/Boost/src/boost/functional/hash/hash.hpp @@ -44,7 +44,7 @@ namespace boost std::size_t hash_value(wchar_t); #endif -#if defined(BOOST_HAS_LONG_LONG) +#if !defined(BOOST_NO_LONG_LONG) std::size_t hash_value(boost::long_long_type); std::size_t hash_value(boost::ulong_long_type); #endif @@ -174,7 +174,7 @@ namespace boost } #endif -#if defined(BOOST_HAS_LONG_LONG) +#if !defined(BOOST_NO_LONG_LONG) inline std::size_t hash_value(boost::long_long_type v) { return hash_detail::hash_value_signed(v); @@ -408,7 +408,7 @@ namespace boost BOOST_HASH_SPECIALIZE_REF(std::wstring) #endif -#if defined(BOOST_HAS_LONG_LONG) +#if !defined(BOOST_NO_LONG_LONG) BOOST_HASH_SPECIALIZE(boost::long_long_type) BOOST_HASH_SPECIALIZE(boost::ulong_long_type) #endif diff --git a/3rdParty/Boost/src/boost/iterator/iterator_concepts.hpp b/3rdParty/Boost/src/boost/iterator/iterator_concepts.hpp new file mode 100644 index 0000000..ced1112 --- /dev/null +++ b/3rdParty/Boost/src/boost/iterator/iterator_concepts.hpp @@ -0,0 +1,284 @@ +// (C) Copyright Jeremy Siek 2002. +// 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_ITERATOR_CONCEPTS_HPP +#define BOOST_ITERATOR_CONCEPTS_HPP + +#include +#include + +// Use boost::detail::iterator_traits to work around some MSVC/Dinkumware problems. +#include + +#include +#include + +#include +#include +#include +#include + +#include + +// Use boost/limits to work around missing limits headers on some compilers +#include +#include + +#include + +#include + +namespace boost_concepts +{ + // Used a different namespace here (instead of "boost") so that the + // concept descriptions do not take for granted the names in + // namespace boost. + + //=========================================================================== + // Iterator Access Concepts + + BOOST_concept(ReadableIterator,(Iterator)) + : boost::Assignable + , boost::CopyConstructible + + { + typedef BOOST_DEDUCED_TYPENAME boost::detail::iterator_traits::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME boost::detail::iterator_traits::reference reference; + + BOOST_CONCEPT_USAGE(ReadableIterator) + { + + value_type v = *i; + boost::ignore_unused_variable_warning(v); + } + private: + Iterator i; + }; + + template < + typename Iterator + , typename ValueType = BOOST_DEDUCED_TYPENAME boost::detail::iterator_traits::value_type + > + struct WritableIterator + : boost::CopyConstructible + { + BOOST_CONCEPT_USAGE(WritableIterator) + { + *i = v; + } + private: + ValueType v; + Iterator i; + }; + + template < + typename Iterator + , typename ValueType = BOOST_DEDUCED_TYPENAME boost::detail::iterator_traits::value_type + > + struct WritableIteratorConcept : WritableIterator {}; + + BOOST_concept(SwappableIterator,(Iterator)) + { + BOOST_CONCEPT_USAGE(SwappableIterator) + { + std::iter_swap(i1, i2); + } + private: + Iterator i1; + Iterator i2; + }; + + BOOST_concept(LvalueIterator,(Iterator)) + { + typedef typename boost::detail::iterator_traits::value_type value_type; + + BOOST_CONCEPT_USAGE(LvalueIterator) + { + value_type& r = const_cast(*i); + boost::ignore_unused_variable_warning(r); + } + private: + Iterator i; + }; + + + //=========================================================================== + // Iterator Traversal Concepts + + BOOST_concept(IncrementableIterator,(Iterator)) + : boost::Assignable + , boost::CopyConstructible + { + typedef typename boost::iterator_traversal::type traversal_category; + + BOOST_CONCEPT_ASSERT(( + boost::Convertible< + traversal_category + , boost::incrementable_traversal_tag + >)); + + BOOST_CONCEPT_USAGE(IncrementableIterator) + { + ++i; + (void)i++; + } + private: + Iterator i; + }; + + BOOST_concept(SinglePassIterator,(Iterator)) + : IncrementableIterator + , boost::EqualityComparable + + { + BOOST_CONCEPT_ASSERT(( + boost::Convertible< + BOOST_DEDUCED_TYPENAME SinglePassIterator::traversal_category + , boost::single_pass_traversal_tag + > )); + }; + + BOOST_concept(ForwardTraversal,(Iterator)) + : SinglePassIterator + , boost::DefaultConstructible + { + typedef typename boost::detail::iterator_traits::difference_type difference_type; + + BOOST_MPL_ASSERT((boost::is_integral)); + BOOST_MPL_ASSERT_RELATION(std::numeric_limits::is_signed, ==, true); + + BOOST_CONCEPT_ASSERT(( + boost::Convertible< + BOOST_DEDUCED_TYPENAME ForwardTraversal::traversal_category + , boost::forward_traversal_tag + > )); + }; + + BOOST_concept(BidirectionalTraversal,(Iterator)) + : ForwardTraversal + { + BOOST_CONCEPT_ASSERT(( + boost::Convertible< + BOOST_DEDUCED_TYPENAME BidirectionalTraversal::traversal_category + , boost::bidirectional_traversal_tag + > )); + + BOOST_CONCEPT_USAGE(BidirectionalTraversal) + { + --i; + (void)i--; + } + private: + Iterator i; + }; + + BOOST_concept(RandomAccessTraversal,(Iterator)) + : BidirectionalTraversal + { + BOOST_CONCEPT_ASSERT(( + boost::Convertible< + BOOST_DEDUCED_TYPENAME RandomAccessTraversal::traversal_category + , boost::random_access_traversal_tag + > )); + + BOOST_CONCEPT_USAGE(RandomAccessTraversal) + { + i += n; + i = i + n; + i = n + i; + i -= n; + i = i - n; + n = i - j; + } + + private: + typename BidirectionalTraversal::difference_type n; + Iterator i, j; + }; + + //=========================================================================== + // Iterator Interoperability + + namespace detail + { + template + void interop_single_pass_constraints(Iterator1 const& i1, Iterator2 const& i2) + { + bool b; + b = i1 == i2; + b = i1 != i2; + + b = i2 == i1; + b = i2 != i1; + boost::ignore_unused_variable_warning(b); + } + + template + void interop_rand_access_constraints( + Iterator1 const& i1, Iterator2 const& i2, + boost::random_access_traversal_tag, boost::random_access_traversal_tag) + { + bool b; + typename boost::detail::iterator_traits::difference_type n; + b = i1 < i2; + b = i1 <= i2; + b = i1 > i2; + b = i1 >= i2; + n = i1 - i2; + + b = i2 < i1; + b = i2 <= i1; + b = i2 > i1; + b = i2 >= i1; + n = i2 - i1; + boost::ignore_unused_variable_warning(b); + boost::ignore_unused_variable_warning(n); + } + + template + void interop_rand_access_constraints( + Iterator1 const&, Iterator2 const&, + boost::single_pass_traversal_tag, boost::single_pass_traversal_tag) + { } + + } // namespace detail + + BOOST_concept(InteroperableIterator,(Iterator)(ConstIterator)) + { + private: + typedef typename boost::detail::pure_traversal_tag< + typename boost::iterator_traversal< + Iterator + >::type + >::type traversal_category; + + typedef typename boost::detail::pure_traversal_tag< + typename boost::iterator_traversal< + ConstIterator + >::type + >::type const_traversal_category; + + public: + BOOST_CONCEPT_ASSERT((SinglePassIterator)); + BOOST_CONCEPT_ASSERT((SinglePassIterator)); + + BOOST_CONCEPT_USAGE(InteroperableIterator) + { + detail::interop_single_pass_constraints(i, ci); + detail::interop_rand_access_constraints(i, ci, traversal_category(), const_traversal_category()); + + ci = i; + } + + private: + Iterator i; + ConstIterator ci; + }; + +} // namespace boost_concepts + +#include + +#endif // BOOST_ITERATOR_CONCEPTS_HPP diff --git a/3rdParty/Boost/src/boost/mpl/aux_/preprocessed/gcc/template_arity.hpp b/3rdParty/Boost/src/boost/mpl/aux_/preprocessed/gcc/template_arity.hpp index 3e7bfba..daec4b8 100644 --- a/3rdParty/Boost/src/boost/mpl/aux_/preprocessed/gcc/template_arity.hpp +++ b/3rdParty/Boost/src/boost/mpl/aux_/preprocessed/gcc/template_arity.hpp @@ -6,11 +6,10 @@ // http://www.boost.org/LICENSE_1_0.txt) // -// Preprocessed version of "boost/mpl/aux_/template_arity.hpp" header +// *Preprocessed* version of the main "template_arity.hpp" header // -- DO NOT modify by hand! namespace boost { namespace mpl { namespace aux { - template< int N > struct arity_tag { typedef char (&type)[N + 1]; @@ -23,7 +22,6 @@ struct max_arity { BOOST_STATIC_CONSTANT(int, value = ( C6 > 0 ? C6 : ( C5 > 0 ? C5 : ( C4 > 0 ? C4 : ( C3 > 0 ? C3 : ( C2 > 0 ? C2 : ( C1 > 0 ? C1 : -1 ) ) ) ) ) ) - ); }; @@ -83,7 +81,7 @@ template< typename F, int N > struct template_arity_impl { BOOST_STATIC_CONSTANT(int, value = - sizeof(arity_helper(type_wrapper(), arity_tag())) - 1 + sizeof(::boost::mpl::aux::arity_helper(type_wrapper(), arity_tag())) - 1 ); }; @@ -92,9 +90,7 @@ struct template_arity { BOOST_STATIC_CONSTANT(int, value = ( max_arity< template_arity_impl< F,1 >::value, template_arity_impl< F,2 >::value, template_arity_impl< F,3 >::value, template_arity_impl< F,4 >::value, template_arity_impl< F,5 >::value, template_arity_impl< F,6 >::value >::value - )); - typedef mpl::int_ type; }; diff --git a/3rdParty/Boost/src/boost/mpl/aux_/template_arity.hpp b/3rdParty/Boost/src/boost/mpl/aux_/template_arity.hpp index 47e4eeb..ed26ea2 100644 --- a/3rdParty/Boost/src/boost/mpl/aux_/template_arity.hpp +++ b/3rdParty/Boost/src/boost/mpl/aux_/template_arity.hpp @@ -14,9 +14,9 @@ // // See http://www.boost.org/libs/mpl for documentation. -// $Id: template_arity.hpp 49267 2008-10-11 06:19:02Z agurtovoy $ -// $Date: 2008-10-11 02:19:02 -0400 (Sat, 11 Oct 2008) $ -// $Revision: 49267 $ +// $Id: template_arity.hpp 61584 2010-04-26 18:48:26Z agurtovoy $ +// $Date: 2010-04-26 14:48:26 -0400 (Mon, 26 Apr 2010) $ +// $Revision: 61584 $ #include #include @@ -98,7 +98,7 @@ template< typename F, BOOST_MPL_AUX_NTTP_DECL(int, N) > struct template_arity_impl { BOOST_STATIC_CONSTANT(int, value = - sizeof(arity_helper(type_wrapper(),arity_tag())) - 1 + sizeof(::boost::mpl::aux::arity_helper(type_wrapper(),arity_tag())) - 1 ); }; diff --git a/3rdParty/Boost/src/boost/mpl/aux_/unwrap.hpp b/3rdParty/Boost/src/boost/mpl/aux_/unwrap.hpp deleted file mode 100644 index dd710a7..0000000 --- a/3rdParty/Boost/src/boost/mpl/aux_/unwrap.hpp +++ /dev/null @@ -1,47 +0,0 @@ - -#ifndef BOOST_MPL_AUX_UNWRAP_HPP_INCLUDED -#define BOOST_MPL_AUX_UNWRAP_HPP_INCLUDED - -// Copyright Peter Dimov and Multi Media Ltd 2001, 2002 -// Copyright David Abrahams 2001 -// -// 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) -// -// See http://www.boost.org/libs/mpl for documentation. - -// $Id: unwrap.hpp 49267 2008-10-11 06:19:02Z agurtovoy $ -// $Date: 2008-10-11 02:19:02 -0400 (Sat, 11 Oct 2008) $ -// $Revision: 49267 $ - -#include - -namespace boost { namespace mpl { namespace aux { - -template< typename F > -inline -F& unwrap(F& f, long) -{ - return f; -} - -template< typename F > -inline -F& -unwrap(reference_wrapper& f, int) -{ - return f; -} - -template< typename F > -inline -F& -unwrap(reference_wrapper const& f, int) -{ - return f; -} - -}}} - -#endif // BOOST_MPL_AUX_UNWRAP_HPP_INCLUDED diff --git a/3rdParty/Boost/src/boost/mpl/for_each.hpp b/3rdParty/Boost/src/boost/mpl/for_each.hpp deleted file mode 100644 index 89abc85..0000000 --- a/3rdParty/Boost/src/boost/mpl/for_each.hpp +++ /dev/null @@ -1,116 +0,0 @@ - -#ifndef BOOST_MPL_FOR_EACH_HPP_INCLUDED -#define BOOST_MPL_FOR_EACH_HPP_INCLUDED - -// Copyright Aleksey Gurtovoy 2000-2008 -// -// 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) -// -// See http://www.boost.org/libs/mpl for documentation. - -// $Id: for_each.hpp 55648 2009-08-18 05:16:53Z agurtovoy $ -// $Date: 2009-08-18 01:16:53 -0400 (Tue, 18 Aug 2009) $ -// $Revision: 55648 $ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace boost { namespace mpl { - -namespace aux { - -template< bool done = true > -struct for_each_impl -{ - template< - typename Iterator - , typename LastIterator - , typename TransformFunc - , typename F - > - static void execute( - Iterator* - , LastIterator* - , TransformFunc* - , F - ) - { - } -}; - -template<> -struct for_each_impl -{ - template< - typename Iterator - , typename LastIterator - , typename TransformFunc - , typename F - > - static void execute( - Iterator* - , LastIterator* - , TransformFunc* - , F f - ) - { - typedef typename deref::type item; - typedef typename apply1::type arg; - - // dwa 2002/9/10 -- make sure not to invoke undefined behavior - // when we pass arg. - value_initialized x; - aux::unwrap(f, 0)(boost::get(x)); - - typedef typename mpl::next::type iter; - for_each_impl::value> - ::execute( static_cast(0), static_cast(0), static_cast(0), f); - } -}; - -} // namespace aux - -// agurt, 17/mar/02: pointer default parameters are necessary to workaround -// MSVC 6.5 function template signature's mangling bug -template< - typename Sequence - , typename TransformOp - , typename F - > -inline -void for_each(F f, Sequence* = 0, TransformOp* = 0) -{ - BOOST_MPL_ASSERT(( is_sequence )); - - typedef typename begin::type first; - typedef typename end::type last; - - aux::for_each_impl< boost::is_same::value > - ::execute(static_cast(0), static_cast(0), static_cast(0), f); -} - -template< - typename Sequence - , typename F - > -inline -void for_each(F f, Sequence* = 0) -{ - for_each >(f); -} - -}} - -#endif // BOOST_MPL_FOR_EACH_HPP_INCLUDED diff --git a/3rdParty/Boost/src/boost/mpl/is_sequence.hpp b/3rdParty/Boost/src/boost/mpl/is_sequence.hpp deleted file mode 100644 index 0c1f67b..0000000 --- a/3rdParty/Boost/src/boost/mpl/is_sequence.hpp +++ /dev/null @@ -1,112 +0,0 @@ - -#ifndef BOOST_MPL_IS_SEQUENCE_HPP_INCLUDED -#define BOOST_MPL_IS_SEQUENCE_HPP_INCLUDED - -// Copyright Aleksey Gurtovoy 2002-2004 -// -// 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) -// -// See http://www.boost.org/libs/mpl for documentation. - -// $Id: is_sequence.hpp 49267 2008-10-11 06:19:02Z agurtovoy $ -// $Date: 2008-10-11 02:19:02 -0400 (Sat, 11 Oct 2008) $ -// $Revision: 49267 $ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) -# include -#elif BOOST_WORKAROUND(BOOST_MSVC, == 1300) -# include -#endif - -#include - -namespace boost { namespace mpl { - -#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) - -namespace aux { - -// agurt, 11/jun/03: -// MSVC 6.5/7.0 fails if 'has_begin' is instantiated on a class type that has a -// 'begin' member that doesn't name a type; e.g. 'has_begin< std::vector >' -// would fail; requiring 'T' to have _both_ 'tag' and 'begin' members workarounds -// the issue for most real-world cases -template< typename T > struct is_sequence_impl - : and_< - identity< aux::has_tag > - , identity< aux::has_begin > - > -{ -}; - -} // namespace aux - -template< - typename BOOST_MPL_AUX_NA_PARAM(T) - > -struct is_sequence - : if_< -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - aux::msvc_is_class -#else - boost::is_class -#endif - , aux::is_sequence_impl - , bool_ - >::type -{ - BOOST_MPL_AUX_LAMBDA_SUPPORT(1, is_sequence, (T)) -}; - -#elif defined(BOOST_MPL_CFG_NO_HAS_XXX) - -template< - typename BOOST_MPL_AUX_NA_PARAM(T) - > -struct is_sequence - : bool_ -{ -}; - -#else - -template< - typename BOOST_MPL_AUX_NA_PARAM(T) - > -struct is_sequence - : not_< is_same< typename begin::type, void_ > > -{ - BOOST_MPL_AUX_LAMBDA_SUPPORT(1, is_sequence, (T)) -}; - -#endif // BOOST_MSVC - -#if defined(BOOST_MPL_CFG_MSVC_60_ETI_BUG) -template<> struct is_sequence - : bool_ -{ -}; -#endif - -BOOST_MPL_AUX_NA_SPEC_NO_ETI(1, is_sequence) - -}} - -#endif // BOOST_MPL_IS_SEQUENCE_HPP_INCLUDED diff --git a/3rdParty/Boost/src/boost/preprocessor/seq/for_each.hpp b/3rdParty/Boost/src/boost/preprocessor/seq/for_each.hpp deleted file mode 100644 index e997a9a..0000000 --- a/3rdParty/Boost/src/boost/preprocessor/seq/for_each.hpp +++ /dev/null @@ -1,60 +0,0 @@ -# /* ************************************************************************** -# * * -# * (C) Copyright Paul Mensonides 2002. -# * 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) -# * * -# ************************************************************************** */ -# -# /* See http://www.boost.org for most recent version. */ -# -# ifndef BOOST_PREPROCESSOR_SEQ_FOR_EACH_HPP -# define BOOST_PREPROCESSOR_SEQ_FOR_EACH_HPP -# -# include -# include -# include -# include -# include -# include -# include -# -# /* BOOST_PP_SEQ_FOR_EACH */ -# -# if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_EDG() -# define BOOST_PP_SEQ_FOR_EACH(macro, data, seq) BOOST_PP_FOR((macro, data, seq (nil)), BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O, BOOST_PP_SEQ_FOR_EACH_M) -# else -# define BOOST_PP_SEQ_FOR_EACH(macro, data, seq) BOOST_PP_SEQ_FOR_EACH_D(macro, data, seq) -# define BOOST_PP_SEQ_FOR_EACH_D(macro, data, seq) BOOST_PP_FOR((macro, data, seq (nil)), BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O, BOOST_PP_SEQ_FOR_EACH_M) -# endif -# -# define BOOST_PP_SEQ_FOR_EACH_P(r, x) BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3, 2, x))) -# -# if BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_STRICT() -# define BOOST_PP_SEQ_FOR_EACH_O(r, x) BOOST_PP_SEQ_FOR_EACH_O_I x -# else -# define BOOST_PP_SEQ_FOR_EACH_O(r, x) BOOST_PP_SEQ_FOR_EACH_O_I(BOOST_PP_TUPLE_ELEM(3, 0, x), BOOST_PP_TUPLE_ELEM(3, 1, x), BOOST_PP_TUPLE_ELEM(3, 2, x)) -# endif -# -# define BOOST_PP_SEQ_FOR_EACH_O_I(macro, data, seq) (macro, data, BOOST_PP_SEQ_TAIL(seq)) -# -# if BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_STRICT() -# define BOOST_PP_SEQ_FOR_EACH_M(r, x) BOOST_PP_SEQ_FOR_EACH_M_IM(r, BOOST_PP_TUPLE_REM_3 x) -# define BOOST_PP_SEQ_FOR_EACH_M_IM(r, im) BOOST_PP_SEQ_FOR_EACH_M_I(r, im) -# else -# define BOOST_PP_SEQ_FOR_EACH_M(r, x) BOOST_PP_SEQ_FOR_EACH_M_I(r, BOOST_PP_TUPLE_ELEM(3, 0, x), BOOST_PP_TUPLE_ELEM(3, 1, x), BOOST_PP_TUPLE_ELEM(3, 2, x)) -# endif -# -# define BOOST_PP_SEQ_FOR_EACH_M_I(r, macro, data, seq) macro(r, data, BOOST_PP_SEQ_HEAD(seq)) -# -# /* BOOST_PP_SEQ_FOR_EACH_R */ -# -# if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_EDG() -# define BOOST_PP_SEQ_FOR_EACH_R(r, macro, data, seq) BOOST_PP_FOR_ ## r((macro, data, seq (nil)), BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O, BOOST_PP_SEQ_FOR_EACH_M) -# else -# define BOOST_PP_SEQ_FOR_EACH_R(r, macro, data, seq) BOOST_PP_SEQ_FOR_EACH_R_I(r, macro, data, seq) -# define BOOST_PP_SEQ_FOR_EACH_R_I(r, macro, data, seq) BOOST_PP_FOR_ ## r((macro, data, seq (nil)), BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O, BOOST_PP_SEQ_FOR_EACH_M) -# endif -# -# endif diff --git a/3rdParty/Boost/src/boost/progress.hpp b/3rdParty/Boost/src/boost/progress.hpp deleted file mode 100644 index fbbf04a..0000000 --- a/3rdParty/Boost/src/boost/progress.hpp +++ /dev/null @@ -1,143 +0,0 @@ -// boost progress.hpp header file ------------------------------------------// - -// Copyright Beman Dawes 1994-99. 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) - -// See http://www.boost.org/libs/timer for documentation. - -// Revision History -// 1 Dec 01 Add leading progress display strings (suggested by Toon Knapen) -// 20 May 01 Introduce several static_casts<> to eliminate warning messages -// (Fixed by Beman, reported by Herve Bronnimann) -// 12 Jan 01 Change to inline implementation to allow use without library -// builds. See docs for more rationale. (Beman Dawes) -// 22 Jul 99 Name changed to .hpp -// 16 Jul 99 Second beta -// 6 Jul 99 Initial boost version - -#ifndef BOOST_PROGRESS_HPP -#define BOOST_PROGRESS_HPP - -#include -#include // for noncopyable -#include // for uintmax_t -#include // for ostream, cout, etc -#include // for string - -namespace boost { - -// progress_timer ----------------------------------------------------------// - -// A progress_timer behaves like a timer except that the destructor displays -// an elapsed time message at an appropriate place in an appropriate form. - -class progress_timer : public timer, private noncopyable -{ - - public: - explicit progress_timer( std::ostream & os = std::cout ) - // os is hint; implementation may ignore, particularly in embedded systems - : m_os(os) {} - ~progress_timer() - { - // A) Throwing an exception from a destructor is a Bad Thing. - // B) The progress_timer destructor does output which may throw. - // C) A progress_timer is usually not critical to the application. - // Therefore, wrap the I/O in a try block, catch and ignore all exceptions. - try - { - // use istream instead of ios_base to workaround GNU problem (Greg Chicares) - std::istream::fmtflags old_flags = m_os.setf( std::istream::fixed, - std::istream::floatfield ); - std::streamsize old_prec = m_os.precision( 2 ); - m_os << elapsed() << " s\n" // "s" is System International d'Unites std - << std::endl; - m_os.flags( old_flags ); - m_os.precision( old_prec ); - } - - catch (...) {} // eat any exceptions - } // ~progress_timer - - private: - std::ostream & m_os; -}; - - -// progress_display --------------------------------------------------------// - -// progress_display displays an appropriate indication of -// progress at an appropriate place in an appropriate form. - -// NOTE: (Jan 12, 2001) Tried to change unsigned long to boost::uintmax_t, but -// found some compilers couldn't handle the required conversion to double. -// Reverted to unsigned long until the compilers catch up. - -class progress_display : private noncopyable -{ - public: - explicit progress_display( unsigned long expected_count, - std::ostream & os = std::cout, - const std::string & s1 = "\n", //leading strings - const std::string & s2 = "", - const std::string & s3 = "" ) - // os is hint; implementation may ignore, particularly in embedded systems - : m_os(os), m_s1(s1), m_s2(s2), m_s3(s3) { restart(expected_count); } - - void restart( unsigned long expected_count ) - // Effects: display appropriate scale - // Postconditions: count()==0, expected_count()==expected_count - { - _count = _next_tic_count = _tic = 0; - _expected_count = expected_count; - - m_os << m_s1 << "0% 10 20 30 40 50 60 70 80 90 100%\n" - << m_s2 << "|----|----|----|----|----|----|----|----|----|----|" - << std::endl // endl implies flush, which ensures display - << m_s3; - if ( !_expected_count ) _expected_count = 1; // prevent divide by zero - } // restart - - unsigned long operator+=( unsigned long increment ) - // Effects: Display appropriate progress tic if needed. - // Postconditions: count()== original count() + increment - // Returns: count(). - { - if ( (_count += increment) >= _next_tic_count ) { display_tic(); } - return _count; - } - - unsigned long operator++() { return operator+=( 1 ); } - unsigned long count() const { return _count; } - unsigned long expected_count() const { return _expected_count; } - - private: - std::ostream & m_os; // may not be present in all imps - const std::string m_s1; // string is more general, safer than - const std::string m_s2; // const char *, and efficiency or size are - const std::string m_s3; // not issues - - unsigned long _count, _expected_count, _next_tic_count; - unsigned int _tic; - void display_tic() - { - // use of floating point ensures that both large and small counts - // work correctly. static_cast<>() is also used several places - // to suppress spurious compiler warnings. - unsigned int tics_needed = - static_cast( - (static_cast(_count)/_expected_count)*50.0 ); - do { m_os << '*' << std::flush; } while ( ++_tic < tics_needed ); - _next_tic_count = - static_cast((_tic/50.0)*_expected_count); - if ( _count == _expected_count ) { - if ( _tic < 51 ) m_os << '*'; - m_os << std::endl; - } - } // display_tic -}; - -} // namespace boost - -#endif // BOOST_PROGRESS_HPP diff --git a/3rdParty/Boost/src/boost/range/algorithm/equal.hpp b/3rdParty/Boost/src/boost/range/algorithm/equal.hpp new file mode 100755 index 0000000..7226440 --- /dev/null +++ b/3rdParty/Boost/src/boost/range/algorithm/equal.hpp @@ -0,0 +1,188 @@ +// Boost.Range library +// +// Copyright Neil Groves 2009. +// Use, modification and distribution is subject to 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) +// +// For more information, see http://www.boost.org/libs/range/ +// +#ifndef BOOST_RANGE_ALGORITHM_EQUAL_HPP_INCLUDED +#define BOOST_RANGE_ALGORITHM_EQUAL_HPP_INCLUDED + +#include +#include +#include + +namespace boost +{ + namespace range_detail + { + // An implementation of equality comparison that is optimized for iterator + // traversal categories less than RandomAccessTraversal. + template< class SinglePassTraversalReadableIterator1, + class SinglePassTraversalReadableIterator2, + class IteratorCategoryTag1, + class IteratorCategoryTag2 > + inline bool equal_impl( SinglePassTraversalReadableIterator1 first1, + SinglePassTraversalReadableIterator1 last1, + SinglePassTraversalReadableIterator2 first2, + SinglePassTraversalReadableIterator2 last2, + IteratorCategoryTag1, + IteratorCategoryTag2 ) + { + do + { + // If we have reached the end of the left range then this is + // the end of the loop. They are equal if and only if we have + // simultaneously reached the end of the right range. + if (first1 == last1) + return first2 == last2; + + // If we have reached the end of the right range at this line + // it indicates that the right range is shorter than the left + // and hence the result is false. + if (first2 == last2) + return false; + + // continue looping if and only if the values are equal + } while(*first1++ == *first2++); + + // Reaching this line in the algorithm indicates that a value + // inequality has been detected. + return false; + } + + template< class SinglePassTraversalReadableIterator1, + class SinglePassTraversalReadableIterator2, + class IteratorCategoryTag1, + class IteratorCategoryTag2, + class BinaryPredicate > + inline bool equal_impl( SinglePassTraversalReadableIterator1 first1, + SinglePassTraversalReadableIterator1 last1, + SinglePassTraversalReadableIterator2 first2, + SinglePassTraversalReadableIterator2 last2, + BinaryPredicate pred, + IteratorCategoryTag1, + IteratorCategoryTag2 ) + { + do + { + // If we have reached the end of the left range then this is + // the end of the loop. They are equal if and only if we have + // simultaneously reached the end of the right range. + if (first1 == last1) + return first2 == last2; + + // If we have reached the end of the right range at this line + // it indicates that the right range is shorter than the left + // and hence the result is false. + if (first2 == last2) + return false; + + // continue looping if and only if the values are equal + } while(pred(*first1++, *first2++)); + + // Reaching this line in the algorithm indicates that a value + // inequality has been detected. + return false; + } + + // An implementation of equality comparison that is optimized for + // random access iterators. + template< class RandomAccessTraversalReadableIterator1, + class RandomAccessTraversalReadableIterator2 > + inline bool equal_impl( RandomAccessTraversalReadableIterator1 first1, + RandomAccessTraversalReadableIterator1 last1, + RandomAccessTraversalReadableIterator2 first2, + RandomAccessTraversalReadableIterator2 last2, + std::random_access_iterator_tag, + std::random_access_iterator_tag ) + { + return ((last1 - first1) == (last2 - first2)) + && std::equal(first1, last1, first2); + } + + template< class RandomAccessTraversalReadableIterator1, + class RandomAccessTraversalReadableIterator2, + class BinaryPredicate > + inline bool equal_impl( RandomAccessTraversalReadableIterator1 first1, + RandomAccessTraversalReadableIterator1 last1, + RandomAccessTraversalReadableIterator2 first2, + RandomAccessTraversalReadableIterator2 last2, + BinaryPredicate pred ) + { + return ((last1 - first1) == (last2 - first2)) + && std::equal(first1, last1, first2, pred); + } + + template< class SinglePassTraversalReadableIterator1, + class SinglePassTraversalReadableIterator2 > + inline bool equal( SinglePassTraversalReadableIterator1 first1, + SinglePassTraversalReadableIterator1 last1, + SinglePassTraversalReadableIterator2 first2, + SinglePassTraversalReadableIterator2 last2 ) + { + BOOST_DEDUCED_TYPENAME std::iterator_traits< SinglePassTraversalReadableIterator1 >::iterator_category tag1; + BOOST_DEDUCED_TYPENAME std::iterator_traits< SinglePassTraversalReadableIterator2 >::iterator_category tag2; + + return equal_impl(first1, last1, first2, last2, tag1, tag2); + } + + template< class SinglePassTraversalReadableIterator1, + class SinglePassTraversalReadableIterator2, + class BinaryPredicate > + inline bool equal( SinglePassTraversalReadableIterator1 first1, + SinglePassTraversalReadableIterator1 last1, + SinglePassTraversalReadableIterator2 first2, + SinglePassTraversalReadableIterator2 last2, + BinaryPredicate pred ) + { + BOOST_DEDUCED_TYPENAME std::iterator_traits< SinglePassTraversalReadableIterator1 >::iterator_category tag1; + BOOST_DEDUCED_TYPENAME std::iterator_traits< SinglePassTraversalReadableIterator2 >::iterator_category tag2; + + return equal_impl(first1, last1, first2, last2, pred, tag1, tag2); + } + + } // namespace range_detail + + namespace range + { + + /// \brief template function equal + /// + /// range-based version of the equal std algorithm + /// + /// \pre SinglePassRange1 is a model of the SinglePassRangeConcept + /// \pre SinglePassRange2 is a model of the SinglePassRangeConcept + /// \pre BinaryPredicate is a model of the BinaryPredicateConcept + template< class SinglePassRange1, class SinglePassRange2 > + inline bool equal( const SinglePassRange1& rng1, const SinglePassRange2& rng2 ) + { + BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); + BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); + + return ::boost::range_detail::equal( + ::boost::begin(rng1), ::boost::end(rng1), + ::boost::begin(rng2), ::boost::end(rng2) ); + } + + /// \overload + template< class SinglePassRange1, class SinglePassRange2, class BinaryPredicate > + inline bool equal( const SinglePassRange1& rng1, const SinglePassRange2& rng2, + BinaryPredicate pred ) + { + BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); + BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); + + return ::boost::range_detail::equal( + ::boost::begin(rng1), ::boost::end(rng1), + ::boost::begin(rng2), ::boost::end(rng2), + pred); + } + + } // namespace range + using range::equal; +} // namespace boost + +#endif // include guard diff --git a/3rdParty/Boost/src/boost/range/as_literal.hpp b/3rdParty/Boost/src/boost/range/as_literal.hpp index 2f04ca8..f67ead7 100644 --- a/3rdParty/Boost/src/boost/range/as_literal.hpp +++ b/3rdParty/Boost/src/boost/range/as_literal.hpp @@ -25,7 +25,7 @@ #include #include -#ifndef BOOST_NO_CWCHAR +#ifndef BOOST_NO_CWCHAR #include #endif @@ -38,41 +38,41 @@ namespace boost return strlen( s ); } -#ifndef BOOST_NO_CWCHAR +#ifndef BOOST_NO_CWCHAR inline std::size_t length( const wchar_t* s ) { return wcslen( s ); } -#endif +#endif // // Remark: the compiler cannot choose between T* and T[sz] // overloads, so we must put the T* internal to the // unconstrained version. - // + // inline bool is_char_ptr( char* ) { return true; } - + inline bool is_char_ptr( const char* ) { return true; } -#ifndef BOOST_NO_CWCHAR +#ifndef BOOST_NO_CWCHAR inline bool is_char_ptr( wchar_t* ) { return true; } - + inline bool is_char_ptr( const wchar_t* ) { return true; } #endif - + template< class T > inline long is_char_ptr( T /* r */ ) { @@ -80,30 +80,30 @@ namespace boost } template< class T > - inline iterator_range + inline iterator_range make_range( T* const r, bool ) { return iterator_range( r, r + length(r) ); } template< class T > - inline iterator_range::type> + inline iterator_range::type> make_range( T& r, long ) { return boost::make_iterator_range( r ); } } - + template< class Range > - inline iterator_range::type> + inline iterator_range::type> as_literal( Range& r ) { return range_detail::make_range( r, range_detail::is_char_ptr(r) ); } template< class Range > - inline iterator_range::type> + inline iterator_range::type> as_literal( const Range& r ) { return range_detail::make_range( r, range_detail::is_char_ptr(r) ); @@ -112,9 +112,9 @@ namespace boost template< class Char, std::size_t sz > inline iterator_range as_literal( Char (&arr)[sz] ) { - return range_detail::make_range( arr, range_detail::is_char_ptr(arr) ); + return range_detail::make_range( arr, range_detail::is_char_ptr(arr) ); } - + template< class Char, std::size_t sz > inline iterator_range as_literal( const Char (&arr)[sz] ) { diff --git a/3rdParty/Boost/src/boost/range/concepts.hpp b/3rdParty/Boost/src/boost/range/concepts.hpp new file mode 100644 index 0000000..8e4d2cf --- /dev/null +++ b/3rdParty/Boost/src/boost/range/concepts.hpp @@ -0,0 +1,331 @@ +// Boost.Range library concept checks +// +// Copyright Neil Groves 2009. Use, modification and distribution +// are subject to 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) +// +// Copyright Daniel Walker 2006. Use, modification and distribution +// are subject to 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) +// +// For more information, see http://www.boost.org/libs/range/ +// + +#ifndef BOOST_RANGE_CONCEPTS_HPP +#define BOOST_RANGE_CONCEPTS_HPP + +#include +#include +#include +#include +#include +#include +#include + +/*! + * \file + * \brief Concept checks for the Boost Range library. + * + * The structures in this file may be used in conjunction with the + * Boost Concept Check library to insure that the type of a function + * parameter is compatible with a range concept. If not, a meaningful + * compile time error is generated. Checks are provided for the range + * concepts related to iterator traversal categories. For example, the + * following line checks that the type T models the ForwardRange + * concept. + * + * \code + * BOOST_CONCEPT_ASSERT((ForwardRangeConcept)); + * \endcode + * + * A different concept check is required to ensure writeable value + * access. For example to check for a ForwardRange that can be written + * to, the following code is required. + * + * \code + * BOOST_CONCEPT_ASSERT((WriteableForwardRangeConcept)); + * \endcode + * + * \see http://www.boost.org/libs/range/doc/range.html for details + * about range concepts. + * \see http://www.boost.org/libs/iterator/doc/iterator_concepts.html + * for details about iterator concepts. + * \see http://www.boost.org/libs/concept_check/concept_check.htm for + * details about concept checks. + */ + +namespace boost { + + namespace range_detail { + +#ifndef BOOST_RANGE_ENABLE_CONCEPT_ASSERT + +// List broken compiler versions here: + #ifdef __GNUC__ + // GNUC 4.2 has strange issues correctly detecting compliance with the Concepts + // hence the least disruptive approach is to turn-off the concept checking for + // this version of the compiler. + #if __GNUC__ == 4 && __GNUC_MINOR__ == 2 + #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0 + #endif + #endif + + #ifdef __BORLANDC__ + #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0 + #endif + + #ifdef __PATHCC__ + #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0 + #endif + +// Default to using the concept asserts unless we have defined it off +// during the search for black listed compilers. + #ifndef BOOST_RANGE_ENABLE_CONCEPT_ASSERT + #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 1 + #endif + +#endif + +#if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + #define BOOST_RANGE_CONCEPT_ASSERT( x ) BOOST_CONCEPT_ASSERT( x ) +#else + #define BOOST_RANGE_CONCEPT_ASSERT( x ) +#endif + + // Rationale for the inclusion of redefined iterator concept + // classes: + // + // The Range algorithms often do not require that the iterators are + // Assignable, but the correct standard conformant iterators + // do require the iterators to be a model of the Assignable concept. + // Iterators that contains a functor that is not assignable therefore + // are not correct models of the standard iterator concepts, + // despite being adequate for most algorithms. An example of this + // use case is the combination of the boost::adaptors::filtered + // class with a boost::lambda::bind generated functor. + // Ultimately modeling the range concepts using composition + // with the Boost.Iterator concepts would render the library + // incompatible with many common Boost.Lambda expressions. + template + struct IncrementableIteratorConcept : CopyConstructible + { +#if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + typedef BOOST_DEDUCED_TYPENAME iterator_traversal::type traversal_category; + + BOOST_RANGE_CONCEPT_ASSERT(( + Convertible< + traversal_category, + incrementable_traversal_tag + >)); + + BOOST_CONCEPT_USAGE(IncrementableIteratorConcept) + { + ++i; + (void)i++; + } + private: + Iterator i; +#endif + }; + + template + struct SinglePassIteratorConcept + : IncrementableIteratorConcept + , EqualityComparable + { +#if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + BOOST_RANGE_CONCEPT_ASSERT(( + Convertible< + BOOST_DEDUCED_TYPENAME SinglePassIteratorConcept::traversal_category, + single_pass_traversal_tag + >)); +#endif + }; + + template + struct ForwardIteratorConcept + : SinglePassIteratorConcept + , DefaultConstructible + { +#if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + typedef BOOST_DEDUCED_TYPENAME boost::detail::iterator_traits::difference_type difference_type; + + BOOST_MPL_ASSERT((is_integral)); + BOOST_MPL_ASSERT_RELATION(std::numeric_limits::is_signed, ==, true); + + BOOST_RANGE_CONCEPT_ASSERT(( + Convertible< + BOOST_DEDUCED_TYPENAME ForwardIteratorConcept::traversal_category, + forward_traversal_tag + >)); +#endif + }; + + template + struct BidirectionalIteratorConcept + : ForwardIteratorConcept + { + #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + BOOST_RANGE_CONCEPT_ASSERT(( + Convertible< + BOOST_DEDUCED_TYPENAME BidirectionalIteratorConcept::traversal_category, + bidirectional_traversal_tag + >)); + + BOOST_CONCEPT_USAGE(BidirectionalIteratorConcept) + { + --i; + (void)i--; + } + private: + Iterator i; + #endif + }; + + template + struct RandomAccessIteratorConcept + : BidirectionalIteratorConcept + { + #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + BOOST_RANGE_CONCEPT_ASSERT(( + Convertible< + BOOST_DEDUCED_TYPENAME RandomAccessIteratorConcept::traversal_category, + random_access_traversal_tag + >)); + + BOOST_CONCEPT_USAGE(RandomAccessIteratorConcept) + { + i += n; + i = i + n; + i = n + i; + i -= n; + i = i - n; + n = i - j; + } + private: + BOOST_DEDUCED_TYPENAME RandomAccessIteratorConcept::difference_type n; + Iterator i; + Iterator j; + #endif + }; + + } // namespace range_detail + + //! Check if a type T models the SinglePassRange range concept. + template + struct SinglePassRangeConcept + { +#if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + typedef BOOST_DEDUCED_TYPENAME range_iterator::type const_iterator; + typedef BOOST_DEDUCED_TYPENAME range_iterator::type iterator; + + BOOST_RANGE_CONCEPT_ASSERT((range_detail::SinglePassIteratorConcept)); + BOOST_RANGE_CONCEPT_ASSERT((range_detail::SinglePassIteratorConcept)); + + BOOST_CONCEPT_USAGE(SinglePassRangeConcept) + { + // This has been modified from assigning to this->i + // (where i was a member variable) to improve + // compatibility with Boost.Lambda + iterator i1 = boost::begin(*m_range); + iterator i2 = boost::end(*m_range); + + ignore_unused_variable_warning(i1); + ignore_unused_variable_warning(i2); + + const_constraints(*m_range); + } + + private: + void const_constraints(const T& const_range) + { + const_iterator ci1 = boost::begin(const_range); + const_iterator ci2 = boost::end(const_range); + + ignore_unused_variable_warning(ci1); + ignore_unused_variable_warning(ci2); + } + + // Rationale: + // The type of m_range is T* rather than T because it allows + // T to be an abstract class. The other obvious alternative of + // T& produces a warning on some compilers. + T* m_range; +#endif + }; + + //! Check if a type T models the ForwardRange range concept. + template + struct ForwardRangeConcept : SinglePassRangeConcept + { +#if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + BOOST_RANGE_CONCEPT_ASSERT((range_detail::ForwardIteratorConcept)); + BOOST_RANGE_CONCEPT_ASSERT((range_detail::ForwardIteratorConcept)); +#endif + }; + + template + struct WriteableRangeConcept + { +#if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + typedef BOOST_DEDUCED_TYPENAME range_iterator::type iterator; + + BOOST_CONCEPT_USAGE(WriteableRangeConcept) + { + *i = v; + } + private: + iterator i; + BOOST_DEDUCED_TYPENAME range_value::type v; +#endif + }; + + //! Check if a type T models the WriteableForwardRange range concept. + template + struct WriteableForwardRangeConcept + : ForwardRangeConcept + , WriteableRangeConcept + { + }; + + //! Check if a type T models the BidirectionalRange range concept. + template + struct BidirectionalRangeConcept : ForwardRangeConcept + { +#if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + BOOST_RANGE_CONCEPT_ASSERT((BidirectionalIteratorConcept)); + BOOST_RANGE_CONCEPT_ASSERT((BidirectionalIteratorConcept)); +#endif + }; + + //! Check if a type T models the WriteableBidirectionalRange range concept. + template + struct WriteableBidirectionalRangeConcept + : BidirectionalRangeConcept + , WriteableRangeConcept + { + }; + + //! Check if a type T models the RandomAccessRange range concept. + template + struct RandomAccessRangeConcept : BidirectionalRangeConcept + { +#if BOOST_RANGE_ENABLE_CONCEPT_ASSERT + BOOST_RANGE_CONCEPT_ASSERT((RandomAccessIteratorConcept)); + BOOST_RANGE_CONCEPT_ASSERT((RandomAccessIteratorConcept)); +#endif + }; + + //! Check if a type T models the WriteableRandomAccessRange range concept. + template + struct WriteableRandomAccessRangeConcept + : RandomAccessRangeConcept + , WriteableRangeConcept + { + }; + +} // namespace boost + +#endif // BOOST_RANGE_CONCEPTS_HPP diff --git a/3rdParty/Boost/src/boost/range/const_iterator.hpp b/3rdParty/Boost/src/boost/range/const_iterator.hpp index 195f9d4..875320f 100644 --- a/3rdParty/Boost/src/boost/range/const_iterator.hpp +++ b/3rdParty/Boost/src/boost/range/const_iterator.hpp @@ -21,6 +21,7 @@ #include #else +#include #include #include #include @@ -31,11 +32,13 @@ namespace boost // default ////////////////////////////////////////////////////////////////////////// + namespace range_detail { + BOOST_RANGE_EXTRACT_OPTIONAL_TYPE( const_iterator ) + } + template< typename C > - struct range_const_iterator - { - typedef BOOST_DEDUCED_TYPENAME C::const_iterator type; - }; + struct range_const_iterator : range_detail::extract_const_iterator + {}; ////////////////////////////////////////////////////////////////////////// // pair diff --git a/3rdParty/Boost/src/boost/range/detail/extract_optional_type.hpp b/3rdParty/Boost/src/boost/range/detail/extract_optional_type.hpp new file mode 100755 index 0000000..8292e34 --- /dev/null +++ b/3rdParty/Boost/src/boost/range/detail/extract_optional_type.hpp @@ -0,0 +1,52 @@ +// Boost.Range library +// +// Copyright Arno Schoedl & Neil Groves 2009. +// Use, modification and distribution is subject to 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) +// +// For more information, see http://www.boost.org/libs/range/ +// +#ifndef BOOST_RANGE_DETAIL_EXTRACT_OPTIONAL_TYPE_HPP_INCLUDED +#define BOOST_RANGE_DETAIL_EXTRACT_OPTIONAL_TYPE_HPP_INCLUDED + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +#ifdef BOOST_NO_PARTIAL_TEMPLATE_SPECIALIZATION + +#define BOOST_RANGE_EXTRACT_OPTIONAL_TYPE( a_typedef ) \ + template< typename C > \ + struct extract_ ## a_typedef \ + { \ + typedef BOOST_DEDUCED_TYPENAME C::a_typedef type; \ + }; + +#else + +namespace boost { + namespace range_detail { + template< typename T > struct exists { typedef void type; }; + } +} + +// Defines extract_some_typedef which exposes T::some_typedef as +// extract_some_typedef::type if T::some_typedef exists. Otherwise +// extract_some_typedef is empty. +#define BOOST_RANGE_EXTRACT_OPTIONAL_TYPE( a_typedef ) \ + template< typename C, typename Enable=void > \ + struct extract_ ## a_typedef \ + {}; \ + template< typename C > \ + struct extract_ ## a_typedef< C \ + , BOOST_DEDUCED_TYPENAME boost::range_detail::exists< BOOST_DEDUCED_TYPENAME C::a_typedef >::type \ + > { \ + typedef BOOST_DEDUCED_TYPENAME C::a_typedef type; \ + }; + +#endif + +#endif // include guard diff --git a/3rdParty/Boost/src/boost/range/detail/implementation_help.hpp b/3rdParty/Boost/src/boost/range/detail/implementation_help.hpp index ca12fa4..1f7d163 100644 --- a/3rdParty/Boost/src/boost/range/detail/implementation_help.hpp +++ b/3rdParty/Boost/src/boost/range/detail/implementation_help.hpp @@ -21,13 +21,13 @@ #include #endif -namespace boost +namespace boost { namespace range_detail { template inline void boost_range_silence_warning( const T& ) { } - + ///////////////////////////////////////////////////////////////////// // end() help ///////////////////////////////////////////////////////////////////// @@ -36,7 +36,7 @@ namespace boost { return s + strlen( s ); } - + #ifndef BOOST_NO_CWCHAR inline const wchar_t* str_end( const wchar_t* s, const wchar_t* ) { @@ -51,7 +51,7 @@ namespace boost ; return s; } -#endif +#endif template< class Char > inline Char* str_end( Char* s ) @@ -64,7 +64,7 @@ namespace boost { return boost_range_array + sz; } - + template< class T, std::size_t sz > inline const T* array_end( const T BOOST_RANGE_ARRAY_REF()[sz] ) { @@ -74,7 +74,7 @@ namespace boost ///////////////////////////////////////////////////////////////////// // size() help ///////////////////////////////////////////////////////////////////// - + template< class Char > inline std::size_t str_size( const Char* const& s ) { @@ -96,7 +96,7 @@ namespace boost } } // namespace 'range_detail' - + } // namespace 'boost' diff --git a/3rdParty/Boost/src/boost/range/detail/misc_concept.hpp b/3rdParty/Boost/src/boost/range/detail/misc_concept.hpp new file mode 100755 index 0000000..74cb919 --- /dev/null +++ b/3rdParty/Boost/src/boost/range/detail/misc_concept.hpp @@ -0,0 +1,33 @@ +// Boost.Range library concept checks +// +// Copyright Neil Groves 2009. Use, modification and distribution +// are subject to 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_RANGE_DETAIL_MISC_CONCEPT_HPP_INCLUDED +#define BOOST_RANGE_DETAIL_MISC_CONCEPT_HPP_INCLUDED + +#include + +namespace boost +{ + namespace range_detail + { + template + class SameTypeConcept + { + public: + BOOST_CONCEPT_USAGE(SameTypeConcept) + { + same_type(a,b); + } + private: + template void same_type(T,T) {} + T1 a; + T2 b; + }; + } +} + +#endif // include guard diff --git a/3rdParty/Boost/src/boost/range/iterator.hpp b/3rdParty/Boost/src/boost/range/iterator.hpp index 21798c5..ec73ddc 100644 --- a/3rdParty/Boost/src/boost/range/iterator.hpp +++ b/3rdParty/Boost/src/boost/range/iterator.hpp @@ -25,46 +25,46 @@ namespace boost { -#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) - - namespace range_detail_vc7_1 - { - template< typename C, typename Sig = void(C) > - struct range_iterator - { - typedef BOOST_RANGE_DEDUCED_TYPENAME - mpl::eval_if_c< is_const::value, - range_const_iterator< typename remove_const::type >, - range_mutable_iterator >::type type; - }; - - template< typename C, typename T > - struct range_iterator< C, void(T[]) > - { - typedef T* type; - }; - } - -#endif +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) + + namespace range_detail_vc7_1 + { + template< typename C, typename Sig = void(C) > + struct range_iterator + { + typedef BOOST_RANGE_DEDUCED_TYPENAME + mpl::eval_if_c< is_const::value, + range_const_iterator< typename remove_const::type >, + range_mutable_iterator >::type type; + }; + + template< typename C, typename T > + struct range_iterator< C, void(T[]) > + { + typedef T* type; + }; + } + +#endif template< typename C > struct range_iterator { #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) - - typedef BOOST_RANGE_DEDUCED_TYPENAME - range_detail_vc7_1::range_iterator::type type; - -#else - - typedef BOOST_RANGE_DEDUCED_TYPENAME - mpl::eval_if_c< is_const::value, + + typedef BOOST_RANGE_DEDUCED_TYPENAME + range_detail_vc7_1::range_iterator::type type; + +#else + + typedef BOOST_RANGE_DEDUCED_TYPENAME + mpl::eval_if_c< is_const::value, range_const_iterator< typename remove_const::type >, range_mutable_iterator >::type type; - -#endif + +#endif }; - + } // namespace boost //#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION diff --git a/3rdParty/Boost/src/boost/range/iterator_range.hpp b/3rdParty/Boost/src/boost/range/iterator_range.hpp index d118224..dfcd4d2 100644 --- a/3rdParty/Boost/src/boost/range/iterator_range.hpp +++ b/3rdParty/Boost/src/boost/range/iterator_range.hpp @@ -1,659 +1,16 @@ // Boost.Range library // -// Copyright Thorsten Ottosen & Pavol Droba 2003-2004. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Copyright Neil Groves 2009. +// Use, modification and distribution is subject to 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) // // For more information, see http://www.boost.org/libs/range/ // +#ifndef BOOST_RANGE_ITERATOR_RANGE_HPP_INCLUDED +#define BOOST_RANGE_ITERATOR_RANGE_HPP_INCLUDED -#ifndef BOOST_RANGE_ITERATOR_RANGE_HPP -#define BOOST_RANGE_ITERATOR_RANGE_HPP - -#include // Define __STL_CONFIG_H, if appropriate. -#include - -#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) - #pragma warning( push ) - #pragma warning( disable : 4996 ) -#endif - -// From boost/dynamic_bitset.hpp; thanks to Matthias Troyer for Cray X1 patch. -#ifndef BOOST_OLD_IOSTREAMS -# if defined(__STL_CONFIG_H) && \ - !defined (__STL_USE_NEW_IOSTREAMS) && !defined(__crayx1) \ - /**/ -# define BOOST_OLD_IOSTREAMS -# endif -#endif // #ifndef BOOST_OLD_IOSTREAMS - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef _STLP_NO_IOSTREAMS -# ifndef BOOST_OLD_IOSTREAMS -# include -# else -# include -# endif -#endif // _STLP_NO_IOSTREAMS -#include - -/*! \file - Defines the \c iterator_class and related functions. - \c iterator_range is a simple wrapper of iterator pair idiom. It provides - a rich subset of Container interface. -*/ - - -namespace boost -{ - namespace iterator_range_detail - { - // - // The functions adl_begin and adl_end are implemented in a separate - // class for gcc-2.9x - // - template - struct iterator_range_impl { - template< class ForwardRange > - static IteratorT adl_begin( ForwardRange& r ) - { - return IteratorT( boost::begin( r ) ); - } - - template< class ForwardRange > - static IteratorT adl_end( ForwardRange& r ) - { - return IteratorT( boost::end( r ) ); - } - }; - - template< class Left, class Right > - inline bool equal( const Left& l, const Right& r ) - { - typedef BOOST_DEDUCED_TYPENAME boost::range_difference::type sz_type; - - sz_type l_size = boost::distance( l ), - r_size = boost::distance( r ); - - if( l_size != r_size ) - return false; - - return std::equal( boost::begin(l), boost::end(l), - boost::begin(r) ); - } - - template< class Left, class Right > - inline bool less_than( const Left& l, const Right& r ) - { - return std::lexicographical_compare( boost::begin(l), - boost::end(l), - boost::begin(r), - boost::end(r) ); - } - - struct range_tag { }; - struct const_range_tag { }; - - } - -// iterator range template class -----------------------------------------// - - //! iterator_range class - /*! - An \c iterator_range delimits a range in a sequence by beginning and ending iterators. - An iterator_range can be passed to an algorithm which requires a sequence as an input. - For example, the \c toupper() function may be used most frequently on strings, - but can also be used on iterator_ranges: - - \code - boost::tolower( find( s, "UPPERCASE STRING" ) ); - \endcode - - Many algorithms working with sequences take a pair of iterators, - delimiting a working range, as an arguments. The \c iterator_range class is an - encapsulation of a range identified by a pair of iterators. - It provides a collection interface, - so it is possible to pass an instance to an algorithm requiring a collection as an input. - */ - template - class iterator_range - { - protected: // Used by sub_range - //! implementation class - typedef iterator_range_detail::iterator_range_impl impl; - public: - - //! this type - typedef iterator_range type; - //BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(value_type); - - //! Encapsulated value type - typedef BOOST_DEDUCED_TYPENAME - iterator_value::type value_type; - - //! Difference type - typedef BOOST_DEDUCED_TYPENAME - iterator_difference::type difference_type; - - //! Size type - typedef std::size_t size_type; // note: must be unsigned - - //! This type - typedef iterator_range this_type; - - //! Refence type - // - // Needed because value-type is the same for - // const and non-const iterators - // - typedef BOOST_DEDUCED_TYPENAME - iterator_reference::type reference; - - //! const_iterator type - /*! - There is no distinction between const_iterator and iterator. - These typedefs are provides to fulfill container interface - */ - typedef IteratorT const_iterator; - //! iterator type - typedef IteratorT iterator; - - private: // for return value of operator()() - typedef BOOST_DEDUCED_TYPENAME - boost::mpl::if_< boost::is_abstract, - reference, value_type >::type abstract_value_type; - - public: - iterator_range() : m_Begin( iterator() ), m_End( iterator() ) - #ifndef NDEBUG - , singular( true ) - #endif - { } - - //! Constructor from a pair of iterators - template< class Iterator > - iterator_range( Iterator Begin, Iterator End ) : - m_Begin(Begin), m_End(End) - #ifndef NDEBUG - , singular(false) - #endif - {} - - //! Constructor from a Range - template< class Range > - iterator_range( const Range& r ) : - m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) - #ifndef NDEBUG - , singular(false) - #endif - {} - - //! Constructor from a Range - template< class Range > - iterator_range( Range& r ) : - m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) - #ifndef NDEBUG - , singular(false) - #endif - {} - - //! Constructor from a Range - template< class Range > - iterator_range( const Range& r, iterator_range_detail::const_range_tag ) : - m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) - #ifndef NDEBUG - , singular(false) - #endif - {} - - //! Constructor from a Range - template< class Range > - iterator_range( Range& r, iterator_range_detail::range_tag ) : - m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) - #ifndef NDEBUG - , singular(false) - #endif - {} - - #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) - this_type& operator=( const this_type& r ) - { - m_Begin = r.begin(); - m_End = r.end(); - - #ifndef NDEBUG - singular = r.singular; - #endif - return *this; - } - #endif - - template< class Iterator > - iterator_range& operator=( const iterator_range& r ) - { - m_Begin = r.begin(); - m_End = r.end(); - #ifndef NDEBUG - singular = r.is_singular(); - #endif - return *this; - } - - template< class ForwardRange > - iterator_range& operator=( ForwardRange& r ) - { - m_Begin = impl::adl_begin( r ); - m_End = impl::adl_end( r ); - #ifndef NDEBUG - singular = false; - #endif - return *this; - } - - template< class ForwardRange > - iterator_range& operator=( const ForwardRange& r ) - { - m_Begin = impl::adl_begin( r ); - m_End = impl::adl_end( r ); - #ifndef NDEBUG - singular = false; - #endif - return *this; - } - - IteratorT begin() const - { - BOOST_ASSERT( !is_singular() ); - return m_Begin; - } - - IteratorT end() const - { - BOOST_ASSERT( !is_singular() ); - return m_End; - } - - difference_type size() const - { - BOOST_ASSERT( !is_singular() ); - return m_End - m_Begin; - } - - bool empty() const - { - BOOST_ASSERT( !is_singular() ); - return m_Begin == m_End; - } - -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) - operator bool() const - { - return !empty(); - } -#else - typedef iterator (iterator_range::*unspecified_bool_type) () const; - operator unspecified_bool_type() const - { - return empty() ? 0: &iterator_range::end; - } -#endif - - bool equal( const iterator_range& r ) const - { - BOOST_ASSERT( !is_singular() ); - return m_Begin == r.m_Begin && m_End == r.m_End; - } - - -#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING - - bool operator==( const iterator_range& r ) const - { - BOOST_ASSERT( !is_singular() ); - return iterator_range_detail::equal( *this, r ); - } - - bool operator!=( const iterator_range& r ) const - { - BOOST_ASSERT( !is_singular() ); - return !operator==(r); - } - - bool operator<( const iterator_range& r ) const - { - BOOST_ASSERT( !is_singular() ); - return iterator_range_detail::less_than( *this, r ); - } - -#endif - - public: // convenience - reference front() const - { - BOOST_ASSERT( !empty() ); - return *m_Begin; - } - - reference back() const - { - BOOST_ASSERT( !empty() ); - IteratorT last( m_End ); - return *--last; - } - - reference operator[]( difference_type at ) const - { - BOOST_ASSERT( at >= 0 && at < size() ); - return m_Begin[at]; - } - - // - // When storing transform iterators, operator[]() - // fails because it returns by reference. Therefore - // operator()() is provided for these cases. - // - abstract_value_type operator()( difference_type at ) const - { - BOOST_ASSERT( at >= 0 && at < size() ); - return m_Begin[at]; - } - - iterator_range& advance_begin( difference_type n ) - { - BOOST_ASSERT( !is_singular() ); - std::advance( m_Begin, n ); - return *this; - } - - iterator_range& advance_end( difference_type n ) - { - BOOST_ASSERT( !is_singular() ); - std::advance( m_End, n ); - return *this; - } - - private: - // begin and end iterators - IteratorT m_Begin; - IteratorT m_End; - - #ifndef NDEBUG - bool singular; - #endif - - public: - bool is_singular() const - { - #ifndef NDEBUG - return singular; - #else - return false; - #endif - } - - protected: - // - // Allow subclasses an easy way to access the - // base type - // - typedef iterator_range iterator_range_; - }; - -// iterator range free-standing operators ---------------------------// - -#ifndef _STLP_NO_IOSTREAMS -# ifndef BOOST_OLD_IOSTREAMS - - //! iterator_range output operator - /*! - Output the range to an ostream. Elements are outputed - in a sequence without separators. - */ - template< typename IteratorT, typename Elem, typename Traits > - inline std::basic_ostream& operator<<( - std::basic_ostream& Os, - const iterator_range& r ) - { - std::copy( r.begin(), r.end(), - std::ostream_iterator< BOOST_DEDUCED_TYPENAME - iterator_value::type, - Elem, Traits>(Os) ); - return Os; - } - -# else - - //! iterator_range output operator - /*! - Output the range to an ostream. Elements are outputed - in a sequence without separators. - */ - template< typename IteratorT > - inline std::ostream& operator<<( - std::ostream& Os, - const iterator_range& r ) - { - std::copy( r.begin(), r.end(), std::ostream_iterator(Os)); - return Os; - } - -# endif -#endif // _STLP_NO_IOSTREAMS - - ///////////////////////////////////////////////////////////////////// - // comparison operators - ///////////////////////////////////////////////////////////////////// - - template< class IteratorT, class ForwardRange > - inline bool operator==( const ForwardRange& l, - const iterator_range& r ) - { - return iterator_range_detail::equal( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator!=( const ForwardRange& l, - const iterator_range& r ) - { - return !iterator_range_detail::equal( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator<( const ForwardRange& l, - const iterator_range& r ) - { - return iterator_range_detail::less_than( l, r ); - } - -#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING -#else - template< class Iterator1T, class Iterator2T > - inline bool operator==( const iterator_range& l, - const iterator_range& r ) - { - return iterator_range_detail::equal( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator==( const iterator_range& l, - const ForwardRange& r ) - { - return iterator_range_detail::equal( l, r ); - } - - - template< class Iterator1T, class Iterator2T > - inline bool operator!=( const iterator_range& l, - const iterator_range& r ) - { - return !iterator_range_detail::equal( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator!=( const iterator_range& l, - const ForwardRange& r ) - { - return !iterator_range_detail::equal( l, r ); - } - - - template< class Iterator1T, class Iterator2T > - inline bool operator<( const iterator_range& l, - const iterator_range& r ) - { - return iterator_range_detail::less_than( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator<( const iterator_range& l, - const ForwardRange& r ) - { - return iterator_range_detail::less_than( l, r ); - } - -#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING - -// iterator range utilities -----------------------------------------// - - //! iterator_range construct helper - /*! - Construct an \c iterator_range from a pair of iterators - - \param Begin A begin iterator - \param End An end iterator - \return iterator_range object - */ - template< typename IteratorT > - inline iterator_range< IteratorT > - make_iterator_range( IteratorT Begin, IteratorT End ) - { - return iterator_range( Begin, End ); - } - -#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING - - template< typename Range > - inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > - make_iterator_range( Range& r ) - { - return iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > - ( boost::begin( r ), boost::end( r ) ); - } - -#else - //! iterator_range construct helper - /*! - Construct an \c iterator_range from a \c Range containing the begin - and end iterators. - */ - template< class ForwardRange > - inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > - make_iterator_range( ForwardRange& r ) - { - return iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > - ( r, iterator_range_detail::range_tag() ); - } - - template< class ForwardRange > - inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > - make_iterator_range( const ForwardRange& r ) - { - return iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > - ( r, iterator_range_detail::const_range_tag() ); - } - -#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING - - namespace iterator_range_detail - { - template< class Range > - inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > - make_range_impl( Range& r, - BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, - BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) - { - // - // Not worth the effort - // - //if( advance_begin == 0 && advance_end == 0 ) - // return make_iterator_range( r ); - // - - BOOST_DEDUCED_TYPENAME range_iterator::type - new_begin = boost::begin( r ), - new_end = boost::end( r ); - std::advance( new_begin, advance_begin ); - std::advance( new_end, advance_end ); - return make_iterator_range( new_begin, new_end ); - } - } - -#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING - - template< class Range > - inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > - make_iterator_range( Range& r, - BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, - BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) - { - //BOOST_ASSERT( advance_begin - advance_end <= size(r) && "creating invalid range" ); - return iterator_range_detail::make_range_impl( r, advance_begin, advance_end ); - } - -#else - - template< class Range > - inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > - make_iterator_range( Range& r, - BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, - BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) - { - //BOOST_ASSERT( advance_begin - advance_end <= size(r) && "creating invalid range" ); - return iterator_range_detail::make_range_impl( r, advance_begin, advance_end ); - } - - template< class Range > - inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > - make_iterator_range( const Range& r, - BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, - BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) - { - //BOOST_ASSERT( advance_begin - advance_end <= size(r) && "creating invalid range" ); - return iterator_range_detail::make_range_impl( r, advance_begin, advance_end ); - } - -#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING - - //! copy a range into a sequence - /*! - Construct a new sequence of the specified type from the elements - in the given range - - \param Range An input range - \return New sequence - */ - template< typename SeqT, typename Range > - inline SeqT copy_range( const Range& r ) - { - return SeqT( boost::begin( r ), boost::end( r ) ); - } - -} // namespace 'boost' - -#undef BOOST_OLD_IOSTREAMS - -#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) - #pragma warning( pop ) -#endif - -#endif +#include "boost/range/iterator_range_core.hpp" +#include "boost/range/iterator_range_io.hpp" +#endif // include guard diff --git a/3rdParty/Boost/src/boost/range/iterator_range_core.hpp b/3rdParty/Boost/src/boost/range/iterator_range_core.hpp new file mode 100755 index 0000000..497b1e3 --- /dev/null +++ b/3rdParty/Boost/src/boost/range/iterator_range_core.hpp @@ -0,0 +1,542 @@ +// Boost.Range library +// +// Copyright Neil Groves & Thorsten Ottosen & Pavol Droba 2003-2004. +// Use, modification and distribution is subject to 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) +// +// For more information, see http://www.boost.org/libs/range/ +// +#ifndef BOOST_RANGE_ITERATOR_RANGE_CORE_HPP_INCLUDED +#define BOOST_RANGE_ITERATOR_RANGE_CORE_HPP_INCLUDED + +#include // Define __STL_CONFIG_H, if appropriate. +#include + +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) + #pragma warning( push ) + #pragma warning( disable : 4996 ) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*! \file + Defines the \c iterator_class and related functions. + \c iterator_range is a simple wrapper of iterator pair idiom. It provides + a rich subset of Container interface. +*/ + + +namespace boost +{ + namespace iterator_range_detail + { + // + // The functions adl_begin and adl_end are implemented in a separate + // class for gcc-2.9x + // + template + struct iterator_range_impl { + template< class ForwardRange > + static IteratorT adl_begin( ForwardRange& r ) + { + return IteratorT( boost::begin( r ) ); + } + + template< class ForwardRange > + static IteratorT adl_end( ForwardRange& r ) + { + return IteratorT( boost::end( r ) ); + } + }; + + template< class Left, class Right > + inline bool less_than( const Left& l, const Right& r ) + { + return std::lexicographical_compare( boost::begin(l), + boost::end(l), + boost::begin(r), + boost::end(r) ); + } + + // This version is maintained since it is used in other boost libraries + // such as Boost.Assign + template< class Left, class Right > + inline bool equal(const Left& l, const Right& r) + { + return boost::equal(l, r); + } + + struct range_tag { }; + struct const_range_tag { }; + + } + +// iterator range template class -----------------------------------------// + + //! iterator_range class + /*! + An \c iterator_range delimits a range in a sequence by beginning and ending iterators. + An iterator_range can be passed to an algorithm which requires a sequence as an input. + For example, the \c toupper() function may be used most frequently on strings, + but can also be used on iterator_ranges: + + \code + boost::tolower( find( s, "UPPERCASE STRING" ) ); + \endcode + + Many algorithms working with sequences take a pair of iterators, + delimiting a working range, as an arguments. The \c iterator_range class is an + encapsulation of a range identified by a pair of iterators. + It provides a collection interface, + so it is possible to pass an instance to an algorithm requiring a collection as an input. + */ + template + class iterator_range + { + protected: // Used by sub_range + //! implementation class + typedef iterator_range_detail::iterator_range_impl impl; + public: + + //! this type + typedef iterator_range type; + //BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(value_type); + + //! Encapsulated value type + typedef BOOST_DEDUCED_TYPENAME + iterator_value::type value_type; + + //! Difference type + typedef BOOST_DEDUCED_TYPENAME + iterator_difference::type difference_type; + + //! Size type + typedef std::size_t size_type; // note: must be unsigned + + //! This type + typedef iterator_range this_type; + + //! Reference type + // + // Needed because value-type is the same for + // const and non-const iterators + // + typedef BOOST_DEDUCED_TYPENAME + iterator_reference::type reference; + + //! const_iterator type + /*! + There is no distinction between const_iterator and iterator. + These typedefs are provides to fulfill container interface + */ + typedef IteratorT const_iterator; + //! iterator type + typedef IteratorT iterator; + + private: // for return value of operator()() + typedef BOOST_DEDUCED_TYPENAME + boost::mpl::if_< boost::is_abstract, + reference, value_type >::type abstract_value_type; + + public: + iterator_range() : m_Begin( iterator() ), m_End( iterator() ) + { } + + //! Constructor from a pair of iterators + template< class Iterator > + iterator_range( Iterator Begin, Iterator End ) : + m_Begin(Begin), m_End(End) + {} + + //! Constructor from a Range + template< class Range > + iterator_range( const Range& r ) : + m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) + {} + + //! Constructor from a Range + template< class Range > + iterator_range( Range& r ) : + m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) + {} + + //! Constructor from a Range + template< class Range > + iterator_range( const Range& r, iterator_range_detail::const_range_tag ) : + m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) + {} + + //! Constructor from a Range + template< class Range > + iterator_range( Range& r, iterator_range_detail::range_tag ) : + m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) + {} + + #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) + this_type& operator=( const this_type& r ) + { + m_Begin = r.begin(); + m_End = r.end(); + return *this; + } + #endif + + template< class Iterator > + iterator_range& operator=( const iterator_range& r ) + { + m_Begin = r.begin(); + m_End = r.end(); + return *this; + } + + template< class ForwardRange > + iterator_range& operator=( ForwardRange& r ) + { + m_Begin = impl::adl_begin( r ); + m_End = impl::adl_end( r ); + return *this; + } + + template< class ForwardRange > + iterator_range& operator=( const ForwardRange& r ) + { + m_Begin = impl::adl_begin( r ); + m_End = impl::adl_end( r ); + return *this; + } + + IteratorT begin() const + { + return m_Begin; + } + + IteratorT end() const + { + return m_End; + } + + difference_type size() const + { + return m_End - m_Begin; + } + + bool empty() const + { + return m_Begin == m_End; + } + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + operator bool() const + { + return !empty(); + } +#else + typedef iterator (iterator_range::*unspecified_bool_type) () const; + operator unspecified_bool_type() const + { + return empty() ? 0: &iterator_range::end; + } +#endif + + bool equal( const iterator_range& r ) const + { + return m_Begin == r.m_Begin && m_End == r.m_End; + } + + +#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + + bool operator==( const iterator_range& r ) const + { + return boost::equal( *this, r ); + } + + bool operator!=( const iterator_range& r ) const + { + return !operator==(r); + } + + bool operator<( const iterator_range& r ) const + { + return iterator_range_detail::less_than( *this, r ); + } + +#endif + + public: // convenience + reference front() const + { + BOOST_ASSERT( !empty() ); + return *m_Begin; + } + + reference back() const + { + BOOST_ASSERT( !empty() ); + IteratorT last( m_End ); + return *--last; + } + + reference operator[]( difference_type at ) const + { + BOOST_ASSERT( at >= 0 && at < size() ); + return m_Begin[at]; + } + + // + // When storing transform iterators, operator[]() + // fails because it returns by reference. Therefore + // operator()() is provided for these cases. + // + abstract_value_type operator()( difference_type at ) const + { + BOOST_ASSERT( at >= 0 && at < size() ); + return m_Begin[at]; + } + + iterator_range& advance_begin( difference_type n ) + { + std::advance( m_Begin, n ); + return *this; + } + + iterator_range& advance_end( difference_type n ) + { + std::advance( m_End, n ); + return *this; + } + + private: + // begin and end iterators + IteratorT m_Begin; + IteratorT m_End; + + protected: + // + // Allow subclasses an easy way to access the + // base type + // + typedef iterator_range iterator_range_; + }; + +// iterator range free-standing operators ---------------------------// + + ///////////////////////////////////////////////////////////////////// + // comparison operators + ///////////////////////////////////////////////////////////////////// + + template< class IteratorT, class ForwardRange > + inline bool operator==( const ForwardRange& l, + const iterator_range& r ) + { + return boost::equal( l, r ); + } + + template< class IteratorT, class ForwardRange > + inline bool operator!=( const ForwardRange& l, + const iterator_range& r ) + { + return !boost::equal( l, r ); + } + + template< class IteratorT, class ForwardRange > + inline bool operator<( const ForwardRange& l, + const iterator_range& r ) + { + return iterator_range_detail::less_than( l, r ); + } + +#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING +#else + template< class Iterator1T, class Iterator2T > + inline bool operator==( const iterator_range& l, + const iterator_range& r ) + { + return boost::equal( l, r ); + } + + template< class IteratorT, class ForwardRange > + inline bool operator==( const iterator_range& l, + const ForwardRange& r ) + { + return boost::equal( l, r ); + } + + + template< class Iterator1T, class Iterator2T > + inline bool operator!=( const iterator_range& l, + const iterator_range& r ) + { + return !boost::equal( l, r ); + } + + template< class IteratorT, class ForwardRange > + inline bool operator!=( const iterator_range& l, + const ForwardRange& r ) + { + return !boost::equal( l, r ); + } + + + template< class Iterator1T, class Iterator2T > + inline bool operator<( const iterator_range& l, + const iterator_range& r ) + { + return iterator_range_detail::less_than( l, r ); + } + + template< class IteratorT, class ForwardRange > + inline bool operator<( const iterator_range& l, + const ForwardRange& r ) + { + return iterator_range_detail::less_than( l, r ); + } + +#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING + +// iterator range utilities -----------------------------------------// + + //! iterator_range construct helper + /*! + Construct an \c iterator_range from a pair of iterators + + \param Begin A begin iterator + \param End An end iterator + \return iterator_range object + */ + template< typename IteratorT > + inline iterator_range< IteratorT > + make_iterator_range( IteratorT Begin, IteratorT End ) + { + return iterator_range( Begin, End ); + } + +#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + + template< typename Range > + inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + make_iterator_range( Range& r ) + { + return iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + ( boost::begin( r ), boost::end( r ) ); + } + +#else + //! iterator_range construct helper + /*! + Construct an \c iterator_range from a \c Range containing the begin + and end iterators. + */ + template< class ForwardRange > + inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + make_iterator_range( ForwardRange& r ) + { + return iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + ( r, iterator_range_detail::range_tag() ); + } + + template< class ForwardRange > + inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + make_iterator_range( const ForwardRange& r ) + { + return iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + ( r, iterator_range_detail::const_range_tag() ); + } + +#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING + + namespace iterator_range_detail + { + template< class Range > + inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + make_range_impl( Range& r, + BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, + BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) + { + // + // Not worth the effort + // + //if( advance_begin == 0 && advance_end == 0 ) + // return make_iterator_range( r ); + // + + BOOST_DEDUCED_TYPENAME range_iterator::type + new_begin = boost::begin( r ), + new_end = boost::end( r ); + std::advance( new_begin, advance_begin ); + std::advance( new_end, advance_end ); + return make_iterator_range( new_begin, new_end ); + } + } + +#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + + template< class Range > + inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + make_iterator_range( Range& r, + BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, + BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) + { + //BOOST_ASSERT( advance_begin - advance_end <= size(r) && "creating invalid range" ); + return iterator_range_detail::make_range_impl( r, advance_begin, advance_end ); + } + +#else + + template< class Range > + inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + make_iterator_range( Range& r, + BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, + BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) + { + //BOOST_ASSERT( advance_begin - advance_end <= size(r) && "creating invalid range" ); + return iterator_range_detail::make_range_impl( r, advance_begin, advance_end ); + } + + template< class Range > + inline iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + make_iterator_range( const Range& r, + BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, + BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) + { + //BOOST_ASSERT( advance_begin - advance_end <= size(r) && "creating invalid range" ); + return iterator_range_detail::make_range_impl( r, advance_begin, advance_end ); + } + +#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING + + //! copy a range into a sequence + /*! + Construct a new sequence of the specified type from the elements + in the given range + + \param Range An input range + \return New sequence + */ + template< typename SeqT, typename Range > + inline SeqT copy_range( const Range& r ) + { + return SeqT( boost::begin( r ), boost::end( r ) ); + } + +} // namespace 'boost' + +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) + #pragma warning( pop ) +#endif + +#endif + diff --git a/3rdParty/Boost/src/boost/range/iterator_range_io.hpp b/3rdParty/Boost/src/boost/range/iterator_range_io.hpp new file mode 100755 index 0000000..51e3a4f --- /dev/null +++ b/3rdParty/Boost/src/boost/range/iterator_range_io.hpp @@ -0,0 +1,93 @@ +// Boost.Range library +// +// Copyright Neil Groves 2009. +// Use, modification and distribution is subject to 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) +// +// For more information, see http://www.boost.org/libs/range/ +// +#ifndef BOOST_RANGE_ITERATOR_RANGE_IO_HPP_INCLUDED +#define BOOST_RANGE_ITERATOR_RANGE_IO_HPP_INCLUDED + +#include +#include + +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) + #pragma warning( push ) + #pragma warning( disable : 4996 ) +#endif + +// From boost/dynamic_bitset.hpp; thanks to Matthias Troyer for Cray X1 patch. +#ifndef BOOST_OLD_IOSTREAMS +# if defined(__STL_CONFIG_H) && \ + !defined (__STL_USE_NEW_IOSTREAMS) && !defined(__crayx1) \ + /**/ +# define BOOST_OLD_IOSTREAMS +# endif +#endif // #ifndef BOOST_OLD_IOSTREAMS + +#ifndef _STLP_NO_IOSTREAMS +# ifndef BOOST_OLD_IOSTREAMS +# include +# else +# include +# endif +#endif // _STLP_NO_IOSTREAMS + +#include +#include +#include +#include + +namespace boost +{ + +#ifndef _STLP_NO_IOSTREAMS +# ifndef BOOST_OLD_IOSTREAMS + + //! iterator_range output operator + /*! + Output the range to an ostream. Elements are outputed + in a sequence without separators. + */ + template< typename IteratorT, typename Elem, typename Traits > + inline std::basic_ostream& operator<<( + std::basic_ostream& Os, + const iterator_range& r ) + { + std::copy( r.begin(), r.end(), + std::ostream_iterator< BOOST_DEDUCED_TYPENAME + iterator_value::type, + Elem, Traits>(Os) ); + return Os; + } + +# else + + //! iterator_range output operator + /*! + Output the range to an ostream. Elements are outputed + in a sequence without separators. + */ + template< typename IteratorT > + inline std::ostream& operator<<( + std::ostream& Os, + const iterator_range& r ) + { + std::copy( r.begin(), r.end(), std::ostream_iterator(Os)); + return Os; + } + +# endif +#endif // _STLP_NO_IOSTREAMS + +} // namespace boost + +#undef BOOST_OLD_IOSTREAMS + +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) + #pragma warning(pop) +#endif + +#endif // include guard diff --git a/3rdParty/Boost/src/boost/range/mutable_iterator.hpp b/3rdParty/Boost/src/boost/range/mutable_iterator.hpp index 2f45c16..7beca66 100644 --- a/3rdParty/Boost/src/boost/range/mutable_iterator.hpp +++ b/3rdParty/Boost/src/boost/range/mutable_iterator.hpp @@ -21,6 +21,7 @@ #include #else +#include #include #include #include @@ -31,11 +32,13 @@ namespace boost // default ////////////////////////////////////////////////////////////////////////// + namespace range_detail { + BOOST_RANGE_EXTRACT_OPTIONAL_TYPE( iterator ) + } + template< typename C > - struct range_mutable_iterator - { - typedef BOOST_DEDUCED_TYPENAME C::iterator type; - }; + struct range_mutable_iterator : range_detail::extract_iterator + {}; ////////////////////////////////////////////////////////////////////////// // pair diff --git a/3rdParty/Boost/src/boost/range/size.hpp b/3rdParty/Boost/src/boost/range/size.hpp index 311a692..2b572d4 100644 --- a/3rdParty/Boost/src/boost/range/size.hpp +++ b/3rdParty/Boost/src/boost/range/size.hpp @@ -20,7 +20,7 @@ #include #include -namespace boost +namespace boost { template< class T > diff --git a/3rdParty/Boost/src/boost/range/size_type.hpp b/3rdParty/Boost/src/boost/range/size_type.hpp index 7ed8dfa..8c184f8 100644 --- a/3rdParty/Boost/src/boost/range/size_type.hpp +++ b/3rdParty/Boost/src/boost/range/size_type.hpp @@ -67,7 +67,8 @@ namespace boost { }; template< class T > - struct range_size : range_size + struct range_size + : detail::range_size { }; } // namespace boost diff --git a/3rdParty/Boost/src/boost/smart_ptr/detail/sp_convertible.hpp b/3rdParty/Boost/src/boost/smart_ptr/detail/sp_convertible.hpp index b7f0ea8..fe44069 100644 --- a/3rdParty/Boost/src/boost/smart_ptr/detail/sp_convertible.hpp +++ b/3rdParty/Boost/src/boost/smart_ptr/detail/sp_convertible.hpp @@ -25,7 +25,7 @@ # define BOOST_SP_NO_SP_CONVERTIBLE #endif -#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) && defined( __BORLANDC__ ) && ( __BORLANDC__ <= 0x620 ) +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) && defined( __BORLANDC__ ) && ( __BORLANDC__ < 0x630 ) # define BOOST_SP_NO_SP_CONVERTIBLE #endif diff --git a/3rdParty/Boost/src/boost/thread/barrier.hpp b/3rdParty/Boost/src/boost/thread/barrier.hpp index 546f5e9..4ca30cb 100644 --- a/3rdParty/Boost/src/boost/thread/barrier.hpp +++ b/3rdParty/Boost/src/boost/thread/barrier.hpp @@ -9,6 +9,7 @@ #define BOOST_BARRIER_JDM030602_HPP #include +#include #include #include @@ -27,7 +28,7 @@ namespace boost : m_threshold(count), m_count(count), m_generation(0) { if (count == 0) - throw std::invalid_argument("count cannot be zero."); + boost::throw_exception(std::invalid_argument("count cannot be zero.")); } bool wait() diff --git a/3rdParty/Boost/src/boost/thread/detail/thread.hpp b/3rdParty/Boost/src/boost/thread/detail/thread.hpp index 170801b..9615a39 100644 --- a/3rdParty/Boost/src/boost/thread/detail/thread.hpp +++ b/3rdParty/Boost/src/boost/thread/detail/thread.hpp @@ -39,10 +39,13 @@ namespace boost public detail::thread_data_base { public: -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES thread_data(F&& f_): f(static_cast(f_)) {} + thread_data(F& f_): + f(f_) + {} #else thread_data(F f_): f(f_) @@ -119,7 +122,7 @@ namespace boost detail::thread_data_ptr get_thread_info() const; -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES template static inline detail::thread_data_ptr make_thread_info(F&& f) { @@ -127,7 +130,7 @@ namespace boost } static inline detail::thread_data_ptr make_thread_info(void (*f)()) { - return detail::thread_data_ptr(detail::heap_new >(f)); + return detail::thread_data_ptr(detail::heap_new >(static_cast(f))); } #else template @@ -141,8 +144,8 @@ namespace boost return detail::thread_data_ptr(detail::heap_new >(f)); } - struct dummy; #endif + struct dummy; public: #ifdef __SUNPRO_CC thread(const volatile thread&); @@ -150,13 +153,22 @@ namespace boost thread(); ~thread(); -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES +#ifdef BOOST_MSVC + template + explicit thread(F f,typename disable_if >, dummy* >::type=0): + thread_info(make_thread_info(f)) + { + start_thread(); + } +#else template thread(F&& f): thread_info(make_thread_info(static_cast(f))) { start_thread(); } +#endif thread(thread&& other) { @@ -343,10 +355,14 @@ namespace boost return lhs.swap(rhs); } -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES + inline thread&& move(thread& t) + { + return static_cast(t); + } inline thread&& move(thread&& t) { - return t; + return static_cast(t); } #else inline detail::thread_move_t move(detail::thread_move_t t) @@ -445,7 +461,7 @@ namespace boost { virtual ~thread_exit_function_base() {} - virtual void operator()() const=0; + virtual void operator()()=0; }; template @@ -458,13 +474,13 @@ namespace boost f(f_) {} - void operator()() const + void operator()() { f(); } }; - void add_thread_exit_function(thread_exit_function_base*); + void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*); } namespace this_thread diff --git a/3rdParty/Boost/src/boost/thread/future.hpp b/3rdParty/Boost/src/boost/thread/future.hpp index 3d694eb..8111d9e 100644 --- a/3rdParty/Boost/src/boost/thread/future.hpp +++ b/3rdParty/Boost/src/boost/thread/future.hpp @@ -1,4 +1,4 @@ -// (C) Copyright 2008-9 Anthony Williams +// (C) Copyright 2008-10 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -218,7 +219,7 @@ namespace boost struct future_traits { typedef boost::scoped_ptr storage_type; -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES typedef T const& source_reference_type; struct dummy; typedef typename boost::mpl::if_,dummy&,T&&>::type rvalue_source_type; @@ -323,7 +324,7 @@ namespace boost move_dest_type get() { wait(); - return *result; + return static_cast(*result); } future_state::state get_state() @@ -403,13 +404,14 @@ namespace boost struct all_futures_lock { - unsigned count; + typedef std::vector::size_type count_type; + count_type count; boost::scoped_array > locks; all_futures_lock(std::vector& futures): count(futures.size()),locks(new boost::unique_lock[count]) { - for(unsigned i=0;i(futures[i].future->mutex); } @@ -632,7 +634,7 @@ namespace boost ~unique_future() {} -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES unique_future(unique_future && other) { future.swap(other.future); @@ -673,7 +675,7 @@ namespace boost { if(!future) { - throw future_uninitialized(); + boost::throw_exception(future_uninitialized()); } return future->get(); @@ -709,7 +711,7 @@ namespace boost { if(!future) { - throw future_uninitialized(); + boost::throw_exception(future_uninitialized()); } future->wait(false); } @@ -724,7 +726,7 @@ namespace boost { if(!future) { - throw future_uninitialized(); + boost::throw_exception(future_uninitialized()); } return future->timed_wait_until(abs_time); } @@ -767,7 +769,7 @@ namespace boost future=other.future; return *this; } -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES shared_future(shared_future && other) { future.swap(other.future); @@ -830,7 +832,7 @@ namespace boost { if(!future) { - throw future_uninitialized(); + boost::throw_exception(future_uninitialized()); } return future->get(); @@ -866,7 +868,7 @@ namespace boost { if(!future) { - throw future_uninitialized(); + boost::throw_exception(future_uninitialized()); } future->wait(false); } @@ -881,7 +883,7 @@ namespace boost { if(!future) { - throw future_uninitialized(); + boost::throw_exception(future_uninitialized()); } return future->timed_wait_until(abs_time); } @@ -929,7 +931,7 @@ namespace boost } // Assignment -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES promise(promise && rhs): future_obtained(rhs.future_obtained) { @@ -974,7 +976,7 @@ namespace boost lazy_init(); if(future_obtained) { - throw future_already_retrieved(); + boost::throw_exception(future_already_retrieved()); } future_obtained=true; return unique_future(future); @@ -986,7 +988,7 @@ namespace boost boost::lock_guard lock(future->mutex); if(future->done) { - throw promise_already_satisfied(); + boost::throw_exception(promise_already_satisfied()); } future->mark_finished_with_result_internal(r); } @@ -998,7 +1000,7 @@ namespace boost boost::lock_guard lock(future->mutex); if(future->done) { - throw promise_already_satisfied(); + boost::throw_exception(promise_already_satisfied()); } future->mark_finished_with_result_internal(static_cast::rvalue_source_type>(r)); } @@ -1009,7 +1011,7 @@ namespace boost boost::lock_guard lock(future->mutex); if(future->done) { - throw promise_already_satisfied(); + boost::throw_exception(promise_already_satisfied()); } future->mark_exceptional_finish_internal(p); } @@ -1063,7 +1065,7 @@ namespace boost } // Assignment -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES promise(promise && rhs): future_obtained(rhs.future_obtained) { @@ -1109,7 +1111,7 @@ namespace boost if(future_obtained) { - throw future_already_retrieved(); + boost::throw_exception(future_already_retrieved()); } future_obtained=true; return unique_future(future); @@ -1121,7 +1123,7 @@ namespace boost boost::lock_guard lock(future->mutex); if(future->done) { - throw promise_already_satisfied(); + boost::throw_exception(promise_already_satisfied()); } future->mark_finished_with_result_internal(); } @@ -1132,7 +1134,7 @@ namespace boost boost::lock_guard lock(future->mutex); if(future->done) { - throw promise_already_satisfied(); + boost::throw_exception(promise_already_satisfied()); } future->mark_exceptional_finish_internal(p); } @@ -1164,7 +1166,7 @@ namespace boost boost::lock_guard lk(this->mutex); if(started) { - throw task_already_started(); + boost::throw_exception(task_already_started()); } started=true; } @@ -1283,7 +1285,7 @@ namespace boost } // assignment -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES packaged_task(packaged_task&& other): future_obtained(other.future_obtained) { @@ -1326,7 +1328,7 @@ namespace boost { if(!task) { - throw task_moved(); + boost::throw_exception(task_moved()); } else if(!future_obtained) { @@ -1335,7 +1337,7 @@ namespace boost } else { - throw future_already_retrieved(); + boost::throw_exception(future_already_retrieved()); } } @@ -1345,7 +1347,7 @@ namespace boost { if(!task) { - throw task_moved(); + boost::throw_exception(task_moved()); } task->run(); } diff --git a/3rdParty/Boost/src/boost/thread/locks.hpp b/3rdParty/Boost/src/boost/thread/locks.hpp index 82394a5..3cd6f28 100644 --- a/3rdParty/Boost/src/boost/thread/locks.hpp +++ b/3rdParty/Boost/src/boost/thread/locks.hpp @@ -248,7 +248,7 @@ namespace boost { timed_lock(target_time); } -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES unique_lock(unique_lock&& other): m(other.m),is_locked(other.is_locked) { @@ -321,17 +321,17 @@ namespace boost swap(temp); return *this; } - void swap(unique_lock& other) - { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); - } void swap(detail::thread_move_t > other) { std::swap(m,other->m); std::swap(is_locked,other->is_locked); } #endif + void swap(unique_lock& other) + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } ~unique_lock() { @@ -344,7 +344,7 @@ namespace boost { if(owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } m->lock(); is_locked=true; @@ -353,7 +353,7 @@ namespace boost { if(owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } is_locked=m->try_lock(); return is_locked; @@ -379,7 +379,7 @@ namespace boost { if(!owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } m->unlock(); is_locked=false; @@ -416,25 +416,30 @@ namespace boost friend class upgrade_lock; }; -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES template void swap(unique_lock&& lhs,unique_lock&& rhs) { lhs.swap(rhs); } -#else +#endif template void swap(unique_lock& lhs,unique_lock& rhs) { lhs.swap(rhs); } -#endif -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES template inline unique_lock&& move(unique_lock&& ul) { - return ul; + return static_cast&&>(ul); + } + + template + inline unique_lock&& move(unique_lock& ul) + { + return static_cast&&>(ul); } #endif @@ -535,24 +540,24 @@ namespace boost return *this; } -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES void swap(shared_lock&& other) { std::swap(m,other.m); std::swap(is_locked,other.is_locked); } #else - void swap(shared_lock& other) - { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); - } void swap(boost::detail::thread_move_t > other) { std::swap(m,other->m); std::swap(is_locked,other->is_locked); } #endif + void swap(shared_lock& other) + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } Mutex* mutex() const { @@ -570,7 +575,7 @@ namespace boost { if(owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } m->lock_shared(); is_locked=true; @@ -579,7 +584,7 @@ namespace boost { if(owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } is_locked=m->try_lock_shared(); return is_locked; @@ -588,7 +593,7 @@ namespace boost { if(owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } is_locked=m->timed_lock_shared(target_time); return is_locked; @@ -598,7 +603,7 @@ namespace boost { if(owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } is_locked=m->timed_lock_shared(target_time); return is_locked; @@ -607,7 +612,7 @@ namespace boost { if(!owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } m->unlock_shared(); is_locked=false; @@ -629,7 +634,7 @@ namespace boost }; -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES template void swap(shared_lock&& lhs,shared_lock&& rhs) { @@ -733,7 +738,7 @@ namespace boost { if(owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } m->lock_upgrade(); is_locked=true; @@ -742,7 +747,7 @@ namespace boost { if(owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } is_locked=m->try_lock_upgrade(); return is_locked; @@ -751,7 +756,7 @@ namespace boost { if(!owns_lock()) { - throw boost::lock_error(); + boost::throw_exception(boost::lock_error()); } m->unlock_upgrade(); is_locked=false; @@ -775,7 +780,7 @@ namespace boost }; -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES template unique_lock::unique_lock(upgrade_lock&& other): m(other.m),is_locked(other.is_locked) @@ -875,7 +880,7 @@ namespace boost try_lock_wrapper(Mutex& m_,try_to_lock_t): base(m_,try_to_lock) {} -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES try_lock_wrapper(try_lock_wrapper&& other): base(other.move()) {} @@ -963,7 +968,7 @@ namespace boost } }; -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES template void swap(try_lock_wrapper&& lhs,try_lock_wrapper&& rhs) { diff --git a/3rdParty/Boost/src/boost/thread/pthread/condition_variable.hpp b/3rdParty/Boost/src/boost/thread/pthread/condition_variable.hpp index 8ec6ae7..8e8f5b5 100644 --- a/3rdParty/Boost/src/boost/thread/pthread/condition_variable.hpp +++ b/3rdParty/Boost/src/boost/thread/pthread/condition_variable.hpp @@ -57,13 +57,13 @@ namespace boost int const res=pthread_mutex_init(&internal_mutex,NULL); if(res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } int const res2=pthread_cond_init(&cond,NULL); if(res2) { BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } } ~condition_variable_any() @@ -87,7 +87,7 @@ namespace boost } if(res) { - throw condition_error(); + boost::throw_exception(condition_error()); } } @@ -117,7 +117,7 @@ namespace boost } if(res) { - throw condition_error(); + boost::throw_exception(condition_error()); } return true; } diff --git a/3rdParty/Boost/src/boost/thread/pthread/condition_variable_fwd.hpp b/3rdParty/Boost/src/boost/thread/pthread/condition_variable_fwd.hpp index 4048cdf..59908f4 100644 --- a/3rdParty/Boost/src/boost/thread/pthread/condition_variable_fwd.hpp +++ b/3rdParty/Boost/src/boost/thread/pthread/condition_variable_fwd.hpp @@ -6,6 +6,7 @@ // (C) Copyright 2007-8 Anthony Williams #include +#include #include #include #include @@ -30,7 +31,7 @@ namespace boost int const res=pthread_cond_init(&cond,NULL); if(res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } } ~condition_variable() diff --git a/3rdParty/Boost/src/boost/thread/pthread/mutex.hpp b/3rdParty/Boost/src/boost/thread/pthread/mutex.hpp index 51d62ae..1f7f790 100644 --- a/3rdParty/Boost/src/boost/thread/pthread/mutex.hpp +++ b/3rdParty/Boost/src/boost/thread/pthread/mutex.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -37,7 +38,7 @@ namespace boost int const res=pthread_mutex_init(&m,NULL); if(res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } } ~mutex() @@ -89,14 +90,14 @@ namespace boost int const res=pthread_mutex_init(&m,NULL); if(res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK int const res2=pthread_cond_init(&cond,NULL); if(res2) { BOOST_VERIFY(!pthread_mutex_destroy(&m)); - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } is_locked=false; #endif diff --git a/3rdParty/Boost/src/boost/thread/pthread/once.hpp b/3rdParty/Boost/src/boost/thread/pthread/once.hpp index f278a57..6321aa2 100644 --- a/3rdParty/Boost/src/boost/thread/pthread/once.hpp +++ b/3rdParty/Boost/src/boost/thread/pthread/once.hpp @@ -10,6 +10,7 @@ // http://www.boost.org/LICENSE_1_0.txt) #include +#include #include #include @@ -58,10 +59,13 @@ namespace boost if(flag.epoch==uninitialized_flag) { flag.epoch=being_initialized; +#ifndef BOOST_NO_EXCEPTIONS try { +#endif pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex); f(); +#ifndef BOOST_NO_EXCEPTIONS } catch(...) { @@ -69,6 +73,7 @@ namespace boost BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv)); throw; } +#endif flag.epoch=--detail::once_global_epoch; BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv)); } diff --git a/3rdParty/Boost/src/boost/thread/pthread/recursive_mutex.hpp b/3rdParty/Boost/src/boost/thread/pthread/recursive_mutex.hpp index f3f7bf1..ad3b7e1 100644 --- a/3rdParty/Boost/src/boost/thread/pthread/recursive_mutex.hpp +++ b/3rdParty/Boost/src/boost/thread/pthread/recursive_mutex.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -42,18 +43,18 @@ namespace boost int const init_attr_res=pthread_mutexattr_init(&attr); if(init_attr_res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); if(set_attr_res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } int const res=pthread_mutex_init(&m,&attr); if(res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); } @@ -111,32 +112,32 @@ namespace boost int const init_attr_res=pthread_mutexattr_init(&attr); if(init_attr_res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); if(set_attr_res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } int const res=pthread_mutex_init(&m,&attr); if(res) { BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); #else int const res=pthread_mutex_init(&m,NULL); if(res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } int const res2=pthread_cond_init(&cond,NULL); if(res2) { BOOST_VERIFY(!pthread_mutex_destroy(&m)); - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } is_locked=false; count=0; diff --git a/3rdParty/Boost/src/boost/thread/pthread/thread_heap_alloc.hpp b/3rdParty/Boost/src/boost/thread/pthread/thread_heap_alloc.hpp index 7cc0aa0..737c298 100644 --- a/3rdParty/Boost/src/boost/thread/pthread/thread_heap_alloc.hpp +++ b/3rdParty/Boost/src/boost/thread/pthread/thread_heap_alloc.hpp @@ -17,7 +17,7 @@ namespace boost return new T(); } -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES template inline T* heap_new(A1&& a1) { diff --git a/3rdParty/Boost/src/boost/thread/win32/basic_timed_mutex.hpp b/3rdParty/Boost/src/boost/thread/win32/basic_timed_mutex.hpp index 751bdbd..7c6797d 100644 --- a/3rdParty/Boost/src/boost/thread/win32/basic_timed_mutex.hpp +++ b/3rdParty/Boost/src/boost/thread/win32/basic_timed_mutex.hpp @@ -61,15 +61,30 @@ namespace boost void lock() { - BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel())); - } - bool timed_lock(::boost::system_time const& wait_until) - { - if(!win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit)) + if(try_lock()) { - return true; + return; } long old_count=active_count; + mark_waiting_and_try_lock(old_count); + + if(old_count&lock_flag_value) + { + bool lock_acquired=false; + void* const sem=get_event(); + + do + { + BOOST_VERIFY(win32::WaitForSingleObject( + sem,::boost::detail::win32::infinite)==0); + clear_waiting_and_try_lock(old_count); + lock_acquired=!(old_count&lock_flag_value); + } + while(!lock_acquired); + } + } + void mark_waiting_and_try_lock(long& old_count) + { for(;;) { long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value); @@ -80,6 +95,33 @@ namespace boost } old_count=current; } + } + + void clear_waiting_and_try_lock(long& old_count) + { + old_count&=~lock_flag_value; + old_count|=event_set_flag_value; + for(;;) + { + long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value; + long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count); + if(current==old_count) + { + break; + } + old_count=current; + } + } + + + bool timed_lock(::boost::system_time const& wait_until) + { + if(try_lock()) + { + return true; + } + long old_count=active_count; + mark_waiting_and_try_lock(old_count); if(old_count&lock_flag_value) { @@ -93,18 +135,7 @@ namespace boost BOOST_INTERLOCKED_DECREMENT(&active_count); return false; } - old_count&=~lock_flag_value; - old_count|=event_set_flag_value; - for(;;) - { - long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value; - long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count); - if(current==old_count) - { - break; - } - old_count=current; - } + clear_waiting_and_try_lock(old_count); lock_acquired=!(old_count&lock_flag_value); } while(!lock_acquired); diff --git a/3rdParty/Boost/src/boost/thread/win32/once.hpp b/3rdParty/Boost/src/boost/thread/win32/once.hpp index a6fcc94..c25f9ab 100644 --- a/3rdParty/Boost/src/boost/thread/win32/once.hpp +++ b/3rdParty/Boost/src/boost/thread/win32/once.hpp @@ -30,81 +30,47 @@ namespace std namespace boost { - typedef long once_flag; - -#define BOOST_ONCE_INIT 0 - - namespace detail + struct once_flag { - struct win32_mutex_scoped_lock - { - void* const mutex_handle; - explicit win32_mutex_scoped_lock(void* mutex_handle_): - mutex_handle(mutex_handle_) - { - BOOST_VERIFY(!win32::WaitForSingleObject(mutex_handle,win32::infinite)); - } - ~win32_mutex_scoped_lock() - { - BOOST_VERIFY(win32::ReleaseMutex(mutex_handle)!=0); - } - private: - void operator=(win32_mutex_scoped_lock&); - }; + long status; + long count; + long throw_count; + void* event_handle; -#ifdef BOOST_NO_ANSI_APIS - template - void int_to_string(I p, wchar_t* buf) + ~once_flag() { - for(unsigned i=0; i < sizeof(I)*2; ++i,++buf) + if(count) { - *buf = L'A' + static_cast((p >> (i*4)) & 0x0f); + BOOST_ASSERT(count==throw_count); } - *buf = 0; - } -#else - template - void int_to_string(I p, char* buf) - { - for(unsigned i=0; i < sizeof(I)*2; ++i,++buf) + + void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event_handle,0); + if(old_event) { - *buf = 'A' + static_cast((p >> (i*4)) & 0x0f); + ::boost::detail::win32::CloseHandle(old_event); } - *buf = 0; } -#endif + }; + +#define BOOST_ONCE_INIT {0,0,0,0} - // create a named mutex. It doesn't really matter what this name is - // as long as it is unique both to this process, and to the address of "flag": - inline void* create_once_mutex(void* flag_address) + namespace detail + { + inline void* allocate_event_handle(void*& handle) { - -#ifdef BOOST_NO_ANSI_APIS - typedef wchar_t char_type; - static const char_type fixed_mutex_name[]=L"{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; -#else - typedef char char_type; - static const char_type fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; -#endif - unsigned const once_mutex_name_fixed_buffer_size=sizeof(fixed_mutex_name)/sizeof(char_type); - unsigned const once_mutex_name_fixed_length=once_mutex_name_fixed_buffer_size-1; - unsigned const once_mutex_name_length=once_mutex_name_fixed_buffer_size+sizeof(void*)*2+sizeof(unsigned long)*2; - char_type mutex_name[once_mutex_name_length]; + void* const new_handle=::boost::detail::win32::create_anonymous_event( + ::boost::detail::win32::manual_reset_event, + ::boost::detail::win32::event_initially_reset); - std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name)); - - BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t)); - detail::int_to_string(reinterpret_cast(flag_address), mutex_name + once_mutex_name_fixed_length); - detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2); - -#ifdef BOOST_NO_ANSI_APIS - return win32::CreateMutexW(0, 0, mutex_name); -#else - return win32::CreateMutexA(0, 0, mutex_name); -#endif + void* event_handle=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&handle, + new_handle,0); + if(event_handle) + { + ::boost::detail::win32::CloseHandle(new_handle); + return event_handle; + } + return new_handle; } - - } @@ -114,18 +80,98 @@ namespace boost // Try for a quick win: if the procedure has already been called // just skip through: long const function_complete_flag_value=0xc15730e2; + long const running_value=0x7f0725e3; + long status; + bool counted=false; + void* event_handle=0; + long throw_count=0; + + while((status=::boost::detail::interlocked_read_acquire(&flag.status)) + !=function_complete_flag_value) + { + status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0); + if(!status) + { + try + { + if(!event_handle) + { + event_handle=::boost::detail::interlocked_read_acquire(&flag.event_handle); + } + if(event_handle) + { + ::boost::detail::win32::ResetEvent(event_handle); + } + f(); + if(!counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + counted=true; + } + BOOST_INTERLOCKED_EXCHANGE(&flag.status,function_complete_flag_value); + if(!event_handle && + (::boost::detail::interlocked_read_acquire(&flag.count)>1)) + { + event_handle=::boost::detail::allocate_event_handle(flag.event_handle); + } + if(event_handle) + { + ::boost::detail::win32::SetEvent(event_handle); + } + throw_count=::boost::detail::interlocked_read_acquire(&flag.throw_count); + break; + } + catch(...) + { + if(counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.throw_count); + } + BOOST_INTERLOCKED_EXCHANGE(&flag.status,0); + if(!event_handle) + { + event_handle=::boost::detail::interlocked_read_acquire(&flag.event_handle); + } + if(event_handle) + { + ::boost::detail::win32::SetEvent(event_handle); + } + throw; + } + } - if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value) + if(!counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + counted=true; + status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==function_complete_flag_value) + { + break; + } + event_handle=::boost::detail::interlocked_read_acquire(&flag.event_handle); + if(!event_handle) + { + event_handle=::boost::detail::allocate_event_handle(flag.event_handle); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject( + event_handle,::boost::detail::win32::infinite)); + } + if(counted || throw_count) { - void* const mutex_handle(::boost::detail::create_once_mutex(&flag)); - BOOST_ASSERT(mutex_handle); - detail::win32::handle_manager const closer(mutex_handle); - detail::win32_mutex_scoped_lock const lock(mutex_handle); - - if(flag!=function_complete_flag_value) + if(!BOOST_INTERLOCKED_EXCHANGE_ADD(&flag.count,(counted?-1:0)-throw_count)) { - f(); - BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value); + if(!event_handle) + { + event_handle=::boost::detail::interlocked_read_acquire(&flag.event_handle); + } + if(event_handle) + { + BOOST_INTERLOCKED_EXCHANGE_POINTER(&flag.event_handle,0); + ::boost::detail::win32::CloseHandle(event_handle); + } } } } diff --git a/3rdParty/Boost/src/boost/thread/win32/thread_heap_alloc.hpp b/3rdParty/Boost/src/boost/thread/win32/thread_heap_alloc.hpp index 9f8186f..b70623a 100644 --- a/3rdParty/Boost/src/boost/thread/win32/thread_heap_alloc.hpp +++ b/3rdParty/Boost/src/boost/thread/win32/thread_heap_alloc.hpp @@ -8,6 +8,7 @@ #include "thread_primitives.hpp" #include #include +#include #if defined( BOOST_USE_WINDOWS_H ) # include @@ -60,7 +61,7 @@ namespace boost void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size); if(!heap_memory) { - throw std::bad_alloc(); + boost::throw_exception(std::bad_alloc()); } return heap_memory; } @@ -86,7 +87,7 @@ namespace boost } } -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES template inline T* heap_new(A1&& a1) { diff --git a/3rdParty/Boost/src/boost/thread/win32/thread_primitives.hpp b/3rdParty/Boost/src/boost/thread/win32/thread_primitives.hpp index 67a1bc3..2359c38 100644 --- a/3rdParty/Boost/src/boost/thread/win32/thread_primitives.hpp +++ b/3rdParty/Boost/src/boost/thread/win32/thread_primitives.hpp @@ -11,6 +11,7 @@ // http://www.boost.org/LICENSE_1_0.txt) #include +#include #include #include #include @@ -177,7 +178,7 @@ namespace boost #endif if(!res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } return res; } @@ -191,7 +192,7 @@ namespace boost #endif if(!res) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } return res; } @@ -204,7 +205,7 @@ namespace boost bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0; if(!success) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } return new_handle; } diff --git a/3rdParty/Boost/src/boost/throw_exception.hpp b/3rdParty/Boost/src/boost/throw_exception.hpp index 656b8de..1d018c5 100644 --- a/3rdParty/Boost/src/boost/throw_exception.hpp +++ b/3rdParty/Boost/src/boost/throw_exception.hpp @@ -36,16 +36,32 @@ #if !defined( BOOST_EXCEPTION_DISABLE ) # include # include -# define BOOST_THROW_EXCEPTION(x) ::boost::throw_exception(::boost::enable_error_info(x) <<\ - ::boost::throw_function(BOOST_CURRENT_FUNCTION) <<\ - ::boost::throw_file(__FILE__) <<\ - ::boost::throw_line(__LINE__)) +# define BOOST_THROW_EXCEPTION(x) ::boost::exception_detail::throw_exception_(x,BOOST_CURRENT_FUNCTION,__FILE__,__LINE__) #else # define BOOST_THROW_EXCEPTION(x) ::boost::throw_exception(x) #endif namespace boost { +#if !defined( BOOST_EXCEPTION_DISABLE ) + namespace + exception_detail + { + template + void + throw_exception_( E const & x, char const * current_function, char const * file, int line ) + { + throw_exception( + set_info( + set_info( + set_info( + enable_error_info(x), + throw_function(current_function)), + throw_file(file)), + throw_line(line))); + } + } +#endif #ifdef BOOST_NO_EXCEPTIONS diff --git a/3rdParty/Boost/src/boost/timer.hpp b/3rdParty/Boost/src/boost/timer.hpp deleted file mode 100644 index 1e3571e..0000000 --- a/3rdParty/Boost/src/boost/timer.hpp +++ /dev/null @@ -1,72 +0,0 @@ -// boost timer.hpp header file ---------------------------------------------// - -// Copyright Beman Dawes 1994-99. 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) - -// See http://www.boost.org/libs/timer for documentation. - -// Revision History -// 01 Apr 01 Modified to use new header. (JMaddock) -// 12 Jan 01 Change to inline implementation to allow use without library -// builds. See docs for more rationale. (Beman Dawes) -// 25 Sep 99 elapsed_max() and elapsed_min() added (John Maddock) -// 16 Jul 99 Second beta -// 6 Jul 99 Initial boost version - -#ifndef BOOST_TIMER_HPP -#define BOOST_TIMER_HPP - -#include -#include -#include - -# ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::clock_t; using ::clock; } -# endif - - -namespace boost { - -// timer -------------------------------------------------------------------// - -// A timer object measures elapsed time. - -// It is recommended that implementations measure wall clock rather than CPU -// time since the intended use is performance measurement on systems where -// total elapsed time is more important than just process or CPU time. - -// Warnings: The maximum measurable elapsed time may well be only 596.5+ hours -// due to implementation limitations. The accuracy of timings depends on the -// accuracy of timing information provided by the underlying platform, and -// this varies a great deal from platform to platform. - -class timer -{ - public: - timer() { _start_time = std::clock(); } // postcondition: elapsed()==0 -// timer( const timer& src ); // post: elapsed()==src.elapsed() -// ~timer(){} -// timer& operator=( const timer& src ); // post: elapsed()==src.elapsed() - void restart() { _start_time = std::clock(); } // post: elapsed()==0 - double elapsed() const // return elapsed time in seconds - { return double(std::clock() - _start_time) / CLOCKS_PER_SEC; } - - double elapsed_max() const // return estimated maximum value for elapsed() - // Portability warning: elapsed_max() may return too high a value on systems - // where std::clock_t overflows or resets at surprising values. - { - return (double((std::numeric_limits::max)()) - - double(_start_time)) / double(CLOCKS_PER_SEC); - } - - double elapsed_min() const // return minimum value for elapsed() - { return double(1)/double(CLOCKS_PER_SEC); } - - private: - std::clock_t _start_time; -}; // timer - -} // namespace boost - -#endif // BOOST_TIMER_HPP diff --git a/3rdParty/Boost/src/boost/type_traits/cv_traits.hpp b/3rdParty/Boost/src/boost/type_traits/cv_traits.hpp deleted file mode 100644 index 5bd6c4f..0000000 --- a/3rdParty/Boost/src/boost/type_traits/cv_traits.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// (C) Copyright Dave Abrahams, Steve Cleary, Beman Dawes, Howard -// Hinnant & John Maddock 2000. -// Use, modification and distribution are subject to 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). -// -// See http://www.boost.org/libs/type_traits for most recent version including documentation. -// -// defines traits classes for cv-qualified types: -// is_const, is_volatile, remove_const, remove_volatile, remove_cv. - -#ifndef BOOST_TT_CV_TRAITS_HPP_INCLUDED -#define BOOST_TT_CV_TRAITS_HPP_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include - -#endif // BOOST_TT_CV_TRAITS_HPP_INCLUDED diff --git a/3rdParty/Boost/src/boost/type_traits/is_empty.hpp b/3rdParty/Boost/src/boost/type_traits/is_empty.hpp index c8eb791..45c4e9e 100644 --- a/3rdParty/Boost/src/boost/type_traits/is_empty.hpp +++ b/3rdParty/Boost/src/boost/type_traits/is_empty.hpp @@ -36,6 +36,12 @@ namespace boost { namespace detail { #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4624) // destructor could not be generated +#endif + template struct empty_helper_t1 : public T { @@ -47,6 +53,10 @@ private: empty_helper_t1& operator=(const empty_helper_t1&); }; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + struct empty_helper_t2 { int i[256]; }; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x600) diff --git a/3rdParty/Boost/src/boost/units/detail/utility.hpp b/3rdParty/Boost/src/boost/units/detail/utility.hpp new file mode 100644 index 0000000..da46b45 --- /dev/null +++ b/3rdParty/Boost/src/boost/units/detail/utility.hpp @@ -0,0 +1,104 @@ +// Boost.Units - A C++ library for zero-overhead dimensional analysis and +// unit/quantity manipulation and conversion +// +// Copyright (C) 2003-2008 Matthias Christian Schabel +// Copyright (C) 2008 Steven Watanabe +// +// 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_UNITS_UTILITY_HPP +#define BOOST_UNITS_UTILITY_HPP + +#include +#include +#include + +#if defined(__GLIBCXX__) || defined(__GLIBCPP__) +#define BOOST_UNITS_USE_DEMANGLING +#include +#endif // __GNUC__ + +#ifdef BOOST_UNITS_USE_DEMANGLING + +#include + +namespace boost { + +namespace units { + +namespace detail { + +inline +std::string +demangle(const char* name) +{ + // need to demangle C++ symbols + char* realname; + std::size_t len; + int stat; + + realname = abi::__cxa_demangle(name,NULL,&len,&stat); + + if (realname != NULL) + { + std::string out(realname); + + std::free(realname); + + boost::replace_all(out,"boost::units::",""); + + return out; + } + + return std::string("demangle :: error - unable to demangle specified symbol"); +} + +} // namespace detail + +template +std::string simplify_typename(const L& /*source*/) +{ + const std::string demangled = detail::demangle(typeid(L).name()); + + return demangled; +} + +} // namespace units + +} // namespace boost + +#else // BOOST_UNITS_USE_DEMANGLING + +namespace boost { + +namespace units { + +namespace detail { + +inline +std::string +demangle(const char* name) +{ + return name; +} + +} // namespace detail + +template +std::string simplify_typename(const L& /*source*/) +{ + return std::string(typeid(L).name()); +} + +} // namespace units + +} // namespace boost + +// To get system-specific predefined macros: +// gcc -arch ppc -dM -E - < /dev/null | sort + +#endif // BOOST_UNITS_USE_DEMANGLING + +#endif // BOOST_UNITS_UTILITY_HPP diff --git a/3rdParty/Boost/src/boost/utility/value_init.hpp b/3rdParty/Boost/src/boost/utility/value_init.hpp deleted file mode 100644 index 5aefac9..0000000 --- a/3rdParty/Boost/src/boost/utility/value_init.hpp +++ /dev/null @@ -1,151 +0,0 @@ -// (C) Copyright 2002-2008, Fernando Luis Cacciola Carballal. -// -// 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) -// -// 21 Ago 2002 (Created) Fernando Cacciola -// 24 Dec 2007 (Refactored and worked around various compiler bugs) Fernando Cacciola, Niels Dekker -// 23 May 2008 (Fixed operator= const issue, added initialized_value) Niels Dekker, Fernando Cacciola -// 21 Ago 2008 (Added swap) Niels Dekker, Fernando Cacciola -// 20 Feb 2009 (Fixed logical const-ness issues) Niels Dekker, Fernando Cacciola -// -#ifndef BOOST_UTILITY_VALUE_INIT_21AGO2002_HPP -#define BOOST_UTILITY_VALUE_INIT_21AGO2002_HPP - -// Note: The implementation of boost::value_initialized had to deal with the -// fact that various compilers haven't fully implemented value-initialization. -// The constructor of boost::value_initialized works around these compiler -// issues, by clearing the bytes of T, before constructing the T object it -// contains. More details on these issues are at libs/utility/value_init.htm - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { - -template -class value_initialized -{ - private : - struct wrapper - { -#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x592)) - typename -#endif - remove_const::type data; - }; - - mutable -#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x592)) - typename -#endif - aligned_storage::value>::type x; - - wrapper * wrapper_address() const - { - return static_cast( static_cast(&x)); - } - - public : - - value_initialized() - { - std::memset(&x, 0, sizeof(x)); -#ifdef BOOST_MSVC -#pragma warning(push) -#if _MSC_VER >= 1310 -// When using MSVC 7.1 or higher, the following placement new expression may trigger warning C4345: -// "behavior change: an object of POD type constructed with an initializer of the form () -// will be default-initialized". It is safe to ignore this warning when using value_initialized. -#pragma warning(disable: 4345) -#endif -#endif - new (wrapper_address()) wrapper(); -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - } - - value_initialized(value_initialized const & arg) - { - new (wrapper_address()) wrapper( static_cast(*(arg.wrapper_address()))); - } - - value_initialized & operator=(value_initialized const & arg) - { - // Assignment is only allowed when T is non-const. - BOOST_STATIC_ASSERT( ! is_const::value ); - *wrapper_address() = static_cast(*(arg.wrapper_address())); - return *this; - } - - ~value_initialized() - { - wrapper_address()->wrapper::~wrapper(); - } - - T const & data() const - { - return wrapper_address()->data; - } - - T& data() - { - return wrapper_address()->data; - } - - void swap(value_initialized & arg) - { - ::boost::swap( this->data(), arg.data() ); - } - - operator T const &() const { return this->data(); } - - operator T&() { return this->data(); } - -} ; - - - -template -T const& get ( value_initialized const& x ) -{ - return x.data() ; -} -template -T& get ( value_initialized& x ) -{ - return x.data() ; -} - -template -void swap ( value_initialized & lhs, value_initialized & rhs ) -{ - lhs.swap(rhs) ; -} - - -class initialized_value_t -{ - public : - - template operator T() const - { - return get( value_initialized() ); - } -}; - -initialized_value_t const initialized_value = {} ; - - -} // namespace boost - - -#endif diff --git a/3rdParty/Boost/src/boost/version.hpp b/3rdParty/Boost/src/boost/version.hpp index e95ff85..82a1daf 100644 --- a/3rdParty/Boost/src/boost/version.hpp +++ b/3rdParty/Boost/src/boost/version.hpp @@ -19,7 +19,7 @@ // BOOST_VERSION / 100 % 1000 is the minor version // BOOST_VERSION / 100000 is the major version -#define BOOST_VERSION 104200 +#define BOOST_VERSION 104300 // // BOOST_LIB_VERSION must be defined to be the same as BOOST_VERSION @@ -27,7 +27,7 @@ // number, y is the minor version number, and z is the patch level if not 0. // This is used by to select which library version to link to. -#define BOOST_LIB_VERSION "1_42" +#define BOOST_LIB_VERSION "1_43" #endif diff --git a/3rdParty/Boost/src/libs/thread/src/pthread/thread.cpp b/3rdParty/Boost/src/libs/thread/src/pthread/thread.cpp index 3a5ce7c..1c13a9a 100644 --- a/3rdParty/Boost/src/libs/thread/src/pthread/thread.cpp +++ b/3rdParty/Boost/src/libs/thread/src/pthread/thread.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef __linux__ #include #elif defined(__APPLE__) || defined(__FreeBSD__) @@ -186,7 +187,7 @@ namespace boost if (res != 0) { thread_info->self.reset(); - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } } diff --git a/3rdParty/Boost/src/libs/thread/src/pthread/timeconv.inl b/3rdParty/Boost/src/libs/thread/src/pthread/timeconv.inl index 5ec3b17..b75a135 100644 --- a/3rdParty/Boost/src/libs/thread/src/pthread/timeconv.inl +++ b/3rdParty/Boost/src/libs/thread/src/pthread/timeconv.inl @@ -1,11 +1,14 @@ // Copyright (C) 2001-2003 // William E. Kempf +// Copyright (C) 2009 Anthony Williams // // 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) // boostinspect:nounnamed +#include + namespace { const int MILLISECONDS_PER_SECOND = 1000; const int NANOSECONDS_PER_SECOND = 1000000000; @@ -18,7 +21,7 @@ inline void to_time(int milliseconds, boost::xtime& xt) { int res = 0; res = boost::xtime_get(&xt, boost::TIME_UTC); - assert(res == boost::TIME_UTC); + BOOST_ASSERT(res == boost::TIME_UTC); xt.sec += (milliseconds / MILLISECONDS_PER_SECOND); xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * @@ -55,7 +58,7 @@ inline void to_timespec_duration(const boost::xtime& xt, timespec& ts) boost::xtime cur; int res = 0; res = boost::xtime_get(&cur, boost::TIME_UTC); - assert(res == boost::TIME_UTC); + BOOST_ASSERT(res == boost::TIME_UTC); if (boost::xtime_cmp(xt, cur) <= 0) { @@ -86,7 +89,7 @@ inline void to_duration(boost::xtime xt, int& milliseconds) boost::xtime cur; int res = 0; res = boost::xtime_get(&cur, boost::TIME_UTC); - assert(res == boost::TIME_UTC); + BOOST_ASSERT(res == boost::TIME_UTC); if (boost::xtime_cmp(xt, cur) <= 0) milliseconds = 0; @@ -108,7 +111,7 @@ inline void to_microduration(boost::xtime xt, int& microseconds) boost::xtime cur; int res = 0; res = boost::xtime_get(&cur, boost::TIME_UTC); - assert(res == boost::TIME_UTC); + BOOST_ASSERT(res == boost::TIME_UTC); if (boost::xtime_cmp(xt, cur) <= 0) microseconds = 0; diff --git a/3rdParty/Boost/src/libs/thread/src/win32/thread.cpp b/3rdParty/Boost/src/libs/thread/src/win32/thread.cpp index 46af860..b85e650 100644 --- a/3rdParty/Boost/src/libs/thread/src/win32/thread.cpp +++ b/3rdParty/Boost/src/libs/thread/src/win32/thread.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -188,7 +189,7 @@ namespace boost uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id); if(!new_thread) { - throw thread_resource_error(); + boost::throw_exception(thread_resource_error()); } intrusive_ptr_add_ref(thread_info.get()); thread_info->thread_handle=(detail::win32::handle)(new_thread); diff --git a/3rdParty/Boost/update.sh b/3rdParty/Boost/update.sh index 1ef3aa5..bb5715c 100755 --- a/3rdParty/Boost/update.sh +++ b/3rdParty/Boost/update.sh @@ -5,6 +5,10 @@ fi TARGET_DIR=src +if [ ! -d "$TARGET_DIR" ]; then + mkdir $TARGET_DIR +fi + ./bcp --boost="$1" \ tools/bcp \ bind.hpp \ @@ -20,6 +24,7 @@ TARGET_DIR=src program_options.hpp \ thread.hpp \ asio.hpp \ + uuid.hpp \ regex.hpp \ $TARGET_DIR @@ -30,4 +35,4 @@ LIBS="date_time regex system thread signals filesystem program_options" for lib in $LIBS; do rm -rf $TARGET_DIR/libs/$lib/build $TARGET_DIR/libs/$lib/*.doc $TARGET_DIR/libs/$lib/src/*.doc $TARGET_DIR/libs/$lib/src/CMakeLists.txt $TARGET_DIR/libs/$lib/test done -rm -rf $TARGET_DIR/tools/bcp/*.html $TARGET_DIR/libs/test $TARGET_DIR/doc $TARGET_DIR/boost.png $TARGET_DIR/boost/test $TARGET_DIR/tools/bcp/Jamfile.v2 $TARGET_DIR/tools/bcp/doc $TARGET_DIR/tools/bcp/test +rm -rf $TARGET_DIR/tools/bcp/*.html $TARGET_DIR/libs/test $TARGET_DIR/doc $TARGET_DIR/boost.png $TARGET_DIR/boost/test $TARGET_DIR/tools/bcp/Jamfile.v2 $TARGET_DIR/tools/bcp/doc $TARGET_DIR/tools/bcp/test $TARGET_DIR/Jamroot diff --git a/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml b/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml index f980fce..e0a63ae 100644 --- a/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml +++ b/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml @@ -19,4 +19,31 @@ + + + Tutorial: Writing an Echo Bot + + + In this chapter, we build a simple echo bot, illustrating how + to use and extend Swiften for your own purposes. + + + + Setting up the build environment + + + + + + Connecting to the network + + + + + + T + + + + -- cgit v0.10.2-6-g49f6