diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2018-08-06 10:35:22 +0200 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2018-08-06 10:35:22 +0200 |
commit | e95946831f8ef53d29590735a2df661385edb008 (patch) | |
tree | e179b6beed4a5a0dd108f078a529ae9f8107ed8e /lib/asio/detail | |
parent | 8bc01ff60629d9096f4b57cfb574ace672a6ef0e (diff) | |
download | dabmod-e95946831f8ef53d29590735a2df661385edb008.tar.gz dabmod-e95946831f8ef53d29590735a2df661385edb008.tar.bz2 dabmod-e95946831f8ef53d29590735a2df661385edb008.zip |
Replace boost by the standalone asio library
Diffstat (limited to 'lib/asio/detail')
246 files changed, 43413 insertions, 0 deletions
diff --git a/lib/asio/detail/array.hpp b/lib/asio/detail/array.hpp new file mode 100644 index 0000000..ba42974 --- /dev/null +++ b/lib/asio/detail/array.hpp @@ -0,0 +1,38 @@ +// +// detail/array.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_ARRAY_HPP +#define ASIO_DETAIL_ARRAY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_ARRAY) +# include <array> +#else // defined(ASIO_HAS_STD_ARRAY) +# include <boost/array.hpp> +#endif // defined(ASIO_HAS_STD_ARRAY) + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_ARRAY) +using std::array; +#else // defined(ASIO_HAS_STD_ARRAY) +using boost::array; +#endif // defined(ASIO_HAS_STD_ARRAY) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_ARRAY_HPP diff --git a/lib/asio/detail/array_fwd.hpp b/lib/asio/detail/array_fwd.hpp new file mode 100644 index 0000000..4161db0 --- /dev/null +++ b/lib/asio/detail/array_fwd.hpp @@ -0,0 +1,34 @@ +// +// detail/array_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_ARRAY_FWD_HPP +#define ASIO_DETAIL_ARRAY_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +namespace boost { + +template<class T, std::size_t N> +class array; + +} // namespace boost + +// Standard library components can't be forward declared, so we'll have to +// include the array header. Fortunately, it's fairly lightweight and doesn't +// add significantly to the compile time. +#if defined(ASIO_HAS_STD_ARRAY) +# include <array> +#endif // defined(ASIO_HAS_STD_ARRAY) + +#endif // ASIO_DETAIL_ARRAY_FWD_HPP diff --git a/lib/asio/detail/assert.hpp b/lib/asio/detail/assert.hpp new file mode 100644 index 0000000..a952a44 --- /dev/null +++ b/lib/asio/detail/assert.hpp @@ -0,0 +1,32 @@ +// +// detail/assert.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_ASSERT_HPP +#define ASIO_DETAIL_ASSERT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_ASSERT) +# include <boost/assert.hpp> +#else // defined(ASIO_HAS_BOOST_ASSERT) +# include <cassert> +#endif // defined(ASIO_HAS_BOOST_ASSERT) + +#if defined(ASIO_HAS_BOOST_ASSERT) +# define ASIO_ASSERT(expr) BOOST_ASSERT(expr) +#else // defined(ASIO_HAS_BOOST_ASSERT) +# define ASIO_ASSERT(expr) assert(expr) +#endif // defined(ASIO_HAS_BOOST_ASSERT) + +#endif // ASIO_DETAIL_ASSERT_HPP diff --git a/lib/asio/detail/atomic_count.hpp b/lib/asio/detail/atomic_count.hpp new file mode 100644 index 0000000..2bf75a5 --- /dev/null +++ b/lib/asio/detail/atomic_count.hpp @@ -0,0 +1,45 @@ +// +// detail/atomic_count.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_ATOMIC_COUNT_HPP +#define ASIO_DETAIL_ATOMIC_COUNT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +// Nothing to include. +#elif defined(ASIO_HAS_STD_ATOMIC) +# include <atomic> +#else // defined(ASIO_HAS_STD_ATOMIC) +# include <boost/detail/atomic_count.hpp> +#endif // defined(ASIO_HAS_STD_ATOMIC) + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) +typedef long atomic_count; +inline void increment(atomic_count& a, long b) { a += b; } +#elif defined(ASIO_HAS_STD_ATOMIC) +typedef std::atomic<long> atomic_count; +inline void increment(atomic_count& a, long b) { a += b; } +#else // defined(ASIO_HAS_STD_ATOMIC) +typedef boost::detail::atomic_count atomic_count; +inline void increment(atomic_count& a, long b) { while (b > 0) ++a, --b; } +#endif // defined(ASIO_HAS_STD_ATOMIC) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_ATOMIC_COUNT_HPP diff --git a/lib/asio/detail/base_from_completion_cond.hpp b/lib/asio/detail/base_from_completion_cond.hpp new file mode 100644 index 0000000..73b4a95 --- /dev/null +++ b/lib/asio/detail/base_from_completion_cond.hpp @@ -0,0 +1,68 @@ +// +// detail/base_from_completion_cond.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP +#define ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/completion_condition.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename CompletionCondition> +class base_from_completion_cond +{ +protected: + explicit base_from_completion_cond(CompletionCondition completion_condition) + : completion_condition_(completion_condition) + { + } + + std::size_t check_for_completion( + const asio::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<transfer_all_t> +{ +protected: + explicit base_from_completion_cond(transfer_all_t) + { + } + + static std::size_t check_for_completion( + const asio::error_code& ec, + std::size_t total_transferred) + { + return transfer_all_t()(ec, total_transferred); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP diff --git a/lib/asio/detail/bind_handler.hpp b/lib/asio/detail/bind_handler.hpp new file mode 100644 index 0000000..0f4f066 --- /dev/null +++ b/lib/asio/detail/bind_handler.hpp @@ -0,0 +1,816 @@ +// +// detail/bind_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_BIND_HANDLER_HPP +#define ASIO_DETAIL_BIND_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler, typename Arg1> +class binder1 +{ +public: + template <typename T> + binder1(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1) + : handler_(ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1) + { + } + + binder1(Handler& handler, const Arg1& arg1) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1) + { + } + +#if defined(ASIO_HAS_MOVE) + binder1(const binder1& other) + : handler_(other.handler_), + arg1_(other.arg1_) + { + } + + binder1(binder1&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast<const Arg1&>(arg1_)); + } + + void operator()() const + { + handler_(arg1_); + } + +//private: + Handler handler_; + Arg1 arg1_; +}; + +template <typename Handler, typename Arg1> +inline void* asio_handler_allocate(std::size_t size, + binder1<Handler, Arg1>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler, typename Arg1> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder1<Handler, Arg1>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler, typename Arg1> +inline bool asio_handler_is_continuation( + binder1<Handler, Arg1>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1> +inline void asio_handler_invoke(Function& function, + binder1<Handler, Arg1>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1> +inline void asio_handler_invoke(const Function& function, + binder1<Handler, Arg1>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Handler, typename Arg1> +inline binder1<typename decay<Handler>::type, Arg1> bind_handler( + ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1) +{ + return binder1<typename decay<Handler>::type, Arg1>(0, + ASIO_MOVE_CAST(Handler)(handler), arg1); +} + +template <typename Handler, typename Arg1, typename Arg2> +class binder2 +{ +public: + template <typename T> + binder2(int, ASIO_MOVE_ARG(T) handler, + const Arg1& arg1, const Arg2& arg2) + : handler_(ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2) + { + } + + binder2(Handler& handler, const Arg1& arg1, const Arg2& arg2) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2) + { + } + +#if defined(ASIO_HAS_MOVE) + binder2(const binder2& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_) + { + } + + binder2(binder2&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_)); + } + + void operator()() const + { + handler_(arg1_, arg2_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; +}; + +template <typename Handler, typename Arg1, typename Arg2> +inline void* asio_handler_allocate(std::size_t size, + binder2<Handler, Arg1, Arg2>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder2<Handler, Arg1, Arg2>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2> +inline bool asio_handler_is_continuation( + binder2<Handler, Arg1, Arg2>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1, typename Arg2> +inline void asio_handler_invoke(Function& function, + binder2<Handler, Arg1, Arg2>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1, typename Arg2> +inline void asio_handler_invoke(const Function& function, + binder2<Handler, Arg1, Arg2>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2> +inline binder2<typename decay<Handler>::type, Arg1, Arg2> bind_handler( + ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2) +{ + return binder2<typename decay<Handler>::type, Arg1, Arg2>(0, + ASIO_MOVE_CAST(Handler)(handler), arg1, arg2); +} + +template <typename Handler, typename Arg1, typename Arg2, typename Arg3> +class binder3 +{ +public: + template <typename T> + binder3(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3) + : handler_(ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3) + { + } + + binder3(Handler& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3) + { + } + +#if defined(ASIO_HAS_MOVE) + binder3(const binder3& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_) + { + } + + binder3(binder3&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; +}; + +template <typename Handler, typename Arg1, typename Arg2, typename Arg3> +inline void* asio_handler_allocate(std::size_t size, + binder3<Handler, Arg1, Arg2, Arg3>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2, typename Arg3> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder3<Handler, Arg1, Arg2, Arg3>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2, typename Arg3> +inline bool asio_handler_is_continuation( + binder3<Handler, Arg1, Arg2, Arg3>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler, + typename Arg1, typename Arg2, typename Arg3> +inline void asio_handler_invoke(Function& function, + binder3<Handler, Arg1, Arg2, Arg3>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Function, typename Handler, + typename Arg1, typename Arg2, typename Arg3> +inline void asio_handler_invoke(const Function& function, + binder3<Handler, Arg1, Arg2, Arg3>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2, typename Arg3> +inline binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3> bind_handler( + ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3) +{ + return binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3>(0, + ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3); +} + +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +class binder4 +{ +public: + template <typename T> + binder4(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) + : handler_(ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4) + { + } + + binder4(Handler& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4) + { + } + +#if defined(ASIO_HAS_MOVE) + binder4(const binder4& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_), + arg4_(other.arg4_) + { + } + + binder4(binder4&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)), + arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_), + static_cast<const Arg4&>(arg4_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_, arg4_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; + Arg4 arg4_; +}; + +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +inline void* asio_handler_allocate(std::size_t size, + binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +inline bool asio_handler_is_continuation( + binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +inline void asio_handler_invoke(Function& function, + binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +inline void asio_handler_invoke(const Function& function, + binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +inline binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4> +bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) +{ + return binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>(0, + ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4); +} + +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +class binder5 +{ +public: + template <typename T> + binder5(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) + : handler_(ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4), + arg5_(arg5) + { + } + + binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4), + arg5_(arg5) + { + } + +#if defined(ASIO_HAS_MOVE) + binder5(const binder5& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_), + arg4_(other.arg4_), + arg5_(other.arg5_) + { + } + + binder5(binder5&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)), + arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_)), + arg5_(ASIO_MOVE_CAST(Arg5)(other.arg5_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_), + static_cast<const Arg4&>(arg4_), static_cast<const Arg5&>(arg5_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_, arg4_, arg5_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; + Arg4 arg4_; + Arg5 arg5_; +}; + +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +inline void* asio_handler_allocate(std::size_t size, + binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +inline bool asio_handler_is_continuation( + binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4, typename Arg5> +inline void asio_handler_invoke(Function& function, + binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4, typename Arg5> +inline void asio_handler_invoke(const Function& function, + binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +inline binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5> +bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) +{ + return binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>(0, + ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4, arg5); +} + +#if defined(ASIO_HAS_MOVE) + +template <typename Handler, typename Arg1> +class move_binder1 +{ +public: + move_binder1(int, ASIO_MOVE_ARG(Handler) handler, + ASIO_MOVE_ARG(Arg1) arg1) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(ASIO_MOVE_CAST(Arg1)(arg1)) + { + } + + move_binder1(move_binder1&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)) + { + } + + void operator()() + { + handler_(ASIO_MOVE_CAST(Arg1)(arg1_)); + } + +//private: + Handler handler_; + Arg1 arg1_; +}; + +template <typename Handler, typename Arg1> +inline void* asio_handler_allocate(std::size_t size, + move_binder1<Handler, Arg1>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler, typename Arg1> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + move_binder1<Handler, Arg1>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler, typename Arg1> +inline bool asio_handler_is_continuation( + move_binder1<Handler, Arg1>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1> +inline void asio_handler_invoke(ASIO_MOVE_ARG(Function) function, + move_binder1<Handler, Arg1>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2> +class move_binder2 +{ +public: + move_binder2(int, ASIO_MOVE_ARG(Handler) handler, + const Arg1& arg1, ASIO_MOVE_ARG(Arg2) arg2) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(ASIO_MOVE_CAST(Arg2)(arg2)) + { + } + + move_binder2(move_binder2&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)) + { + } + + void operator()() + { + handler_(static_cast<const Arg1&>(arg1_), + ASIO_MOVE_CAST(Arg2)(arg2_)); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; +}; + +template <typename Handler, typename Arg1, typename Arg2> +inline void* asio_handler_allocate(std::size_t size, + move_binder2<Handler, Arg1, Arg2>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + move_binder2<Handler, Arg1, Arg2>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2> +inline bool asio_handler_is_continuation( + move_binder2<Handler, Arg1, Arg2>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1, typename Arg2> +inline void asio_handler_invoke(ASIO_MOVE_ARG(Function) function, + move_binder2<Handler, Arg1, Arg2>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +} + +#endif // defined(ASIO_HAS_MOVE) + +} // namespace detail + +template <typename Handler, typename Arg1, typename Allocator> +struct associated_allocator<detail::binder1<Handler, Arg1>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const detail::binder1<Handler, Arg1>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Handler, typename Arg1, typename Arg2, typename Allocator> +struct associated_allocator<detail::binder2<Handler, Arg1, Arg2>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const detail::binder2<Handler, Arg1, Arg2>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Handler, typename Arg1, typename Executor> +struct associated_executor<detail::binder1<Handler, Arg1>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const detail::binder1<Handler, Arg1>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +template <typename Handler, typename Arg1, typename Arg2, typename Executor> +struct associated_executor<detail::binder2<Handler, Arg1, Arg2>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const detail::binder2<Handler, Arg1, Arg2>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +#if defined(ASIO_HAS_MOVE) + +template <typename Handler, typename Arg1, typename Allocator> +struct associated_allocator<detail::move_binder1<Handler, Arg1>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const detail::move_binder1<Handler, Arg1>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Handler, typename Arg1, typename Arg2, typename Allocator> +struct associated_allocator< + detail::move_binder2<Handler, Arg1, Arg2>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Handler, typename Arg1, typename Executor> +struct associated_executor<detail::move_binder1<Handler, Arg1>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const detail::move_binder1<Handler, Arg1>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +template <typename Handler, typename Arg1, typename Arg2, typename Executor> +struct associated_executor<detail::move_binder2<Handler, Arg1, Arg2>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +#endif // defined(ASIO_HAS_MOVE) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BIND_HANDLER_HPP diff --git a/lib/asio/detail/buffer_resize_guard.hpp b/lib/asio/detail/buffer_resize_guard.hpp new file mode 100644 index 0000000..58ebc4c --- /dev/null +++ b/lib/asio/detail/buffer_resize_guard.hpp @@ -0,0 +1,66 @@ +// +// detail/buffer_resize_guard.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP +#define ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/limits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper class to manage buffer resizing in an exception safe way. +template <typename Buffer> +class buffer_resize_guard +{ +public: + // Constructor. + buffer_resize_guard(Buffer& buffer) + : buffer_(buffer), + old_size_(buffer.size()) + { + } + + // Destructor rolls back the buffer resize unless commit was called. + ~buffer_resize_guard() + { + if (old_size_ != (std::numeric_limits<size_t>::max)()) + { + buffer_.resize(old_size_); + } + } + + // Commit the resize transaction. + void commit() + { + old_size_ = (std::numeric_limits<size_t>::max)(); + } + +private: + // The buffer being managed. + Buffer& buffer_; + + // The size of the buffer at the time the guard was constructed. + size_t old_size_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP diff --git a/lib/asio/detail/buffer_sequence_adapter.hpp b/lib/asio/detail/buffer_sequence_adapter.hpp new file mode 100644 index 0000000..92a8e3d --- /dev/null +++ b/lib/asio/detail/buffer_sequence_adapter.hpp @@ -0,0 +1,544 @@ +// +// detail/buffer_sequence_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP +#define ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/buffer.hpp" +#include "asio/detail/array_fwd.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class buffer_sequence_adapter_base +{ +#if defined(ASIO_WINDOWS_RUNTIME) +public: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 1 }; + +protected: + typedef Windows::Storage::Streams::IBuffer^ native_buffer_type; + + ASIO_DECL static void init_native_buffer( + native_buffer_type& buf, + const asio::mutable_buffer& buffer); + + ASIO_DECL static void init_native_buffer( + native_buffer_type& buf, + const asio::const_buffer& buffer); +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) +public: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + +protected: + typedef WSABUF native_buffer_type; + + static void init_native_buffer(WSABUF& buf, + const asio::mutable_buffer& buffer) + { + buf.buf = static_cast<char*>(buffer.data()); + buf.len = static_cast<ULONG>(buffer.size()); + } + + static void init_native_buffer(WSABUF& buf, + const asio::const_buffer& buffer) + { + buf.buf = const_cast<char*>(static_cast<const char*>(buffer.data())); + buf.len = static_cast<ULONG>(buffer.size()); + } +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +public: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + +protected: + typedef iovec native_buffer_type; + + static void init_iov_base(void*& base, void* addr) + { + base = addr; + } + + template <typename T> + static void init_iov_base(T& base, void* addr) + { + base = static_cast<T>(addr); + } + + static void init_native_buffer(iovec& iov, + const asio::mutable_buffer& buffer) + { + init_iov_base(iov.iov_base, buffer.data()); + iov.iov_len = buffer.size(); + } + + static void init_native_buffer(iovec& iov, + const asio::const_buffer& buffer) + { + init_iov_base(iov.iov_base, const_cast<void*>(buffer.data())); + iov.iov_len = buffer.size(); + } +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +}; + +// Helper class to translate buffers into the native buffer representation. +template <typename Buffer, typename Buffers> +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter(const Buffers& buffer_sequence) + : count_(0), total_buffer_size_(0) + { + buffer_sequence_adapter::init( + asio::buffer_sequence_begin(buffer_sequence), + asio::buffer_sequence_end(buffer_sequence)); + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return count_; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const Buffers& buffer_sequence) + { + return buffer_sequence_adapter::all_empty( + asio::buffer_sequence_begin(buffer_sequence), + asio::buffer_sequence_end(buffer_sequence)); + } + + static void validate(const Buffers& buffer_sequence) + { + buffer_sequence_adapter::validate( + asio::buffer_sequence_begin(buffer_sequence), + asio::buffer_sequence_end(buffer_sequence)); + } + + static Buffer first(const Buffers& buffer_sequence) + { + return buffer_sequence_adapter::first( + asio::buffer_sequence_begin(buffer_sequence), + asio::buffer_sequence_end(buffer_sequence)); + } + +private: + template <typename Iterator> + void init(Iterator begin, Iterator end) + { + Iterator iter = begin; + for (; iter != end && count_ < max_buffers; ++iter, ++count_) + { + Buffer buffer(*iter); + init_native_buffer(buffers_[count_], buffer); + total_buffer_size_ += buffer.size(); + } + } + + template <typename Iterator> + static bool all_empty(Iterator begin, Iterator end) + { + Iterator iter = begin; + std::size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + if (Buffer(*iter).size() > 0) + return false; + return true; + } + + template <typename Iterator> + static void validate(Iterator begin, Iterator end) + { + Iterator iter = begin; + for (; iter != end; ++iter) + { + Buffer buffer(*iter); + buffer.data(); + } + } + + template <typename Iterator> + static Buffer first(Iterator begin, Iterator end) + { + Iterator iter = begin; + for (; iter != end; ++iter) + { + Buffer buffer(*iter); + if (buffer.size() != 0) + return buffer; + } + return Buffer(); + } + + native_buffer_type buffers_[max_buffers]; + std::size_t count_; + std::size_t total_buffer_size_; +}; + +template <typename Buffer> +class buffer_sequence_adapter<Buffer, asio::mutable_buffer> + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const asio::mutable_buffer& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const asio::mutable_buffer& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const asio::mutable_buffer& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const asio::mutable_buffer& buffer_sequence) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +template <typename Buffer> +class buffer_sequence_adapter<Buffer, asio::const_buffer> + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const asio::const_buffer& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const asio::const_buffer& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const asio::const_buffer& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const asio::const_buffer& buffer_sequence) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +#if !defined(ASIO_NO_DEPRECATED) + +template <typename Buffer> +class buffer_sequence_adapter<Buffer, asio::mutable_buffers_1> + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const asio::mutable_buffers_1& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const asio::mutable_buffers_1& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const asio::mutable_buffers_1& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const asio::mutable_buffers_1& buffer_sequence) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +template <typename Buffer> +class buffer_sequence_adapter<Buffer, asio::const_buffers_1> + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const asio::const_buffers_1& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const asio::const_buffers_1& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const asio::const_buffers_1& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const asio::const_buffers_1& buffer_sequence) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +#endif // !defined(ASIO_NO_DEPRECATED) + +template <typename Buffer, typename Elem> +class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> > + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::array<Elem, 2>& buffer_sequence) + { + init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); + init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); + total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return 2; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::array<Elem, 2>& buffer_sequence) + { + return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; + } + + static void validate(const boost::array<Elem, 2>& buffer_sequence) + { + buffer_sequence[0].data(); + buffer_sequence[1].data(); + } + + static Buffer first(const boost::array<Elem, 2>& buffer_sequence) + { + return Buffer(buffer_sequence[0].size() != 0 + ? buffer_sequence[0] : buffer_sequence[1]); + } + +private: + native_buffer_type buffers_[2]; + std::size_t total_buffer_size_; +}; + +#if defined(ASIO_HAS_STD_ARRAY) + +template <typename Buffer, typename Elem> +class buffer_sequence_adapter<Buffer, std::array<Elem, 2> > + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const std::array<Elem, 2>& buffer_sequence) + { + init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); + init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); + total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return 2; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const std::array<Elem, 2>& buffer_sequence) + { + return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; + } + + static void validate(const std::array<Elem, 2>& buffer_sequence) + { + buffer_sequence[0].data(); + buffer_sequence[1].data(); + } + + static Buffer first(const std::array<Elem, 2>& buffer_sequence) + { + return Buffer(buffer_sequence[0].size() != 0 + ? buffer_sequence[0] : buffer_sequence[1]); + } + +private: + native_buffer_type buffers_[2]; + std::size_t total_buffer_size_; +}; + +#endif // defined(ASIO_HAS_STD_ARRAY) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/buffer_sequence_adapter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP diff --git a/lib/asio/detail/buffered_stream_storage.hpp b/lib/asio/detail/buffered_stream_storage.hpp new file mode 100644 index 0000000..c5eb081 --- /dev/null +++ b/lib/asio/detail/buffered_stream_storage.hpp @@ -0,0 +1,126 @@ +// +// detail/buffered_stream_storage.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP +#define ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/buffer.hpp" +#include "asio/detail/assert.hpp" +#include <cstddef> +#include <cstring> +#include <vector> + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class buffered_stream_storage +{ +public: + // The type of the bytes stored in the buffer. + typedef unsigned char byte_type; + + // The type used for offsets into the buffer. + typedef std::size_t size_type; + + // Constructor. + explicit buffered_stream_storage(std::size_t buffer_capacity) + : begin_offset_(0), + end_offset_(0), + buffer_(buffer_capacity) + { + } + + /// Clear the buffer. + void clear() + { + begin_offset_ = 0; + end_offset_ = 0; + } + + // Return a pointer to the beginning of the unread data. + mutable_buffer data() + { + return asio::buffer(buffer_) + begin_offset_; + } + + // Return a pointer to the beginning of the unread data. + const_buffer data() const + { + return asio::buffer(buffer_) + begin_offset_; + } + + // Is there no unread data in the buffer. + bool empty() const + { + return begin_offset_ == end_offset_; + } + + // Return the amount of unread data the is in the buffer. + size_type size() const + { + return end_offset_ - begin_offset_; + } + + // Resize the buffer to the specified length. + void resize(size_type length) + { + ASIO_ASSERT(length <= capacity()); + if (begin_offset_ + length <= capacity()) + { + end_offset_ = begin_offset_ + length; + } + else + { + using namespace std; // For memmove. + memmove(&buffer_[0], &buffer_[0] + begin_offset_, size()); + end_offset_ = length; + begin_offset_ = 0; + } + } + + // Return the maximum size for data in the buffer. + size_type capacity() const + { + return buffer_.size(); + } + + // Consume multiple bytes from the beginning of the buffer. + void consume(size_type count) + { + ASIO_ASSERT(begin_offset_ + count <= end_offset_); + begin_offset_ += count; + if (empty()) + clear(); + } + +private: + // The offset to the beginning of the unread data. + size_type begin_offset_; + + // The offset to the end of the unread data. + size_type end_offset_; + + // The data in the buffer. + std::vector<byte_type> buffer_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP diff --git a/lib/asio/detail/call_stack.hpp b/lib/asio/detail/call_stack.hpp new file mode 100644 index 0000000..5725a10 --- /dev/null +++ b/lib/asio/detail/call_stack.hpp @@ -0,0 +1,125 @@ +// +// detail/call_stack.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CALL_STACK_HPP +#define ASIO_DETAIL_CALL_STACK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/tss_ptr.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper class to determine whether or not the current thread is inside an +// invocation of io_context::run() for a specified io_context object. +template <typename Key, typename Value = unsigned char> +class call_stack +{ +public: + // Context class automatically pushes the key/value pair on to the stack. + class context + : private noncopyable + { + public: + // Push the key on to the stack. + explicit context(Key* k) + : key_(k), + next_(call_stack<Key, Value>::top_) + { + value_ = reinterpret_cast<unsigned char*>(this); + call_stack<Key, Value>::top_ = this; + } + + // Push the key/value pair on to the stack. + context(Key* k, Value& v) + : key_(k), + value_(&v), + next_(call_stack<Key, Value>::top_) + { + call_stack<Key, Value>::top_ = this; + } + + // Pop the key/value pair from the stack. + ~context() + { + call_stack<Key, Value>::top_ = next_; + } + + // Find the next context with the same key. + Value* next_by_key() const + { + context* elem = next_; + while (elem) + { + if (elem->key_ == key_) + return elem->value_; + elem = elem->next_; + } + return 0; + } + + private: + friend class call_stack<Key, Value>; + + // The key associated with the context. + Key* key_; + + // The value associated with the context. + Value* value_; + + // The next element in the stack. + context* next_; + }; + + friend class context; + + // Determine whether the specified owner is on the stack. Returns address of + // key if present, 0 otherwise. + static Value* contains(Key* k) + { + context* elem = top_; + while (elem) + { + if (elem->key_ == k) + return elem->value_; + elem = elem->next_; + } + return 0; + } + + // Obtain the value at the top of the stack. + static Value* top() + { + context* elem = top_; + return elem ? elem->value_ : 0; + } + +private: + // The top of the stack of calls for the current thread. + static tss_ptr<context> top_; +}; + +template <typename Key, typename Value> +tss_ptr<typename call_stack<Key, Value>::context> +call_stack<Key, Value>::top_; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CALL_STACK_HPP diff --git a/lib/asio/detail/chrono.hpp b/lib/asio/detail/chrono.hpp new file mode 100644 index 0000000..8f56bee --- /dev/null +++ b/lib/asio/detail/chrono.hpp @@ -0,0 +1,66 @@ +// +// detail/chrono.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CHRONO_HPP +#define ASIO_DETAIL_CHRONO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_CHRONO) +# include <chrono> +#elif defined(ASIO_HAS_BOOST_CHRONO) +# include <boost/chrono/system_clocks.hpp> +#endif // defined(ASIO_HAS_BOOST_CHRONO) + +namespace asio { +namespace chrono { + +#if defined(ASIO_HAS_STD_CHRONO) +using std::chrono::duration; +using std::chrono::time_point; +using std::chrono::duration_cast; +using std::chrono::nanoseconds; +using std::chrono::microseconds; +using std::chrono::milliseconds; +using std::chrono::seconds; +using std::chrono::minutes; +using std::chrono::hours; +using std::chrono::time_point_cast; +#if defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +typedef std::chrono::monotonic_clock steady_clock; +#else // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +using std::chrono::steady_clock; +#endif // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +using std::chrono::system_clock; +using std::chrono::high_resolution_clock; +#elif defined(ASIO_HAS_BOOST_CHRONO) +using boost::chrono::duration; +using boost::chrono::time_point; +using boost::chrono::duration_cast; +using boost::chrono::nanoseconds; +using boost::chrono::microseconds; +using boost::chrono::milliseconds; +using boost::chrono::seconds; +using boost::chrono::minutes; +using boost::chrono::hours; +using boost::chrono::time_point_cast; +using boost::chrono::system_clock; +using boost::chrono::steady_clock; +using boost::chrono::high_resolution_clock; +#endif // defined(ASIO_HAS_BOOST_CHRONO) + +} // namespace chrono +} // namespace asio + +#endif // ASIO_DETAIL_CHRONO_HPP diff --git a/lib/asio/detail/chrono_time_traits.hpp b/lib/asio/detail/chrono_time_traits.hpp new file mode 100644 index 0000000..d1528f7 --- /dev/null +++ b/lib/asio/detail/chrono_time_traits.hpp @@ -0,0 +1,190 @@ +// +// detail/chrono_time_traits.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP +#define ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/cstdint.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper template to compute the greatest common divisor. +template <int64_t v1, int64_t v2> +struct gcd { enum { value = gcd<v2, v1 % v2>::value }; }; + +template <int64_t v1> +struct gcd<v1, 0> { enum { value = v1 }; }; + +// Adapts std::chrono clocks for use with a deadline timer. +template <typename Clock, typename WaitTraits> +struct chrono_time_traits +{ + // The clock type. + typedef Clock clock_type; + + // The duration type of the clock. + typedef typename clock_type::duration duration_type; + + // The time point type of the clock. + typedef typename clock_type::time_point time_type; + + // The period of the clock. + typedef typename duration_type::period period_type; + + // Get the current time. + static time_type now() + { + return clock_type::now(); + } + + // Add a duration to a time. + static time_type add(const time_type& t, const duration_type& d) + { + const time_type epoch; + if (t >= epoch) + { + if ((time_type::max)() - t < d) + return (time_type::max)(); + } + else // t < epoch + { + if (-(t - (time_type::min)()) > d) + return (time_type::min)(); + } + + return t + d; + } + + // Subtract one time from another. + static duration_type subtract(const time_type& t1, const time_type& t2) + { + const time_type epoch; + if (t1 >= epoch) + { + if (t2 >= epoch) + { + return t1 - t2; + } + else if (t2 == (time_type::min)()) + { + return (duration_type::max)(); + } + else if ((time_type::max)() - t1 < epoch - t2) + { + return (duration_type::max)(); + } + else + { + return t1 - t2; + } + } + else // t1 < epoch + { + if (t2 < epoch) + { + return t1 - t2; + } + else if (t1 == (time_type::min)()) + { + return (duration_type::min)(); + } + else if ((time_type::max)() - t2 < epoch - t1) + { + return (duration_type::min)(); + } + else + { + return -(t2 - t1); + } + } + } + + // Test whether one time is less than another. + static bool less_than(const time_type& t1, const time_type& t2) + { + return t1 < t2; + } + + // Implement just enough of the posix_time::time_duration interface to supply + // what the timer_queue requires. + class posix_time_duration + { + public: + explicit posix_time_duration(const duration_type& d) + : d_(d) + { + } + + int64_t ticks() const + { + return d_.count(); + } + + int64_t total_seconds() const + { + return duration_cast<1, 1>(); + } + + int64_t total_milliseconds() const + { + return duration_cast<1, 1000>(); + } + + int64_t total_microseconds() const + { + return duration_cast<1, 1000000>(); + } + + private: + template <int64_t Num, int64_t Den> + int64_t duration_cast() const + { + const int64_t num1 = period_type::num / gcd<period_type::num, Num>::value; + const int64_t num2 = Num / gcd<period_type::num, Num>::value; + + const int64_t den1 = period_type::den / gcd<period_type::den, Den>::value; + const int64_t den2 = Den / gcd<period_type::den, Den>::value; + + const int64_t num = num1 * den2; + const int64_t den = num2 * den1; + + if (num == 1 && den == 1) + return ticks(); + else if (num != 1 && den == 1) + return ticks() * num; + else if (num == 1 && period_type::den != 1) + return ticks() / den; + else + return ticks() * num / den; + } + + duration_type d_; + }; + + // Convert to POSIX duration type. + static posix_time_duration to_posix_duration(const duration_type& d) + { + return posix_time_duration(WaitTraits::to_wait_duration(d)); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP diff --git a/lib/asio/detail/completion_handler.hpp b/lib/asio/detail/completion_handler.hpp new file mode 100644 index 0000000..58a2e6d --- /dev/null +++ b/lib/asio/detail/completion_handler.hpp @@ -0,0 +1,83 @@ +// +// detail/completion_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_COMPLETION_HANDLER_HPP +#define ASIO_DETAIL_COMPLETION_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class completion_handler : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(completion_handler); + + completion_handler(Handler& h) + : operation(&completion_handler::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(h)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + completion_handler* h(static_cast<completion_handler*>(base)); + ptr p = { asio::detail::addressof(h->handler_), h, h }; + handler_work<Handler> w(h->handler_); + + ASIO_HANDLER_COMPLETION((*h)); + + // 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(ASIO_MOVE_CAST(Handler)(h->handler_)); + p.h = asio::detail::addressof(handler); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN(()); + w.complete(handler, handler); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_COMPLETION_HANDLER_HPP diff --git a/lib/asio/detail/concurrency_hint.hpp b/lib/asio/detail/concurrency_hint.hpp new file mode 100644 index 0000000..229124d --- /dev/null +++ b/lib/asio/detail/concurrency_hint.hpp @@ -0,0 +1,94 @@ +// +// detail/concurrency_hint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CONCURRENCY_HINT_HPP +#define ASIO_DETAIL_CONCURRENCY_HINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/noncopyable.hpp" + +// The concurrency hint ID and mask are used to identify when a "well-known" +// concurrency hint value has been passed to the io_context. +#define ASIO_CONCURRENCY_HINT_ID 0xA5100000u +#define ASIO_CONCURRENCY_HINT_ID_MASK 0xFFFF0000u + +// If set, this bit indicates that the scheduler should perform locking. +#define ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER 0x1u + +// If set, this bit indicates that the reactor should perform locking when +// managing descriptor registrations. +#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION 0x2u + +// If set, this bit indicates that the reactor should perform locking for I/O. +#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO 0x4u + +// Helper macro to determine if we have a special concurrency hint. +#define ASIO_CONCURRENCY_HINT_IS_SPECIAL(hint) \ + ((static_cast<unsigned>(hint) \ + & ASIO_CONCURRENCY_HINT_ID_MASK) \ + == ASIO_CONCURRENCY_HINT_ID) + +// Helper macro to determine if locking is enabled for a given facility. +#define ASIO_CONCURRENCY_HINT_IS_LOCKING(facility, hint) \ + (((static_cast<unsigned>(hint) \ + & (ASIO_CONCURRENCY_HINT_ID_MASK \ + | ASIO_CONCURRENCY_HINT_LOCKING_ ## facility)) \ + ^ ASIO_CONCURRENCY_HINT_ID) != 0) + +// This special concurrency hint disables locking in both the scheduler and +// reactor I/O. This hint has the following restrictions: +// +// - Care must be taken to ensure that all operations on the io_context and any +// of its associated I/O objects (such as sockets and timers) occur in only +// one thread at a time. +// +// - Asynchronous resolve operations fail with operation_not_supported. +// +// - If a signal_set is used with the io_context, signal_set objects cannot be +// used with any other io_context in the program. +#define ASIO_CONCURRENCY_HINT_UNSAFE \ + static_cast<int>(ASIO_CONCURRENCY_HINT_ID) + +// This special concurrency hint disables locking in the reactor I/O. This hint +// has the following restrictions: +// +// - Care must be taken to ensure that run functions on the io_context, and all +// operations on the io_context's associated I/O objects (such as sockets and +// timers), occur in only one thread at a time. +#define ASIO_CONCURRENCY_HINT_UNSAFE_IO \ + static_cast<int>(ASIO_CONCURRENCY_HINT_ID \ + | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \ + | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION) + +// The special concurrency hint provides full thread safety. +#define ASIO_CONCURRENCY_HINT_SAFE \ + static_cast<int>(ASIO_CONCURRENCY_HINT_ID \ + | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \ + | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION \ + | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO) + +// This #define may be overridden at compile time to specify a program-wide +// default concurrency hint, used by the zero-argument io_context constructor. +#if !defined(ASIO_CONCURRENCY_HINT_DEFAULT) +# define ASIO_CONCURRENCY_HINT_DEFAULT -1 +#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT) + +// This #define may be overridden at compile time to specify a program-wide +// concurrency hint, used by the one-argument io_context constructor when +// passed a value of 1. +#if !defined(ASIO_CONCURRENCY_HINT_1) +# define ASIO_CONCURRENCY_HINT_1 1 +#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT) + +#endif // ASIO_DETAIL_CONCURRENCY_HINT_HPP diff --git a/lib/asio/detail/conditionally_enabled_event.hpp b/lib/asio/detail/conditionally_enabled_event.hpp new file mode 100644 index 0000000..0fda401 --- /dev/null +++ b/lib/asio/detail/conditionally_enabled_event.hpp @@ -0,0 +1,112 @@ +// +// detail/conditionally_enabled_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP +#define ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/conditionally_enabled_mutex.hpp" +#include "asio/detail/event.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/null_event.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Mutex adapter used to conditionally enable or disable locking. +class conditionally_enabled_event + : private noncopyable +{ +public: + // Constructor. + conditionally_enabled_event() + { + } + + // Destructor. + ~conditionally_enabled_event() + { + } + + // Signal the event. (Retained for backward compatibility.) + void signal(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.signal(lock); + } + + // Signal all waiters. + void signal_all(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.signal_all(lock); + } + + // Unlock the mutex and signal one waiter. + void unlock_and_signal_one( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.unlock_and_signal_one(lock); + } + + // If there's a waiter, unlock the mutex and signal it. + bool maybe_unlock_and_signal_one( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + return event_.maybe_unlock_and_signal_one(lock); + else + return false; + } + + // Reset the event. + void clear(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.clear(lock); + } + + // Wait for the event to become signalled. + void wait(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.wait(lock); + else + null_event().wait(lock); + } + + // Timed wait for the event to become signalled. + bool wait_for_usec( + conditionally_enabled_mutex::scoped_lock& lock, long usec) + { + if (lock.mutex_.enabled_) + return event_.wait_for_usec(lock, usec); + else + return null_event().wait_for_usec(lock, usec); + } + +private: + asio::detail::event event_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP diff --git a/lib/asio/detail/conditionally_enabled_mutex.hpp b/lib/asio/detail/conditionally_enabled_mutex.hpp new file mode 100644 index 0000000..2872db9 --- /dev/null +++ b/lib/asio/detail/conditionally_enabled_mutex.hpp @@ -0,0 +1,149 @@ +// +// detail/conditionally_enabled_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP +#define ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Mutex adapter used to conditionally enable or disable locking. +class conditionally_enabled_mutex + : private noncopyable +{ +public: + // Helper class to lock and unlock a mutex automatically. + class scoped_lock + : private noncopyable + { + public: + // Tag type used to distinguish constructors. + enum adopt_lock_t { adopt_lock }; + + // Constructor adopts a lock that is already held. + scoped_lock(conditionally_enabled_mutex& m, adopt_lock_t) + : mutex_(m), + locked_(m.enabled_) + { + } + + // Constructor acquires the lock. + explicit scoped_lock(conditionally_enabled_mutex& m) + : mutex_(m) + { + if (m.enabled_) + { + mutex_.mutex_.lock(); + locked_ = true; + } + else + locked_ = false; + } + + // Destructor releases the lock. + ~scoped_lock() + { + if (locked_) + mutex_.mutex_.unlock(); + } + + // Explicitly acquire the lock. + void lock() + { + if (mutex_.enabled_ && !locked_) + { + mutex_.mutex_.lock(); + locked_ = true; + } + } + + // Explicitly release the lock. + void unlock() + { + if (locked_) + { + mutex_.unlock(); + locked_ = false; + } + } + + // Test whether the lock is held. + bool locked() const + { + return locked_; + } + + // Get the underlying mutex. + asio::detail::mutex& mutex() + { + return mutex_.mutex_; + } + + private: + friend class conditionally_enabled_event; + conditionally_enabled_mutex& mutex_; + bool locked_; + }; + + // Constructor. + explicit conditionally_enabled_mutex(bool enabled) + : enabled_(enabled) + { + } + + // Destructor. + ~conditionally_enabled_mutex() + { + } + + // Determine whether locking is enabled. + bool enabled() const + { + return enabled_; + } + + // Lock the mutex. + void lock() + { + if (enabled_) + mutex_.lock(); + } + + // Unlock the mutex. + void unlock() + { + if (enabled_) + mutex_.unlock(); + } + +private: + friend class scoped_lock; + friend class conditionally_enabled_event; + asio::detail::mutex mutex_; + const bool enabled_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP diff --git a/lib/asio/detail/config.hpp b/lib/asio/detail/config.hpp new file mode 100644 index 0000000..cde334e --- /dev/null +++ b/lib/asio/detail/config.hpp @@ -0,0 +1,1437 @@ +// +// detail/config.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CONFIG_HPP +#define ASIO_DETAIL_CONFIG_HPP + +#if defined(ASIO_STANDALONE) +# define ASIO_DISABLE_BOOST_ARRAY 1 +# define ASIO_DISABLE_BOOST_ASSERT 1 +# define ASIO_DISABLE_BOOST_BIND 1 +# define ASIO_DISABLE_BOOST_CHRONO 1 +# define ASIO_DISABLE_BOOST_DATE_TIME 1 +# define ASIO_DISABLE_BOOST_LIMITS 1 +# define ASIO_DISABLE_BOOST_REGEX 1 +# define ASIO_DISABLE_BOOST_STATIC_CONSTANT 1 +# define ASIO_DISABLE_BOOST_THROW_EXCEPTION 1 +# define ASIO_DISABLE_BOOST_WORKAROUND 1 +#else // defined(ASIO_STANDALONE) +# include <boost/config.hpp> +# include <boost/version.hpp> +# define ASIO_HAS_BOOST_CONFIG 1 +#endif // defined(ASIO_STANDALONE) + +// Default to a header-only implementation. The user must specifically request +// separate compilation by defining either ASIO_SEPARATE_COMPILATION or +// ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). +#if !defined(ASIO_HEADER_ONLY) +# if !defined(ASIO_SEPARATE_COMPILATION) +# if !defined(ASIO_DYN_LINK) +# define ASIO_HEADER_ONLY 1 +# endif // !defined(ASIO_DYN_LINK) +# endif // !defined(ASIO_SEPARATE_COMPILATION) +#endif // !defined(ASIO_HEADER_ONLY) + +#if defined(ASIO_HEADER_ONLY) +# define ASIO_DECL inline +#else // defined(ASIO_HEADER_ONLY) +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +// We need to import/export our code only if the user has specifically asked +// for it by defining ASIO_DYN_LINK. +# if defined(ASIO_DYN_LINK) +// Export if this is our own source, otherwise import. +# if defined(ASIO_SOURCE) +# define ASIO_DECL __declspec(dllexport) +# else // defined(ASIO_SOURCE) +# define ASIO_DECL __declspec(dllimport) +# endif // defined(ASIO_SOURCE) +# endif // defined(ASIO_DYN_LINK) +# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +#endif // defined(ASIO_HEADER_ONLY) + +// If ASIO_DECL isn't defined yet define it now. +#if !defined(ASIO_DECL) +# define ASIO_DECL +#endif // !defined(ASIO_DECL) + +// Microsoft Visual C++ detection. +#if !defined(ASIO_MSVC) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +# define ASIO_MSVC BOOST_MSVC +# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \ + || (!defined(__MWERKS__) && !defined(__EDG_VERSION__))) +# define ASIO_MSVC _MSC_VER +# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +#endif // !defined(ASIO_MSVC) +#if defined(ASIO_MSVC) +# include <ciso646> // Needed for _HAS_CXX17. +#endif // defined(ASIO_MSVC) + +// Clang / libc++ detection. +#if defined(__clang__) +# if (__cplusplus >= 201103) +# if __has_include(<__config>) +# include <__config> +# if defined(_LIBCPP_VERSION) +# define ASIO_HAS_CLANG_LIBCXX 1 +# endif // defined(_LIBCPP_VERSION) +# endif // __has_include(<__config>) +# endif // (__cplusplus >= 201103) +#endif // defined(__clang__) + +// Android platform detection. +#if defined(__ANDROID__) +# include <android/api-level.h> +#endif // defined(__ANDROID__) + +// Support move construction and assignment on compilers known to allow it. +#if !defined(ASIO_HAS_MOVE) +# if !defined(ASIO_DISABLE_MOVE) +# if defined(__clang__) +# if __has_feature(__cxx_rvalue_references__) +# define ASIO_HAS_MOVE 1 +# endif // __has_feature(__cxx_rvalue_references__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_MOVE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_MOVE) +#endif // !defined(ASIO_HAS_MOVE) + +// If ASIO_MOVE_CAST isn't defined, and move support is available, define +// ASIO_MOVE_ARG and ASIO_MOVE_CAST to take advantage of rvalue +// references and perfect forwarding. +#if defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST) +# define ASIO_MOVE_ARG(type) type&& +# define ASIO_MOVE_ARG2(type1, type2) type1, type2&& +# define ASIO_MOVE_CAST(type) static_cast<type&&> +# define ASIO_MOVE_CAST2(type1, type2) static_cast<type1, type2&&> +#endif // defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST) + +// If ASIO_MOVE_CAST still isn't defined, default to a C++03-compatible +// implementation. Note that older g++ and MSVC versions don't like it when you +// pass a non-member function through a const reference, so for most compilers +// we'll play it safe and stick with the old approach of passing the handler by +// value. +#if !defined(ASIO_MOVE_CAST) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# define ASIO_MOVE_ARG(type) const type& +# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# define ASIO_MOVE_ARG(type) type +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# elif defined(ASIO_MSVC) +# if (_MSC_VER >= 1400) +# define ASIO_MOVE_ARG(type) const type& +# else // (_MSC_VER >= 1400) +# define ASIO_MOVE_ARG(type) type +# endif // (_MSC_VER >= 1400) +# else +# define ASIO_MOVE_ARG(type) type +# endif +# define ASIO_MOVE_CAST(type) static_cast<const type&> +# define ASIO_MOVE_CAST2(type1, type2) static_cast<const type1, type2&> +#endif // !defined(ASIO_MOVE_CAST) + +// Support variadic templates on compilers known to allow it. +#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) +# if !defined(ASIO_DISABLE_VARIADIC_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_variadic_templates__) +# define ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // __has_feature(__cxx_variadic_templates__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_VARIADIC_TEMPLATES) +#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +// Support deleted functions on compilers known to allow it. +#if !defined(ASIO_DELETED) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_DELETED = delete +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(__clang__) +# if __has_feature(__cxx_deleted_functions__) +# define ASIO_DELETED = delete +# endif // __has_feature(__cxx_deleted_functions__) +# endif // defined(__clang__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_DELETED = delete +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# if !defined(ASIO_DELETED) +# define ASIO_DELETED +# endif // !defined(ASIO_DELETED) +#endif // !defined(ASIO_DELETED) + +// Support constexpr on compilers known to allow it. +#if !defined(ASIO_HAS_CONSTEXPR) +# if !defined(ASIO_DISABLE_CONSTEXPR) +# if defined(__clang__) +# if __has_feature(__cxx_constexpr__) +# define ASIO_HAS_CONSTEXPR 1 +# endif // __has_feature(__cxx_constexr__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_CONSTEXPR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_HAS_CONSTEXPR 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_CONSTEXPR) +#endif // !defined(ASIO_HAS_CONSTEXPR) +#if !defined(ASIO_CONSTEXPR) +# if defined(ASIO_HAS_CONSTEXPR) +# define ASIO_CONSTEXPR constexpr +# else // defined(ASIO_HAS_CONSTEXPR) +# define ASIO_CONSTEXPR +# endif // defined(ASIO_HAS_CONSTEXPR) +#endif // !defined(ASIO_CONSTEXPR) + +// Support noexcept on compilers known to allow it. +#if !defined(ASIO_NOEXCEPT) +# if !defined(ASIO_DISABLE_NOEXCEPT) +# if (BOOST_VERSION >= 105300) +# define ASIO_NOEXCEPT BOOST_NOEXCEPT +# define ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define ASIO_NOEXCEPT noexcept(true) +# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_NOEXCEPT noexcept(true) +# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_NOEXCEPT noexcept(true) +# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_NOEXCEPT) +# if !defined(ASIO_NOEXCEPT) +# define ASIO_NOEXCEPT +# endif // !defined(ASIO_NOEXCEPT) +# if !defined(ASIO_NOEXCEPT_OR_NOTHROW) +# define ASIO_NOEXCEPT_OR_NOTHROW throw() +# endif // !defined(ASIO_NOEXCEPT_OR_NOTHROW) +#endif // !defined(ASIO_NOEXCEPT) + +// Support automatic type deduction on compilers known to support it. +#if !defined(ASIO_HAS_DECLTYPE) +# if !defined(ASIO_DISABLE_DECLTYPE) +# if defined(__clang__) +# if __has_feature(__cxx_decltype__) +# define ASIO_HAS_DECLTYPE 1 +# endif // __has_feature(__cxx_decltype__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_DECLTYPE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_DECLTYPE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_DECLTYPE) +#endif // !defined(ASIO_HAS_DECLTYPE) + +// Support alias templates on compilers known to allow it. +#if !defined(ASIO_HAS_ALIAS_TEMPLATES) +# if !defined(ASIO_DISABLE_ALIAS_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_alias_templates__) +# define ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // __has_feature(__cxx_alias_templates__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_ALIAS_TEMPLATES) +#endif // !defined(ASIO_HAS_ALIAS_TEMPLATES) + +// Standard library support for system errors. +#if !defined(ASIO_HAS_STD_SYSTEM_ERROR) +# if !defined(ASIO_DISABLE_STD_SYSTEM_ERROR) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_SYSTEM_ERROR 1 +# elif (__cplusplus >= 201103) +# if __has_include(<system_error>) +# define ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // __has_include(<system_error>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_SYSTEM_ERROR) +#endif // !defined(ASIO_HAS_STD_SYSTEM_ERROR) + +// Compliant C++11 compilers put noexcept specifiers on error_category members. +#if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) +# if (BOOST_VERSION >= 105300) +# define ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // (_MSC_VER >= 1900) +# endif // defined(ASIO_MSVC) +# if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) +# define ASIO_ERROR_CATEGORY_NOEXCEPT +# endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) +#endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) + +// Standard library support for arrays. +#if !defined(ASIO_HAS_STD_ARRAY) +# if !defined(ASIO_DISABLE_STD_ARRAY) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_ARRAY 1 +# elif (__cplusplus >= 201103) +# if __has_include(<array>) +# define ASIO_HAS_STD_ARRAY 1 +# endif // __has_include(<array>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_ARRAY 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define ASIO_HAS_STD_ARRAY 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_ARRAY) +#endif // !defined(ASIO_HAS_STD_ARRAY) + +// Standard library support for shared_ptr and weak_ptr. +#if !defined(ASIO_HAS_STD_SHARED_PTR) +# if !defined(ASIO_DISABLE_STD_SHARED_PTR) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_SHARED_PTR 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_SHARED_PTR 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_SHARED_PTR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define ASIO_HAS_STD_SHARED_PTR 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_SHARED_PTR) +#endif // !defined(ASIO_HAS_STD_SHARED_PTR) + +// Standard library support for allocator_arg_t. +#if !defined(ASIO_HAS_STD_ALLOCATOR_ARG) +# if !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_ALLOCATOR_ARG 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG) +#endif // !defined(ASIO_HAS_STD_ALLOCATOR_ARG) + +// Standard library support for atomic operations. +#if !defined(ASIO_HAS_STD_ATOMIC) +# if !defined(ASIO_DISABLE_STD_ATOMIC) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_ATOMIC 1 +# elif (__cplusplus >= 201103) +# if __has_include(<atomic>) +# define ASIO_HAS_STD_ATOMIC 1 +# endif // __has_include(<atomic>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_ATOMIC 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_ATOMIC 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_ATOMIC) +#endif // !defined(ASIO_HAS_STD_ATOMIC) + +// Standard library support for chrono. Some standard libraries (such as the +// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x +// drafts, rather than the eventually standardised name of steady_clock. +#if !defined(ASIO_HAS_STD_CHRONO) +# if !defined(ASIO_DISABLE_STD_CHRONO) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_CHRONO 1 +# elif (__cplusplus >= 201103) +# if __has_include(<chrono>) +# define ASIO_HAS_STD_CHRONO 1 +# endif // __has_include(<chrono>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_CHRONO 1 +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) +# define ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_CHRONO 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_CHRONO) +#endif // !defined(ASIO_HAS_STD_CHRONO) + +// Boost support for chrono. +#if !defined(ASIO_HAS_BOOST_CHRONO) +# if !defined(ASIO_DISABLE_BOOST_CHRONO) +# if (BOOST_VERSION >= 104700) +# define ASIO_HAS_BOOST_CHRONO 1 +# endif // (BOOST_VERSION >= 104700) +# endif // !defined(ASIO_DISABLE_BOOST_CHRONO) +#endif // !defined(ASIO_HAS_BOOST_CHRONO) + +// Some form of chrono library is available. +#if !defined(ASIO_HAS_CHRONO) +# if defined(ASIO_HAS_STD_CHRONO) \ + || defined(ASIO_HAS_BOOST_CHRONO) +# define ASIO_HAS_CHRONO 1 +# endif // defined(ASIO_HAS_STD_CHRONO) + // || defined(ASIO_HAS_BOOST_CHRONO) +#endif // !defined(ASIO_HAS_CHRONO) + +// Boost support for the DateTime library. +#if !defined(ASIO_HAS_BOOST_DATE_TIME) +# if !defined(ASIO_DISABLE_BOOST_DATE_TIME) +# define ASIO_HAS_BOOST_DATE_TIME 1 +# endif // !defined(ASIO_DISABLE_BOOST_DATE_TIME) +#endif // !defined(ASIO_HAS_BOOST_DATE_TIME) + +// Standard library support for addressof. +#if !defined(ASIO_HAS_STD_ADDRESSOF) +# if !defined(ASIO_DISABLE_STD_ADDRESSOF) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_ADDRESSOF 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_ADDRESSOF 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_ADDRESSOF 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_ADDRESSOF 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_ADDRESSOF) +#endif // !defined(ASIO_HAS_STD_ADDRESSOF) + +// Standard library support for the function class. +#if !defined(ASIO_HAS_STD_FUNCTION) +# if !defined(ASIO_DISABLE_STD_FUNCTION) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_FUNCTION 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_STD_FUNCTION 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_FUNCTION 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_FUNCTION 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_FUNCTION) +#endif // !defined(ASIO_HAS_STD_FUNCTION) + +// Standard library support for type traits. +#if !defined(ASIO_HAS_STD_TYPE_TRAITS) +# if !defined(ASIO_DISABLE_STD_TYPE_TRAITS) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_TYPE_TRAITS 1 +# elif (__cplusplus >= 201103) +# if __has_include(<type_traits>) +# define ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // __has_include(<type_traits>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_TYPE_TRAITS) +#endif // !defined(ASIO_HAS_STD_TYPE_TRAITS) + +// Standard library support for the nullptr_t type. +#if !defined(ASIO_HAS_NULLPTR) +# if !defined(ASIO_DISABLE_NULLPTR) +# if defined(__clang__) +# if __has_feature(__cxx_nullptr__) +# define ASIO_HAS_NULLPTR 1 +# endif // __has_feature(__cxx_rvalue_references__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_NULLPTR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_NULLPTR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_NULLPTR) +#endif // !defined(ASIO_HAS_NULLPTR) + +// Standard library support for the C++11 allocator additions. +#if !defined(ASIO_HAS_CXX11_ALLOCATORS) +# if !defined(ASIO_DISABLE_CXX11_ALLOCATORS) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_CXX11_ALLOCATORS 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_CXX11_ALLOCATORS) +#endif // !defined(ASIO_HAS_CXX11_ALLOCATORS) + +// Standard library support for the cstdint header. +#if !defined(ASIO_HAS_CSTDINT) +# if !defined(ASIO_DISABLE_CSTDINT) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_CSTDINT 1 +# elif (__cplusplus >= 201103) +# define ASIO_HAS_CSTDINT 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_CSTDINT 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_CSTDINT 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_CSTDINT) +#endif // !defined(ASIO_HAS_CSTDINT) + +// Standard library support for the thread class. +#if !defined(ASIO_HAS_STD_THREAD) +# if !defined(ASIO_DISABLE_STD_THREAD) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_THREAD 1 +# elif (__cplusplus >= 201103) +# if __has_include(<thread>) +# define ASIO_HAS_STD_THREAD 1 +# endif // __has_include(<thread>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_THREAD 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_THREAD 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_THREAD) +#endif // !defined(ASIO_HAS_STD_THREAD) + +// Standard library support for the mutex and condition variable classes. +#if !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# if !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# elif (__cplusplus >= 201103) +# if __has_include(<mutex>) +# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // __has_include(<mutex>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +#endif // !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +// Standard library support for the call_once function. +#if !defined(ASIO_HAS_STD_CALL_ONCE) +# if !defined(ASIO_DISABLE_STD_CALL_ONCE) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_CALL_ONCE 1 +# elif (__cplusplus >= 201103) +# if __has_include(<mutex>) +# define ASIO_HAS_STD_CALL_ONCE 1 +# endif // __has_include(<mutex>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_CALL_ONCE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_CALL_ONCE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_CALL_ONCE) +#endif // !defined(ASIO_HAS_STD_CALL_ONCE) + +// Standard library support for futures. +#if !defined(ASIO_HAS_STD_FUTURE) +# if !defined(ASIO_DISABLE_STD_FUTURE) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_FUTURE 1 +# elif (__cplusplus >= 201103) +# if __has_include(<future>) +# define ASIO_HAS_STD_FUTURE 1 +# endif // __has_include(<mutex>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# if defined(_GLIBCXX_HAS_GTHREADS) +# define ASIO_HAS_STD_FUTURE 1 +# endif // defined(_GLIBCXX_HAS_GTHREADS) +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_FUTURE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_FUTURE) +#endif // !defined(ASIO_HAS_STD_FUTURE) + +// Standard library support for std::string_view. +#if !defined(ASIO_HAS_STD_STRING_VIEW) +# if !defined(ASIO_DISABLE_STD_STRING_VIEW) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include(<string_view>) +# define ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include(<string_view>) +# endif // (__cplusplus >= 201703) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define ASIO_HAS_STD_STRING_VIEW 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1910 && _HAS_CXX17) +# define ASIO_HAS_STD_STRING_VIEW +# endif // (_MSC_VER >= 1910 && _HAS_CXX17) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_STRING_VIEW) +#endif // !defined(ASIO_HAS_STD_STRING_VIEW) + +// Standard library support for std::experimental::string_view. +#if !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# if !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# if __has_include(<experimental/string_view>) +# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include(<experimental/string_view>) +# endif // (__cplusplus >= 201402) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201402) +# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# endif // !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +#endif // !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +// Standard library has a string_view that we can use. +#if !defined(ASIO_HAS_STRING_VIEW) +# if !defined(ASIO_DISABLE_STRING_VIEW) +# if defined(ASIO_HAS_STD_STRING_VIEW) +# define ASIO_HAS_STRING_VIEW 1 +# elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# define ASIO_HAS_STRING_VIEW 1 +# endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# endif // !defined(ASIO_DISABLE_STRING_VIEW) +#endif // !defined(ASIO_HAS_STRING_VIEW) + +// Standard library support for iostream move construction and assignment. +#if !defined(ASIO_HAS_STD_IOSTREAM_MOVE) +# if !defined(ASIO_DISABLE_STD_IOSTREAM_MOVE) +# if defined(__GNUC__) +# if (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_IOSTREAM_MOVE) +#endif // !defined(ASIO_HAS_STD_IOSTREAM_MOVE) + +// Standard library has invoke_result (which supersedes result_of). +#if !defined(ASIO_HAS_STD_INVOKE_RESULT) +# if !defined(ASIO_DISABLE_STD_INVOKE_RESULT) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1910 && _HAS_CXX17) +# define ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (_MSC_VER >= 1910 && _HAS_CXX17) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_INVOKE_RESULT) +#endif // !defined(ASIO_HAS_STD_INVOKE_RESULT) + +// Windows App target. Windows but with a limited API. +#if !defined(ASIO_WINDOWS_APP) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +# include <winapifamily.h> +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define ASIO_WINDOWS_APP 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +#endif // !defined(ASIO_WINDOWS_APP) + +// Legacy WinRT target. Windows App is preferred. +#if !defined(ASIO_WINDOWS_RUNTIME) +# if !defined(ASIO_WINDOWS_APP) +# if defined(__cplusplus_winrt) +# include <winapifamily.h> +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define ASIO_WINDOWS_RUNTIME 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(__cplusplus_winrt) +# endif // !defined(ASIO_WINDOWS_APP) +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +// Windows target. Excludes WinRT but includes Windows App targets. +#if !defined(ASIO_WINDOWS) +# if !defined(ASIO_WINDOWS_RUNTIME) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# define ASIO_WINDOWS 1 +# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# define ASIO_WINDOWS 1 +# elif defined(ASIO_WINDOWS_APP) +# define ASIO_WINDOWS 1 +# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# endif // !defined(ASIO_WINDOWS_RUNTIME) +#endif // !defined(ASIO_WINDOWS) + +// Windows: target OS version. +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || defined(__BORLANDC__) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") +# else // defined(_MSC_VER) || defined(__BORLANDC__) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# define _WIN32_WINNT 0x0501 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# endif // defined(__BORLANDC__) +# 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) +# endif // defined(__CYGWIN__) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: minimise header inclusion. +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: suppress definition of "min" and "max" macros. +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(ASIO_NO_NOMINMAX) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: IO Completion Ports. +#if !defined(ASIO_HAS_IOCP) +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# if !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP) +# if !defined(ASIO_DISABLE_IOCP) +# define ASIO_HAS_IOCP 1 +# endif // !defined(ASIO_DISABLE_IOCP) +# endif // !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +#endif // !defined(ASIO_HAS_IOCP) + +// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to +// get access to the various platform feature macros, e.g. to be able to test +// for threads support. +#if !defined(ASIO_HAS_UNISTD_H) +# if !defined(ASIO_HAS_BOOST_CONFIG) +# if defined(unix) \ + || defined(__unix) \ + || defined(_XOPEN_SOURCE) \ + || defined(_POSIX_SOURCE) \ + || (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) +# define ASIO_HAS_UNISTD_H 1 +# endif +# endif // !defined(ASIO_HAS_BOOST_CONFIG) +#endif // !defined(ASIO_HAS_UNISTD_H) +#if defined(ASIO_HAS_UNISTD_H) +# include <unistd.h> +#endif // defined(ASIO_HAS_UNISTD_H) + +// Linux: epoll, eventfd and timerfd. +#if defined(__linux__) +# include <linux/version.h> +# if !defined(ASIO_HAS_EPOLL) +# if !defined(ASIO_DISABLE_EPOLL) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# define ASIO_HAS_EPOLL 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# endif // !defined(ASIO_DISABLE_EPOLL) +# endif // !defined(ASIO_HAS_EPOLL) +# if !defined(ASIO_HAS_EVENTFD) +# if !defined(ASIO_DISABLE_EVENTFD) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define ASIO_HAS_EVENTFD 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(ASIO_DISABLE_EVENTFD) +# endif // !defined(ASIO_HAS_EVENTFD) +# if !defined(ASIO_HAS_TIMERFD) +# if defined(ASIO_HAS_EPOLL) +# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define ASIO_HAS_TIMERFD 1 +# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# endif // defined(ASIO_HAS_EPOLL) +# endif // !defined(ASIO_HAS_TIMERFD) +#endif // defined(__linux__) + +// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) +# if !defined(ASIO_HAS_KQUEUE) +# if !defined(ASIO_DISABLE_KQUEUE) +# define ASIO_HAS_KQUEUE 1 +# endif // !defined(ASIO_DISABLE_KQUEUE) +# endif // !defined(ASIO_HAS_KQUEUE) +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + +// Solaris: /dev/poll. +#if defined(__sun) +# if !defined(ASIO_HAS_DEV_POLL) +# if !defined(ASIO_DISABLE_DEV_POLL) +# define ASIO_HAS_DEV_POLL 1 +# endif // !defined(ASIO_DISABLE_DEV_POLL) +# endif // !defined(ASIO_HAS_DEV_POLL) +#endif // defined(__sun) + +// Serial ports. +#if !defined(ASIO_HAS_SERIAL_PORT) +# if defined(ASIO_HAS_IOCP) \ + || !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(ASIO_DISABLE_SERIAL_PORT) +# define ASIO_HAS_SERIAL_PORT 1 +# endif // !defined(ASIO_DISABLE_SERIAL_PORT) +# endif // !defined(__SYMBIAN32__) +# endif // defined(ASIO_HAS_IOCP) + // || !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(ASIO_HAS_SERIAL_PORT) + +// Windows: stream handles. +#if !defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) +# if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +# if defined(ASIO_HAS_IOCP) +# define ASIO_HAS_WINDOWS_STREAM_HANDLE 1 +# endif // defined(ASIO_HAS_IOCP) +# endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +#endif // !defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) + +// Windows: random access handles. +#if !defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +# if defined(ASIO_HAS_IOCP) +# define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 +# endif // defined(ASIO_HAS_IOCP) +# endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +#endif // !defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + +// Windows: object handles. +#if !defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) +# if !defined(ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP) +# define ASIO_HAS_WINDOWS_OBJECT_HANDLE 1 +# endif // !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP) +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# endif // !defined(ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +#endif // !defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +// Windows: OVERLAPPED wrapper. +#if !defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) +# if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +# if defined(ASIO_HAS_IOCP) +# define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 +# endif // defined(ASIO_HAS_IOCP) +# endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +#endif // !defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) + +// POSIX: stream-oriented file descriptors. +#if !defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) +# if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +#endif // !defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +// UNIX domain sockets. +#if !defined(ASIO_HAS_LOCAL_SOCKETS) +# if !defined(ASIO_DISABLE_LOCAL_SOCKETS) +# if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define ASIO_HAS_LOCAL_SOCKETS 1 +# endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS) +#endif // !defined(ASIO_HAS_LOCAL_SOCKETS) + +// Can use sigaction() instead of signal(). +#if !defined(ASIO_HAS_SIGACTION) +# if !defined(ASIO_DISABLE_SIGACTION) +# if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define ASIO_HAS_SIGACTION 1 +# endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(ASIO_DISABLE_SIGACTION) +#endif // !defined(ASIO_HAS_SIGACTION) + +// Can use signal(). +#if !defined(ASIO_HAS_SIGNAL) +# if !defined(ASIO_DISABLE_SIGNAL) +# if !defined(UNDER_CE) +# define ASIO_HAS_SIGNAL 1 +# endif // !defined(UNDER_CE) +# endif // !defined(ASIO_DISABLE_SIGNAL) +#endif // !defined(ASIO_HAS_SIGNAL) + +// Can use getaddrinfo() and getnameinfo(). +#if !defined(ASIO_HAS_GETADDRINFO) +# if !defined(ASIO_DISABLE_GETADDRINFO) +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# define ASIO_HAS_GETADDRINFO 1 +# elif defined(UNDER_CE) +# define ASIO_HAS_GETADDRINFO 1 +# endif // defined(UNDER_CE) +# elif defined(__MACH__) && defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# define ASIO_HAS_GETADDRINFO 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# define ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__MACH__) && defined(__APPLE__) +# define ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MACH__) && defined(__APPLE__) +# endif // !defined(ASIO_DISABLE_GETADDRINFO) +#endif // !defined(ASIO_HAS_GETADDRINFO) + +// Whether standard iostreams are disabled. +#if !defined(ASIO_NO_IOSTREAM) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM) +# define ASIO_NO_IOSTREAM 1 +# endif // !defined(BOOST_NO_IOSTREAM) +#endif // !defined(ASIO_NO_IOSTREAM) + +// Whether exception handling is disabled. +#if !defined(ASIO_NO_EXCEPTIONS) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS) +# define ASIO_NO_EXCEPTIONS 1 +# endif // !defined(BOOST_NO_EXCEPTIONS) +#endif // !defined(ASIO_NO_EXCEPTIONS) + +// Whether the typeid operator is supported. +#if !defined(ASIO_NO_TYPEID) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID) +# define ASIO_NO_TYPEID 1 +# endif // !defined(BOOST_NO_TYPEID) +#endif // !defined(ASIO_NO_TYPEID) + +// Threads. +#if !defined(ASIO_HAS_THREADS) +# if !defined(ASIO_DISABLE_THREADS) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# define ASIO_HAS_THREADS 1 +# elif defined(__GNUC__) && !defined(__MINGW32__) \ + && !defined(linux) && !defined(__linux) && !defined(__linux__) +# define ASIO_HAS_THREADS 1 +# elif defined(_MT) || defined(__MT__) +# define ASIO_HAS_THREADS 1 +# elif defined(_REENTRANT) +# define ASIO_HAS_THREADS 1 +# elif defined(__APPLE__) +# define ASIO_HAS_THREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define ASIO_HAS_THREADS 1 +# elif defined(_PTHREADS) +# define ASIO_HAS_THREADS 1 +# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# endif // !defined(ASIO_DISABLE_THREADS) +#endif // !defined(ASIO_HAS_THREADS) + +// POSIX threads. +#if !defined(ASIO_HAS_PTHREADS) +# if defined(ASIO_HAS_THREADS) +# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# define ASIO_HAS_PTHREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define ASIO_HAS_PTHREADS 1 +# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# endif // defined(ASIO_HAS_THREADS) +#endif // !defined(ASIO_HAS_PTHREADS) + +// Helper to prevent macro expansion. +#define ASIO_PREVENT_MACRO_SUBSTITUTION + +// Helper to define in-class constants. +#if !defined(ASIO_STATIC_CONSTANT) +# if !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define ASIO_STATIC_CONSTANT(type, assignment) \ + BOOST_STATIC_CONSTANT(type, assignment) +# else // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define ASIO_STATIC_CONSTANT(type, assignment) \ + static const type assignment +# endif // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT) +#endif // !defined(ASIO_STATIC_CONSTANT) + +// Boost array library. +#if !defined(ASIO_HAS_BOOST_ARRAY) +# if !defined(ASIO_DISABLE_BOOST_ARRAY) +# define ASIO_HAS_BOOST_ARRAY 1 +# endif // !defined(ASIO_DISABLE_BOOST_ARRAY) +#endif // !defined(ASIO_HAS_BOOST_ARRAY) + +// Boost assert macro. +#if !defined(ASIO_HAS_BOOST_ASSERT) +# if !defined(ASIO_DISABLE_BOOST_ASSERT) +# define ASIO_HAS_BOOST_ASSERT 1 +# endif // !defined(ASIO_DISABLE_BOOST_ASSERT) +#endif // !defined(ASIO_HAS_BOOST_ASSERT) + +// Boost limits header. +#if !defined(ASIO_HAS_BOOST_LIMITS) +# if !defined(ASIO_DISABLE_BOOST_LIMITS) +# define ASIO_HAS_BOOST_LIMITS 1 +# endif // !defined(ASIO_DISABLE_BOOST_LIMITS) +#endif // !defined(ASIO_HAS_BOOST_LIMITS) + +// Boost throw_exception function. +#if !defined(ASIO_HAS_BOOST_THROW_EXCEPTION) +# if !defined(ASIO_DISABLE_BOOST_THROW_EXCEPTION) +# define ASIO_HAS_BOOST_THROW_EXCEPTION 1 +# endif // !defined(ASIO_DISABLE_BOOST_THROW_EXCEPTION) +#endif // !defined(ASIO_HAS_BOOST_THROW_EXCEPTION) + +// Boost regex library. +#if !defined(ASIO_HAS_BOOST_REGEX) +# if !defined(ASIO_DISABLE_BOOST_REGEX) +# define ASIO_HAS_BOOST_REGEX 1 +# endif // !defined(ASIO_DISABLE_BOOST_REGEX) +#endif // !defined(ASIO_HAS_BOOST_REGEX) + +// Boost bind function. +#if !defined(ASIO_HAS_BOOST_BIND) +# if !defined(ASIO_DISABLE_BOOST_BIND) +# define ASIO_HAS_BOOST_BIND 1 +# endif // !defined(ASIO_DISABLE_BOOST_BIND) +#endif // !defined(ASIO_HAS_BOOST_BIND) + +// Boost's BOOST_WORKAROUND macro. +#if !defined(ASIO_HAS_BOOST_WORKAROUND) +# if !defined(ASIO_DISABLE_BOOST_WORKAROUND) +# define ASIO_HAS_BOOST_WORKAROUND 1 +# endif // !defined(ASIO_DISABLE_BOOST_WORKAROUND) +#endif // !defined(ASIO_HAS_BOOST_WORKAROUND) + +// Microsoft Visual C++'s secure C runtime library. +#if !defined(ASIO_HAS_SECURE_RTL) +# if !defined(ASIO_DISABLE_SECURE_RTL) +# if defined(ASIO_MSVC) \ + && (ASIO_MSVC >= 1400) \ + && !defined(UNDER_CE) +# define ASIO_HAS_SECURE_RTL 1 +# endif // defined(ASIO_MSVC) + // && (ASIO_MSVC >= 1400) + // && !defined(UNDER_CE) +# endif // !defined(ASIO_DISABLE_SECURE_RTL) +#endif // !defined(ASIO_HAS_SECURE_RTL) + +// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. +#if !defined(ASIO_HAS_HANDLER_HOOKS) +# if !defined(ASIO_DISABLE_HANDLER_HOOKS) +# if defined(__GNUC__) +# if (__GNUC__ >= 3) +# define ASIO_HAS_HANDLER_HOOKS 1 +# endif // (__GNUC__ >= 3) +# elif !defined(__BORLANDC__) +# define ASIO_HAS_HANDLER_HOOKS 1 +# endif // !defined(__BORLANDC__) +# endif // !defined(ASIO_DISABLE_HANDLER_HOOKS) +#endif // !defined(ASIO_HAS_HANDLER_HOOKS) + +// Support for the __thread keyword extension. +#if !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +# if defined(__linux__) +# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# if !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !(defined(__clang__) && defined(__ANDROID__)) +# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define ASIO_THREAD_KEYWORD __thread +# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) +# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) + // && !(defined(__clang__) && defined(__ANDROID__)) +# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# endif // defined(__linux__) +# if defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME) +# if (_MSC_VER >= 1700) +# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define ASIO_THREAD_KEYWORD __declspec(thread) +# endif // (_MSC_VER >= 1700) +# endif // defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME) +#endif // !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +#if !defined(ASIO_THREAD_KEYWORD) +# define ASIO_THREAD_KEYWORD __thread +#endif // !defined(ASIO_THREAD_KEYWORD) + +// Support for POSIX ssize_t typedef. +#if !defined(ASIO_DISABLE_SSIZE_T) +# if defined(__linux__) \ + || (defined(__MACH__) && defined(__APPLE__)) +# define ASIO_HAS_SSIZE_T 1 +# endif // defined(__linux__) + // || (defined(__MACH__) && defined(__APPLE__)) +#endif // !defined(ASIO_DISABLE_SSIZE_T) + +// Helper macros to manage the transition away from the old services-based API. +#if defined(ASIO_ENABLE_OLD_SERVICES) +# define ASIO_SVC_TPARAM , typename Service +# define ASIO_SVC_TPARAM_DEF1(d1) , typename Service d1 +# define ASIO_SVC_TPARAM_DEF2(d1, d2) , typename Service d1, d2 +# define ASIO_SVC_TARG , Service +# define ASIO_SVC_T Service +# define ASIO_SVC_TPARAM1 , typename Service1 +# define ASIO_SVC_TPARAM1_DEF1(d1) , typename Service1 d1 +# define ASIO_SVC_TPARAM1_DEF2(d1, d2) , typename Service1 d1, d2 +# define ASIO_SVC_TARG1 , Service1 +# define ASIO_SVC_T1 Service1 +# define ASIO_SVC_ACCESS public +#else // defined(ASIO_ENABLE_OLD_SERVICES) +# define ASIO_SVC_TPARAM +# define ASIO_SVC_TPARAM_DEF1(d1) +# define ASIO_SVC_TPARAM_DEF2(d1, d2) +# define ASIO_SVC_TARG +// ASIO_SVC_T is defined at each point of use. +# define ASIO_SVC_TPARAM1 +# define ASIO_SVC_TPARAM1_DEF1(d1) +# define ASIO_SVC_TPARAM1_DEF2(d1, d2) +# define ASIO_SVC_TARG1 +// ASIO_SVC_T1 is defined at each point of use. +# define ASIO_SVC_ACCESS protected +#endif // defined(ASIO_ENABLE_OLD_SERVICES) + +// Helper macros to manage transition away from error_code return values. +#if defined(ASIO_NO_DEPRECATED) +# define ASIO_SYNC_OP_VOID void +# define ASIO_SYNC_OP_VOID_RETURN(e) return +#else // defined(ASIO_NO_DEPRECATED) +# define ASIO_SYNC_OP_VOID asio::error_code +# define ASIO_SYNC_OP_VOID_RETURN(e) return e +#endif // defined(ASIO_NO_DEPRECATED) + +// Newer gcc, clang need special treatment to suppress unused typedef warnings. +#if defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 7) +# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // (__clang_major__ >= 7) +# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \ + || (__clang_major__ > 3) +# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6)) + // || (__clang_major__ > 3) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(ASIO_UNUSED_TYPEDEF) +# define ASIO_UNUSED_TYPEDEF +#endif // !defined(ASIO_UNUSED_TYPEDEF) + +// Some versions of gcc generate spurious warnings about unused variables. +#if defined(__GNUC__) +# if (__GNUC__ >= 4) +# define ASIO_UNUSED_VARIABLE __attribute__((__unused__)) +# endif // (__GNUC__ >= 4) +#endif // defined(__GNUC__) +#if !defined(ASIO_UNUSED_VARIABLE) +# define ASIO_UNUSED_VARIABLE +#endif // !defined(ASIO_UNUSED_VARIABLE) + +// Support co_await on compilers known to allow it. +#if !defined(ASIO_HAS_CO_AWAIT) +# if !defined(ASIO_DISABLE_CO_AWAIT) +# if defined(ASIO_MSVC) +# if (_MSC_FULL_VER >= 190023506) +# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# define ASIO_HAS_CO_AWAIT 1 +# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# endif // (_MSC_FULL_VER >= 190023506) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_CO_AWAIT) +# if defined(__clang__) +# if (__cpp_coroutines >= 201703) +# if __has_include(<experimental/coroutine>) +# define ASIO_HAS_CO_AWAIT 1 +# endif // __has_include(<experimental/coroutine>) +# endif // (__cpp_coroutines >= 201703) +# endif // defined(__clang__) +#endif // !defined(ASIO_HAS_CO_AWAIT) + +#endif // ASIO_DETAIL_CONFIG_HPP diff --git a/lib/asio/detail/consuming_buffers.hpp b/lib/asio/detail/consuming_buffers.hpp new file mode 100644 index 0000000..8127ae7 --- /dev/null +++ b/lib/asio/detail/consuming_buffers.hpp @@ -0,0 +1,414 @@ +// +// detail/consuming_buffers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CONSUMING_BUFFERS_HPP +#define ASIO_DETAIL_CONSUMING_BUFFERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cstddef> +#include "asio/buffer.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/limits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper template to determine the maximum number of prepared buffers. +template <typename Buffers> +struct prepared_buffers_max +{ + enum { value = buffer_sequence_adapter_base::max_buffers }; +}; + +template <typename Elem, std::size_t N> +struct prepared_buffers_max<boost::array<Elem, N> > +{ + enum { value = N }; +}; + +#if defined(ASIO_HAS_STD_ARRAY) + +template <typename Elem, std::size_t N> +struct prepared_buffers_max<std::array<Elem, N> > +{ + enum { value = N }; +}; + +#endif // defined(ASIO_HAS_STD_ARRAY) + +// A buffer sequence used to represent a subsequence of the buffers. +template <typename Buffer, std::size_t MaxBuffers> +struct prepared_buffers +{ + typedef Buffer value_type; + typedef const Buffer* const_iterator; + + enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 }; + + prepared_buffers() : count(0) {} + const_iterator begin() const { return elems; } + const_iterator end() const { return elems + count; } + + Buffer elems[max_buffers]; + std::size_t count; +}; + +// A proxy for a sub-range in a list of buffers. +template <typename Buffer, typename Buffers, typename Buffer_Iterator> +class consuming_buffers +{ +public: + typedef prepared_buffers<Buffer, prepared_buffers_max<Buffers>::value> + prepared_buffers_type; + + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const Buffers& buffers) + : buffers_(buffers), + total_consumed_(0), + next_elem_(0), + next_elem_offset_(0) + { + using asio::buffer_size; + total_size_ = buffer_size(buffers); + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= total_size_; + } + + // Get the buffer for a single transfer, with a size. + prepared_buffers_type prepare(std::size_t max_size) + { + prepared_buffers_type result; + + Buffer_Iterator next = asio::buffer_sequence_begin(buffers_); + Buffer_Iterator end = asio::buffer_sequence_end(buffers_); + + std::advance(next, next_elem_); + std::size_t elem_offset = next_elem_offset_; + while (next != end && max_size > 0 && (result.count) < result.max_buffers) + { + Buffer next_buf = Buffer(*next) + elem_offset; + result.elems[result.count] = asio::buffer(next_buf, max_size); + max_size -= result.elems[result.count].size(); + elem_offset = 0; + if (result.elems[result.count].size() > 0) + ++result.count; + ++next; + } + + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + + Buffer_Iterator next = asio::buffer_sequence_begin(buffers_); + Buffer_Iterator end = asio::buffer_sequence_end(buffers_); + + std::advance(next, next_elem_); + while (next != end && size > 0) + { + Buffer next_buf = Buffer(*next) + next_elem_offset_; + if (size < next_buf.size()) + { + next_elem_offset_ += size; + size = 0; + } + else + { + size -= next_buf.size(); + next_elem_offset_ = 0; + ++next_elem_; + ++next; + } + } + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + Buffers buffers_; + std::size_t total_size_; + std::size_t total_consumed_; + std::size_t next_elem_; + std::size_t next_elem_offset_; +}; + +// Base class of all consuming_buffers specialisations for single buffers. +template <typename Buffer> +class consuming_single_buffer +{ +public: + // Construct to represent the entire list of buffers. + template <typename Buffer1> + explicit consuming_single_buffer(const Buffer1& buffer) + : buffer_(buffer), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= buffer_.size(); + } + + // Get the buffer for a single transfer, with a size. + Buffer prepare(std::size_t max_size) + { + return asio::buffer(buffer_ + total_consumed_, max_size); + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + Buffer buffer_; + std::size_t total_consumed_; +}; + +template <> +class consuming_buffers<mutable_buffer, mutable_buffer, const mutable_buffer*> + : public consuming_single_buffer<ASIO_MUTABLE_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffer& buffer) + : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer) + { + } +}; + +template <> +class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*> + : public consuming_single_buffer<ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffer& buffer) + : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) + { + } +}; + +template <> +class consuming_buffers<const_buffer, const_buffer, const const_buffer*> + : public consuming_single_buffer<ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const const_buffer& buffer) + : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) + { + } +}; + +#if !defined(ASIO_NO_DEPRECATED) + +template <> +class consuming_buffers<mutable_buffer, + mutable_buffers_1, const mutable_buffer*> + : public consuming_single_buffer<ASIO_MUTABLE_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffers_1& buffer) + : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer) + { + } +}; + +template <> +class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*> + : public consuming_single_buffer<ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffers_1& buffer) + : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) + { + } +}; + +template <> +class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*> + : public consuming_single_buffer<ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const const_buffers_1& buffer) + : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) + { + } +}; + +#endif // !defined(ASIO_NO_DEPRECATED) + +template <typename Buffer, typename Elem> +class consuming_buffers<Buffer, boost::array<Elem, 2>, + typename boost::array<Elem, 2>::const_iterator> +{ +public: + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const boost::array<Elem, 2>& buffers) + : buffers_(buffers), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= + Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); + } + + // Get the buffer for a single transfer, with a size. + boost::array<Buffer, 2> prepare(std::size_t max_size) + { + boost::array<Buffer, 2> result = {{ + Buffer(buffers_[0]), Buffer(buffers_[1]) }}; + std::size_t buffer0_size = result[0].size(); + result[0] = asio::buffer(result[0] + total_consumed_, max_size); + result[1] = asio::buffer( + result[1] + (total_consumed_ < buffer0_size + ? 0 : total_consumed_ - buffer0_size), + max_size - result[0].size()); + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + boost::array<Elem, 2> buffers_; + std::size_t total_consumed_; +}; + +#if defined(ASIO_HAS_STD_ARRAY) + +template <typename Buffer, typename Elem> +class consuming_buffers<Buffer, std::array<Elem, 2>, + typename std::array<Elem, 2>::const_iterator> +{ +public: + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const std::array<Elem, 2>& buffers) + : buffers_(buffers), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= + Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); + } + + // Get the buffer for a single transfer, with a size. + std::array<Buffer, 2> prepare(std::size_t max_size) + { + std::array<Buffer, 2> result = {{ + Buffer(buffers_[0]), Buffer(buffers_[1]) }}; + std::size_t buffer0_size = result[0].size(); + result[0] = asio::buffer(result[0] + total_consumed_, max_size); + result[1] = asio::buffer( + result[1] + (total_consumed_ < buffer0_size + ? 0 : total_consumed_ - buffer0_size), + max_size - result[0].size()); + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + std::array<Elem, 2> buffers_; + std::size_t total_consumed_; +}; + +#endif // defined(ASIO_HAS_STD_ARRAY) + +// Specialisation for null_buffers to ensure that the null_buffers type is +// always passed through to the underlying read or write operation. +template <typename Buffer> +class consuming_buffers<Buffer, null_buffers, const mutable_buffer*> + : public asio::null_buffers +{ +public: + consuming_buffers(const null_buffers&) + { + // No-op. + } + + bool empty() + { + return false; + } + + null_buffers prepare(std::size_t) + { + return null_buffers(); + } + + void consume(std::size_t) + { + // No-op. + } + + std::size_t total_consumed() const + { + return 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP diff --git a/lib/asio/detail/cstddef.hpp b/lib/asio/detail/cstddef.hpp new file mode 100644 index 0000000..3912da4 --- /dev/null +++ b/lib/asio/detail/cstddef.hpp @@ -0,0 +1,31 @@ +// +// detail/cstddef.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CSTDDEF_HPP +#define ASIO_DETAIL_CSTDDEF_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cstddef> + +namespace asio { + +#if defined(ASIO_HAS_NULLPTR) +using std::nullptr_t; +#else // defined(ASIO_HAS_NULLPTR) +struct nullptr_t {}; +#endif // defined(ASIO_HAS_NULLPTR) + +} // namespace asio + +#endif // ASIO_DETAIL_CSTDDEF_HPP diff --git a/lib/asio/detail/cstdint.hpp b/lib/asio/detail/cstdint.hpp new file mode 100644 index 0000000..62342b2 --- /dev/null +++ b/lib/asio/detail/cstdint.hpp @@ -0,0 +1,60 @@ +// +// detail/cstdint.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_CSTDINT_HPP +#define ASIO_DETAIL_CSTDINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_CSTDINT) +# include <cstdint> +#else // defined(ASIO_HAS_CSTDINT) +# include <boost/cstdint.hpp> +#endif // defined(ASIO_HAS_CSTDINT) + +namespace asio { + +#if defined(ASIO_HAS_CSTDINT) +using std::int16_t; +using std::int_least16_t; +using std::uint16_t; +using std::uint_least16_t; +using std::int32_t; +using std::int_least32_t; +using std::uint32_t; +using std::uint_least32_t; +using std::int64_t; +using std::int_least64_t; +using std::uint64_t; +using std::uint_least64_t; +using std::uintmax_t; +#else // defined(ASIO_HAS_CSTDINT) +using boost::int16_t; +using boost::int_least16_t; +using boost::uint16_t; +using boost::uint_least16_t; +using boost::int32_t; +using boost::int_least32_t; +using boost::uint32_t; +using boost::uint_least32_t; +using boost::int64_t; +using boost::int_least64_t; +using boost::uint64_t; +using boost::uint_least64_t; +using boost::uintmax_t; +#endif // defined(ASIO_HAS_CSTDINT) + +} // namespace asio + +#endif // ASIO_DETAIL_CSTDINT_HPP diff --git a/lib/asio/detail/date_time_fwd.hpp b/lib/asio/detail/date_time_fwd.hpp new file mode 100644 index 0000000..a159562 --- /dev/null +++ b/lib/asio/detail/date_time_fwd.hpp @@ -0,0 +1,34 @@ +// +// detail/date_time_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_DATE_TIME_FWD_HPP +#define ASIO_DETAIL_DATE_TIME_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +namespace boost { +namespace date_time { + +template<class T, class TimeSystem> +class base_time; + +} // namespace date_time +namespace posix_time { + +class ptime; + +} // namespace posix_time +} // namespace boost + +#endif // ASIO_DETAIL_DATE_TIME_FWD_HPP diff --git a/lib/asio/detail/deadline_timer_service.hpp b/lib/asio/detail/deadline_timer_service.hpp new file mode 100644 index 0000000..f58a6e0 --- /dev/null +++ b/lib/asio/detail/deadline_timer_service.hpp @@ -0,0 +1,278 @@ +// +// detail/deadline_timer_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP +#define ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cstddef> +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue.hpp" +#include "asio/detail/timer_queue_ptime.hpp" +#include "asio/detail/timer_scheduler.hpp" +#include "asio/detail/wait_handler.hpp" +#include "asio/detail/wait_op.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +# include <chrono> +# include <thread> +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +class deadline_timer_service + : public service_base<deadline_timer_service<Time_Traits> > +{ +public: + // The time type. + typedef typename Time_Traits::time_type time_type; + + // The duration type. + typedef typename Time_Traits::duration_type duration_type; + + // The implementation type of the timer. This type is dependent on the + // underlying implementation of the timer service. + struct implementation_type + : private asio::detail::noncopyable + { + time_type expiry; + bool might_have_pending_waits; + typename timer_queue<Time_Traits>::per_timer_data timer_data; + }; + + // Constructor. + deadline_timer_service(asio::io_context& io_context) + : service_base<deadline_timer_service<Time_Traits> >(io_context), + scheduler_(asio::use_service<timer_scheduler>(io_context)) + { + scheduler_.init_task(); + scheduler_.add_timer_queue(timer_queue_); + } + + // Destructor. + ~deadline_timer_service() + { + scheduler_.remove_timer_queue(timer_queue_); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // Construct a new timer implementation. + void construct(implementation_type& impl) + { + impl.expiry = time_type(); + impl.might_have_pending_waits = false; + } + + // Destroy a timer implementation. + void destroy(implementation_type& impl) + { + asio::error_code ec; + cancel(impl, ec); + } + + // Move-construct a new serial port implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + scheduler_.move_timer(timer_queue_, impl.timer_data, other_impl.timer_data); + + impl.expiry = other_impl.expiry; + other_impl.expiry = time_type(); + + impl.might_have_pending_waits = other_impl.might_have_pending_waits; + other_impl.might_have_pending_waits = false; + } + + // Move-assign from another serial port implementation. + void move_assign(implementation_type& impl, + deadline_timer_service& other_service, + implementation_type& other_impl) + { + if (this != &other_service) + if (impl.might_have_pending_waits) + scheduler_.cancel_timer(timer_queue_, impl.timer_data); + + other_service.scheduler_.move_timer(other_service.timer_queue_, + impl.timer_data, other_impl.timer_data); + + impl.expiry = other_impl.expiry; + other_impl.expiry = time_type(); + + impl.might_have_pending_waits = other_impl.might_have_pending_waits; + other_impl.might_have_pending_waits = false; + } + + // Cancel any asynchronous wait operations associated with the timer. + std::size_t cancel(implementation_type& impl, asio::error_code& ec) + { + if (!impl.might_have_pending_waits) + { + ec = asio::error_code(); + return 0; + } + + ASIO_HANDLER_OPERATION((scheduler_.context(), + "deadline_timer", &impl, 0, "cancel")); + + std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data); + impl.might_have_pending_waits = false; + ec = asio::error_code(); + return count; + } + + // Cancels one asynchronous wait operation associated with the timer. + std::size_t cancel_one(implementation_type& impl, + asio::error_code& ec) + { + if (!impl.might_have_pending_waits) + { + ec = asio::error_code(); + return 0; + } + + ASIO_HANDLER_OPERATION((scheduler_.context(), + "deadline_timer", &impl, 0, "cancel_one")); + + std::size_t count = scheduler_.cancel_timer( + timer_queue_, impl.timer_data, 1); + if (count == 0) + impl.might_have_pending_waits = false; + ec = asio::error_code(); + return count; + } + + // Get the expiry time for the timer as an absolute time. + time_type expiry(const implementation_type& impl) const + { + return impl.expiry; + } + + // Get the expiry time for the timer as an absolute time. + time_type expires_at(const implementation_type& impl) const + { + return impl.expiry; + } + + // Get the expiry time for the timer relative to now. + duration_type expires_from_now(const implementation_type& impl) const + { + return Time_Traits::subtract(this->expiry(impl), Time_Traits::now()); + } + + // Set the expiry time for the timer as an absolute time. + std::size_t expires_at(implementation_type& impl, + const time_type& expiry_time, asio::error_code& ec) + { + std::size_t count = cancel(impl, ec); + impl.expiry = expiry_time; + ec = asio::error_code(); + return count; + } + + // Set the expiry time for the timer relative to now. + std::size_t expires_after(implementation_type& impl, + const duration_type& expiry_time, asio::error_code& ec) + { + return expires_at(impl, + Time_Traits::add(Time_Traits::now(), expiry_time), ec); + } + + // Set the expiry time for the timer relative to now. + std::size_t expires_from_now(implementation_type& impl, + const duration_type& expiry_time, asio::error_code& ec) + { + return expires_at(impl, + Time_Traits::add(Time_Traits::now(), expiry_time), ec); + } + + // Perform a blocking wait on the timer. + void wait(implementation_type& impl, asio::error_code& ec) + { + time_type now = Time_Traits::now(); + ec = asio::error_code(); + while (Time_Traits::less_than(now, impl.expiry) && !ec) + { + this->do_wait(Time_Traits::to_posix_duration( + Time_Traits::subtract(impl.expiry, now)), ec); + now = Time_Traits::now(); + } + } + + // Start an asynchronous wait on the timer. + template <typename Handler> + void async_wait(implementation_type& impl, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef wait_handler<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + impl.might_have_pending_waits = true; + + ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "deadline_timer", &impl, 0, "async_wait")); + + scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p); + p.v = p.p = 0; + } + +private: + // Helper function to wait given a duration type. The duration type should + // either be of type boost::posix_time::time_duration, or implement the + // required subset of its interface. + template <typename Duration> + void do_wait(const Duration& timeout, asio::error_code& ec) + { +#if defined(ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_for( + std::chrono::seconds(timeout.total_seconds()) + + std::chrono::microseconds(timeout.total_microseconds())); + ec = asio::error_code(); +#else // defined(ASIO_WINDOWS_RUNTIME) + ::timeval tv; + tv.tv_sec = timeout.total_seconds(); + tv.tv_usec = timeout.total_microseconds() % 1000000; + socket_ops::select(0, 0, 0, 0, &tv, ec); +#endif // defined(ASIO_WINDOWS_RUNTIME) + } + + // The queue of timers. + timer_queue<Time_Traits> timer_queue_; + + // The object that schedules and executes timers. Usually a reactor. + timer_scheduler& scheduler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP diff --git a/lib/asio/detail/dependent_type.hpp b/lib/asio/detail/dependent_type.hpp new file mode 100644 index 0000000..85b41c8 --- /dev/null +++ b/lib/asio/detail/dependent_type.hpp @@ -0,0 +1,36 @@ +// +// detail/dependent_type.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_DEPENDENT_TYPE_HPP +#define ASIO_DETAIL_DEPENDENT_TYPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename DependsOn, typename T> +struct dependent_type +{ + typedef T type; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_DEPENDENT_TYPE_HPP diff --git a/lib/asio/detail/descriptor_ops.hpp b/lib/asio/detail/descriptor_ops.hpp new file mode 100644 index 0000000..9c0560a --- /dev/null +++ b/lib/asio/detail/descriptor_ops.hpp @@ -0,0 +1,121 @@ +// +// detail/descriptor_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_DESCRIPTOR_OPS_HPP +#define ASIO_DETAIL_DESCRIPTOR_OPS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include <cstddef> +#include "asio/error.hpp" +#include "asio/error_code.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace descriptor_ops { + +// Descriptor state bits. +enum +{ + // The user wants a non-blocking descriptor. + user_set_non_blocking = 1, + + // The descriptor has been set non-blocking. + internal_non_blocking = 2, + + // Helper "state" used to determine whether the descriptor is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, + + // The descriptor may have been dup()-ed. + possible_dup = 4 +}; + +typedef unsigned char state_type; + +template <typename ReturnType> +inline ReturnType error_wrapper(ReturnType return_value, + asio::error_code& ec) +{ + ec = asio::error_code(errno, + asio::error::get_system_category()); + return return_value; +} + +ASIO_DECL int open(const char* path, int flags, + asio::error_code& ec); + +ASIO_DECL int close(int d, state_type& state, + asio::error_code& ec); + +ASIO_DECL bool set_user_non_blocking(int d, + state_type& state, bool value, asio::error_code& ec); + +ASIO_DECL bool set_internal_non_blocking(int d, + state_type& state, bool value, asio::error_code& ec); + +typedef iovec buf; + +ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, asio::error_code& ec); + +ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred); + +ASIO_DECL std::size_t sync_write(int d, state_type state, + const buf* bufs, std::size_t count, bool all_empty, + asio::error_code& ec); + +ASIO_DECL bool non_blocking_write(int d, + const buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred); + +ASIO_DECL int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, asio::error_code& ec); + +ASIO_DECL int fcntl(int d, int cmd, asio::error_code& ec); + +ASIO_DECL int fcntl(int d, int cmd, + long arg, asio::error_code& ec); + +ASIO_DECL int poll_read(int d, + state_type state, asio::error_code& ec); + +ASIO_DECL int poll_write(int d, + state_type state, asio::error_code& ec); + +ASIO_DECL int poll_error(int d, + state_type state, asio::error_code& ec); + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/descriptor_ops.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP diff --git a/lib/asio/detail/descriptor_read_op.hpp b/lib/asio/detail/descriptor_read_op.hpp new file mode 100644 index 0000000..6db4bfb --- /dev/null +++ b/lib/asio/detail/descriptor_read_op.hpp @@ -0,0 +1,128 @@ +// +// detail/descriptor_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP +#define ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence> +class descriptor_read_op_base : public reactor_op +{ +public: + descriptor_read_op_base(int descriptor, + const MutableBufferSequence& buffers, func_type complete_func) + : reactor_op(&descriptor_read_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static status do_perform(reactor_op* base) + { + descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base)); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(o->buffers_); + + status result = descriptor_ops::non_blocking_read(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + int descriptor_; + MutableBufferSequence buffers_; +}; + +template <typename MutableBufferSequence, typename Handler> +class descriptor_read_op + : public descriptor_read_op_base<MutableBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); + + descriptor_read_op(int descriptor, + const MutableBufferSequence& buffers, Handler& handler) + : descriptor_read_op_base<MutableBufferSequence>( + descriptor, buffers, &descriptor_read_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_read_op* o(static_cast<descriptor_read_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP diff --git a/lib/asio/detail/descriptor_write_op.hpp b/lib/asio/detail/descriptor_write_op.hpp new file mode 100644 index 0000000..a9ec2a9 --- /dev/null +++ b/lib/asio/detail/descriptor_write_op.hpp @@ -0,0 +1,128 @@ +// +// detail/descriptor_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP +#define ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence> +class descriptor_write_op_base : public reactor_op +{ +public: + descriptor_write_op_base(int descriptor, + const ConstBufferSequence& buffers, func_type complete_func) + : reactor_op(&descriptor_write_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static status do_perform(reactor_op* base) + { + descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base)); + + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(o->buffers_); + + status result = descriptor_ops::non_blocking_write(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + int descriptor_; + ConstBufferSequence buffers_; +}; + +template <typename ConstBufferSequence, typename Handler> +class descriptor_write_op + : public descriptor_write_op_base<ConstBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); + + descriptor_write_op(int descriptor, + const ConstBufferSequence& buffers, Handler& handler) + : descriptor_write_op_base<ConstBufferSequence>( + descriptor, buffers, &descriptor_write_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_write_op* o(static_cast<descriptor_write_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP diff --git a/lib/asio/detail/dev_poll_reactor.hpp b/lib/asio/detail/dev_poll_reactor.hpp new file mode 100644 index 0000000..e9e4e29 --- /dev/null +++ b/lib/asio/detail/dev_poll_reactor.hpp @@ -0,0 +1,218 @@ +// +// detail/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_DEV_POLL_REACTOR_HPP +#define ASIO_DETAIL_DEV_POLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_DEV_POLL) + +#include <cstddef> +#include <vector> +#include <sys/devpoll.h> +#include "asio/detail/hash_map.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/select_interrupter.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class dev_poll_reactor + : public execution_context_service_base<dev_poll_reactor> +{ +public: + enum op_types { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor data. + struct per_descriptor_data + { + }; + + // Constructor. + ASIO_DECL dev_poll_reactor(asio::execution_context& ctx); + + // Destructor. + ASIO_DECL ~dev_poll_reactor(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + ASIO_DECL void notify_fork( + asio::execution_context::fork_event fork_ev); + + // Initialise the task. + ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Move descriptor registration from one descriptor_data object to another. + ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, + bool is_continuation, bool allow_speculative); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data&, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data&); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&); + + // Add a new timer queue to the reactor. + template <typename Time_Traits> + void add_timer_queue(timer_queue<Time_Traits>& queue); + + // Remove a timer queue from the reactor. + template <typename Time_Traits> + void remove_timer_queue(timer_queue<Time_Traits>& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template <typename Time_Traits> + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template <typename Time_Traits> + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source); + + // Run /dev/poll once until interrupted or events are ready to be dispatched. + ASIO_DECL void run(long usec, op_queue<operation>& ops); + + // Interrupt the select loop. + ASIO_DECL void interrupt(); + +private: + // Create the /dev/poll file descriptor. Throws an exception if the descriptor + // cannot be created. + ASIO_DECL static int do_dev_poll_create(); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // 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. + ASIO_DECL int get_timeout(int msec); + + // 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. + ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec); + + // Add a pending event entry for the given descriptor. + ASIO_DECL ::pollfd& add_pending_event_change(int descriptor); + + // The scheduler implementation used to post completions. + scheduler& scheduler_; + + // Mutex to protect access to internal data. + asio::detail::mutex mutex_; + + // The /dev/poll file descriptor. + int dev_poll_fd_; + + // Vector of /dev/poll events waiting to be written to the descriptor. + std::vector< ::pollfd> pending_event_changes_; + + // Hash map to associate a descriptor with a pending event change index. + hash_map<int, std::size_t> pending_event_change_index_; + + // The interrupter is used to break a blocking DP_POLL operation. + select_interrupter interrupter_; + + // The queues of read, write and except operations. + reactor_op_queue<socket_type> op_queue_[max_ops]; + + // The timer queues. + timer_queue_set timer_queues_; + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/dev_poll_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/dev_poll_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_DEV_POLL) + +#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP diff --git a/lib/asio/detail/epoll_reactor.hpp b/lib/asio/detail/epoll_reactor.hpp new file mode 100644 index 0000000..5f58109 --- /dev/null +++ b/lib/asio/detail/epoll_reactor.hpp @@ -0,0 +1,266 @@ +// +// detail/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_EPOLL_REACTOR_HPP +#define ASIO_DETAIL_EPOLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_EPOLL) + +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/conditionally_enabled_mutex.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/object_pool.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/select_interrupter.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/execution_context.hpp" + +#if defined(ASIO_HAS_TIMERFD) +# include <sys/timerfd.h> +#endif // defined(ASIO_HAS_TIMERFD) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class epoll_reactor + : public execution_context_service_base<epoll_reactor> +{ +private: + // The mutex type used by this reactor. + typedef conditionally_enabled_mutex mutex; + +public: + enum op_types { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor queues. + class descriptor_state : operation + { + friend class epoll_reactor; + friend class object_pool_access; + + descriptor_state* next_; + descriptor_state* prev_; + + mutex mutex_; + epoll_reactor* reactor_; + int descriptor_; + uint32_t registered_events_; + op_queue<reactor_op> op_queue_[max_ops]; + bool try_speculative_[max_ops]; + bool shutdown_; + + ASIO_DECL descriptor_state(bool locking); + void set_ready_events(uint32_t events) { task_result_ = events; } + void add_ready_events(uint32_t events) { task_result_ |= events; } + ASIO_DECL operation* perform_io(uint32_t events); + ASIO_DECL static void do_complete( + void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred); + }; + + // Per-descriptor data. + typedef descriptor_state* per_descriptor_data; + + // Constructor. + ASIO_DECL epoll_reactor(asio::execution_context& ctx); + + // Destructor. + ASIO_DECL ~epoll_reactor(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + ASIO_DECL void notify_fork( + asio::execution_context::fork_event fork_ev); + + // Initialise the task. + ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Move descriptor registration from one descriptor_data object to another. + ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data& descriptor_data); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data( + per_descriptor_data& descriptor_data); + + // Add a new timer queue to the reactor. + template <typename Time_Traits> + void add_timer_queue(timer_queue<Time_Traits>& timer_queue); + + // Remove a timer queue from the reactor. + template <typename Time_Traits> + void remove_timer_queue(timer_queue<Time_Traits>& timer_queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template <typename Time_Traits> + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template <typename Time_Traits> + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source); + + // Run epoll once until interrupted or events are ready to be dispatched. + ASIO_DECL void run(long usec, op_queue<operation>& ops); + + // Interrupt the select loop. + ASIO_DECL void interrupt(); + +private: + // The hint to pass to epoll_create to size its data structures. + enum { epoll_size = 20000 }; + + // Create the epoll file descriptor. Throws an exception if the descriptor + // cannot be created. + ASIO_DECL static int do_epoll_create(); + + // Create the timerfd file descriptor. Does not throw. + ASIO_DECL static int do_timerfd_create(); + + // Allocate a new descriptor state object. + ASIO_DECL descriptor_state* allocate_descriptor_state(); + + // Free an existing descriptor state object. + ASIO_DECL void free_descriptor_state(descriptor_state* s); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + ASIO_DECL void update_timeout(); + + // 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. + ASIO_DECL int get_timeout(int msec); + +#if defined(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. + ASIO_DECL int get_timeout(itimerspec& ts); +#endif // defined(ASIO_HAS_TIMERFD) + + // The scheduler implementation used to post completions. + scheduler& scheduler_; + + // Mutex to protect access to internal data. + mutex mutex_; + + // The interrupter is used to break a blocking epoll_wait call. + select_interrupter interrupter_; + + // The epoll file descriptor. + int epoll_fd_; + + // The timer file descriptor. + int timer_fd_; + + // The timer queues. + timer_queue_set timer_queues_; + + // Whether the service has been shut down. + bool shutdown_; + + // Mutex to protect access to the registered descriptors. + mutex registered_descriptors_mutex_; + + // Keep track of all registered descriptors. + object_pool<descriptor_state> registered_descriptors_; + + // Helper class to do post-perform_io cleanup. + struct perform_io_cleanup_on_block_exit; + friend struct perform_io_cleanup_on_block_exit; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/epoll_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/epoll_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_EPOLL) + +#endif // ASIO_DETAIL_EPOLL_REACTOR_HPP diff --git a/lib/asio/detail/event.hpp b/lib/asio/detail/event.hpp new file mode 100644 index 0000000..da8fa77 --- /dev/null +++ b/lib/asio/detail/event.hpp @@ -0,0 +1,48 @@ +// +// detail/event.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_EVENT_HPP +#define ASIO_DETAIL_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_event.hpp" +#elif defined(ASIO_WINDOWS) +# include "asio/detail/win_event.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_event.hpp" +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# include "asio/detail/std_event.hpp" +#else +# error Only Windows, POSIX and std::condition_variable are supported! +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) +typedef null_event event; +#elif defined(ASIO_WINDOWS) +typedef win_event event; +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_event event; +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +typedef std_event event; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_EVENT_HPP diff --git a/lib/asio/detail/eventfd_select_interrupter.hpp b/lib/asio/detail/eventfd_select_interrupter.hpp new file mode 100644 index 0000000..f6e594b --- /dev/null +++ b/lib/asio/detail/eventfd_select_interrupter.hpp @@ -0,0 +1,83 @@ +// +// detail/eventfd_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP +#define ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_EVENTFD) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class eventfd_select_interrupter +{ +public: + // Constructor. + ASIO_DECL eventfd_select_interrupter(); + + // Destructor. + ASIO_DECL ~eventfd_select_interrupter(); + + // Recreate the interrupter's descriptors. Used after a fork. + ASIO_DECL void recreate(); + + // Interrupt the select call. + ASIO_DECL void interrupt(); + + // Reset the select interrupt. Returns true if the call was interrupted. + ASIO_DECL bool reset(); + + // Get the read descriptor to be passed to select. + int read_descriptor() const + { + return read_descriptor_; + } + +private: + // Open the descriptors. Throws on error. + ASIO_DECL void open_descriptors(); + + // Close the descriptors. + ASIO_DECL void close_descriptors(); + + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // 64bit value will be written on the other end of the connection and this + // descriptor will become readable. + int read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // 64bit non-zero value may be written to this to wake up the select which is + // waiting for the other end to become readable. This descriptor will only + // differ from the read descriptor when a pipe is used. + int write_descriptor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/eventfd_select_interrupter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_EVENTFD) + +#endif // ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP diff --git a/lib/asio/detail/executor_op.hpp b/lib/asio/detail/executor_op.hpp new file mode 100644 index 0000000..2d5c7e8 --- /dev/null +++ b/lib/asio/detail/executor_op.hpp @@ -0,0 +1,84 @@ +// +// detail/executor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_EXECUTOR_OP_HPP +#define ASIO_DETAIL_EXECUTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/scheduler_operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler, typename Alloc, + typename Operation = scheduler_operation> +class executor_op : public Operation +{ +public: + ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op); + + template <typename H> + executor_op(ASIO_MOVE_ARG(H) h, const Alloc& allocator) + : Operation(&executor_op::do_complete), + handler_(ASIO_MOVE_CAST(H)(h)), + allocator_(allocator) + { + } + + static void do_complete(void* owner, Operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + executor_op* o(static_cast<executor_op*>(base)); + Alloc allocator(o->allocator_); + ptr p = { detail::addressof(allocator), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // 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(ASIO_MOVE_CAST(Handler)(o->handler_)); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN(()); + asio_handler_invoke_helpers::invoke(handler, handler); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + Alloc allocator_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_EXECUTOR_OP_HPP diff --git a/lib/asio/detail/fd_set_adapter.hpp b/lib/asio/detail/fd_set_adapter.hpp new file mode 100644 index 0000000..fd373da --- /dev/null +++ b/lib/asio/detail/fd_set_adapter.hpp @@ -0,0 +1,39 @@ +// +// detail/fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_FD_SET_ADAPTER_HPP +#define ASIO_DETAIL_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/posix_fd_set_adapter.hpp" +#include "asio/detail/win_fd_set_adapter.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef win_fd_set_adapter fd_set_adapter; +#else +typedef posix_fd_set_adapter fd_set_adapter; +#endif + +} // namespace detail +} // namespace asio + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP diff --git a/lib/asio/detail/fenced_block.hpp b/lib/asio/detail/fenced_block.hpp new file mode 100644 index 0000000..dc34bd9 --- /dev/null +++ b/lib/asio/detail/fenced_block.hpp @@ -0,0 +1,80 @@ +// +// detail/fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_FENCED_BLOCK_HPP +#define ASIO_DETAIL_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) \ + || defined(ASIO_DISABLE_FENCED_BLOCK) +# include "asio/detail/null_fenced_block.hpp" +#elif defined(ASIO_HAS_STD_ATOMIC) +# include "asio/detail/std_fenced_block.hpp" +#elif defined(__MACH__) && defined(__APPLE__) +# include "asio/detail/macos_fenced_block.hpp" +#elif defined(__sun) +# include "asio/detail/solaris_fenced_block.hpp" +#elif defined(__GNUC__) && defined(__arm__) \ + && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) +# include "asio/detail/gcc_arm_fenced_block.hpp" +#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) +# include "asio/detail/gcc_hppa_fenced_block.hpp" +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# include "asio/detail/gcc_x86_fenced_block.hpp" +#elif defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) +# include "asio/detail/gcc_sync_fenced_block.hpp" +#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE) +# include "asio/detail/win_fenced_block.hpp" +#else +# include "asio/detail/null_fenced_block.hpp" +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) \ + || defined(ASIO_DISABLE_FENCED_BLOCK) +typedef null_fenced_block fenced_block; +#elif defined(ASIO_HAS_STD_ATOMIC) +typedef std_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__) && defined(__arm__) \ + && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) +typedef gcc_arm_fenced_block fenced_block; +#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) +typedef gcc_hppa_fenced_block fenced_block; +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +typedef gcc_x86_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_sync_fenced_block fenced_block; +#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE) +typedef win_fenced_block fenced_block; +#else +typedef null_fenced_block fenced_block; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_FENCED_BLOCK_HPP diff --git a/lib/asio/detail/functional.hpp b/lib/asio/detail/functional.hpp new file mode 100644 index 0000000..a37e9e6 --- /dev/null +++ b/lib/asio/detail/functional.hpp @@ -0,0 +1,38 @@ +// +// detail/functional.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_FUNCTIONAL_HPP +#define ASIO_DETAIL_FUNCTIONAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <functional> + +#if !defined(ASIO_HAS_STD_FUNCTION) +# include <boost/function.hpp> +#endif // !defined(ASIO_HAS_STD_FUNCTION) + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_FUNCTION) +using std::function; +#else // defined(ASIO_HAS_STD_FUNCTION) +using boost::function; +#endif // defined(ASIO_HAS_STD_FUNCTION) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_FUNCTIONAL_HPP diff --git a/lib/asio/detail/gcc_arm_fenced_block.hpp b/lib/asio/detail/gcc_arm_fenced_block.hpp new file mode 100644 index 0000000..7919a55 --- /dev/null +++ b/lib/asio/detail/gcc_arm_fenced_block.hpp @@ -0,0 +1,91 @@ +// +// detail/gcc_arm_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) && defined(__arm__) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_arm_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit gcc_arm_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit gcc_arm_fenced_block(full_t) + { + barrier(); + } + + // Destructor. + ~gcc_arm_fenced_block() + { + barrier(); + } + +private: + static void barrier() + { +#if defined(__ARM_ARCH_4__) \ + || defined(__ARM_ARCH_4T__) \ + || defined(__ARM_ARCH_5__) \ + || defined(__ARM_ARCH_5E__) \ + || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) \ + || defined(__ARM_ARCH_6__) \ + || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6T2__) +# if defined(__thumb__) + // This is just a placeholder and almost certainly not sufficient. + __asm__ __volatile__ ("" : : : "memory"); +# else // defined(__thumb__) + int a = 0, b = 0; + __asm__ __volatile__ ("swp %0, %1, [%2]" + : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc"); +# endif // defined(__thumb__) +#else + // ARMv7 and later. + __asm__ __volatile__ ("dmb" : : : "memory"); +#endif + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) && defined(__arm__) + +#endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP diff --git a/lib/asio/detail/gcc_hppa_fenced_block.hpp b/lib/asio/detail/gcc_hppa_fenced_block.hpp new file mode 100644 index 0000000..d3957ce --- /dev/null +++ b/lib/asio/detail/gcc_hppa_fenced_block.hpp @@ -0,0 +1,68 @@ +// +// detail/gcc_hppa_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_hppa_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit gcc_hppa_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit gcc_hppa_fenced_block(full_t) + { + barrier(); + } + + // Destructor. + ~gcc_hppa_fenced_block() + { + barrier(); + } + +private: + static void barrier() + { + // This is just a placeholder and almost certainly not sufficient. + __asm__ __volatile__ ("" : : : "memory"); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) + +#endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP diff --git a/lib/asio/detail/gcc_sync_fenced_block.hpp b/lib/asio/detail/gcc_sync_fenced_block.hpp new file mode 100644 index 0000000..90d176f --- /dev/null +++ b/lib/asio/detail/gcc_sync_fenced_block.hpp @@ -0,0 +1,65 @@ +// +// detail/gcc_sync_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_sync_fenced_block + : private noncopyable +{ +public: + enum half_or_full_t { half, full }; + + // Constructor. + explicit gcc_sync_fenced_block(half_or_full_t) + : value_(0) + { + __sync_lock_test_and_set(&value_, 1); + } + + // Destructor. + ~gcc_sync_fenced_block() + { + __sync_lock_release(&value_); + } + +private: + int value_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) + // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + // && !defined(__INTEL_COMPILER) && !defined(__ICL) + // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + +#endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP diff --git a/lib/asio/detail/gcc_x86_fenced_block.hpp b/lib/asio/detail/gcc_x86_fenced_block.hpp new file mode 100644 index 0000000..1366def --- /dev/null +++ b/lib/asio/detail/gcc_x86_fenced_block.hpp @@ -0,0 +1,99 @@ +// +// detail/gcc_x86_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP +#define ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class gcc_x86_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit gcc_x86_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit gcc_x86_fenced_block(full_t) + { + lbarrier(); + } + + // Destructor. + ~gcc_x86_fenced_block() + { + sbarrier(); + } + +private: + static int barrier() + { + int r = 0, m = 1; + __asm__ __volatile__ ( + "xchgl %0, %1" : + "=r"(r), "=m"(m) : + "0"(1), "m"(m) : + "memory", "cc"); + return r; + } + + static void lbarrier() + { +#if defined(__SSE2__) +# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __builtin_ia32_lfence(); +# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __asm__ __volatile__ ("lfence" ::: "memory"); +# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) +#else // defined(__SSE2__) + barrier(); +#endif // defined(__SSE2__) + } + + static void sbarrier() + { +#if defined(__SSE2__) +# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __builtin_ia32_sfence(); +# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __asm__ __volatile__ ("sfence" ::: "memory"); +# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) +#else // defined(__SSE2__) + barrier(); +#endif // defined(__SSE2__) + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP diff --git a/lib/asio/detail/global.hpp b/lib/asio/detail/global.hpp new file mode 100644 index 0000000..085ac64 --- /dev/null +++ b/lib/asio/detail/global.hpp @@ -0,0 +1,52 @@ +// +// detail/global.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_GLOBAL_HPP +#define ASIO_DETAIL_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_global.hpp" +#elif defined(ASIO_WINDOWS) +# include "asio/detail/win_global.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_global.hpp" +#elif defined(ASIO_HAS_STD_CALL_ONCE) +# include "asio/detail/std_global.hpp" +#else +# error Only Windows, POSIX and std::call_once are supported! +#endif + +namespace asio { +namespace detail { + +template <typename T> +inline T& global() +{ +#if !defined(ASIO_HAS_THREADS) + return null_global<T>(); +#elif defined(ASIO_WINDOWS) + return win_global<T>(); +#elif defined(ASIO_HAS_PTHREADS) + return posix_global<T>(); +#elif defined(ASIO_HAS_STD_CALL_ONCE) + return std_global<T>(); +#endif +} + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_GLOBAL_HPP diff --git a/lib/asio/detail/handler_alloc_helpers.hpp b/lib/asio/detail/handler_alloc_helpers.hpp new file mode 100644 index 0000000..afefb4d --- /dev/null +++ b/lib/asio/detail/handler_alloc_helpers.hpp @@ -0,0 +1,235 @@ +// +// detail/handler_alloc_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP +#define ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/handler_alloc_hook.hpp" + +#include "asio/detail/push_options.hpp" + +// Calls to asio_handler_allocate and asio_handler_deallocate must be made from +// a namespace that does not contain any overloads of these functions. The +// asio_handler_alloc_helpers namespace is defined here for that purpose. +namespace asio_handler_alloc_helpers { + +template <typename Handler> +inline void* allocate(std::size_t s, Handler& h) +{ +#if !defined(ASIO_HAS_HANDLER_HOOKS) + return ::operator new(s); +#else + using asio::asio_handler_allocate; + return asio_handler_allocate(s, asio::detail::addressof(h)); +#endif +} + +template <typename Handler> +inline void deallocate(void* p, std::size_t s, Handler& h) +{ +#if !defined(ASIO_HAS_HANDLER_HOOKS) + ::operator delete(p); +#else + using asio::asio_handler_deallocate; + asio_handler_deallocate(p, s, asio::detail::addressof(h)); +#endif +} + +} // namespace asio_handler_alloc_helpers + +namespace asio { +namespace detail { + +template <typename Handler, typename T> +class hook_allocator +{ +public: + typedef T value_type; + + template <typename U> + struct rebind + { + typedef hook_allocator<Handler, U> other; + }; + + explicit hook_allocator(Handler& h) + : handler_(h) + { + } + + template <typename U> + hook_allocator(const hook_allocator<Handler, U>& a) + : handler_(a.handler_) + { + } + + T* allocate(std::size_t n) + { + return static_cast<T*>( + asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_)); + } + + void deallocate(T* p, std::size_t n) + { + asio_handler_alloc_helpers::deallocate(p, sizeof(T) * n, handler_); + } + +//private: + Handler& handler_; +}; + +template <typename Handler> +class hook_allocator<Handler, void> +{ +public: + typedef void value_type; + + template <typename U> + struct rebind + { + typedef hook_allocator<Handler, U> other; + }; + + explicit hook_allocator(Handler& h) + : handler_(h) + { + } + + template <typename U> + hook_allocator(const hook_allocator<Handler, U>& a) + : handler_(a.handler_) + { + } + +//private: + Handler& handler_; +}; + +template <typename Handler, typename Allocator> +struct get_hook_allocator +{ + typedef Allocator type; + + static type get(Handler&, const Allocator& a) + { + return a; + } +}; + +template <typename Handler, typename T> +struct get_hook_allocator<Handler, std::allocator<T> > +{ + typedef hook_allocator<Handler, T> type; + + static type get(Handler& handler, const std::allocator<T>&) + { + return type(handler); + } +}; + +} // namespace detail +} // namespace asio + +#define ASIO_DEFINE_HANDLER_PTR(op) \ + struct ptr \ + { \ + Handler* h; \ + op* v; \ + op* p; \ + ~ptr() \ + { \ + reset(); \ + } \ + static op* allocate(Handler& handler) \ + { \ + typedef typename ::asio::associated_allocator< \ + Handler>::type associated_allocator_type; \ + typedef typename ::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::type hook_allocator_type; \ + ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \ + ::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::get( \ + handler, ::asio::get_associated_allocator(handler))); \ + return a.allocate(1); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + typedef typename ::asio::associated_allocator< \ + Handler>::type associated_allocator_type; \ + typedef typename ::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::type hook_allocator_type; \ + ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \ + ::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::get( \ + *h, ::asio::get_associated_allocator(*h))); \ + a.deallocate(static_cast<op*>(v), 1); \ + v = 0; \ + } \ + } \ + } \ + /**/ + +#define ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op) \ + struct ptr \ + { \ + const Alloc* a; \ + void* v; \ + op* p; \ + ~ptr() \ + { \ + reset(); \ + } \ + static op* allocate(const Alloc& a) \ + { \ + typedef typename ::asio::detail::get_recycling_allocator< \ + Alloc>::type recycling_allocator_type; \ + ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \ + ::asio::detail::get_recycling_allocator<Alloc>::get(a)); \ + return a1.allocate(1); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + typedef typename ::asio::detail::get_recycling_allocator< \ + Alloc>::type recycling_allocator_type; \ + ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \ + ::asio::detail::get_recycling_allocator<Alloc>::get(*a)); \ + a1.deallocate(static_cast<op*>(v), 1); \ + v = 0; \ + } \ + } \ + } \ + /**/ + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP diff --git a/lib/asio/detail/handler_cont_helpers.hpp b/lib/asio/detail/handler_cont_helpers.hpp new file mode 100644 index 0000000..110ba94 --- /dev/null +++ b/lib/asio/detail/handler_cont_helpers.hpp @@ -0,0 +1,45 @@ +// +// detail/handler_cont_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP +#define ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/memory.hpp" +#include "asio/handler_continuation_hook.hpp" + +#include "asio/detail/push_options.hpp" + +// Calls to asio_handler_is_continuation must be made from a namespace that +// does not contain overloads of this function. This namespace is defined here +// for that purpose. +namespace asio_handler_cont_helpers { + +template <typename Context> +inline bool is_continuation(Context& context) +{ +#if !defined(ASIO_HAS_HANDLER_HOOKS) + return false; +#else + using asio::asio_handler_is_continuation; + return asio_handler_is_continuation( + asio::detail::addressof(context)); +#endif +} + +} // namespace asio_handler_cont_helpers + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP diff --git a/lib/asio/detail/handler_invoke_helpers.hpp b/lib/asio/detail/handler_invoke_helpers.hpp new file mode 100644 index 0000000..4c65c4c --- /dev/null +++ b/lib/asio/detail/handler_invoke_helpers.hpp @@ -0,0 +1,57 @@ +// +// detail/handler_invoke_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP +#define ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/memory.hpp" +#include "asio/handler_invoke_hook.hpp" + +#include "asio/detail/push_options.hpp" + +// Calls to asio_handler_invoke must be made from a namespace that does not +// contain overloads of this function. The asio_handler_invoke_helpers +// namespace is defined here for that purpose. +namespace asio_handler_invoke_helpers { + +template <typename Function, typename Context> +inline void invoke(Function& function, Context& context) +{ +#if !defined(ASIO_HAS_HANDLER_HOOKS) + Function tmp(function); + tmp(); +#else + using asio::asio_handler_invoke; + asio_handler_invoke(function, asio::detail::addressof(context)); +#endif +} + +template <typename Function, typename Context> +inline void invoke(const Function& function, Context& context) +{ +#if !defined(ASIO_HAS_HANDLER_HOOKS) + Function tmp(function); + tmp(); +#else + using asio::asio_handler_invoke; + asio_handler_invoke(function, asio::detail::addressof(context)); +#endif +} + +} // namespace asio_handler_invoke_helpers + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP diff --git a/lib/asio/detail/handler_tracking.hpp b/lib/asio/detail/handler_tracking.hpp new file mode 100644 index 0000000..83f820e --- /dev/null +++ b/lib/asio/detail/handler_tracking.hpp @@ -0,0 +1,238 @@ +// +// detail/handler_tracking.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_HANDLER_TRACKING_HPP +#define ASIO_DETAIL_HANDLER_TRACKING_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +namespace asio { + +class execution_context; + +} // namespace asio + +#if defined(ASIO_CUSTOM_HANDLER_TRACKING) +# include ASIO_CUSTOM_HANDLER_TRACKING +#elif defined(ASIO_ENABLE_HANDLER_TRACKING) +# include "asio/error_code.hpp" +# include "asio/detail/cstdint.hpp" +# include "asio/detail/static_mutex.hpp" +# include "asio/detail/tss_ptr.hpp" +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_CUSTOM_HANDLER_TRACKING) + +// The user-specified header must define the following macros: +// - ASIO_INHERIT_TRACKED_HANDLER +// - ASIO_ALSO_INHERIT_TRACKED_HANDLER +// - ASIO_HANDLER_TRACKING_INIT +// - ASIO_HANDLER_CREATION(args) +// - ASIO_HANDLER_COMPLETION(args) +// - ASIO_HANDLER_INVOCATION_BEGIN(args) +// - ASIO_HANDLER_INVOCATION_END +// - ASIO_HANDLER_OPERATION(args) +// - ASIO_HANDLER_REACTOR_REGISTRATION(args) +// - ASIO_HANDLER_REACTOR_DEREGISTRATION(args) +// - ASIO_HANDLER_REACTOR_READ_EVENT +// - ASIO_HANDLER_REACTOR_WRITE_EVENT +// - ASIO_HANDLER_REACTOR_ERROR_EVENT +// - ASIO_HANDLER_REACTOR_EVENTS(args) +// - ASIO_HANDLER_REACTOR_OPERATION(args) + +# if !defined(ASIO_ENABLE_HANDLER_TRACKING) +# define ASIO_ENABLE_HANDLER_TRACKING 1 +# endif /// !defined(ASIO_ENABLE_HANDLER_TRACKING) + +#elif defined(ASIO_ENABLE_HANDLER_TRACKING) + +class handler_tracking +{ +public: + class completion; + + // Base class for objects containing tracked handlers. + class tracked_handler + { + private: + // Only the handler_tracking class will have access to the id. + friend class handler_tracking; + friend class completion; + uint64_t id_; + + protected: + // Constructor initialises with no id. + tracked_handler() : id_(0) {} + + // Prevent deletion through this type. + ~tracked_handler() {} + }; + + // Initialise the tracking system. + ASIO_DECL static void init(); + + // Record the creation of a tracked handler. + ASIO_DECL static void creation( + execution_context& context, tracked_handler& h, + const char* object_type, void* object, + uintmax_t native_handle, const char* op_name); + + class completion + { + public: + // Constructor records that handler is to be invoked with no arguments. + ASIO_DECL explicit completion(const tracked_handler& h); + + // Destructor records only when an exception is thrown from the handler, or + // if the memory is being freed without the handler having been invoked. + ASIO_DECL ~completion(); + + // Records that handler is to be invoked with no arguments. + ASIO_DECL void invocation_begin(); + + // Records that handler is to be invoked with one arguments. + ASIO_DECL void invocation_begin(const asio::error_code& ec); + + // Constructor records that handler is to be invoked with two arguments. + ASIO_DECL void invocation_begin( + const asio::error_code& ec, std::size_t bytes_transferred); + + // Constructor records that handler is to be invoked with two arguments. + ASIO_DECL void invocation_begin( + const asio::error_code& ec, int signal_number); + + // Constructor records that handler is to be invoked with two arguments. + ASIO_DECL void invocation_begin( + const asio::error_code& ec, const char* arg); + + // Record that handler invocation has ended. + ASIO_DECL void invocation_end(); + + private: + friend class handler_tracking; + uint64_t id_; + bool invoked_; + completion* next_; + }; + + // Record an operation that is not directly associated with a handler. + ASIO_DECL static void operation(execution_context& context, + const char* object_type, void* object, + uintmax_t native_handle, const char* op_name); + + // Record that a descriptor has been registered with the reactor. + ASIO_DECL static void reactor_registration(execution_context& context, + uintmax_t native_handle, uintmax_t registration); + + // Record that a descriptor has been deregistered from the reactor. + ASIO_DECL static void reactor_deregistration(execution_context& context, + uintmax_t native_handle, uintmax_t registration); + + // Record a reactor-based operation that is associated with a handler. + ASIO_DECL static void reactor_events(execution_context& context, + uintmax_t registration, unsigned events); + + // Record a reactor-based operation that is associated with a handler. + ASIO_DECL static void reactor_operation( + const tracked_handler& h, const char* op_name, + const asio::error_code& ec); + + // Record a reactor-based operation that is associated with a handler. + ASIO_DECL static void reactor_operation( + const tracked_handler& h, const char* op_name, + const asio::error_code& ec, std::size_t bytes_transferred); + + // Write a line of output. + ASIO_DECL static void write_line(const char* format, ...); + +private: + struct tracking_state; + ASIO_DECL static tracking_state* get_state(); +}; + +# define ASIO_INHERIT_TRACKED_HANDLER \ + : public asio::detail::handler_tracking::tracked_handler + +# define ASIO_ALSO_INHERIT_TRACKED_HANDLER \ + , public asio::detail::handler_tracking::tracked_handler + +# define ASIO_HANDLER_TRACKING_INIT \ + asio::detail::handler_tracking::init() + +# define ASIO_HANDLER_CREATION(args) \ + asio::detail::handler_tracking::creation args + +# define ASIO_HANDLER_COMPLETION(args) \ + asio::detail::handler_tracking::completion tracked_completion args + +# define ASIO_HANDLER_INVOCATION_BEGIN(args) \ + tracked_completion.invocation_begin args + +# define ASIO_HANDLER_INVOCATION_END \ + tracked_completion.invocation_end() + +# define ASIO_HANDLER_OPERATION(args) \ + asio::detail::handler_tracking::operation args + +# define ASIO_HANDLER_REACTOR_REGISTRATION(args) \ + asio::detail::handler_tracking::reactor_registration args + +# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \ + asio::detail::handler_tracking::reactor_deregistration args + +# define ASIO_HANDLER_REACTOR_READ_EVENT 1 +# define ASIO_HANDLER_REACTOR_WRITE_EVENT 2 +# define ASIO_HANDLER_REACTOR_ERROR_EVENT 4 + +# define ASIO_HANDLER_REACTOR_EVENTS(args) \ + asio::detail::handler_tracking::reactor_events args + +# define ASIO_HANDLER_REACTOR_OPERATION(args) \ + asio::detail::handler_tracking::reactor_operation args + +#else // defined(ASIO_ENABLE_HANDLER_TRACKING) + +# define ASIO_INHERIT_TRACKED_HANDLER +# define ASIO_ALSO_INHERIT_TRACKED_HANDLER +# define ASIO_HANDLER_TRACKING_INIT (void)0 +# define ASIO_HANDLER_CREATION(args) (void)0 +# define ASIO_HANDLER_COMPLETION(args) (void)0 +# define ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0 +# define ASIO_HANDLER_INVOCATION_END (void)0 +# define ASIO_HANDLER_OPERATION(args) (void)0 +# define ASIO_HANDLER_REACTOR_REGISTRATION(args) (void)0 +# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) (void)0 +# define ASIO_HANDLER_REACTOR_READ_EVENT 0 +# define ASIO_HANDLER_REACTOR_WRITE_EVENT 0 +# define ASIO_HANDLER_REACTOR_ERROR_EVENT 0 +# define ASIO_HANDLER_REACTOR_EVENTS(args) (void)0 +# define ASIO_HANDLER_REACTOR_OPERATION(args) (void)0 + +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/handler_tracking.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_HANDLER_TRACKING_HPP diff --git a/lib/asio/detail/handler_type_requirements.hpp b/lib/asio/detail/handler_type_requirements.hpp new file mode 100644 index 0000000..9181bc5 --- /dev/null +++ b/lib/asio/detail/handler_type_requirements.hpp @@ -0,0 +1,556 @@ +// +// detail/handler_type_requirements.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP +#define ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +// Older versions of gcc have difficulty compiling the sizeof expressions where +// we test the handler type requirements. We'll disable checking of handler type +// requirements for those compilers, but otherwise enable it by default. +#if !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS) +# if !defined(__GNUC__) || (__GNUC__ >= 4) +# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1 +# endif // !defined(__GNUC__) || (__GNUC__ >= 4) +#endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS) + +// With C++0x we can use a combination of enhanced SFINAE and static_assert to +// generate better template error messages. As this technique is not yet widely +// portable, we'll only enable it for tested compilers. +#if !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(ASIO_MSVC) +# if defined(__clang__) +# if __has_feature(__cxx_static_assert__) +# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1 +# endif // __has_feature(cxx_static_assert) +# endif // defined(__clang__) +#endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS) + +#if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) +# include "asio/async_result.hpp" +#endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +namespace asio { +namespace detail { + +#if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +# if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) + +template <typename Handler> +auto zero_arg_copyable_handler_test(Handler h, void*) + -> decltype( + sizeof(Handler(static_cast<const Handler&>(h))), + ((h)()), + char(0)); + +template <typename Handler> +char (&zero_arg_copyable_handler_test(Handler, ...))[2]; + +template <typename Handler, typename Arg1> +auto one_arg_handler_test(Handler h, Arg1* a1) + -> decltype( + sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1)), + char(0)); + +template <typename Handler> +char (&one_arg_handler_test(Handler h, ...))[2]; + +template <typename Handler, typename Arg1, typename Arg2> +auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2) + -> decltype( + sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1, *a2)), + char(0)); + +template <typename Handler> +char (&two_arg_handler_test(Handler, ...))[2]; + +template <typename Handler, typename Arg1, typename Arg2> +auto two_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2) + -> decltype( + sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1, ASIO_MOVE_CAST(Arg2)(*a2))), + char(0)); + +template <typename Handler> +char (&two_arg_move_handler_test(Handler, ...))[2]; + +# define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \ + static_assert(expr, msg); + +# else // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) + +# define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) + +# endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) + +template <typename T> T& lvref(); +template <typename T> T& lvref(T); +template <typename T> const T& clvref(); +template <typename T> const T& clvref(T); +#if defined(ASIO_HAS_MOVE) +template <typename T> T rvref(); +template <typename T> T rvref(T); +#else // defined(ASIO_HAS_MOVE) +template <typename T> const T& rvref(); +template <typename T> const T& rvref(T); +#endif // defined(ASIO_HAS_MOVE) +template <typename T> char argbyv(T); + +template <int> +struct handler_type_requirements +{ +}; + +#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void()) asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::zero_arg_copyable_handler_test( \ + asio::detail::clvref< \ + asio_true_handler_type>(), 0)) == 1, \ + "CompletionHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::clvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()(), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_READ_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, std::size_t)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0), \ + static_cast<const std::size_t*>(0))) == 1, \ + "ReadHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>(), \ + asio::detail::lvref<const std::size_t>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_WRITE_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, std::size_t)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0), \ + static_cast<const std::size_t*>(0))) == 1, \ + "WriteHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>(), \ + asio::detail::lvref<const std::size_t>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_ACCEPT_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::one_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0))) == 1, \ + "AcceptHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \ + handler_type, handler, socket_type) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, socket_type)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_move_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0), \ + static_cast<socket_type*>(0))) == 1, \ + "MoveAcceptHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>(), \ + asio::detail::rvref<socket_type>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_CONNECT_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::one_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0))) == 1, \ + "ConnectHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_RANGE_CONNECT_HANDLER_CHECK( \ + handler_type, handler, endpoint_type) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, endpoint_type)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0), \ + static_cast<const endpoint_type*>(0))) == 1, \ + "RangeConnectHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>(), \ + asio::detail::lvref<const endpoint_type>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, iter_type)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0), \ + static_cast<const iter_type*>(0))) == 1, \ + "IteratorConnectHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>(), \ + asio::detail::lvref<const iter_type>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_RESOLVE_HANDLER_CHECK( \ + handler_type, handler, range_type) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, range_type)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0), \ + static_cast<const range_type*>(0))) == 1, \ + "ResolveHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>(), \ + asio::detail::lvref<const range_type>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_WAIT_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::one_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0))) == 1, \ + "WaitHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_SIGNAL_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, int)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0), \ + static_cast<const int*>(0))) == 1, \ + "SignalHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>(), \ + asio::detail::lvref<const int>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::one_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0))) == 1, \ + "HandshakeHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, std::size_t)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0), \ + static_cast<const std::size_t*>(0))) == 1, \ + "BufferedHandshakeHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>(), \ + asio::detail::lvref<const std::size_t>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#define ASIO_SHUTDOWN_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::one_arg_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0))) == 1, \ + "ShutdownHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + +#else // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_READ_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_WRITE_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_ACCEPT_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \ + handler_type, handler, socket_type) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_CONNECT_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_RANGE_CONNECT_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_RESOLVE_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_WAIT_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_SIGNAL_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#define ASIO_SHUTDOWN_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int ASIO_UNUSED_TYPEDEF + +#endif // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP diff --git a/lib/asio/detail/handler_work.hpp b/lib/asio/detail/handler_work.hpp new file mode 100644 index 0000000..cce5c4b --- /dev/null +++ b/lib/asio/detail/handler_work.hpp @@ -0,0 +1,95 @@ +// +// detail/handler_work.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_HANDLER_WORK_HPP +#define ASIO_DETAIL_HANDLER_WORK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// A helper class template to allow completion handlers to be dispatched +// through either the new executors framework or the old invocaton hook. The +// primary template uses the new executors framework. +template <typename Handler, typename Executor + = typename associated_executor<Handler>::type> +class handler_work +{ +public: + explicit handler_work(Handler& handler) ASIO_NOEXCEPT + : executor_(associated_executor<Handler>::get(handler)) + { + } + + static void start(Handler& handler) ASIO_NOEXCEPT + { + Executor ex(associated_executor<Handler>::get(handler)); + ex.on_work_started(); + } + + ~handler_work() + { + executor_.on_work_finished(); + } + + template <typename Function> + void complete(Function& function, Handler& handler) + { + executor_.dispatch(ASIO_MOVE_CAST(Function)(function), + associated_allocator<Handler>::get(handler)); + } + +private: + // Disallow copying and assignment. + handler_work(const handler_work&); + handler_work& operator=(const handler_work&); + + typename associated_executor<Handler>::type executor_; +}; + +// This specialisation dispatches a handler through the old invocation hook. +// The specialisation is not strictly required for correctness, as the +// system_executor will dispatch through the hook anyway. However, by doing +// this we avoid an extra copy of the handler. +template <typename Handler> +class handler_work<Handler, system_executor> +{ +public: + explicit handler_work(Handler&) ASIO_NOEXCEPT {} + static void start(Handler&) ASIO_NOEXCEPT {} + ~handler_work() {} + + template <typename Function> + void complete(Function& function, Handler& handler) + { + asio_handler_invoke_helpers::invoke(function, handler); + } + +private: + // Disallow copying and assignment. + handler_work(const handler_work&); + handler_work& operator=(const handler_work&); +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_WORK_HPP diff --git a/lib/asio/detail/hash_map.hpp b/lib/asio/detail/hash_map.hpp new file mode 100644 index 0000000..e70970d --- /dev/null +++ b/lib/asio/detail/hash_map.hpp @@ -0,0 +1,331 @@ +// +// detail/hash_map.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_HASH_MAP_HPP +#define ASIO_DETAIL_HASH_MAP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <list> +#include <utility> +#include "asio/detail/assert.hpp" +#include "asio/detail/noncopyable.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# include "asio/detail/socket_types.hpp" +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +inline std::size_t calculate_hash_value(int i) +{ + return static_cast<std::size_t>(i); +} + +inline std::size_t calculate_hash_value(void* p) +{ + return reinterpret_cast<std::size_t>(p) + + (reinterpret_cast<std::size_t>(p) >> 3); +} + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +inline std::size_t calculate_hash_value(SOCKET s) +{ + return static_cast<std::size_t>(s); +} +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +// Note: assumes K and V are POD types. +template <typename K, typename V> +class hash_map + : private noncopyable +{ +public: + // The type of a value in the map. + typedef std::pair<K, V> value_type; + + // The type of a non-const iterator over the hash map. + typedef typename std::list<value_type>::iterator iterator; + + // The type of a const iterator over the hash map. + typedef typename std::list<value_type>::const_iterator const_iterator; + + // Constructor. + hash_map() + : size_(0), + buckets_(0), + num_buckets_(0) + { + } + + // Destructor. + ~hash_map() + { + delete[] buckets_; + } + + // Get an iterator for the beginning of the map. + iterator begin() + { + return values_.begin(); + } + + // Get an iterator for the beginning of the map. + const_iterator begin() const + { + return values_.begin(); + } + + // Get an iterator for the end of the map. + iterator end() + { + return values_.end(); + } + + // Get an iterator for the end of the map. + const_iterator end() const + { + return values_.end(); + } + + // Check whether the map is empty. + bool empty() const + { + return values_.empty(); + } + + // Find an entry in the map. + iterator find(const K& k) + { + if (num_buckets_) + { + size_t bucket = calculate_hash_value(k) % num_buckets_; + iterator it = buckets_[bucket].first; + if (it == values_.end()) + return values_.end(); + iterator end_it = buckets_[bucket].last; + ++end_it; + while (it != end_it) + { + if (it->first == k) + return it; + ++it; + } + } + return values_.end(); + } + + // Find an entry in the map. + const_iterator find(const K& k) const + { + if (num_buckets_) + { + size_t bucket = calculate_hash_value(k) % num_buckets_; + const_iterator it = buckets_[bucket].first; + if (it == values_.end()) + return it; + const_iterator end_it = buckets_[bucket].last; + ++end_it; + while (it != end_it) + { + if (it->first == k) + return it; + ++it; + } + } + return values_.end(); + } + + // Insert a new entry into the map. + std::pair<iterator, bool> insert(const value_type& v) + { + if (size_ + 1 >= num_buckets_) + rehash(hash_size(size_ + 1)); + size_t bucket = calculate_hash_value(v.first) % num_buckets_; + iterator it = buckets_[bucket].first; + if (it == values_.end()) + { + buckets_[bucket].first = buckets_[bucket].last = + values_insert(values_.end(), v); + ++size_; + return std::pair<iterator, bool>(buckets_[bucket].last, true); + } + iterator end_it = buckets_[bucket].last; + ++end_it; + while (it != end_it) + { + if (it->first == v.first) + return std::pair<iterator, bool>(it, false); + ++it; + } + buckets_[bucket].last = values_insert(end_it, v); + ++size_; + return std::pair<iterator, bool>(buckets_[bucket].last, true); + } + + // Erase an entry from the map. + void erase(iterator it) + { + ASIO_ASSERT(it != values_.end()); + ASIO_ASSERT(num_buckets_ != 0); + + 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) + buckets_[bucket].first = buckets_[bucket].last = values_.end(); + else if (is_first) + ++buckets_[bucket].first; + else if (is_last) + --buckets_[bucket].last; + + values_erase(it); + --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() + { + // Clear the values. + values_.clear(); + size_ = 0; + + // Initialise all buckets to empty. + iterator end_it = values_.end(); + for (size_t i = 0; i < num_buckets_; ++i) + buckets_[i].first = buckets_[i].last = end_it; + } + +private: + // Calculate the hash size for the specified number of elements. + static std::size_t hash_size(std::size_t num_elems) + { + static std::size_t sizes[] = + { +#if defined(ASIO_HASH_MAP_BUCKETS) + ASIO_HASH_MAP_BUCKETS +#else // ASIO_HASH_MAP_BUCKETS + 3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, + 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, + 12582917, 25165843 +#endif // ASIO_HASH_MAP_BUCKETS + }; + const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1; + for (std::size_t i = 0; i < nth_size; ++i) + if (num_elems < sizes[i]) + return sizes[i]; + return sizes[nth_size]; + } + + // Re-initialise the hash from the values already contained in the list. + void rehash(std::size_t num_buckets) + { + if (num_buckets == num_buckets_) + return; + ASIO_ASSERT(num_buckets != 0); + + iterator end_iter = values_.end(); + + // Update number of buckets and initialise all buckets to empty. + bucket_type* tmp = new bucket_type[num_buckets]; + delete[] buckets_; + buckets_ = tmp; + num_buckets_ = num_buckets; + for (std::size_t i = 0; i < num_buckets_; ++i) + buckets_[i].first = buckets_[i].last = end_iter; + + // Put all values back into the hash. + iterator iter = values_.begin(); + while (iter != end_iter) + { + std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_; + if (buckets_[bucket].last == end_iter) + { + buckets_[bucket].first = buckets_[bucket].last = iter++; + } + else if (++buckets_[bucket].last == iter) + { + ++iter; + } + else + { + values_.splice(buckets_[bucket].last, values_, iter++); + --buckets_[bucket].last; + } + } + } + + // Insert an element into the values list by splicing from the spares list, + // if a spare is available, and otherwise by inserting a new element. + iterator values_insert(iterator it, const value_type& v) + { + if (spares_.empty()) + { + return values_.insert(it, v); + } + else + { + spares_.front() = v; + values_.splice(it, spares_, spares_.begin()); + return --it; + } + } + + // Erase an element from the values list by splicing it to the spares list. + void values_erase(iterator it) + { + *it = value_type(); + spares_.splice(spares_.begin(), values_, it); + } + + // The number of elements in the hash. + std::size_t size_; + + // The list of all values in the hash map. + std::list<value_type> values_; + + // The list of spare nodes waiting to be recycled. Assumes that POD types only + // are stored in the hash map. + std::list<value_type> spares_; + + // The type for a bucket in the hash table. + struct bucket_type + { + iterator first; + iterator last; + }; + + // The buckets in the hash. + bucket_type* buckets_; + + // The number of buckets in the hash. + std::size_t num_buckets_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HASH_MAP_HPP diff --git a/lib/asio/detail/impl/buffer_sequence_adapter.ipp b/lib/asio/detail/impl/buffer_sequence_adapter.ipp new file mode 100644 index 0000000..323c8ad --- /dev/null +++ b/lib/asio/detail/impl/buffer_sequence_adapter.ipp @@ -0,0 +1,118 @@ +// +// detail/impl/buffer_sequence_adapter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP +#define ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include <robuffer.h> +#include <windows.storage.streams.h> +#include <wrl/implements.h> +#include "asio/detail/buffer_sequence_adapter.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class winrt_buffer_impl : + public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags< + Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>, + ABI::Windows::Storage::Streams::IBuffer, + Windows::Storage::Streams::IBufferByteAccess> +{ +public: + explicit winrt_buffer_impl(const asio::const_buffer& b) + { + bytes_ = const_cast<byte*>(static_cast<const byte*>(b.data())); + length_ = b.size(); + capacity_ = b.size(); + } + + explicit winrt_buffer_impl(const asio::mutable_buffer& b) + { + bytes_ = static_cast<byte*>(b.data()); + length_ = 0; + capacity_ = b.size(); + } + + ~winrt_buffer_impl() + { + } + + STDMETHODIMP Buffer(byte** value) + { + *value = bytes_; + return S_OK; + } + + STDMETHODIMP get_Capacity(UINT32* value) + { + *value = capacity_; + return S_OK; + } + + STDMETHODIMP get_Length(UINT32 *value) + { + *value = length_; + return S_OK; + } + + STDMETHODIMP put_Length(UINT32 value) + { + if (value > capacity_) + return E_INVALIDARG; + length_ = value; + return S_OK; + } + +private: + byte* bytes_; + UINT32 length_; + UINT32 capacity_; +}; + +void buffer_sequence_adapter_base::init_native_buffer( + buffer_sequence_adapter_base::native_buffer_type& buf, + const asio::mutable_buffer& buffer) +{ + std::memset(&buf, 0, sizeof(native_buffer_type)); + Microsoft::WRL::ComPtr<IInspectable> insp + = Microsoft::WRL::Make<winrt_buffer_impl>(buffer); + buf = reinterpret_cast<Windows::Storage::Streams::IBuffer^>(insp.Get()); +} + +void buffer_sequence_adapter_base::init_native_buffer( + buffer_sequence_adapter_base::native_buffer_type& buf, + const asio::const_buffer& buffer) +{ + std::memset(&buf, 0, sizeof(native_buffer_type)); + Microsoft::WRL::ComPtr<IInspectable> insp + = Microsoft::WRL::Make<winrt_buffer_impl>(buffer); + Platform::Object^ buf_obj = reinterpret_cast<Platform::Object^>(insp.Get()); + buf = reinterpret_cast<Windows::Storage::Streams::IBuffer^>(insp.Get()); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP diff --git a/lib/asio/detail/impl/descriptor_ops.ipp b/lib/asio/detail/impl/descriptor_ops.ipp new file mode 100644 index 0000000..1af643f --- /dev/null +++ b/lib/asio/detail/impl/descriptor_ops.ipp @@ -0,0 +1,474 @@ +// +// detail/impl/descriptor_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP +#define ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cerrno> +#include "asio/detail/descriptor_ops.hpp" +#include "asio/error.hpp" + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace descriptor_ops { + +int open(const char* path, int flags, asio::error_code& ec) +{ + errno = 0; + int result = error_wrapper(::open(path, flags), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +} + +int close(int d, state_type& state, asio::error_code& ec) +{ + int result = 0; + if (d != -1) + { + errno = 0; + result = error_wrapper(::close(d), ec); + + if (result != 0 + && (ec == asio::error::would_block + || ec == asio::error::try_again)) + { + // According to UNIX Network Programming Vol. 1, it is possible for + // close() to fail with EWOULDBLOCK under certain circumstances. What + // isn't clear is the state of the descriptor after this error. The one + // current OS where this behaviour is seen, Windows, says that the socket + // remains open. Therefore we'll put the descriptor back into blocking + // mode and have another attempt at closing it. +#if defined(__SYMBIAN32__) + int flags = ::fcntl(d, F_GETFL, 0); + if (flags >= 0) + ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = 0; + ::ioctl(d, FIONBIO, &arg); +#endif // defined(__SYMBIAN32__) + state &= ~non_blocking; + + errno = 0; + result = error_wrapper(::close(d), ec); + } + } + + if (result == 0) + ec = asio::error_code(); + return result; +} + +bool set_user_non_blocking(int d, state_type& state, + bool value, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return false; + } + + errno = 0; +#if defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); + if (result >= 0) + { + errno = 0; + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = error_wrapper(::fcntl(d, F_SETFL, flag), ec); + } +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); +#endif // defined(__SYMBIAN32__) + + if (result >= 0) + { + ec = asio::error_code(); + if (value) + state |= user_set_non_blocking; + else + { + // Clearing the user-set non-blocking mode always overrides any + // internally-set non-blocking flag. Any subsequent asynchronous + // operations will need to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + return true; + } + + return false; +} + +bool set_internal_non_blocking(int d, state_type& state, + bool value, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return false; + } + + if (!value && (state & user_set_non_blocking)) + { + // It does not make sense to clear the internal non-blocking flag if the + // user still wants non-blocking behaviour. Return an error and let the + // caller figure out whether to update the user-set non-blocking flag. + ec = asio::error::invalid_argument; + return false; + } + + errno = 0; +#if defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); + if (result >= 0) + { + errno = 0; + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = error_wrapper(::fcntl(d, F_SETFL, flag), ec); + } +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); +#endif // defined(__SYMBIAN32__) + + if (result >= 0) + { + ec = asio::error_code(); + if (value) + state |= internal_non_blocking; + else + state &= ~internal_non_blocking; + return true; + } + + return false; +} + +std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty) + { + ec = asio::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + errno = 0; + signed_size_type bytes = error_wrapper(::readv( + d, bufs, static_cast<int>(count)), ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + +bool non_blocking_read(int d, buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + errno = 0; + signed_size_type bytes = error_wrapper(::readv( + d, bufs, static_cast<int>(count)), ec); + + // Check for end of stream. + if (bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes > 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +std::size_t sync_write(int d, state_type state, const buf* bufs, + std::size_t count, bool all_empty, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (all_empty) + { + ec = asio::error_code(); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + errno = 0; + signed_size_type bytes = error_wrapper(::writev( + d, bufs, static_cast<int>(count)), ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + +bool non_blocking_write(int d, const buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + errno = 0; + signed_size_type bytes = error_wrapper(::writev( + d, bufs, static_cast<int>(count)), ec); + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::ioctl(d, cmd, arg), ec); + + if (result >= 0) + { + ec = asio::error_code(); + + // 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 (cmd == static_cast<long>(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // 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. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int fcntl(int d, int cmd, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::fcntl(d, cmd), ec); + if (result != -1) + ec = asio::error_code(); + return result; +} + +int fcntl(int d, int cmd, long arg, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::fcntl(d, cmd, arg), ec); + if (result != -1) + ec = asio::error_code(); + return result; +} + +int poll_read(int d, state_type state, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLIN; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : -1; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, timeout), ec); + if (result == 0) + ec = (state & user_set_non_blocking) + ? asio::error::would_block : asio::error_code(); + else if (result > 0) + ec = asio::error_code(); + return result; +} + +int poll_write(int d, state_type state, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLOUT; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : -1; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, timeout), ec); + if (result == 0) + ec = (state & user_set_non_blocking) + ? asio::error::would_block : asio::error_code(); + else if (result > 0) + ec = asio::error_code(); + return result; +} + +int poll_error(int d, state_type state, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLPRI | POLLERR | POLLHUP; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : -1; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, timeout), ec); + if (result == 0) + ec = (state & user_set_non_blocking) + ? asio::error::would_block : asio::error_code(); + else if (result > 0) + ec = asio::error_code(); + return result; +} + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP diff --git a/lib/asio/detail/impl/dev_poll_reactor.hpp b/lib/asio/detail/impl/dev_poll_reactor.hpp new file mode 100644 index 0000000..4cd8aaf --- /dev/null +++ b/lib/asio/detail/impl/dev_poll_reactor.hpp @@ -0,0 +1,91 @@ +// +// detail/impl/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP +#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_DEV_POLL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +template <typename Time_Traits> +void dev_poll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + interrupter_.interrupt(); +} + +template <typename Time_Traits> +std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template <typename Time_Traits> +void dev_poll_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_DEV_POLL) + +#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP diff --git a/lib/asio/detail/impl/dev_poll_reactor.ipp b/lib/asio/detail/impl/dev_poll_reactor.ipp new file mode 100644 index 0000000..1ca376c --- /dev/null +++ b/lib/asio/detail/impl/dev_poll_reactor.ipp @@ -0,0 +1,446 @@ +// +// detail/impl/dev_poll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP +#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_DEV_POLL) + +#include "asio/detail/dev_poll_reactor.hpp" +#include "asio/detail/assert.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +dev_poll_reactor::dev_poll_reactor(asio::execution_context& ctx) + : asio::detail::execution_context_service_base<dev_poll_reactor>(ctx), + scheduler_(use_service<scheduler>(ctx)), + mutex_(), + dev_poll_fd_(do_dev_poll_create()), + interrupter_(), + shutdown_(false) +{ + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); +} + +dev_poll_reactor::~dev_poll_reactor() +{ + shutdown(); + ::close(dev_poll_fd_); +} + +void dev_poll_reactor::shutdown() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue<operation> ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void dev_poll_reactor::notify_fork( + asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == asio::execution_context::fork_child) + { + detail::mutex::scoped_lock lock(mutex_); + + if (dev_poll_fd_ != -1) + ::close(dev_poll_fd_); + dev_poll_fd_ = -1; + dev_poll_fd_ = do_dev_poll_create(); + + interrupter_.recreate(); + + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + + // Re-register all descriptors with /dev/poll. The changes will be written + // to the /dev/poll descriptor the next time the reactor is run. + for (int i = 0; i < max_ops; ++i) + { + reactor_op_queue<socket_type>::iterator iter = op_queue_[i].begin(); + reactor_op_queue<socket_type>::iterator end = op_queue_[i].end(); + for (; iter != end; ++iter) + { + ::pollfd& pending_ev = add_pending_event_change(iter->first); + pending_ev.events |= POLLERR | POLLHUP; + switch (i) + { + case read_op: pending_ev.events |= POLLIN; break; + case write_op: pending_ev.events |= POLLOUT; break; + case except_op: pending_ev.events |= POLLPRI; break; + default: break; + } + } + } + interrupter_.interrupt(); + } +} + +void dev_poll_reactor::init_task() +{ + scheduler_.init_task(); +} + +int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&) +{ + return 0; +} + +int dev_poll_reactor::register_internal_descriptor(int op_type, + socket_type descriptor, per_descriptor_data&, reactor_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + op_queue_[op_type].enqueue_operation(descriptor, op); + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLERR | POLLHUP; + switch (op_type) + { + case read_op: ev.events |= POLLIN; break; + case write_op: ev.events |= POLLOUT; break; + case except_op: ev.events |= POLLPRI; break; + default: break; + } + interrupter_.interrupt(); + + return 0; +} + +void dev_poll_reactor::move_descriptor(socket_type, + dev_poll_reactor::per_descriptor_data&, + dev_poll_reactor::per_descriptor_data&) +{ +} + +void dev_poll_reactor::start_op(int op_type, socket_type descriptor, + dev_poll_reactor::per_descriptor_data&, reactor_op* op, + bool is_continuation, bool allow_speculative) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + if (allow_speculative) + { + if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) + { + if (!op_queue_[op_type].has_operation(descriptor)) + { + if (op->perform()) + { + lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + } + } + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + scheduler_.work_started(); + if (first) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLERR | POLLHUP; + if (op_type == read_op + || op_queue_[read_op].has_operation(descriptor)) + ev.events |= POLLIN; + if (op_type == write_op + || op_queue_[write_op].has_operation(descriptor)) + ev.events |= POLLOUT; + if (op_type == except_op + || op_queue_[except_op].has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } +} + +void dev_poll_reactor::cancel_ops(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void dev_poll_reactor::deregister_descriptor(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&, bool) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from /dev/poll. + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLREMOVE; + interrupter_.interrupt(); + + // Cancel any outstanding operations associated with the descriptor. + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void dev_poll_reactor::deregister_internal_descriptor( + socket_type descriptor, dev_poll_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from /dev/poll. Since this function is only called + // during a fork, we can apply the change immediately. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + + // Destroy all operations associated with the descriptor. + op_queue<operation> ops; + asio::error_code ec; + for (int i = 0; i < max_ops; ++i) + op_queue_[i].cancel_operations(descriptor, ops, ec); +} + +void dev_poll_reactor::cleanup_descriptor_data( + dev_poll_reactor::per_descriptor_data&) +{ +} + +void dev_poll_reactor::run(long usec, op_queue<operation>& ops) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (usec == 0 && 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(); + if (events_size > 0) + { + errno = 0; + int result = ::write(dev_poll_fd_, + &pending_event_changes_[0], events_size); + if (result != static_cast<int>(events_size)) + { + asio::error_code ec = asio::error_code( + errno, asio::error::get_system_category()); + for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) + { + int descriptor = pending_event_changes_[i].fd; + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + pending_event_changes_.clear(); + pending_event_change_index_.clear(); + } + + // Calculate timeout. + int timeout; + if (usec == 0) + timeout = 0; + else + { + timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1); + timeout = get_timeout(timeout); + } + lock.unlock(); + + // Block on the /dev/poll descriptor. + ::pollfd events[128] = { { 0, 0, 0 } }; + ::dvpoll dp = { 0, 0, 0 }; + dp.dp_fds = events; + dp.dp_nfds = 128; + dp.dp_timeout = timeout; + int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); + + lock.lock(); + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].fd; + if (descriptor == interrupter_.read_descriptor()) + { + interrupter_.reset(); + } + else + { + bool more_reads = false; + bool more_writes = false; + bool more_except = false; + + // 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 = + op_queue_[except_op].perform_operations(descriptor, ops); + else + more_except = op_queue_[except_op].has_operation(descriptor); + + if (events[i].events & (POLLIN | POLLERR | POLLHUP)) + more_reads = op_queue_[read_op].perform_operations(descriptor, ops); + else + more_reads = op_queue_[read_op].has_operation(descriptor); + + if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) + more_writes = op_queue_[write_op].perform_operations(descriptor, ops); + else + more_writes = op_queue_[write_op].has_operation(descriptor); + + if ((events[i].events & (POLLERR | POLLHUP)) != 0 + && !more_except && !more_reads && !more_writes) + { + // If we have an event and no operations associated with the + // descriptor then we need to delete the descriptor from /dev/poll. + // The poll operation can produce POLLHUP or POLLERR events when there + // is no operation pending, so if we do not remove the descriptor we + // can end up in a tight polling loop. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + } + else + { + ::pollfd ev = { 0, 0, 0 }; + ev.fd = descriptor; + ev.events = POLLERR | POLLHUP; + if (more_reads) + ev.events |= POLLIN; + if (more_writes) + ev.events |= POLLOUT; + if (more_except) + ev.events |= POLLPRI; + ev.revents = 0; + int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); + if (result != sizeof(ev)) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + } + } + timer_queues_.get_ready_timers(ops); +} + +void dev_poll_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +int dev_poll_reactor::do_dev_poll_create() +{ + int fd = ::open("/dev/poll", O_RDWR); + if (fd == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "/dev/poll"); + } + return fd; +} + +void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +int dev_poll_reactor::get_timeout(int msec) +{ + // 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. + const int max_msec = 5 * 60 * 1000; + return timer_queues_.wait_duration_msec( + (msec < 0 || max_msec < msec) ? max_msec : msec); +} + +void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec) +{ + bool need_interrupt = false; + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + scheduler_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + +::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor) +{ + hash_map<int, std::size_t>::iterator iter + = pending_event_change_index_.find(descriptor); + if (iter == pending_event_change_index_.end()) + { + std::size_t index = pending_event_changes_.size(); + pending_event_changes_.reserve(pending_event_changes_.size() + 1); + pending_event_change_index_.insert(std::make_pair(descriptor, index)); + pending_event_changes_.push_back(::pollfd()); + pending_event_changes_[index].fd = descriptor; + pending_event_changes_[index].revents = 0; + return pending_event_changes_[index]; + } + else + { + return pending_event_changes_[iter->second]; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_DEV_POLL) + +#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP diff --git a/lib/asio/detail/impl/epoll_reactor.hpp b/lib/asio/detail/impl/epoll_reactor.hpp new file mode 100644 index 0000000..f990059 --- /dev/null +++ b/lib/asio/detail/impl/epoll_reactor.hpp @@ -0,0 +1,89 @@ +// +// detail/impl/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP +#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(ASIO_HAS_EPOLL) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +template <typename Time_Traits> +void epoll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op) +{ + mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + update_timeout(); +} + +template <typename Time_Traits> +std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template <typename Time_Traits> +void epoll_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_EPOLL) + +#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP diff --git a/lib/asio/detail/impl/epoll_reactor.ipp b/lib/asio/detail/impl/epoll_reactor.ipp new file mode 100644 index 0000000..65584a4 --- /dev/null +++ b/lib/asio/detail/impl/epoll_reactor.ipp @@ -0,0 +1,787 @@ +// +// detail/impl/epoll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP +#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_EPOLL) + +#include <cstddef> +#include <sys/epoll.h> +#include "asio/detail/epoll_reactor.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#if defined(ASIO_HAS_TIMERFD) +# include <sys/timerfd.h> +#endif // defined(ASIO_HAS_TIMERFD) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +epoll_reactor::epoll_reactor(asio::execution_context& ctx) + : execution_context_service_base<epoll_reactor>(ctx), + scheduler_(use_service<scheduler>(ctx)), + mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), + interrupter_(), + epoll_fd_(do_epoll_create()), + timer_fd_(do_timerfd_create()), + shutdown_(false), + registered_descriptors_mutex_(mutex_.enabled()) +{ + // Add the interrupter's descriptor to epoll. + epoll_event ev = { 0, { 0 } }; + 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); + } +} + +epoll_reactor::~epoll_reactor() +{ + if (epoll_fd_ != -1) + close(epoll_fd_); + if (timer_fd_ != -1) + close(timer_fd_); +} + +void epoll_reactor::shutdown() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue<operation> ops; + + while (descriptor_state* state = registered_descriptors_.first()) + { + for (int i = 0; i < max_ops; ++i) + ops.push(state->op_queue_[i]); + state->shutdown_ = true; + registered_descriptors_.free(state); + } + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void epoll_reactor::notify_fork( + asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == asio::execution_context::fork_child) + { + if (epoll_fd_ != -1) + ::close(epoll_fd_); + epoll_fd_ = -1; + epoll_fd_ = do_epoll_create(); + + if (timer_fd_ != -1) + ::close(timer_fd_); + timer_fd_ = -1; + timer_fd_ = do_timerfd_create(); + + interrupter_.recreate(); + + // Add the interrupter's descriptor to epoll. + epoll_event ev = { 0, { 0 } }; + 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); + } + + update_timeout(); + + // Re-register all descriptors with epoll. + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + for (descriptor_state* state = registered_descriptors_.first(); + state != 0; state = state->next_) + { + ev.events = state->registered_events_; + ev.data.ptr = state; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, state->descriptor_, &ev); + if (result != 0) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "epoll re-registration"); + } + } + } +} + +void epoll_reactor::init_task() +{ + scheduler_.init_task(); +} + +int epoll_reactor::register_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + descriptor_data = allocate_descriptor_state(); + + ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + + { + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + descriptor_data->reactor_ = this; + descriptor_data->descriptor_ = descriptor; + descriptor_data->shutdown_ = false; + for (int i = 0; i < max_ops; ++i) + descriptor_data->try_speculative_[i] = true; + } + + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET; + descriptor_data->registered_events_ = ev.events; + ev.data.ptr = descriptor_data; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + { + if (errno == EPERM) + { + // This file descriptor type is not supported by epoll. However, if it is + // a regular file then operations on it will not block. We will allow + // this descriptor to be used and fail later if an operation on it would + // otherwise require a trip through the reactor. + descriptor_data->registered_events_ = 0; + return 0; + } + return errno; + } + + return 0; +} + +int epoll_reactor::register_internal_descriptor( + int op_type, socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op) +{ + descriptor_data = allocate_descriptor_state(); + + ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + + { + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + descriptor_data->reactor_ = this; + descriptor_data->descriptor_ = descriptor; + descriptor_data->shutdown_ = false; + descriptor_data->op_queue_[op_type].push(op); + for (int i = 0; i < max_ops; ++i) + descriptor_data->try_speculative_[i] = true; + } + + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET; + descriptor_data->registered_events_ = ev.events; + ev.data.ptr = descriptor_data; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + return errno; + + return 0; +} + +void epoll_reactor::move_descriptor(socket_type, + epoll_reactor::per_descriptor_data& target_descriptor_data, + epoll_reactor::per_descriptor_data& source_descriptor_data) +{ + target_descriptor_data = source_descriptor_data; + source_descriptor_data = 0; +} + +void epoll_reactor::start_op(int op_type, socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) +{ + if (!descriptor_data) + { + op->ec_ = asio::error::bad_descriptor; + post_immediate_completion(op, is_continuation); + return; + } + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (descriptor_data->shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + if (descriptor_data->op_queue_[op_type].empty()) + { + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) + { + if (descriptor_data->try_speculative_[op_type]) + { + if (reactor_op::status status = op->perform()) + { + if (status == reactor_op::done_and_exhausted) + if (descriptor_data->registered_events_ != 0) + descriptor_data->try_speculative_[op_type] = false; + descriptor_lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + + if (descriptor_data->registered_events_ == 0) + { + op->ec_ = asio::error::operation_not_supported; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + if (op_type == write_op) + { + if ((descriptor_data->registered_events_ & EPOLLOUT) == 0) + { + epoll_event ev = { 0, { 0 } }; + ev.events = descriptor_data->registered_events_ | EPOLLOUT; + ev.data.ptr = descriptor_data; + if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev) == 0) + { + descriptor_data->registered_events_ |= ev.events; + } + else + { + op->ec_ = asio::error_code(errno, + asio::error::get_system_category()); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + } + } + else if (descriptor_data->registered_events_ == 0) + { + op->ec_ = asio::error::operation_not_supported; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + else + { + if (op_type == write_op) + { + descriptor_data->registered_events_ |= EPOLLOUT; + } + + epoll_event ev = { 0, { 0 } }; + ev.events = descriptor_data->registered_events_; + ev.data.ptr = descriptor_data; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + } + } + + descriptor_data->op_queue_[op_type].push(op); + scheduler_.work_started(); +} + +void epoll_reactor::cancel_ops(socket_type, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + scheduler_.post_deferred_completions(ops); +} + +void epoll_reactor::deregister_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, bool closing) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + if (closing) + { + // The descriptor will be automatically removed from the epoll set when + // it is closed. + } + else if (descriptor_data->registered_events_ != 0) + { + epoll_event ev = { 0, { 0 } }; + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); + } + + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + + scheduler_.post_deferred_completions(ops); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void epoll_reactor::deregister_internal_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + epoll_event ev = { 0, { 0 } }; + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); + + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + ops.push(descriptor_data->op_queue_[i]); + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void epoll_reactor::cleanup_descriptor_data( + per_descriptor_data& descriptor_data) +{ + if (descriptor_data) + { + free_descriptor_state(descriptor_data); + descriptor_data = 0; + } +} + +void epoll_reactor::run(long usec, op_queue<operation>& ops) +{ + // This code relies on the fact that the scheduler queues the reactor task + // behind all descriptor operations generated by this function. This means, + // that by the time we reach this point, any previously returned descriptor + // operations have already been dequeued. Therefore it is now safe for us to + // reuse and return them for the scheduler to queue again. + + // Calculate timeout. Check the timer queues only if timerfd is not in use. + int timeout; + if (usec == 0) + timeout = 0; + else + { + timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1); + if (timer_fd_ == -1) + { + mutex::scoped_lock lock(mutex_); + timeout = get_timeout(timeout); + } + } + + // Block on the epoll descriptor. + epoll_event events[128]; + int num_events = epoll_wait(epoll_fd_, events, 128, timeout); + +#if defined(ASIO_ENABLE_HANDLER_TRACKING) + // Trace the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) + { + // Ignore. + } +# if defined(ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + // Ignore. + } +# endif // defined(ASIO_HAS_TIMERFD) + else + { + unsigned event_mask = 0; + if ((events[i].events & EPOLLIN) != 0) + event_mask |= ASIO_HANDLER_REACTOR_READ_EVENT; + if ((events[i].events & EPOLLOUT)) + event_mask |= ASIO_HANDLER_REACTOR_WRITE_EVENT; + if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0) + event_mask |= ASIO_HANDLER_REACTOR_ERROR_EVENT; + ASIO_HANDLER_REACTOR_EVENTS((context(), + reinterpret_cast<uintmax_t>(ptr), event_mask)); + } + } +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +#if defined(ASIO_HAS_TIMERFD) + bool check_timers = (timer_fd_ == -1); +#else // defined(ASIO_HAS_TIMERFD) + bool check_timers = true; +#endif // defined(ASIO_HAS_TIMERFD) + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) + { + // 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(ASIO_HAS_TIMERFD) + if (timer_fd_ == -1) + check_timers = true; +#else // defined(ASIO_HAS_TIMERFD) + check_timers = true; +#endif // defined(ASIO_HAS_TIMERFD) + } +#if defined(ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + check_timers = true; + } +#endif // defined(ASIO_HAS_TIMERFD) + else + { + // The descriptor operation doesn't count as work in and of itself, so we + // don't call work_started() here. This still allows the scheduler to + // stop if the only remaining operations are descriptor operations. + descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr); + if (!ops.is_enqueued(descriptor_data)) + { + descriptor_data->set_ready_events(events[i].events); + ops.push(descriptor_data); + } + else + { + descriptor_data->add_ready_events(events[i].events); + } + } + } + + if (check_timers) + { + mutex::scoped_lock common_lock(mutex_); + timer_queues_.get_ready_timers(ops); + +#if defined(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(ASIO_HAS_TIMERFD) + } +} + +void epoll_reactor::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); +} + +int epoll_reactor::do_epoll_create() +{ +#if defined(EPOLL_CLOEXEC) + int fd = epoll_create1(EPOLL_CLOEXEC); +#else // defined(EPOLL_CLOEXEC) + int fd = -1; + errno = EINVAL; +#endif // defined(EPOLL_CLOEXEC) + + if (fd == -1 && (errno == EINVAL || errno == ENOSYS)) + { + fd = epoll_create(epoll_size); + if (fd != -1) + ::fcntl(fd, F_SETFD, FD_CLOEXEC); + } + + if (fd == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "epoll"); + } + + return fd; +} + +int epoll_reactor::do_timerfd_create() +{ +#if defined(ASIO_HAS_TIMERFD) +# if defined(TFD_CLOEXEC) + int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); +# else // defined(TFD_CLOEXEC) + int fd = -1; + errno = EINVAL; +# endif // defined(TFD_CLOEXEC) + + if (fd == -1 && errno == EINVAL) + { + fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (fd != -1) + ::fcntl(fd, F_SETFD, FD_CLOEXEC); + } + + return fd; +#else // defined(ASIO_HAS_TIMERFD) + return -1; +#endif // defined(ASIO_HAS_TIMERFD) +} + +epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state() +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); +} + +void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s) +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + registered_descriptors_.free(s); +} + +void epoll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +void epoll_reactor::update_timeout() +{ +#if defined(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(ASIO_HAS_TIMERFD) + interrupt(); +} + +int epoll_reactor::get_timeout(int msec) +{ + // 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. + const int max_msec = 5 * 60 * 1000; + return timer_queues_.wait_duration_msec( + (msec < 0 || max_msec < msec) ? max_msec : msec); +} + +#if defined(ASIO_HAS_TIMERFD) +int epoll_reactor::get_timeout(itimerspec& ts) +{ + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + + 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(ASIO_HAS_TIMERFD) + +struct epoll_reactor::perform_io_cleanup_on_block_exit +{ + explicit perform_io_cleanup_on_block_exit(epoll_reactor* r) + : reactor_(r), first_op_(0) + { + } + + ~perform_io_cleanup_on_block_exit() + { + if (first_op_) + { + // Post the remaining completed operations for invocation. + if (!ops_.empty()) + reactor_->scheduler_.post_deferred_completions(ops_); + + // A user-initiated operation has completed, but there's no need to + // explicitly call work_finished() here. Instead, we'll take advantage of + // the fact that the scheduler will call work_finished() once we return. + } + else + { + // No user-initiated operations have completed, so we need to compensate + // for the work_finished() call that the scheduler will make once this + // operation returns. + reactor_->scheduler_.compensating_work_started(); + } + } + + epoll_reactor* reactor_; + op_queue<operation> ops_; + operation* first_op_; +}; + +epoll_reactor::descriptor_state::descriptor_state(bool locking) + : operation(&epoll_reactor::descriptor_state::do_complete), + mutex_(locking) +{ +} + +operation* epoll_reactor::descriptor_state::perform_io(uint32_t events) +{ + mutex_.lock(); + perform_io_cleanup_on_block_exit io_cleanup(reactor_); + mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events & (flag[j] | EPOLLERR | EPOLLHUP)) + { + try_speculative_[j] = true; + while (reactor_op* op = op_queue_[j].front()) + { + if (reactor_op::status status = op->perform()) + { + op_queue_[j].pop(); + io_cleanup.ops_.push(op); + if (status == reactor_op::done_and_exhausted) + { + try_speculative_[j] = false; + break; + } + } + else + break; + } + } + } + + // The first operation will be returned for completion now. The others will + // be posted for later by the io_cleanup object's destructor. + io_cleanup.first_op_ = io_cleanup.ops_.front(); + io_cleanup.ops_.pop(); + return io_cleanup.first_op_; +} + +void epoll_reactor::descriptor_state::do_complete( + void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred) +{ + if (owner) + { + descriptor_state* descriptor_data = static_cast<descriptor_state*>(base); + uint32_t events = static_cast<uint32_t>(bytes_transferred); + if (operation* op = descriptor_data->perform_io(events)) + { + op->complete(owner, ec, 0); + } + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_EPOLL) + +#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP diff --git a/lib/asio/detail/impl/eventfd_select_interrupter.ipp b/lib/asio/detail/impl/eventfd_select_interrupter.ipp new file mode 100644 index 0000000..c56e89a --- /dev/null +++ b/lib/asio/detail/impl/eventfd_select_interrupter.ipp @@ -0,0 +1,165 @@ +// +// detail/impl/eventfd_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP +#define ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_EVENTFD) + +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include <asm/unistd.h> +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include <sys/eventfd.h> +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#include "asio/detail/cstdint.hpp" +#include "asio/detail/eventfd_select_interrupter.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +eventfd_select_interrupter::eventfd_select_interrupter() +{ + open_descriptors(); +} + +void eventfd_select_interrupter::open_descriptors() +{ +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + } +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) + write_descriptor_ = read_descriptor_ = + ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); +# else // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) + errno = EINVAL; + write_descriptor_ = read_descriptor_ = -1; +# endif // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) + if (read_descriptor_ == -1 && errno == EINVAL) + { + write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + } + } +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + + if (read_descriptor_ == -1) + { + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC); + } + else + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "eventfd_select_interrupter"); + } + } +} + +eventfd_select_interrupter::~eventfd_select_interrupter() +{ + close_descriptors(); +} + +void eventfd_select_interrupter::close_descriptors() +{ + if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) + ::close(write_descriptor_); + if (read_descriptor_ != -1) + ::close(read_descriptor_); +} + +void eventfd_select_interrupter::recreate() +{ + close_descriptors(); + + write_descriptor_ = -1; + read_descriptor_ = -1; + + open_descriptors(); +} + +void eventfd_select_interrupter::interrupt() +{ + uint64_t counter(1UL); + int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); + (void)result; +} + +bool eventfd_select_interrupter::reset() +{ + if (write_descriptor_ == read_descriptor_) + { + for (;;) + { + // Only perform one read. The kernel maintains an atomic counter. + uint64_t counter(0); + errno = 0; + int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + return was_interrupted; + } + } + else + { + for (;;) + { + // Clear all data from the pipe. + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_EVENTFD) + +#endif // ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP diff --git a/lib/asio/detail/impl/handler_tracking.ipp b/lib/asio/detail/impl/handler_tracking.ipp new file mode 100644 index 0000000..5a4ff6f --- /dev/null +++ b/lib/asio/detail/impl/handler_tracking.ipp @@ -0,0 +1,358 @@ +// +// detail/impl/handler_tracking.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP +#define ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_CUSTOM_HANDLER_TRACKING) + +// The handler tracking implementation is provided by the user-specified header. + +#elif defined(ASIO_ENABLE_HANDLER_TRACKING) + +#include <cstdarg> +#include <cstdio> +#include "asio/detail/handler_tracking.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) +# include "asio/time_traits.hpp" +#elif defined(ASIO_HAS_CHRONO) +# include "asio/detail/chrono.hpp" +# include "asio/detail/chrono_time_traits.hpp" +# include "asio/wait_traits.hpp" +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + +#if defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/socket_types.hpp" +#elif !defined(ASIO_WINDOWS) +# include <unistd.h> +#endif // !defined(ASIO_WINDOWS) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct handler_tracking_timestamp +{ + uint64_t seconds; + uint64_t microseconds; + + handler_tracking_timestamp() + { +#if defined(ASIO_HAS_BOOST_DATE_TIME) + boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); + boost::posix_time::time_duration now = + boost::posix_time::microsec_clock::universal_time() - epoch; +#elif defined(ASIO_HAS_CHRONO) + typedef chrono_time_traits<chrono::system_clock, + asio::wait_traits<chrono::system_clock> > traits_helper; + traits_helper::posix_time_duration now( + chrono::system_clock::now().time_since_epoch()); +#endif + seconds = static_cast<uint64_t>(now.total_seconds()); + microseconds = static_cast<uint64_t>(now.total_microseconds() % 1000000); + } +}; + +struct handler_tracking::tracking_state +{ + static_mutex mutex_; + uint64_t next_id_; + tss_ptr<completion>* current_completion_; +}; + +handler_tracking::tracking_state* handler_tracking::get_state() +{ + static tracking_state state = { ASIO_STATIC_MUTEX_INIT, 1, 0 }; + return &state; +} + +void handler_tracking::init() +{ + static tracking_state* state = get_state(); + + state->mutex_.init(); + + static_mutex::scoped_lock lock(state->mutex_); + if (state->current_completion_ == 0) + state->current_completion_ = new tss_ptr<completion>; +} + +void handler_tracking::creation(execution_context&, + handler_tracking::tracked_handler& h, + const char* object_type, void* object, + uintmax_t /*native_handle*/, const char* op_name) +{ + static tracking_state* state = get_state(); + + static_mutex::scoped_lock lock(state->mutex_); + h.id_ = state->next_id_++; + lock.unlock(); + + handler_tracking_timestamp timestamp; + + uint64_t current_id = 0; + if (completion* current_completion = *state->current_completion_) + current_id = current_completion->id_; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|%llu*%llu|%.20s@%p.%.50s\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + current_id, h.id_, object_type, object, op_name); +} + +handler_tracking::completion::completion( + const handler_tracking::tracked_handler& h) + : id_(h.id_), + invoked_(false), + next_(*get_state()->current_completion_) +{ + *get_state()->current_completion_ = this; +} + +handler_tracking::completion::~completion() +{ + if (id_) + { + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%c%I64u|\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|%c%llu|\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + invoked_ ? '!' : '~', id_); + } + + *get_state()->current_completion_ = next_; +} + +void handler_tracking::completion::invocation_begin() +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, id_); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const asio::error_code& ec) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value()); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const asio::error_code& ec, std::size_t bytes_transferred) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,bytes_transferred=%I64u\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,bytes_transferred=%llu\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value(), + static_cast<uint64_t>(bytes_transferred)); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const asio::error_code& ec, int signal_number) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,signal_number=%d\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,signal_number=%d\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value(), signal_number); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const asio::error_code& ec, const char* arg) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,%.50s\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,%.50s\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value(), arg); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_end() +{ + if (id_) + { + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|<%I64u|\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|<%llu|\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, id_); + + id_ = 0; + } +} + +void handler_tracking::operation(execution_context&, + const char* object_type, void* object, + uintmax_t /*native_handle*/, const char* op_name) +{ + static tracking_state* state = get_state(); + + handler_tracking_timestamp timestamp; + + unsigned long long current_id = 0; + if (completion* current_completion = *state->current_completion_) + current_id = current_completion->id_; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%I64u|%.20s@%p.%.50s\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|%llu|%.20s@%p.%.50s\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + current_id, object_type, object, op_name); +} + +void handler_tracking::reactor_registration(execution_context& /*context*/, + uintmax_t /*native_handle*/, uintmax_t /*registration*/) +{ +} + +void handler_tracking::reactor_deregistration(execution_context& /*context*/, + uintmax_t /*native_handle*/, uintmax_t /*registration*/) +{ +} + +void handler_tracking::reactor_events(execution_context& /*context*/, + uintmax_t /*native_handle*/, unsigned /*events*/) +{ +} + +void handler_tracking::reactor_operation( + const tracked_handler& h, const char* op_name, + const asio::error_code& ec) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + h.id_, op_name, ec.category().name(), ec.value()); +} + +void handler_tracking::reactor_operation( + const tracked_handler& h, const char* op_name, + const asio::error_code& ec, std::size_t bytes_transferred) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d,bytes_transferred=%I64u\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d,bytes_transferred=%llu\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + h.id_, op_name, ec.category().name(), ec.value(), + static_cast<uint64_t>(bytes_transferred)); +} + +void handler_tracking::write_line(const char* format, ...) +{ + using namespace std; // For sprintf (or equivalent). + + va_list args; + va_start(args, format); + + char line[256] = ""; +#if defined(ASIO_HAS_SECURE_RTL) + int length = vsprintf_s(line, sizeof(line), format, args); +#else // defined(ASIO_HAS_SECURE_RTL) + int length = vsprintf(line, format, args); +#endif // defined(ASIO_HAS_SECURE_RTL) + + va_end(args); + +#if defined(ASIO_WINDOWS_RUNTIME) + wchar_t wline[256] = L""; + mbstowcs_s(0, wline, sizeof(wline) / sizeof(wchar_t), line, length); + ::OutputDebugStringW(wline); +#elif defined(ASIO_WINDOWS) + HANDLE stderr_handle = ::GetStdHandle(STD_ERROR_HANDLE); + DWORD bytes_written = 0; + ::WriteFile(stderr_handle, line, length, &bytes_written, 0); +#else // defined(ASIO_WINDOWS) + ::write(STDERR_FILENO, line, length); +#endif // defined(ASIO_WINDOWS) +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +#endif // ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP diff --git a/lib/asio/detail/impl/kqueue_reactor.hpp b/lib/asio/detail/impl/kqueue_reactor.hpp new file mode 100644 index 0000000..136d167 --- /dev/null +++ b/lib/asio/detail/impl/kqueue_reactor.hpp @@ -0,0 +1,93 @@ +// +// detail/impl/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP +#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_KQUEUE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template <typename Time_Traits> +void kqueue_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void kqueue_reactor::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op) +{ + mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + interrupt(); +} + +template <typename Time_Traits> +std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template <typename Time_Traits> +void kqueue_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_KQUEUE) + +#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP diff --git a/lib/asio/detail/impl/kqueue_reactor.ipp b/lib/asio/detail/impl/kqueue_reactor.ipp new file mode 100644 index 0000000..73986e0 --- /dev/null +++ b/lib/asio/detail/impl/kqueue_reactor.ipp @@ -0,0 +1,566 @@ +// +// detail/impl/kqueue_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP +#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_KQUEUE) + +#include "asio/detail/kqueue_reactor.hpp" +#include "asio/detail/scheduler.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(__NetBSD__) +# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ + EV_SET(ev, ident, filt, flags, fflags, data, \ + reinterpret_cast<intptr_t>(static_cast<void*>(udata))) +#else +# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ + EV_SET(ev, ident, filt, flags, fflags, data, udata) +#endif + +namespace asio { +namespace detail { + +kqueue_reactor::kqueue_reactor(asio::execution_context& ctx) + : execution_context_service_base<kqueue_reactor>(ctx), + scheduler_(use_service<scheduler>(ctx)), + mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), + kqueue_fd_(do_kqueue_create()), + interrupter_(), + shutdown_(false), + registered_descriptors_mutex_(mutex_.enabled()) +{ + struct kevent events[1]; + ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD, 0, 0, &interrupter_); + if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1) + { + asio::error_code error(errno, + asio::error::get_system_category()); + asio::detail::throw_error(error); + } +} + +kqueue_reactor::~kqueue_reactor() +{ + close(kqueue_fd_); +} + +void kqueue_reactor::shutdown() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue<operation> ops; + + while (descriptor_state* state = registered_descriptors_.first()) + { + for (int i = 0; i < max_ops; ++i) + ops.push(state->op_queue_[i]); + state->shutdown_ = true; + registered_descriptors_.free(state); + } + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void kqueue_reactor::notify_fork( + asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == asio::execution_context::fork_child) + { + // The kqueue descriptor is automatically closed in the child. + kqueue_fd_ = -1; + kqueue_fd_ = do_kqueue_create(); + + interrupter_.recreate(); + + struct kevent events[2]; + ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD, 0, 0, &interrupter_); + if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "kqueue interrupter registration"); + } + + // Re-register all descriptors with kqueue. + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + for (descriptor_state* state = registered_descriptors_.first(); + state != 0; state = state->next_) + { + if (state->num_kevents_ > 0) + { + ASIO_KQUEUE_EV_SET(&events[0], state->descriptor_, + EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, state); + ASIO_KQUEUE_EV_SET(&events[1], state->descriptor_, + EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, state); + if (::kevent(kqueue_fd_, events, state->num_kevents_, 0, 0, 0) == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "kqueue re-registration"); + } + } + } + } +} + +void kqueue_reactor::init_task() +{ + scheduler_.init_task(); +} + +int kqueue_reactor::register_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + descriptor_data = allocate_descriptor_state(); + + ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + + mutex::scoped_lock lock(descriptor_data->mutex_); + + descriptor_data->descriptor_ = descriptor; + descriptor_data->num_kevents_ = 0; + descriptor_data->shutdown_ = false; + + return 0; +} + +int kqueue_reactor::register_internal_descriptor( + int op_type, socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op) +{ + descriptor_data = allocate_descriptor_state(); + + ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + + mutex::scoped_lock lock(descriptor_data->mutex_); + + descriptor_data->descriptor_ = descriptor; + descriptor_data->num_kevents_ = 1; + descriptor_data->shutdown_ = false; + descriptor_data->op_queue_[op_type].push(op); + + struct kevent events[1]; + ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1) + return errno; + + return 0; +} + +void kqueue_reactor::move_descriptor(socket_type, + kqueue_reactor::per_descriptor_data& target_descriptor_data, + kqueue_reactor::per_descriptor_data& source_descriptor_data) +{ + target_descriptor_data = source_descriptor_data; + source_descriptor_data = 0; +} + +void kqueue_reactor::start_op(int op_type, socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) +{ + if (!descriptor_data) + { + op->ec_ = asio::error::bad_descriptor; + post_immediate_completion(op, is_continuation); + return; + } + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (descriptor_data->shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + if (descriptor_data->op_queue_[op_type].empty()) + { + static const int num_kevents[max_ops] = { 1, 2, 1 }; + + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) + { + if (op->perform()) + { + descriptor_lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + if (descriptor_data->num_kevents_ < num_kevents[op_type]) + { + struct kevent events[2]; + ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + if (::kevent(kqueue_fd_, events, num_kevents[op_type], 0, 0, 0) != -1) + { + descriptor_data->num_kevents_ = num_kevents[op_type]; + } + else + { + op->ec_ = asio::error_code(errno, + asio::error::get_system_category()); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + } + else + { + if (descriptor_data->num_kevents_ < num_kevents[op_type]) + descriptor_data->num_kevents_ = num_kevents[op_type]; + + struct kevent events[2]; + ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0); + } + } + + descriptor_data->op_queue_[op_type].push(op); + scheduler_.work_started(); +} + +void kqueue_reactor::cancel_ops(socket_type, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + scheduler_.post_deferred_completions(ops); +} + +void kqueue_reactor::deregister_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, bool closing) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + if (closing) + { + // The descriptor will be automatically removed from the kqueue when it + // is closed. + } + else + { + struct kevent events[2]; + ASIO_KQUEUE_EV_SET(&events[0], descriptor, + EVFILT_READ, EV_DELETE, 0, 0, 0); + ASIO_KQUEUE_EV_SET(&events[1], descriptor, + EVFILT_WRITE, EV_DELETE, 0, 0, 0); + ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0); + } + + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + + scheduler_.post_deferred_completions(ops); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void kqueue_reactor::deregister_internal_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + struct kevent events[2]; + ASIO_KQUEUE_EV_SET(&events[0], descriptor, + EVFILT_READ, EV_DELETE, 0, 0, 0); + ASIO_KQUEUE_EV_SET(&events[1], descriptor, + EVFILT_WRITE, EV_DELETE, 0, 0, 0); + ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0); + + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + ops.push(descriptor_data->op_queue_[i]); + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void kqueue_reactor::cleanup_descriptor_data( + per_descriptor_data& descriptor_data) +{ + if (descriptor_data) + { + free_descriptor_state(descriptor_data); + descriptor_data = 0; + } +} + +void kqueue_reactor::run(long usec, op_queue<operation>& ops) +{ + mutex::scoped_lock lock(mutex_); + + // Determine how long to block while waiting for events. + timespec timeout_buf = { 0, 0 }; + timespec* timeout = usec ? get_timeout(usec, timeout_buf) : &timeout_buf; + + lock.unlock(); + + // Block on the kqueue descriptor. + struct kevent events[128]; + int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); + +#if defined(ASIO_ENABLE_HANDLER_TRACKING) + // Trace the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = reinterpret_cast<void*>(events[i].udata); + if (ptr != &interrupter_) + { + unsigned event_mask = 0; + switch (events[i].filter) + { + case EVFILT_READ: + event_mask |= ASIO_HANDLER_REACTOR_READ_EVENT; + break; + case EVFILT_WRITE: + event_mask |= ASIO_HANDLER_REACTOR_WRITE_EVENT; + break; + } + if ((events[i].flags & (EV_ERROR | EV_OOBAND)) != 0) + event_mask |= ASIO_HANDLER_REACTOR_ERROR_EVENT; + ASIO_HANDLER_REACTOR_EVENTS((context(), + reinterpret_cast<uintmax_t>(ptr), event_mask)); + } + } +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = reinterpret_cast<void*>(events[i].udata); + if (ptr == &interrupter_) + { + interrupter_.reset(); + } + else + { + descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (events[i].filter == EVFILT_WRITE + && descriptor_data->num_kevents_ == 2 + && descriptor_data->op_queue_[write_op].empty()) + { + // Some descriptor types, like serial ports, don't seem to support + // EV_CLEAR with EVFILT_WRITE. Since we have no pending write + // operations we'll remove the EVFILT_WRITE registration here so that + // we don't end up in a tight spin. + struct kevent delete_events[1]; + ASIO_KQUEUE_EV_SET(&delete_events[0], + descriptor_data->descriptor_, EVFILT_WRITE, EV_DELETE, 0, 0, 0); + ::kevent(kqueue_fd_, delete_events, 1, 0, 0, 0); + descriptor_data->num_kevents_ = 1; + } + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. +#if defined(__NetBSD__) + static const unsigned int filter[max_ops] = +#else + static const int filter[max_ops] = +#endif + { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; + for (int j = max_ops - 1; j >= 0; --j) + { + 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_ = asio::error_code( + static_cast<int>(events[i].data), + 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; + } + } + } + } + } + } + + lock.lock(); + timer_queues_.get_ready_timers(ops); +} + +void kqueue_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +int kqueue_reactor::do_kqueue_create() +{ + int fd = ::kqueue(); + if (fd == -1) + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "kqueue"); + } + return fd; +} + +kqueue_reactor::descriptor_state* kqueue_reactor::allocate_descriptor_state() +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); +} + +void kqueue_reactor::free_descriptor_state(kqueue_reactor::descriptor_state* s) +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + registered_descriptors_.free(s); +} + +void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timespec* kqueue_reactor::get_timeout(long usec, timespec& ts) +{ + // 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. + const long max_usec = 5 * 60 * 1000 * 1000; + usec = timer_queues_.wait_duration_usec( + (usec < 0 || max_usec < usec) ? max_usec : usec); + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + return &ts; +} + +} // namespace detail +} // namespace asio + +#undef ASIO_KQUEUE_EV_SET + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_KQUEUE) + +#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP diff --git a/lib/asio/detail/impl/null_event.ipp b/lib/asio/detail/impl/null_event.ipp new file mode 100644 index 0000000..22ade40 --- /dev/null +++ b/lib/asio/detail/impl/null_event.ipp @@ -0,0 +1,74 @@ +// +// detail/impl/null_event.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_NULL_EVENT_IPP +#define ASIO_DETAIL_IMPL_NULL_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +# include <thread> +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# include "asio/detail/socket_types.hpp" +#else +# include <unistd.h> +# if defined(__hpux) +# include <sys/time.h> +# endif +# if !defined(__hpux) || defined(__SELECT) +# include <sys/select.h> +# endif +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void null_event::do_wait() +{ +#if defined(ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_until((std::chrono::steady_clock::time_point::max)()); +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ::Sleep(INFINITE); +#else + ::pause(); +#endif +} + +void null_event::do_wait_for_usec(long usec) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_for(std::chrono::microseconds(usec)); +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ::Sleep(usec / 1000); +#elif defined(__hpux) && defined(__SELECT) + timespec ts; + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + ::pselect(0, 0, 0, 0, &ts, 0); +#else + timeval tv; + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + ::select(0, 0, 0, 0, &tv); +#endif +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_NULL_EVENT_IPP diff --git a/lib/asio/detail/impl/pipe_select_interrupter.ipp b/lib/asio/detail/impl/pipe_select_interrupter.ipp new file mode 100644 index 0000000..13931ab --- /dev/null +++ b/lib/asio/detail/impl/pipe_select_interrupter.ipp @@ -0,0 +1,124 @@ +// +// detail/impl/pipe_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP +#define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) +#if !defined(ASIO_WINDOWS) +#if !defined(__CYGWIN__) +#if !defined(__SYMBIAN32__) +#if !defined(ASIO_HAS_EVENTFD) + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include "asio/detail/pipe_select_interrupter.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +pipe_select_interrupter::pipe_select_interrupter() +{ + open_descriptors(); +} + +void pipe_select_interrupter::open_descriptors() +{ + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + +#if defined(FD_CLOEXEC) + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC); +#endif // defined(FD_CLOEXEC) + } + else + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "pipe_select_interrupter"); + } +} + +pipe_select_interrupter::~pipe_select_interrupter() +{ + close_descriptors(); +} + +void pipe_select_interrupter::close_descriptors() +{ + if (read_descriptor_ != -1) + ::close(read_descriptor_); + if (write_descriptor_ != -1) + ::close(write_descriptor_); +} + +void pipe_select_interrupter::recreate() +{ + close_descriptors(); + + write_descriptor_ = -1; + read_descriptor_ = -1; + + open_descriptors(); +} + +void pipe_select_interrupter::interrupt() +{ + char byte = 0; + signed_size_type result = ::write(write_descriptor_, &byte, 1); + (void)result; +} + +bool pipe_select_interrupter::reset() +{ + for (;;) + { + char data[1024]; + signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_EVENTFD) +#endif // !defined(__SYMBIAN32__) +#endif // !defined(__CYGWIN__) +#endif // !defined(ASIO_WINDOWS) +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP diff --git a/lib/asio/detail/impl/posix_event.ipp b/lib/asio/detail/impl/posix_event.ipp new file mode 100644 index 0000000..4b46ab0 --- /dev/null +++ b/lib/asio/detail/impl/posix_event.ipp @@ -0,0 +1,59 @@ +// +// detail/impl/posix_event.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_POSIX_EVENT_IPP +#define ASIO_DETAIL_IMPL_POSIX_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include "asio/detail/posix_event.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +posix_event::posix_event() + : state_(0) +{ +#if (defined(__MACH__) && defined(__APPLE__)) \ + || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + int error = ::pthread_cond_init(&cond_, 0); +#else // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + ::pthread_condattr_t attr; + ::pthread_condattr_init(&attr); + int error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + if (error == 0) + error = ::pthread_cond_init(&cond_, &attr); +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "event"); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_EVENT_IPP diff --git a/lib/asio/detail/impl/posix_mutex.ipp b/lib/asio/detail/impl/posix_mutex.ipp new file mode 100644 index 0000000..27272b5 --- /dev/null +++ b/lib/asio/detail/impl/posix_mutex.ipp @@ -0,0 +1,46 @@ +// +// detail/impl/posix_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP +#define ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include "asio/detail/posix_mutex.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +posix_mutex::posix_mutex() +{ + int error = ::pthread_mutex_init(&mutex_, 0); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "mutex"); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP diff --git a/lib/asio/detail/impl/posix_thread.ipp b/lib/asio/detail/impl/posix_thread.ipp new file mode 100644 index 0000000..69bd16f --- /dev/null +++ b/lib/asio/detail/impl/posix_thread.ipp @@ -0,0 +1,84 @@ +// +// detail/impl/posix_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_POSIX_THREAD_IPP +#define ASIO_DETAIL_IMPL_POSIX_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include "asio/detail/posix_thread.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +posix_thread::~posix_thread() +{ + if (!joined_) + ::pthread_detach(thread_); +} + +void posix_thread::join() +{ + if (!joined_) + { + ::pthread_join(thread_, 0); + joined_ = true; + } +} + +std::size_t posix_thread::hardware_concurrency() +{ +#if defined(_SC_NPROCESSORS_ONLN) + long result = sysconf(_SC_NPROCESSORS_ONLN); + if (result > 0) + return result; +#endif // defined(_SC_NPROCESSORS_ONLN) + return 0; +} + +void posix_thread::start_thread(func_base* arg) +{ + int error = ::pthread_create(&thread_, 0, + asio_detail_posix_thread_function, arg); + if (error != 0) + { + delete arg; + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); + } +} + +void* asio_detail_posix_thread_function(void* arg) +{ + posix_thread::auto_func_base_ptr func = { + static_cast<posix_thread::func_base*>(arg) }; + func.ptr->run(); + return 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_THREAD_IPP diff --git a/lib/asio/detail/impl/posix_tss_ptr.ipp b/lib/asio/detail/impl/posix_tss_ptr.ipp new file mode 100644 index 0000000..54b58bd --- /dev/null +++ b/lib/asio/detail/impl/posix_tss_ptr.ipp @@ -0,0 +1,46 @@ +// +// detail/impl/posix_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP +#define ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include "asio/detail/posix_tss_ptr.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void posix_tss_ptr_create(pthread_key_t& key) +{ + int error = ::pthread_key_create(&key, 0); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "tss"); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP diff --git a/lib/asio/detail/impl/reactive_descriptor_service.ipp b/lib/asio/detail/impl/reactive_descriptor_service.ipp new file mode 100644 index 0000000..f9505ca --- /dev/null +++ b/lib/asio/detail/impl/reactive_descriptor_service.ipp @@ -0,0 +1,222 @@ +// +// detail/impl/reactive_descriptor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP +#define ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include "asio/error.hpp" +#include "asio/detail/reactive_descriptor_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +reactive_descriptor_service::reactive_descriptor_service( + asio::io_context& io_context) + : service_base<reactive_descriptor_service>(io_context), + reactor_(asio::use_service<reactor>(io_context)) +{ + reactor_.init_task(); +} + +void reactive_descriptor_service::shutdown() +{ +} + +void reactive_descriptor_service::construct( + reactive_descriptor_service::implementation_type& impl) +{ + impl.descriptor_ = -1; + impl.state_ = 0; +} + +void reactive_descriptor_service::move_construct( + reactive_descriptor_service::implementation_type& impl, + reactive_descriptor_service::implementation_type& other_impl) +{ + impl.descriptor_ = other_impl.descriptor_; + other_impl.descriptor_ = -1; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + reactor_.move_descriptor(impl.descriptor_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_descriptor_service::move_assign( + reactive_descriptor_service::implementation_type& impl, + reactive_descriptor_service& other_service, + reactive_descriptor_service::implementation_type& other_impl) +{ + destroy(impl); + + impl.descriptor_ = other_impl.descriptor_; + other_impl.descriptor_ = -1; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + other_service.reactor_.move_descriptor(impl.descriptor_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_descriptor_service::destroy( + reactive_descriptor_service::implementation_type& impl) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "close")); + + reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, + (impl.state_ & descriptor_ops::possible_dup) == 0); + + asio::error_code ignored_ec; + descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } +} + +asio::error_code reactive_descriptor_service::assign( + reactive_descriptor_service::implementation_type& impl, + const native_handle_type& native_descriptor, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_descriptor, impl.reactor_data_)) + { + ec = asio::error_code(err, + asio::error::get_system_category()); + return ec; + } + + impl.descriptor_ = native_descriptor; + impl.state_ = descriptor_ops::possible_dup; + ec = asio::error_code(); + return ec; +} + +asio::error_code reactive_descriptor_service::close( + reactive_descriptor_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "close")); + + reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, + (impl.state_ & descriptor_ops::possible_dup) == 0); + + descriptor_ops::close(impl.descriptor_, impl.state_, ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = asio::error_code(); + } + + // The descriptor is closed by the OS even if close() returns an error. + // + // (Actually, POSIX says the state of the descriptor is unspecified. On + // Linux the descriptor is apparently closed anyway; e.g. see + // http://lkml.org/lkml/2005/9/10/129 + // We'll just have to assume that other OSes follow the same behaviour.) + construct(impl); + + return ec; +} + +reactive_descriptor_service::native_handle_type +reactive_descriptor_service::release( + reactive_descriptor_service::implementation_type& impl) +{ + native_handle_type descriptor = impl.descriptor_; + + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "release")); + + reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, false); + reactor_.cleanup_descriptor_data(impl.reactor_data_); + construct(impl); + } + + return descriptor; +} + +asio::error_code reactive_descriptor_service::cancel( + reactive_descriptor_service::implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "cancel")); + + reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); + ec = asio::error_code(); + return ec; +} + +void reactive_descriptor_service::start_op( + reactive_descriptor_service::implementation_type& impl, + int op_type, reactor_op* op, bool is_continuation, + bool is_non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & descriptor_ops::non_blocking) || + descriptor_ops::set_internal_non_blocking( + impl.descriptor_, impl.state_, true, op->ec_)) + { + reactor_.start_op(op_type, impl.descriptor_, + impl.reactor_data_, op, is_continuation, is_non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op, is_continuation); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP diff --git a/lib/asio/detail/impl/reactive_serial_port_service.ipp b/lib/asio/detail/impl/reactive_serial_port_service.ipp new file mode 100644 index 0000000..c907835 --- /dev/null +++ b/lib/asio/detail/impl/reactive_serial_port_service.ipp @@ -0,0 +1,152 @@ +// +// detail/impl/reactive_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP +#define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SERIAL_PORT) +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include <cstring> +#include "asio/detail/reactive_serial_port_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +reactive_serial_port_service::reactive_serial_port_service( + asio::io_context& io_context) + : service_base<reactive_serial_port_service>(io_context), + descriptor_service_(io_context) +{ +} + +void reactive_serial_port_service::shutdown() +{ + descriptor_service_.shutdown(); +} + +asio::error_code reactive_serial_port_service::open( + reactive_serial_port_service::implementation_type& impl, + const std::string& device, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + descriptor_ops::state_type state = 0; + int fd = descriptor_ops::open(device.c_str(), + O_RDWR | O_NONBLOCK | O_NOCTTY, ec); + if (fd < 0) + return ec; + + int s = descriptor_ops::fcntl(fd, F_GETFL, ec); + if (s >= 0) + s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); + if (s < 0) + { + asio::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // Set up default serial port options. + termios ios; + errno = 0; + s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); + if (s >= 0) + { +#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + ::cfmakeraw(&ios); +#else + ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK + | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + ios.c_oflag &= ~OPOST; + ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + ios.c_cflag &= ~(CSIZE | PARENB); + ios.c_cflag |= CS8; +#endif + ios.c_iflag |= IGNPAR; + ios.c_cflag |= CREAD | CLOCAL; + errno = 0; + s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); + } + if (s < 0) + { + asio::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // We're done. Take ownership of the serial port descriptor. + if (descriptor_service_.assign(impl, fd, ec)) + { + asio::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + } + + return ec; +} + +asio::error_code reactive_serial_port_service::do_set_option( + reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::store_function_type store, + const void* option, asio::error_code& ec) +{ + termios ios; + errno = 0; + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native_handle(impl), &ios), ec); + if (ec) + return ec; + + if (store(option, ios, ec)) + return ec; + + errno = 0; + descriptor_ops::error_wrapper(::tcsetattr( + descriptor_service_.native_handle(impl), TCSANOW, &ios), ec); + return ec; +} + +asio::error_code reactive_serial_port_service::do_get_option( + const reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::load_function_type load, + void* option, asio::error_code& ec) const +{ + termios ios; + errno = 0; + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native_handle(impl), &ios), ec); + if (ec) + return ec; + + return load(option, ios, ec); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP diff --git a/lib/asio/detail/impl/reactive_socket_service_base.ipp b/lib/asio/detail/impl/reactive_socket_service_base.ipp new file mode 100644 index 0000000..129b851 --- /dev/null +++ b/lib/asio/detail/impl/reactive_socket_service_base.ipp @@ -0,0 +1,300 @@ +// +// detail/reactive_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) \ + && !defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/reactive_socket_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +reactive_socket_service_base::reactive_socket_service_base( + asio::io_context& io_context) + : io_context_(io_context), + reactor_(use_service<reactor>(io_context)) +{ + reactor_.init_task(); +} + +void reactive_socket_service_base::base_shutdown() +{ +} + +void reactive_socket_service_base::construct( + reactive_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; +} + +void reactive_socket_service_base::base_move_construct( + reactive_socket_service_base::base_implementation_type& impl, + reactive_socket_service_base::base_implementation_type& other_impl) +{ + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + reactor_.move_descriptor(impl.socket_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_socket_service_base::base_move_assign( + reactive_socket_service_base::base_implementation_type& impl, + reactive_socket_service_base& other_service, + reactive_socket_service_base::base_implementation_type& other_impl) +{ + destroy(impl); + + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + other_service.reactor_.move_descriptor(impl.socket_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_socket_service_base::destroy( + reactive_socket_service_base::base_implementation_type& impl) +{ + if (impl.socket_ != invalid_socket) + { + ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "close")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, + (impl.state_ & socket_ops::possible_dup) == 0); + + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } +} + +asio::error_code reactive_socket_service_base::close( + reactive_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "close")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, + (impl.state_ & socket_ops::possible_dup) == 0); + + socket_ops::close(impl.socket_, impl.state_, false, ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = asio::error_code(); + } + + // The descriptor is closed by the OS even if close() returns an error. + // + // (Actually, POSIX says the state of the descriptor is unspecified. On + // Linux the descriptor is apparently closed anyway; e.g. see + // http://lkml.org/lkml/2005/9/10/129 + // We'll just have to assume that other OSes follow the same behaviour. The + // known exception is when Windows's closesocket() function fails with + // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close(). + construct(impl); + + return ec; +} + +socket_type reactive_socket_service_base::release( + reactive_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return invalid_socket; + } + + ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "release")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false); + reactor_.cleanup_descriptor_data(impl.reactor_data_); + socket_type sock = impl.socket_; + construct(impl); + ec = asio::error_code(); + return sock; +} + +asio::error_code reactive_socket_service_base::cancel( + reactive_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "cancel")); + + reactor_.cancel_ops(impl.socket_, impl.reactor_data_); + ec = asio::error_code(); + return ec; +} + +asio::error_code reactive_socket_service_base::do_open( + reactive_socket_service_base::base_implementation_type& impl, + int af, int type, int protocol, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(af, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) + { + ec = asio::error_code(err, + asio::error::get_system_category()); + return ec; + } + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + ec = asio::error_code(); + return ec; +} + +asio::error_code reactive_socket_service_base::do_assign( + reactive_socket_service_base::base_implementation_type& impl, int type, + const reactive_socket_service_base::native_handle_type& native_socket, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_socket, impl.reactor_data_)) + { + ec = asio::error_code(err, + asio::error::get_system_category()); + return ec; + } + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.state_ |= socket_ops::possible_dup; + ec = asio::error_code(); + return ec; +} + +void reactive_socket_service_base::start_op( + reactive_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op, bool is_continuation, + bool is_non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, true, op->ec_)) + { + reactor_.start_op(op_type, impl.socket_, + impl.reactor_data_, op, is_continuation, is_non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op, is_continuation); +} + +void reactive_socket_service_base::start_accept_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, bool is_continuation, bool peer_is_open) +{ + if (!peer_is_open) + start_op(impl, reactor::read_op, op, is_continuation, true, false); + else + { + op->ec_ = asio::error::already_open; + reactor_.post_immediate_completion(op, is_continuation); + } +} + +void reactive_socket_service_base::start_connect_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, bool is_continuation, + const socket_addr_type* addr, size_t addrlen) +{ + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, true, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == asio::error::in_progress + || op->ec_ == asio::error::would_block) + { + op->ec_ = asio::error_code(); + reactor_.start_op(reactor::connect_op, impl.socket_, + impl.reactor_data_, op, is_continuation, false); + return; + } + } + } + + reactor_.post_immediate_completion(op, is_continuation); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_IOCP) + // && !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP diff --git a/lib/asio/detail/impl/resolver_service_base.ipp b/lib/asio/detail/impl/resolver_service_base.ipp new file mode 100644 index 0000000..540bb66 --- /dev/null +++ b/lib/asio/detail/impl/resolver_service_base.ipp @@ -0,0 +1,154 @@ +// +// detail/impl/resolver_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/resolver_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class resolver_service_base::work_io_context_runner +{ +public: + work_io_context_runner(asio::io_context& io_context) + : io_context_(io_context) {} + void operator()() { io_context_.run(); } +private: + asio::io_context& io_context_; +}; + +resolver_service_base::resolver_service_base( + asio::io_context& io_context) + : io_context_impl_(asio::use_service<io_context_impl>(io_context)), + work_io_context_(new asio::io_context(-1)), + work_io_context_impl_(asio::use_service< + io_context_impl>(*work_io_context_)), + work_(asio::make_work_guard(*work_io_context_)), + work_thread_(0) +{ +} + +resolver_service_base::~resolver_service_base() +{ + base_shutdown(); +} + +void resolver_service_base::base_shutdown() +{ + work_.reset(); + if (work_io_context_.get()) + { + work_io_context_->stop(); + if (work_thread_.get()) + { + work_thread_->join(); + work_thread_.reset(); + } + work_io_context_.reset(); + } +} + +void resolver_service_base::base_notify_fork( + asio::io_context::fork_event fork_ev) +{ + if (work_thread_.get()) + { + if (fork_ev == asio::io_context::fork_prepare) + { + work_io_context_->stop(); + work_thread_->join(); + } + else + { + work_io_context_->restart(); + work_thread_.reset(new asio::detail::thread( + work_io_context_runner(*work_io_context_))); + } + } +} + +void resolver_service_base::construct( + resolver_service_base::implementation_type& impl) +{ + impl.reset(static_cast<void*>(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::destroy( + resolver_service_base::implementation_type& impl) +{ + ASIO_HANDLER_OPERATION((io_context_impl_.context(), + "resolver", &impl, 0, "cancel")); + + impl.reset(); +} + +void resolver_service_base::move_construct(implementation_type& impl, + implementation_type& other_impl) +{ + impl = ASIO_MOVE_CAST(implementation_type)(other_impl); +} + +void resolver_service_base::move_assign(implementation_type& impl, + resolver_service_base&, implementation_type& other_impl) +{ + destroy(impl); + impl = ASIO_MOVE_CAST(implementation_type)(other_impl); +} + +void resolver_service_base::cancel( + resolver_service_base::implementation_type& impl) +{ + ASIO_HANDLER_OPERATION((io_context_impl_.context(), + "resolver", &impl, 0, "cancel")); + + impl.reset(static_cast<void*>(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::start_resolve_op(resolve_op* op) +{ + if (ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + io_context_impl_.concurrency_hint())) + { + start_work_thread(); + io_context_impl_.work_started(); + work_io_context_impl_.post_immediate_completion(op, false); + } + else + { + op->ec_ = asio::error::operation_not_supported; + io_context_impl_.post_immediate_completion(op, false); + } +} + +void resolver_service_base::start_work_thread() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + if (!work_thread_.get()) + { + work_thread_.reset(new asio::detail::thread( + work_io_context_runner(*work_io_context_))); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP diff --git a/lib/asio/detail/impl/scheduler.ipp b/lib/asio/detail/impl/scheduler.ipp new file mode 100644 index 0000000..35bc678 --- /dev/null +++ b/lib/asio/detail/impl/scheduler.ipp @@ -0,0 +1,571 @@ +// +// detail/impl/scheduler.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SCHEDULER_IPP +#define ASIO_DETAIL_IMPL_SCHEDULER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/concurrency_hint.hpp" +#include "asio/detail/event.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/detail/scheduler.hpp" +#include "asio/detail/scheduler_thread_info.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct scheduler::task_cleanup +{ + ~task_cleanup() + { + if (this_thread_->private_outstanding_work > 0) + { + asio::detail::increment( + scheduler_->outstanding_work_, + this_thread_->private_outstanding_work); + } + this_thread_->private_outstanding_work = 0; + + // Enqueue the completed operations and reinsert the task at the end of + // the operation queue. + lock_->lock(); + scheduler_->task_interrupted_ = true; + scheduler_->op_queue_.push(this_thread_->private_op_queue); + scheduler_->op_queue_.push(&scheduler_->task_operation_); + } + + scheduler* scheduler_; + mutex::scoped_lock* lock_; + thread_info* this_thread_; +}; + +struct scheduler::work_cleanup +{ + ~work_cleanup() + { + if (this_thread_->private_outstanding_work > 1) + { + asio::detail::increment( + scheduler_->outstanding_work_, + this_thread_->private_outstanding_work - 1); + } + else if (this_thread_->private_outstanding_work < 1) + { + scheduler_->work_finished(); + } + this_thread_->private_outstanding_work = 0; + +#if defined(ASIO_HAS_THREADS) + if (!this_thread_->private_op_queue.empty()) + { + lock_->lock(); + scheduler_->op_queue_.push(this_thread_->private_op_queue); + } +#endif // defined(ASIO_HAS_THREADS) + } + + scheduler* scheduler_; + mutex::scoped_lock* lock_; + thread_info* this_thread_; +}; + +scheduler::scheduler( + asio::execution_context& ctx, int concurrency_hint) + : asio::detail::execution_context_service_base<scheduler>(ctx), + one_thread_(concurrency_hint == 1 + || !ASIO_CONCURRENCY_HINT_IS_LOCKING( + SCHEDULER, concurrency_hint) + || !ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, concurrency_hint)), + mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING( + SCHEDULER, concurrency_hint)), + task_(0), + task_interrupted_(true), + outstanding_work_(0), + stopped_(false), + shutdown_(false), + concurrency_hint_(concurrency_hint) +{ + ASIO_HANDLER_TRACKING_INIT; +} + +void scheduler::shutdown() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + // Destroy handler objects. + while (!op_queue_.empty()) + { + operation* o = op_queue_.front(); + op_queue_.pop(); + if (o != &task_operation_) + o->destroy(); + } + + // Reset to initial state. + task_ = 0; +} + +void scheduler::init_task() +{ + mutex::scoped_lock lock(mutex_); + if (!shutdown_ && !task_) + { + task_ = &use_service<reactor>(this->context()); + op_queue_.push(&task_operation_); + wake_one_thread_and_unlock(lock); + } +} + +std::size_t scheduler::run(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + + std::size_t n = 0; + for (; do_run_one(lock, this_thread, ec); lock.lock()) + if (n != (std::numeric_limits<std::size_t>::max)()) + ++n; + return n; +} + +std::size_t scheduler::run_one(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + + return do_run_one(lock, this_thread, ec); +} + +std::size_t scheduler::wait_one(long usec, asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + + return do_wait_one(lock, this_thread, usec, ec); +} + +std::size_t scheduler::poll(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + +#if defined(ASIO_HAS_THREADS) + // We want to support nested calls to poll() and poll_one(), so any handlers + // that are already on a thread-private queue need to be put on to the main + // queue now. + if (one_thread_) + if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key())) + op_queue_.push(outer_info->private_op_queue); +#endif // defined(ASIO_HAS_THREADS) + + std::size_t n = 0; + for (; do_poll_one(lock, this_thread, ec); lock.lock()) + if (n != (std::numeric_limits<std::size_t>::max)()) + ++n; + return n; +} + +std::size_t scheduler::poll_one(asio::error_code& ec) +{ + ec = asio::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + +#if defined(ASIO_HAS_THREADS) + // We want to support nested calls to poll() and poll_one(), so any handlers + // that are already on a thread-private queue need to be put on to the main + // queue now. + if (one_thread_) + if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key())) + op_queue_.push(outer_info->private_op_queue); +#endif // defined(ASIO_HAS_THREADS) + + return do_poll_one(lock, this_thread, ec); +} + +void scheduler::stop() +{ + mutex::scoped_lock lock(mutex_); + stop_all_threads(lock); +} + +bool scheduler::stopped() const +{ + mutex::scoped_lock lock(mutex_); + return stopped_; +} + +void scheduler::restart() +{ + mutex::scoped_lock lock(mutex_); + stopped_ = false; +} + +void scheduler::compensating_work_started() +{ + thread_info_base* this_thread = thread_call_stack::contains(this); + ++static_cast<thread_info*>(this_thread)->private_outstanding_work; +} + +void scheduler::post_immediate_completion( + scheduler::operation* op, bool is_continuation) +{ +#if defined(ASIO_HAS_THREADS) + if (one_thread_ || is_continuation) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + ++static_cast<thread_info*>(this_thread)->private_outstanding_work; + static_cast<thread_info*>(this_thread)->private_op_queue.push(op); + return; + } + } +#else // defined(ASIO_HAS_THREADS) + (void)is_continuation; +#endif // defined(ASIO_HAS_THREADS) + + work_started(); + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void scheduler::post_deferred_completion(scheduler::operation* op) +{ +#if defined(ASIO_HAS_THREADS) + if (one_thread_) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + static_cast<thread_info*>(this_thread)->private_op_queue.push(op); + return; + } + } +#endif // defined(ASIO_HAS_THREADS) + + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void scheduler::post_deferred_completions( + op_queue<scheduler::operation>& ops) +{ + if (!ops.empty()) + { +#if defined(ASIO_HAS_THREADS) + if (one_thread_) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + static_cast<thread_info*>(this_thread)->private_op_queue.push(ops); + return; + } + } +#endif // defined(ASIO_HAS_THREADS) + + mutex::scoped_lock lock(mutex_); + op_queue_.push(ops); + wake_one_thread_and_unlock(lock); + } +} + +void scheduler::do_dispatch( + scheduler::operation* op) +{ + work_started(); + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void scheduler::abandon_operations( + op_queue<scheduler::operation>& ops) +{ + op_queue<scheduler::operation> ops2; + ops2.push(ops); +} + +std::size_t scheduler::do_run_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, + const asio::error_code& ec) +{ + while (!stopped_) + { + if (!op_queue_.empty()) + { + // Prepare to execute first handler from queue. + operation* o = op_queue_.front(); + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + if (o == &task_operation_) + { + task_interrupted_ = more_handlers; + + if (more_handlers && !one_thread_) + wakeup_event_.unlock_and_signal_one(lock); + else + lock.unlock(); + + task_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // 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 ? 0 : -1, this_thread.private_op_queue); + } + else + { + std::size_t task_result = o->task_result_; + + if (more_handlers && !one_thread_) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Complete the operation. May throw an exception. Deletes the object. + o->complete(this, ec, task_result); + + return 1; + } + } + else + { + wakeup_event_.clear(lock); + wakeup_event_.wait(lock); + } + } + + return 0; +} + +std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, long usec, + const asio::error_code& ec) +{ + if (stopped_) + return 0; + + operation* o = op_queue_.front(); + if (o == 0) + { + wakeup_event_.clear(lock); + wakeup_event_.wait_for_usec(lock, usec); + usec = 0; // Wait at most once. + o = op_queue_.front(); + } + + if (o == &task_operation_) + { + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + task_interrupted_ = more_handlers; + + if (more_handlers && !one_thread_) + wakeup_event_.unlock_and_signal_one(lock); + else + lock.unlock(); + + { + task_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // 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 ? 0 : usec, this_thread.private_op_queue); + } + + o = op_queue_.front(); + if (o == &task_operation_) + { + if (!one_thread_) + wakeup_event_.maybe_unlock_and_signal_one(lock); + return 0; + } + } + + if (o == 0) + return 0; + + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + std::size_t task_result = o->task_result_; + + if (more_handlers && !one_thread_) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Complete the operation. May throw an exception. Deletes the object. + o->complete(this, ec, task_result); + + return 1; +} + +std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, + const asio::error_code& ec) +{ + if (stopped_) + return 0; + + operation* o = op_queue_.front(); + if (o == &task_operation_) + { + op_queue_.pop(); + lock.unlock(); + + { + task_cleanup c = { this, &lock, &this_thread }; + (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(0, this_thread.private_op_queue); + } + + o = op_queue_.front(); + if (o == &task_operation_) + { + wakeup_event_.maybe_unlock_and_signal_one(lock); + return 0; + } + } + + if (o == 0) + return 0; + + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + std::size_t task_result = o->task_result_; + + if (more_handlers && !one_thread_) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Complete the operation. May throw an exception. Deletes the object. + o->complete(this, ec, task_result); + + return 1; +} + +void scheduler::stop_all_threads( + mutex::scoped_lock& lock) +{ + stopped_ = true; + wakeup_event_.signal_all(lock); + + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } +} + +void scheduler::wake_one_thread_and_unlock( + mutex::scoped_lock& lock) +{ + if (!wakeup_event_.maybe_unlock_and_signal_one(lock)) + { + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + lock.unlock(); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_SCHEDULER_IPP diff --git a/lib/asio/detail/impl/select_reactor.hpp b/lib/asio/detail/impl/select_reactor.hpp new file mode 100644 index 0000000..04a04d4 --- /dev/null +++ b/lib/asio/detail/impl/select_reactor.hpp @@ -0,0 +1,100 @@ +// +// detail/impl/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP +#define ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) \ + || (!defined(ASIO_HAS_DEV_POLL) \ + && !defined(ASIO_HAS_EPOLL) \ + && !defined(ASIO_HAS_KQUEUE) \ + && !defined(ASIO_WINDOWS_RUNTIME)) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template <typename Time_Traits> +void select_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + interrupter_.interrupt(); +} + +template <typename Time_Traits> +std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template <typename Time_Traits> +void select_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + // || (!defined(ASIO_HAS_DEV_POLL) + // && !defined(ASIO_HAS_EPOLL) + // && !defined(ASIO_HAS_KQUEUE) + // && !defined(ASIO_WINDOWS_RUNTIME)) + +#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP diff --git a/lib/asio/detail/impl/select_reactor.ipp b/lib/asio/detail/impl/select_reactor.ipp new file mode 100644 index 0000000..262bc69 --- /dev/null +++ b/lib/asio/detail/impl/select_reactor.ipp @@ -0,0 +1,333 @@ +// +// detail/impl/select_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP +#define ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) \ + || (!defined(ASIO_HAS_DEV_POLL) \ + && !defined(ASIO_HAS_EPOLL) \ + && !defined(ASIO_HAS_KQUEUE) \ + && !defined(ASIO_WINDOWS_RUNTIME)) + +#include "asio/detail/fd_set_adapter.hpp" +#include "asio/detail/select_reactor.hpp" +#include "asio/detail/signal_blocker.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_IOCP) +class select_reactor::thread_function +{ +public: + explicit thread_function(select_reactor* r) + : this_(r) + { + } + + void operator()() + { + this_->run_thread(); + } + +private: + select_reactor* this_; +}; +#endif // defined(ASIO_HAS_IOCP) + +select_reactor::select_reactor(asio::execution_context& ctx) + : execution_context_service_base<select_reactor>(ctx), + scheduler_(use_service<scheduler_type>(ctx)), + mutex_(), + interrupter_(), +#if defined(ASIO_HAS_IOCP) + stop_thread_(false), + thread_(0), +#endif // defined(ASIO_HAS_IOCP) + shutdown_(false) +{ +#if defined(ASIO_HAS_IOCP) + asio::detail::signal_blocker sb; + thread_ = new asio::detail::thread(thread_function(this)); +#endif // defined(ASIO_HAS_IOCP) +} + +select_reactor::~select_reactor() +{ + shutdown(); +} + +void select_reactor::shutdown() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; +#if defined(ASIO_HAS_IOCP) + stop_thread_ = true; +#endif // defined(ASIO_HAS_IOCP) + lock.unlock(); + +#if defined(ASIO_HAS_IOCP) + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } +#endif // defined(ASIO_HAS_IOCP) + + op_queue<operation> ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void select_reactor::notify_fork( + asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == asio::execution_context::fork_child) + interrupter_.recreate(); +} + +void select_reactor::init_task() +{ + scheduler_.init_task(); +} + +int select_reactor::register_descriptor(socket_type, + select_reactor::per_descriptor_data&) +{ + return 0; +} + +int select_reactor::register_internal_descriptor( + int op_type, socket_type descriptor, + select_reactor::per_descriptor_data&, reactor_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + op_queue_[op_type].enqueue_operation(descriptor, op); + interrupter_.interrupt(); + + return 0; +} + +void select_reactor::move_descriptor(socket_type, + select_reactor::per_descriptor_data&, + select_reactor::per_descriptor_data&) +{ +} + +void select_reactor::start_op(int op_type, socket_type descriptor, + select_reactor::per_descriptor_data&, reactor_op* op, + bool is_continuation, bool) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + scheduler_.work_started(); + if (first) + interrupter_.interrupt(); +} + +void select_reactor::cancel_ops(socket_type descriptor, + select_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void select_reactor::deregister_descriptor(socket_type descriptor, + select_reactor::per_descriptor_data&, bool) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, asio::error::operation_aborted); +} + +void select_reactor::deregister_internal_descriptor( + socket_type descriptor, select_reactor::per_descriptor_data&) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + op_queue_[i].cancel_operations(descriptor, ops); +} + +void select_reactor::cleanup_descriptor_data( + select_reactor::per_descriptor_data&) +{ +} + +void select_reactor::run(long usec, op_queue<operation>& ops) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + +#if defined(ASIO_HAS_IOCP) + // Check if the thread is supposed to stop. + if (stop_thread_) + return; +#endif // defined(ASIO_HAS_IOCP) + + // Set up the descriptor sets. + for (int i = 0; i < max_select_ops; ++i) + fd_sets_[i].reset(); + fd_sets_[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) + { + have_work_to_do = have_work_to_do || !op_queue_[i].empty(); + fd_sets_[i].set(op_queue_[i], ops); + if (fd_sets_[i].max_descriptor() > max_fd) + max_fd = fd_sets_[i].max_descriptor(); + } + +#if defined(ASIO_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(); + fd_sets_[write_op].set(op_queue_[connect_op], ops); + if (fd_sets_[write_op].max_descriptor() > max_fd) + max_fd = fd_sets_[write_op].max_descriptor(); + fd_sets_[except_op].set(op_queue_[connect_op], ops); + if (fd_sets_[except_op].max_descriptor() > max_fd) + max_fd = fd_sets_[except_op].max_descriptor(); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!usec && !have_work_to_do) + return; + + // Determine how long to block while waiting for events. + timeval tv_buf = { 0, 0 }; + timeval* tv = usec ? get_timeout(usec, tv_buf) : &tv_buf; + + lock.unlock(); + + // Block on the select call until descriptors become ready. + asio::error_code ec; + int retval = socket_ops::select(static_cast<int>(max_fd + 1), + fd_sets_[read_op], fd_sets_[write_op], fd_sets_[except_op], tv, ec); + + // Reset the interrupter. + if (retval > 0 && fd_sets_[read_op].is_set(interrupter_.read_descriptor())) + { + interrupter_.reset(); + --retval; + } + + lock.lock(); + + // Dispatch all ready operations. + if (retval > 0) + { +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + fd_sets_[except_op].perform(op_queue_[connect_op], ops); + fd_sets_[write_op].perform(op_queue_[connect_op], ops); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + for (int i = max_select_ops - 1; i >= 0; --i) + fd_sets_[i].perform(op_queue_[i], ops); + } + timer_queues_.get_ready_timers(ops); +} + +void select_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +#if defined(ASIO_HAS_IOCP) +void select_reactor::run_thread() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + op_queue<operation> ops; + run(true, ops); + scheduler_.post_deferred_completions(ops); + lock.lock(); + } +} +#endif // defined(ASIO_HAS_IOCP) + +void select_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void select_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timeval* select_reactor::get_timeout(long usec, timeval& tv) +{ + // 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. + const long max_usec = 5 * 60 * 1000 * 1000; + usec = timer_queues_.wait_duration_usec( + (usec < 0 || max_usec < usec) ? max_usec : usec); + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + return &tv; +} + +void select_reactor::cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec) +{ + bool need_interrupt = false; + op_queue<operation> ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + scheduler_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + // || (!defined(ASIO_HAS_DEV_POLL) + // && !defined(ASIO_HAS_EPOLL) + // && !defined(ASIO_HAS_KQUEUE)) + // && !defined(ASIO_WINDOWS_RUNTIME)) + +#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP diff --git a/lib/asio/detail/impl/service_registry.hpp b/lib/asio/detail/impl/service_registry.hpp new file mode 100644 index 0000000..d4db589 --- /dev/null +++ b/lib/asio/detail/impl/service_registry.hpp @@ -0,0 +1,94 @@ +// +// detail/impl/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP +#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Service> +Service& service_registry::use_service() +{ + execution_context::service::key key; + init_key<Service>(key, 0); + factory_type factory = &service_registry::create<Service, execution_context>; + return *static_cast<Service*>(do_use_service(key, factory, &owner_)); +} + +template <typename Service> +Service& service_registry::use_service(io_context& owner) +{ + execution_context::service::key key; + init_key<Service>(key, 0); + factory_type factory = &service_registry::create<Service, io_context>; + return *static_cast<Service*>(do_use_service(key, factory, &owner)); +} + +template <typename Service> +void service_registry::add_service(Service* new_service) +{ + execution_context::service::key key; + init_key<Service>(key, 0); + return do_add_service(key, new_service); +} + +template <typename Service> +bool service_registry::has_service() const +{ + execution_context::service::key key; + init_key<Service>(key, 0); + return do_has_service(key); +} + +template <typename Service> +inline void service_registry::init_key( + execution_context::service::key& key, ...) +{ + init_key_from_id(key, Service::id); +} + +#if !defined(ASIO_NO_TYPEID) +template <typename Service> +void service_registry::init_key(execution_context::service::key& key, + typename enable_if< + is_base_of<typename Service::key_type, Service>::value>::type*) +{ + key.type_info_ = &typeid(typeid_wrapper<Service>); + key.id_ = 0; +} + +template <typename Service> +void service_registry::init_key_from_id(execution_context::service::key& key, + const service_id<Service>& /*id*/) +{ + key.type_info_ = &typeid(typeid_wrapper<Service>); + key.id_ = 0; +} +#endif // !defined(ASIO_NO_TYPEID) + +template <typename Service, typename Owner> +execution_context::service* service_registry::create(void* owner) +{ + return new Service(*static_cast<Owner*>(owner)); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP diff --git a/lib/asio/detail/impl/service_registry.ipp b/lib/asio/detail/impl/service_registry.ipp new file mode 100644 index 0000000..a465033 --- /dev/null +++ b/lib/asio/detail/impl/service_registry.ipp @@ -0,0 +1,197 @@ +// +// detail/impl/service_registry.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP +#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <vector> +#include "asio/detail/service_registry.hpp" +#include "asio/detail/throw_exception.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +service_registry::service_registry(execution_context& owner) + : owner_(owner), + first_service_(0) +{ +} + +service_registry::~service_registry() +{ +} + +void service_registry::shutdown_services() +{ + execution_context::service* service = first_service_; + while (service) + { + service->shutdown(); + service = service->next_; + } +} + +void service_registry::destroy_services() +{ + while (first_service_) + { + execution_context::service* next_service = first_service_->next_; + destroy(first_service_); + first_service_ = next_service; + } +} + +void service_registry::notify_fork(execution_context::fork_event fork_ev) +{ + // Make a copy of all of the services while holding the lock. We don't want + // to hold the lock while calling into each service, as it may try to call + // back into this class. + std::vector<execution_context::service*> services; + { + asio::detail::mutex::scoped_lock lock(mutex_); + execution_context::service* service = first_service_; + while (service) + { + services.push_back(service); + service = service->next_; + } + } + + // If processing the fork_prepare event, we want to go in reverse order of + // service registration, which happens to be the existing order of the + // services in the vector. For the other events we want to go in the other + // direction. + std::size_t num_services = services.size(); + if (fork_ev == execution_context::fork_prepare) + for (std::size_t i = 0; i < num_services; ++i) + services[i]->notify_fork(fork_ev); + else + for (std::size_t i = num_services; i > 0; --i) + services[i - 1]->notify_fork(fork_ev); +} + +void service_registry::init_key_from_id(execution_context::service::key& key, + const execution_context::id& id) +{ + key.type_info_ = 0; + key.id_ = &id; +} + +bool service_registry::keys_match( + const execution_context::service::key& key1, + const execution_context::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; +} + +void service_registry::destroy(execution_context::service* service) +{ + delete service; +} + +execution_context::service* service_registry::do_use_service( + const execution_context::service::key& key, + factory_type factory, void* owner) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + // First see if there is an existing service object with the given key. + execution_context::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Create a new service object. The service registry's mutex is not locked + // at this time to allow for nested calls into this function from the new + // service's constructor. + lock.unlock(); + 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 + // while the lock was released. + service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Service was successfully initialised, pass ownership to registry. + new_service.ptr_->next_ = first_service_; + first_service_ = new_service.ptr_; + new_service.ptr_ = 0; + return first_service_; +} + +void service_registry::do_add_service( + const execution_context::service::key& key, + execution_context::service* new_service) +{ + if (&owner_ != &new_service->context()) + asio::detail::throw_exception(invalid_service_owner()); + + asio::detail::mutex::scoped_lock lock(mutex_); + + // Check if there is an existing service object with the given key. + execution_context::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + asio::detail::throw_exception(service_already_exists()); + service = service->next_; + } + + // Take ownership of the service object. + new_service->key_ = key; + new_service->next_ = first_service_; + first_service_ = new_service; +} + +bool service_registry::do_has_service( + const execution_context::service::key& key) const +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + execution_context::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return true; + service = service->next_; + } + + return false; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP diff --git a/lib/asio/detail/impl/signal_set_service.ipp b/lib/asio/detail/impl/signal_set_service.ipp new file mode 100644 index 0000000..dd68fc1 --- /dev/null +++ b/lib/asio/detail/impl/signal_set_service.ipp @@ -0,0 +1,669 @@ +// +// detail/impl/signal_set_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP +#define ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <cstring> +#include <stdexcept> +#include "asio/detail/reactor.hpp" +#include "asio/detail/signal_blocker.hpp" +#include "asio/detail/signal_set_service.hpp" +#include "asio/detail/static_mutex.hpp" +#include "asio/detail/throw_exception.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct signal_state +{ + // Mutex used for protecting global state. + static_mutex mutex_; + + // The read end of the pipe used for signal notifications. + int read_descriptor_; + + // The write end of the pipe used for signal notifications. + int write_descriptor_; + + // Whether the signal state has been prepared for a fork. + bool fork_prepared_; + + // The head of a linked list of all signal_set_service instances. + class signal_set_service* service_list_; + + // A count of the number of objects that are registered for each signal. + std::size_t registration_count_[max_signal_number]; +}; + +signal_state* get_signal_state() +{ + static signal_state state = { + ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } }; + return &state; +} + +void asio_signal_handler(int signal_number) +{ +#if defined(ASIO_WINDOWS) \ + || defined(ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) + signal_set_service::deliver_signal(signal_number); +#else // defined(ASIO_WINDOWS) + // || defined(ASIO_WINDOWS_RUNTIME) + // || defined(__CYGWIN__) + int saved_errno = errno; + signal_state* state = get_signal_state(); + signed_size_type result = ::write(state->write_descriptor_, + &signal_number, sizeof(signal_number)); + (void)result; + errno = saved_errno; +#endif // defined(ASIO_WINDOWS) + // || defined(ASIO_WINDOWS_RUNTIME) + // || defined(__CYGWIN__) + +#if defined(ASIO_HAS_SIGNAL) && !defined(ASIO_HAS_SIGACTION) + ::signal(signal_number, asio_signal_handler); +#endif // defined(ASIO_HAS_SIGNAL) && !defined(ASIO_HAS_SIGACTION) +} + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +class signal_set_service::pipe_read_op : public reactor_op +{ +public: + pipe_read_op() + : reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete) + { + } + + static status do_perform(reactor_op*) + { + signal_state* state = get_signal_state(); + + int fd = state->read_descriptor_; + int signal_number = 0; + while (::read(fd, &signal_number, sizeof(int)) == sizeof(int)) + if (signal_number >= 0 && signal_number < max_signal_number) + signal_set_service::deliver_signal(signal_number); + + return not_done; + } + + static void do_complete(void* /*owner*/, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + pipe_read_op* o(static_cast<pipe_read_op*>(base)); + delete o; + } +}; +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +signal_set_service::signal_set_service( + asio::io_context& io_context) + : service_base<signal_set_service>(io_context), + io_context_(asio::use_service<io_context_impl>(io_context)), +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + reactor_(asio::use_service<reactor>(io_context)), +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + next_(0), + prev_(0) +{ + get_signal_state()->mutex_.init(); + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + reactor_.init_task(); +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + + for (int i = 0; i < max_signal_number; ++i) + registrations_[i] = 0; + + add_service(this); +} + +signal_set_service::~signal_set_service() +{ + remove_service(this); +} + +void signal_set_service::shutdown() +{ + remove_service(this); + + op_queue<operation> ops; + + for (int i = 0; i < max_signal_number; ++i) + { + registration* reg = registrations_[i]; + while (reg) + { + ops.push(*reg->queue_); + reg = reg->next_in_table_; + } + } + + io_context_.abandon_operations(ops); +} + +void signal_set_service::notify_fork( + asio::io_context::fork_event fork_ev) +{ +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + switch (fork_ev) + { + case asio::io_context::fork_prepare: + { + int read_descriptor = state->read_descriptor_; + state->fork_prepared_ = true; + lock.unlock(); + reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_); + reactor_.cleanup_descriptor_data(reactor_data_); + } + break; + case asio::io_context::fork_parent: + if (state->fork_prepared_) + { + int read_descriptor = state->read_descriptor_; + state->fork_prepared_ = false; + lock.unlock(); + reactor_.register_internal_descriptor(reactor::read_op, + read_descriptor, reactor_data_, new pipe_read_op); + } + break; + case asio::io_context::fork_child: + if (state->fork_prepared_) + { + asio::detail::signal_blocker blocker; + close_descriptors(); + open_descriptors(); + int read_descriptor = state->read_descriptor_; + state->fork_prepared_ = false; + lock.unlock(); + reactor_.register_internal_descriptor(reactor::read_op, + read_descriptor, reactor_data_, new pipe_read_op); + } + break; + default: + break; + } +#else // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + (void)fork_ev; +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::construct( + signal_set_service::implementation_type& impl) +{ + impl.signals_ = 0; +} + +void signal_set_service::destroy( + signal_set_service::implementation_type& impl) +{ + asio::error_code ignored_ec; + clear(impl, ignored_ec); + cancel(impl, ignored_ec); +} + +asio::error_code signal_set_service::add( + signal_set_service::implementation_type& impl, + int signal_number, asio::error_code& ec) +{ + // Check that the signal number is valid. + if (signal_number < 0 || signal_number >= max_signal_number) + { + ec = asio::error::invalid_argument; + return ec; + } + + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + // Find the appropriate place to insert the registration. + registration** insertion_point = &impl.signals_; + registration* next = impl.signals_; + while (next && next->signal_number_ < signal_number) + { + insertion_point = &next->next_in_set_; + next = next->next_in_set_; + } + + // Only do something if the signal is not already registered. + if (next == 0 || next->signal_number_ != signal_number) + { + registration* new_registration = new registration; + +#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + // Register for the signal if we're the first. + if (state->registration_count_[signal_number] == 0) + { +# if defined(ASIO_HAS_SIGACTION) + using namespace std; // For memset. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = asio_signal_handler; + sigfillset(&sa.sa_mask); + if (::sigaction(signal_number, &sa, 0) == -1) +# else // defined(ASIO_HAS_SIGACTION) + if (::signal(signal_number, asio_signal_handler) == SIG_ERR) +# endif // defined(ASIO_HAS_SIGACTION) + { +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error::invalid_argument; +# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(errno, + asio::error::get_system_category()); +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + delete new_registration; + return ec; + } + } +#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + + // Record the new registration in the set. + new_registration->signal_number_ = signal_number; + new_registration->queue_ = &impl.queue_; + new_registration->next_in_set_ = next; + *insertion_point = new_registration; + + // Insert registration into the registration table. + new_registration->next_in_table_ = registrations_[signal_number]; + if (registrations_[signal_number]) + registrations_[signal_number]->prev_in_table_ = new_registration; + registrations_[signal_number] = new_registration; + + ++state->registration_count_[signal_number]; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code signal_set_service::remove( + signal_set_service::implementation_type& impl, + int signal_number, asio::error_code& ec) +{ + // Check that the signal number is valid. + if (signal_number < 0 || signal_number >= max_signal_number) + { + ec = asio::error::invalid_argument; + return ec; + } + + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + // Find the signal number in the list of registrations. + registration** deletion_point = &impl.signals_; + registration* reg = impl.signals_; + while (reg && reg->signal_number_ < signal_number) + { + deletion_point = ®->next_in_set_; + reg = reg->next_in_set_; + } + + if (reg != 0 && reg->signal_number_ == signal_number) + { +#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + // Set signal handler back to the default if we're the last. + if (state->registration_count_[signal_number] == 1) + { +# if defined(ASIO_HAS_SIGACTION) + using namespace std; // For memset. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + if (::sigaction(signal_number, &sa, 0) == -1) +# else // defined(ASIO_HAS_SIGACTION) + if (::signal(signal_number, SIG_DFL) == SIG_ERR) +# endif // defined(ASIO_HAS_SIGACTION) + { +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error::invalid_argument; +# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(errno, + asio::error::get_system_category()); +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + return ec; + } + } +#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + + // Remove the registration from the set. + *deletion_point = reg->next_in_set_; + + // Remove the registration from the registration table. + if (registrations_[signal_number] == reg) + registrations_[signal_number] = reg->next_in_table_; + if (reg->prev_in_table_) + reg->prev_in_table_->next_in_table_ = reg->next_in_table_; + if (reg->next_in_table_) + reg->next_in_table_->prev_in_table_ = reg->prev_in_table_; + + --state->registration_count_[signal_number]; + + delete reg; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code signal_set_service::clear( + signal_set_service::implementation_type& impl, + asio::error_code& ec) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + while (registration* reg = impl.signals_) + { +#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + // Set signal handler back to the default if we're the last. + if (state->registration_count_[reg->signal_number_] == 1) + { +# if defined(ASIO_HAS_SIGACTION) + using namespace std; // For memset. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + if (::sigaction(reg->signal_number_, &sa, 0) == -1) +# else // defined(ASIO_HAS_SIGACTION) + if (::signal(reg->signal_number_, SIG_DFL) == SIG_ERR) +# endif // defined(ASIO_HAS_SIGACTION) + { +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error::invalid_argument; +# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(errno, + asio::error::get_system_category()); +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + return ec; + } + } +#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) + + // Remove the registration from the registration table. + if (registrations_[reg->signal_number_] == reg) + registrations_[reg->signal_number_] = reg->next_in_table_; + if (reg->prev_in_table_) + reg->prev_in_table_->next_in_table_ = reg->next_in_table_; + if (reg->next_in_table_) + reg->next_in_table_->prev_in_table_ = reg->prev_in_table_; + + --state->registration_count_[reg->signal_number_]; + + impl.signals_ = reg->next_in_set_; + delete reg; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code signal_set_service::cancel( + signal_set_service::implementation_type& impl, + asio::error_code& ec) +{ + ASIO_HANDLER_OPERATION((io_context_.context(), + "signal_set", &impl, 0, "cancel")); + + op_queue<operation> ops; + { + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + while (signal_op* op = impl.queue_.front()) + { + op->ec_ = asio::error::operation_aborted; + impl.queue_.pop(); + ops.push(op); + } + } + + io_context_.post_deferred_completions(ops); + + ec = asio::error_code(); + return ec; +} + +void signal_set_service::deliver_signal(int signal_number) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + signal_set_service* service = state->service_list_; + while (service) + { + op_queue<operation> ops; + + registration* reg = service->registrations_[signal_number]; + while (reg) + { + if (reg->queue_->empty()) + { + ++reg->undelivered_; + } + else + { + while (signal_op* op = reg->queue_->front()) + { + op->signal_number_ = signal_number; + reg->queue_->pop(); + ops.push(op); + } + } + + reg = reg->next_in_table_; + } + + service->io_context_.post_deferred_completions(ops); + + service = service->next_; + } +} + +void signal_set_service::add_service(signal_set_service* service) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + // If this is the first service to be created, open a new pipe. + if (state->service_list_ == 0) + open_descriptors(); +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + + // If an io_context object is thread-unsafe then it must be the only + // io_context used to create signal_set objects. + if (state->service_list_ != 0) + { + if (!ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + service->io_context_.concurrency_hint()) + || !ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + state->service_list_->io_context_.concurrency_hint())) + { + std::logic_error ex( + "Thread-unsafe io_context objects require " + "exclusive access to signal handling."); + asio::detail::throw_exception(ex); + } + } + + // Insert service into linked list of all services. + service->next_ = state->service_list_; + service->prev_ = 0; + if (state->service_list_) + state->service_list_->prev_ = service; + state->service_list_ = service; + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + // Register for pipe readiness notifications. + int read_descriptor = state->read_descriptor_; + lock.unlock(); + service->reactor_.register_internal_descriptor(reactor::read_op, + read_descriptor, service->reactor_data_, new pipe_read_op); +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::remove_service(signal_set_service* service) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + if (service->next_ || service->prev_ || state->service_list_ == service) + { +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + // Disable the pipe readiness notifications. + int read_descriptor = state->read_descriptor_; + lock.unlock(); + service->reactor_.deregister_internal_descriptor( + read_descriptor, service->reactor_data_); + service->reactor_.cleanup_descriptor_data(service->reactor_data_); + lock.lock(); +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + + // Remove service from linked list of all services. + if (state->service_list_ == service) + state->service_list_ = service->next_; + if (service->prev_) + service->prev_->next_ = service->next_; + if (service->next_) + service->next_->prev_= service->prev_; + service->next_ = 0; + service->prev_ = 0; + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + // If this is the last service to be removed, close the pipe. + if (state->service_list_ == 0) + close_descriptors(); +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + } +} + +void signal_set_service::open_descriptors() +{ +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + signal_state* state = get_signal_state(); + + int pipe_fds[2]; + if (::pipe(pipe_fds) == 0) + { + state->read_descriptor_ = pipe_fds[0]; + ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK); + + state->write_descriptor_ = pipe_fds[1]; + ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK); + +#if defined(FD_CLOEXEC) + ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC); + ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC); +#endif // defined(FD_CLOEXEC) + } + else + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "signal_set_service pipe"); + } +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::close_descriptors() +{ +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + signal_state* state = get_signal_state(); + + if (state->read_descriptor_ != -1) + ::close(state->read_descriptor_); + state->read_descriptor_ = -1; + + if (state->write_descriptor_ != -1) + ::close(state->write_descriptor_); + state->write_descriptor_ = -1; +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::start_wait_op( + signal_set_service::implementation_type& impl, signal_op* op) +{ + io_context_.work_started(); + + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + registration* reg = impl.signals_; + while (reg) + { + if (reg->undelivered_ > 0) + { + --reg->undelivered_; + op->signal_number_ = reg->signal_number_; + io_context_.post_deferred_completion(op); + return; + } + + reg = reg->next_in_set_; + } + + impl.queue_.push(op); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP diff --git a/lib/asio/detail/impl/socket_ops.ipp b/lib/asio/detail/impl/socket_ops.ipp new file mode 100644 index 0000000..5e74733 --- /dev/null +++ b/lib/asio/detail/impl/socket_ops.ipp @@ -0,0 +1,3571 @@ +// +// detail/impl/socket_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SOCKET_OPS_IPP +#define ASIO_DETAIL_SOCKET_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <cerrno> +#include <new> +#include "asio/detail/assert.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +# include <codecvt> +# include <locale> +# include <string> +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) \ + || defined(__MACH__) && defined(__APPLE__) +# if defined(ASIO_HAS_PTHREADS) +# include <pthread.h> +# endif // defined(ASIO_HAS_PTHREADS) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // || defined(__MACH__) && defined(__APPLE__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace socket_ops { + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +struct msghdr { int msg_namelen; }; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) +// HP-UX doesn't declare these functions extern "C", so they are declared again +// here to avoid linker errors about undefined symbols. +extern "C" char* if_indextoname(unsigned int, char*); +extern "C" unsigned int if_nametoindex(const char*); +#endif // defined(__hpux) + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +inline void clear_last_error() +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + WSASetLastError(0); +#else + errno = 0; +#endif +} + +#if !defined(ASIO_WINDOWS_RUNTIME) + +template <typename ReturnType> +inline ReturnType error_wrapper(ReturnType return_value, + asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(WSAGetLastError(), + asio::error::get_system_category()); +#else + ec = asio::error_code(errno, + asio::error::get_system_category()); +#endif + return return_value; +} + +template <typename SockLenType> +inline socket_type call_accept(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return invalid_socket; + } + + clear_last_error(); + + socket_type new_s = error_wrapper(call_accept( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (new_s == invalid_socket) + return new_s; + +#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + int optval = 1; + int result = error_wrapper(::setsockopt(new_s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(new_s); + return invalid_socket; + } +#endif + + ec = asio::error_code(); + return new_s; +} + +socket_type sync_accept(socket_type s, state_type state, + socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) +{ + // Accept a socket. + for (;;) + { + // Try to complete the operation without blocking. + socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket != invalid_socket) + return new_socket; + + // Operation failed. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + { + if (state & user_set_non_blocking) + return invalid_socket; + // Fall through to retry operation. + } + else if (ec == asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return invalid_socket; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return invalid_socket; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_aborted; + + if (!ec) + { + // Get the address of the peer. + if (addr && addrlen) + { + LPSOCKADDR local_addr = 0; + int local_addr_length = 0; + LPSOCKADDR remote_addr = 0; + int remote_addr_length = 0; + GetAcceptExSockaddrs(output_buffer, 0, address_length, + address_length, &local_addr, &local_addr_length, + &remote_addr, &remote_addr_length); + if (static_cast<std::size_t>(remote_addr_length) > *addrlen) + { + ec = asio::error::invalid_argument; + } + else + { + using namespace std; // For memcpy. + memcpy(addr, remote_addr, remote_addr_length); + *addrlen = static_cast<std::size_t>(remote_addr_length); + } + } + + // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname + // and getpeername will work on the accepted socket. + SOCKET update_ctx_param = s; + socket_ops::state_type state = 0; + socket_ops::setsockopt(new_socket, state, + SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + &update_ctx_param, sizeof(SOCKET), ec); + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, socket_type& new_socket) +{ + for (;;) + { + // Accept the waiting connection. + new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket != invalid_socket) + return true; + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Operation failed. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + { + // Fall through to retry operation. + } + else if (ec == asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return true; + + return false; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +template <typename SockLenType> +inline int call_bind(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::bind(s, addr, (SockLenType)addrlen); +} + +int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_bind( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +int close(socket_type s, state_type& state, + bool destruction, asio::error_code& ec) +{ + int result = 0; + if (s != invalid_socket) + { + // We don't want the destructor to block, so set the socket to linger in + // the background. If the user doesn't like this behaviour then they need + // to explicitly close the socket. + if (destruction && (state & user_set_linger)) + { + ::linger opt; + opt.l_onoff = 0; + opt.l_linger = 0; + asio::error_code ignored_ec; + socket_ops::setsockopt(s, state, SOL_SOCKET, + SO_LINGER, &opt, sizeof(opt), ignored_ec); + } + + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + result = error_wrapper(::closesocket(s), ec); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + result = error_wrapper(::close(s), ec); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + + if (result != 0 + && (ec == asio::error::would_block + || ec == asio::error::try_again)) + { + // According to UNIX Network Programming Vol. 1, it is possible for + // close() to fail with EWOULDBLOCK under certain circumstances. What + // isn't clear is the state of the descriptor after this error. The one + // current OS where this behaviour is seen, Windows, says that the socket + // remains open. Therefore we'll put the descriptor back into blocking + // mode and have another attempt at closing it. +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = 0; + ::ioctlsocket(s, FIONBIO, &arg); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(__SYMBIAN32__) + int flags = ::fcntl(s, F_GETFL, 0); + if (flags >= 0) + ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK); +# else // defined(__SYMBIAN32__) + ioctl_arg_type arg = 0; + ::ioctl(s, FIONBIO, &arg); +# endif // defined(__SYMBIAN32__) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + state &= ~non_blocking; + + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + result = error_wrapper(::closesocket(s), ec); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + result = error_wrapper(::close(s), ec); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + } + } + + if (result == 0) + ec = asio::error_code(); + return result; +} + +bool set_user_non_blocking(socket_type s, + state_type& state, bool value, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return false; + } + + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); +#elif defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + if (result >= 0) + { + clear_last_error(); + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = error_wrapper(::fcntl(s, F_SETFL, flag), ec); + } +#else + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); +#endif + + if (result >= 0) + { + ec = asio::error_code(); + if (value) + state |= user_set_non_blocking; + else + { + // Clearing the user-set non-blocking mode always overrides any + // internally-set non-blocking flag. Any subsequent asynchronous + // operations will need to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + return true; + } + + return false; +} + +bool set_internal_non_blocking(socket_type s, + state_type& state, bool value, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return false; + } + + if (!value && (state & user_set_non_blocking)) + { + // It does not make sense to clear the internal non-blocking flag if the + // user still wants non-blocking behaviour. Return an error and let the + // caller figure out whether to update the user-set non-blocking flag. + ec = asio::error::invalid_argument; + return false; + } + + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); +#elif defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + if (result >= 0) + { + clear_last_error(); + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = error_wrapper(::fcntl(s, F_SETFL, flag), ec); + } +#else + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); +#endif + + if (result >= 0) + { + ec = asio::error_code(); + if (value) + state |= internal_non_blocking; + else + state &= ~internal_non_blocking; + return true; + } + + return false; +} + +int shutdown(socket_type s, int what, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(::shutdown(s, what), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +template <typename SockLenType> +inline int call_connect(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::connect(s, addr, (SockLenType)addrlen); +} + +int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_connect( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = asio::error_code(); +#if defined(__linux__) + else if (ec == asio::error::try_again) + ec = asio::error::no_buffer_space; +#endif // defined(__linux__) + return result; +} + +void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + // Perform the connect operation. + socket_ops::connect(s, addr, addrlen, ec); + if (ec != asio::error::in_progress + && ec != asio::error::would_block) + { + // The connect operation finished immediately. + return; + } + + // Wait for socket to become ready. + if (socket_ops::poll_connect(s, -1, ec) < 0) + return; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == socket_error_retval) + return; + + // Return the result of the connect operation. + ec = asio::error_code(connect_error, + asio::error::get_system_category()); +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_connect(socket_type s, asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + switch (ec.value()) + { + case ERROR_CONNECTION_REFUSED: + ec = asio::error::connection_refused; + break; + case ERROR_NETWORK_UNREACHABLE: + ec = asio::error::network_unreachable; + break; + case ERROR_HOST_UNREACHABLE: + ec = asio::error::host_unreachable; + break; + case ERROR_SEM_TIMEOUT: + ec = asio::error::timed_out; + break; + default: + break; + } + + if (!ec) + { + // Need to set the SO_UPDATE_CONNECT_CONTEXT option so that getsockname + // and getpeername will work on the connected socket. + socket_ops::state_type state = 0; + const int so_update_connect_context = 0x7010; + socket_ops::setsockopt(s, state, SOL_SOCKET, + so_update_connect_context, 0, 0, ec); + } +} + +#endif // defined(ASIO_HAS_IOCP) + +bool non_blocking_connect(socket_type s, asio::error_code& ec) +{ + // Check if the connect operation has finished. This is required since we may + // get spurious readiness notifications from the reactor. +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + fd_set except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + timeval zero_timeout; + zero_timeout.tv_sec = 0; + zero_timeout.tv_usec = 0; + int ready = ::select(s + 1, 0, &write_fds, &except_fds, &zero_timeout); +#else // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + int ready = ::poll(&fds, 1, 0); +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (ready == 0) + { + // The asynchronous connect operation is still in progress. + return false; + } + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == 0) + { + if (connect_error) + { + ec = asio::error_code(connect_error, + asio::error::get_system_category()); + } + else + ec = asio::error_code(); + } + + return true; +} + +int socketpair(int af, int type, int protocol, + socket_type sv[2], asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + (void)(af); + (void)(type); + (void)(protocol); + (void)(sv); + ec = asio::error::operation_not_supported; + return socket_error_retval; +#else + clear_last_error(); + int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); + if (result == 0) + ec = asio::error_code(); + return result; +#endif +} + +bool sockatmark(socket_type s, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return false; + } + +#if defined(SIOCATMARK) + ioctl_arg_type value = 0; +# if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec); +# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec); +# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = asio::error_code(); +# if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = asio::error::not_socket; +# endif // defined(ENOTTY) +#else // defined(SIOCATMARK) + int value = error_wrapper(::sockatmark(s), ec); + if (value != -1) + ec = asio::error_code(); +#endif // defined(SIOCATMARK) + + return ec ? false : value != 0; +} + +size_t available(socket_type s, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + ioctl_arg_type value = 0; +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec); +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = asio::error_code(); +#if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = asio::error::not_socket; +#endif // defined(ENOTTY) + + return ec ? static_cast<size_t>(0) : static_cast<size_t>(value); +} + +int listen(socket_type s, int backlog, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(::listen(s, backlog), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +inline void init_buf_iov_base(void*& base, void* addr) +{ + base = addr; +} + +template <typename T> +inline void init_buf_iov_base(T& base, void* addr) +{ + base = static_cast<T>(addr); +} + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef WSABUF buf; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef iovec buf; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +void init_buf(buf& b, void* data, size_t size) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast<char*>(data); + b.len = static_cast<u_long>(size); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, data); + b.iov_len = size; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +void init_buf(buf& b, const void* data, size_t size) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast<char*>(const_cast<void*>(data)); + b.len = static_cast<u_long>(size); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, const_cast<void*>(data)); + b.iov_len = size; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) +{ + name = addr; +} + +inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) +{ + name = const_cast<socket_addr_type*>(addr); +} + +template <typename T> +inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) +{ + name = reinterpret_cast<T>(addr); +} + +template <typename T> +inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) +{ + name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr)); +} + +signed_size_type recv(socket_type s, buf* bufs, size_t count, + int flags, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast<DWORD>(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = error_wrapper(::WSARecv(s, bufs, + recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + ec.assign(0, ec.category()); + if (result != 0) + return socket_error_retval; + ec = asio::error_code(); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = bufs; + msg.msg_iovlen = static_cast<int>(count); + signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec = asio::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if ((state & stream_oriented) && bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + asio::error_code& ec, size_t bytes_transferred) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } + + // Check for connection closed. + else if (!ec && bytes_transferred == 0 + && (state & stream_oriented) != 0 + && !all_empty) + { + ec = asio::error::eof; + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check for end of stream. + if (is_stream && bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, + int flags, socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast<DWORD>(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + *addrlen = (std::size_t)tmp_addrlen; + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + ec.assign(0, ec.category()); + if (result != 0) + return socket_error_retval; + ec = asio::error_code(); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = static_cast<int>(*addrlen); + msg.msg_iov = bufs; + msg.msg_iovlen = static_cast<int>(count); + signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); + *addrlen = msg.msg_namelen; + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, + size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recvfrom( + s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recvfrom( + s, bufs, count, flags, addr, addrlen, ec); + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +signed_size_type recvmsg(socket_type s, buf* bufs, size_t count, + int in_flags, int& out_flags, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + out_flags = 0; + return socket_ops::recv(s, bufs, count, in_flags, ec); +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = bufs; + msg.msg_iovlen = static_cast<int>(count); + signed_size_type result = error_wrapper(::recvmsg(s, &msg, in_flags), ec); + if (result >= 0) + { + ec = asio::error_code(); + out_flags = msg.msg_flags; + } + else + out_flags = 0; + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recvmsg(socket_type s, state_type state, + buf* bufs, size_t count, int in_flags, int& out_flags, + asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recvmsg( + s, bufs, count, in_flags, out_flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_recvmsg( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_recvmsg(socket_type s, + buf* bufs, size_t count, int in_flags, int& out_flags, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recvmsg( + s, bufs, count, in_flags, out_flags, ec); + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +signed_size_type send(socket_type s, const buf* bufs, size_t count, + int flags, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast<DWORD>(count); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs), + send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = asio::error_code(); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = const_cast<buf*>(bufs); + msg.msg_iovlen = static_cast<int>(count); +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_send(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, bool all_empty, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes to a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec = asio::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(ASIO_HAS_IOCP) + +void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } +} + +#else // defined(ASIO_HAS_IOCP) + +bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(ASIO_HAS_IOCP) + +signed_size_type sendto(socket_type s, const buf* bufs, size_t count, + int flags, const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast<DWORD>(count); + DWORD bytes_transferred = 0; + int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs), + send_buf_count, &bytes_transferred, flags, addr, + static_cast<int>(addrlen), 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = asio::error_code(); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = static_cast<int>(addrlen); + msg.msg_iov = const_cast<buf*>(bufs); + msg.msg_iovlen = static_cast<int>(count); +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_sendto(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::sendto( + s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + +#if !defined(ASIO_HAS_IOCP) + +bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::sendto( + s, bufs, count, flags, addr, addrlen, ec); + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = asio::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // !defined(ASIO_HAS_IOCP) + +socket_type socket(int af, int type, int protocol, + asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + socket_type s = error_wrapper(::WSASocketW(af, type, protocol, 0, 0, + WSA_FLAG_OVERLAPPED), ec); + if (s == invalid_socket) + return s; + + if (af == ASIO_OS_DEF(AF_INET6)) + { + // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to + // false. This will only succeed on Windows Vista and later versions of + // Windows, where a dual-stack IPv4/v6 implementation is available. + DWORD optval = 0; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast<const char*>(&optval), sizeof(optval)); + } + + ec = asio::error_code(); + + return s; +#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + socket_type s = error_wrapper(::socket(af, type, protocol), ec); + if (s == invalid_socket) + return s; + + int optval = 1; + int result = error_wrapper(::setsockopt(s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(s); + return invalid_socket; + } + + return s; +#else + int s = error_wrapper(::socket(af, type, protocol), ec); + if (s >= 0) + ec = asio::error_code(); + return s; +#endif +} + +template <typename SockLenType> +inline int call_setsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + const void* optval, std::size_t optlen) +{ + return ::setsockopt(s, level, optname, + (const char*)optval, (SockLenType)optlen); +} + +int setsockopt(socket_type s, state_type& state, int level, int optname, + const void* optval, std::size_t optlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (optlen != sizeof(int)) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + if (*static_cast<const int*>(optval)) + state |= enable_connection_aborted; + else + state &= ~enable_connection_aborted; + ec = asio::error_code(); + return 0; + } + + if (level == SOL_SOCKET && optname == SO_LINGER) + state |= user_set_linger; + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); + if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) + { + clear_last_error(); + return error_wrapper(sso(s, level, optname, + reinterpret_cast<const char*>(optval), + static_cast<int>(optlen)), ec); + } + } + ec = asio::error::fault; + return socket_error_retval; +#else // defined(__BORLANDC__) + clear_last_error(); + int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result == 0) + { + ec = asio::error_code(); + +#if defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + // To implement portable behaviour for SO_REUSEADDR with UDP sockets we + // need to also set SO_REUSEPORT on BSD-based platforms. + if ((state & datagram_oriented) + && level == SOL_SOCKET && optname == SO_REUSEADDR) + { + call_setsockopt(&msghdr::msg_namelen, s, + SOL_SOCKET, SO_REUSEPORT, optval, optlen); + } +#endif + } + + return result; +#endif // defined(__BORLANDC__) +} + +template <typename SockLenType> +inline int call_getsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + void* optval, std::size_t* optlen) +{ + SockLenType tmp_optlen = (SockLenType)*optlen; + int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); + *optlen = (std::size_t)tmp_optlen; + return result; +} + +int getsockopt(socket_type s, state_type state, int level, int optname, + void* optval, size_t* optlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (*optlen != sizeof(int)) + { + ec = asio::error::invalid_argument; + return socket_error_retval; + } + + *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0; + ec = asio::error_code(); + return 0; + } + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); + if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) + { + clear_last_error(); + int tmp_optlen = static_cast<int>(*optlen); + int result = error_wrapper(gso(s, level, optname, + reinterpret_cast<char*>(optval), &tmp_optlen), ec); + *optlen = static_cast<size_t>(tmp_optlen); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are + // only supported on Windows Vista and later. To simplify program logic + // we will fake success of getting this option and specify that the + // value is non-zero (i.e. true). This corresponds to the behavior of + // IPv6 sockets on Windows platforms pre-Vista. + *static_cast<DWORD*>(optval) = 1; + ec = asio::error_code(); + } + return result; + } + } + ec = asio::error::fault; + return socket_error_retval; +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + clear_last_error(); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only + // supported on Windows Vista and later. To simplify program logic we will + // fake success of getting this option and specify that the value is + // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets + // on Windows platforms pre-Vista. + *static_cast<DWORD*>(optval) = 1; + ec = asio::error_code(); + } + if (result == 0) + ec = asio::error_code(); + return result; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + clear_last_error(); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); +#if defined(__linux__) + if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) + && (optname == SO_SNDBUF || optname == SO_RCVBUF)) + { + // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel + // to set the buffer size to N*2. Linux puts additional stuff into the + // buffers so that only about half is actually available to the application. + // The retrieved value is divided by 2 here to make it appear as though the + // correct value has been set. + *static_cast<int*>(optval) /= 2; + } +#endif // defined(__linux__) + if (result == 0) + ec = asio::error_code(); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +template <typename SockLenType> +inline int call_getpeername(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getpeername(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) \ + || defined(__CYGWIN__) + if (cached) + { + // Check if socket is still connected. + DWORD connect_time = 0; + size_t connect_time_len = sizeof(connect_time); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME, + &connect_time, &connect_time_len, ec) == socket_error_retval) + { + return socket_error_retval; + } + if (connect_time == 0xFFFFFFFF) + { + ec = asio::error::not_connected; + return socket_error_retval; + } + + // The cached value is still valid. + ec = asio::error_code(); + return 0; + } +#else // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) + // || defined(__CYGWIN__) + (void)cached; +#endif // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) + // || defined(__CYGWIN__) + + clear_last_error(); + int result = error_wrapper(call_getpeername( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +template <typename SockLenType> +inline int call_getsockname(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getsockname(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_getsockname( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = asio::error_code(); + return result; +} + +int ioctl(socket_type s, state_type& state, int cmd, + ioctl_arg_type* arg, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); +#elif defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + int result = error_wrapper(::ioctl(s, + static_cast<unsigned int>(cmd), arg), ec); +#else + int result = error_wrapper(::ioctl(s, cmd, arg), ec); +#endif + if (result >= 0) + { + ec = asio::error_code(); + + // 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 (cmd == static_cast<int>(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // 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. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + if (!readfds && !writefds && !exceptfds && timeout) + { + DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + if (milliseconds == 0) + milliseconds = 1; // Force context switch. + ::Sleep(milliseconds); + ec = asio::error_code(); + return 0; + } + + // The select() call allows timeout values measured in microseconds, but the + // system clock (as wrapped by boost::posix_time::microsec_clock) typically + // has a resolution of 10 milliseconds. This can lead to a spinning select + // reactor, meaning increased CPU usage, when waiting for the earliest + // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight + // spin we'll use a minimum timeout of 1 millisecond. + if (timeout && timeout->tv_sec == 0 + && timeout->tv_usec > 0 && timeout->tv_usec < 1000) + timeout->tv_usec = 1000; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) && defined(__SELECT) + timespec ts; + ts.tv_sec = timeout ? timeout->tv_sec : 0; + ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; + return error_wrapper(::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0), ec); +#else + int result = error_wrapper(::select(nfds, readfds, + writefds, exceptfds, timeout), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif +} + +int poll_read(socket_type s, state_type state, + int msec, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + clear_last_error(); + int result = error_wrapper(::select(s + 1, &fds, 0, 0, timeout), ec); +#else // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLIN; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : msec; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, timeout), ec); +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (result == 0) + ec = (state & user_set_non_blocking) + ? asio::error::would_block : asio::error_code(); + else if (result > 0) + ec = asio::error_code(); + return result; +} + +int poll_write(socket_type s, state_type state, + int msec, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + clear_last_error(); + int result = error_wrapper(::select(s + 1, 0, &fds, 0, timeout), ec); +#else // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : msec; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, timeout), ec); +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (result == 0) + ec = (state & user_set_non_blocking) + ? asio::error::would_block : asio::error_code(); + else if (result > 0) + ec = asio::error_code(); + return result; +} + +int poll_error(socket_type s, state_type state, + int msec, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + clear_last_error(); + int result = error_wrapper(::select(s + 1, 0, 0, &fds, timeout), ec); +#else // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLPRI | POLLERR | POLLHUP; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : msec; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, timeout), ec); +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (result == 0) + ec = (state & user_set_non_blocking) + ? asio::error::would_block : asio::error_code(); + else if (result > 0) + ec = asio::error_code(); + return result; +} + +int poll_connect(socket_type s, int msec, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + fd_set except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + timeval timeout_obj; + timeval* timeout; + if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + clear_last_error(); + int result = error_wrapper(::select( + s + 1, 0, &write_fds, &except_fds, timeout), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#else // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, msec), ec); + if (result >= 0) + ec = asio::error_code(); + return result; +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) +} + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +const char* inet_ntop(int af, const void* src, char* dest, size_t length, + unsigned long scope_id, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS_RUNTIME) + using namespace std; // For sprintf. + const unsigned char* bytes = static_cast<const unsigned char*>(src); + if (af == ASIO_OS_DEF(AF_INET)) + { + sprintf_s(dest, length, "%u.%u.%u.%u", + bytes[0], bytes[1], bytes[2], bytes[3]); + return dest; + } + else if (af == ASIO_OS_DEF(AF_INET6)) + { + size_t n = 0, b = 0, z = 0; + while (n < length && b < 16) + { + if (bytes[b] == 0 && bytes[b + 1] == 0 && z == 0) + { + do b += 2; while (b < 16 && bytes[b] == 0 && bytes[b + 1] == 0); + n += sprintf_s(dest + n, length - n, ":%s", b < 16 ? "" : ":"), ++z; + } + else + { + n += sprintf_s(dest + n, length - n, "%s%x", b ? ":" : "", + (static_cast<u_long_type>(bytes[b]) << 8) | bytes[b + 1]); + b += 2; + } + } + if (scope_id) + n += sprintf_s(dest + n, length - n, "%%%lu", scope_id); + return dest; + } + else + { + ec = asio::error::address_family_not_supported; + return 0; + } +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy. + + if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6)) + { + ec = asio::error::address_family_not_supported; + return 0; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + DWORD address_length; + if (af == ASIO_OS_DEF(AF_INET)) + { + address_length = sizeof(sockaddr_in4_type); + address.v4.sin_family = ASIO_OS_DEF(AF_INET); + address.v4.sin_port = 0; + memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); + } + else // AF_INET6 + { + address_length = sizeof(sockaddr_in6_type); + address.v6.sin6_family = ASIO_OS_DEF(AF_INET6); + address.v6.sin6_port = 0; + address.v6.sin6_flowinfo = 0; + address.v6.sin6_scope_id = scope_id; + memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); + } + + DWORD string_length = static_cast<DWORD>(length); +#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) + LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); + int result = error_wrapper(::WSAAddressToStringW(&address.base, + address_length, 0, string_buffer, &string_length), ec); + ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, + dest, static_cast<int>(length), 0, 0); +#else + int result = error_wrapper(::WSAAddressToStringA( + &address.base, address_length, 0, dest, &string_length), ec); +#endif + + // Windows may set error code on success. + if (result != socket_error_retval) + ec = asio::error_code(); + + // Windows may not set an error code on failure. + else if (result == socket_error_retval && !ec) + ec = asio::error::invalid_argument; + + return result == socket_error_retval ? 0 : dest; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + const char* result = error_wrapper(::inet_ntop( + af, src, dest, static_cast<int>(length)), ec); + if (result == 0 && !ec) + ec = asio::error::invalid_argument; + if (result != 0 && af == ASIO_OS_DEF(AF_INET6) && scope_id != 0) + { + using namespace std; // For strcat and sprintf. + char if_name[IF_NAMESIZE + 1] = "%"; + const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src); + bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) + && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); + bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff) + && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02)); + if ((!is_link_local && !is_multicast_link_local) + || if_indextoname(static_cast<unsigned>(scope_id), if_name + 1) == 0) + sprintf(if_name + 1, "%lu", scope_id); + strcat(dest, if_name); + } + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS_RUNTIME) + using namespace std; // For sscanf. + unsigned char* bytes = static_cast<unsigned char*>(dest); + if (af == ASIO_OS_DEF(AF_INET)) + { + unsigned int b0, b1, b2, b3; + if (sscanf_s(src, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) != 4) + { + ec = asio::error::invalid_argument; + return -1; + } + if (b0 > 255 || b1 > 255 || b2 > 255 || b3 > 255) + { + ec = asio::error::invalid_argument; + return -1; + } + bytes[0] = static_cast<unsigned char>(b0); + bytes[1] = static_cast<unsigned char>(b1); + bytes[2] = static_cast<unsigned char>(b2); + bytes[3] = static_cast<unsigned char>(b3); + ec = asio::error_code(); + return 1; + } + else if (af == ASIO_OS_DEF(AF_INET6)) + { + unsigned char* bytes = static_cast<unsigned char*>(dest); + std::memset(bytes, 0, 16); + unsigned char back_bytes[16] = { 0 }; + int num_front_bytes = 0, num_back_bytes = 0; + const char* p = src; + + enum { fword, fcolon, bword, scope, done } state = fword; + unsigned long current_word = 0; + while (state != done) + { + if (current_word > 0xFFFF) + { + ec = asio::error::invalid_argument; + return -1; + } + + switch (state) + { + case fword: + if (*p >= '0' && *p <= '9') + current_word = current_word * 16 + *p++ - '0'; + else if (*p >= 'a' && *p <= 'f') + current_word = current_word * 16 + *p++ - 'a' + 10; + else if (*p >= 'A' && *p <= 'F') + current_word = current_word * 16 + *p++ - 'A' + 10; + else + { + if (num_front_bytes == 16) + { + ec = asio::error::invalid_argument; + return -1; + } + + bytes[num_front_bytes++] = (current_word >> 8) & 0xFF; + bytes[num_front_bytes++] = current_word & 0xFF; + current_word = 0; + + if (*p == ':') + state = fcolon, ++p; + else if (*p == '%') + state = scope, ++p; + else if (*p == 0) + state = done; + else + { + ec = asio::error::invalid_argument; + return -1; + } + } + break; + + case fcolon: + if (*p == ':') + state = bword, ++p; + else + state = fword; + break; + + case bword: + if (*p >= '0' && *p <= '9') + current_word = current_word * 16 + *p++ - '0'; + else if (*p >= 'a' && *p <= 'f') + current_word = current_word * 16 + *p++ - 'a' + 10; + else if (*p >= 'A' && *p <= 'F') + current_word = current_word * 16 + *p++ - 'A' + 10; + else + { + if (num_front_bytes + num_back_bytes == 16) + { + ec = asio::error::invalid_argument; + return -1; + } + + back_bytes[num_back_bytes++] = (current_word >> 8) & 0xFF; + back_bytes[num_back_bytes++] = current_word & 0xFF; + current_word = 0; + + if (*p == ':') + state = bword, ++p; + else if (*p == '%') + state = scope, ++p; + else if (*p == 0) + state = done; + else + { + ec = asio::error::invalid_argument; + return -1; + } + } + break; + + case scope: + if (*p >= '0' && *p <= '9') + current_word = current_word * 10 + *p++ - '0'; + else if (*p == 0) + *scope_id = current_word, state = done; + else + { + ec = asio::error::invalid_argument; + return -1; + } + break; + + default: + break; + } + } + + for (int i = 0; i < num_back_bytes; ++i) + bytes[16 - num_back_bytes + i] = back_bytes[i]; + + ec = asio::error_code(); + return 1; + } + else + { + ec = asio::error::address_family_not_supported; + return -1; + } +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy and strcmp. + + if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6)) + { + ec = asio::error::address_family_not_supported; + return -1; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + int address_length = sizeof(sockaddr_storage_type); +#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) + int num_wide_chars = static_cast<int>(strlen(src)) + 1; + LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); + ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); + int result = error_wrapper(::WSAStringToAddressW( + wide_buffer, af, 0, &address.base, &address_length), ec); +#else + int result = error_wrapper(::WSAStringToAddressA( + const_cast<char*>(src), af, 0, &address.base, &address_length), ec); +#endif + + if (af == ASIO_OS_DEF(AF_INET)) + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); + ec = asio::error_code(); + } + else if (strcmp(src, "255.255.255.255") == 0) + { + static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE; + ec = asio::error_code(); + } + } + else // AF_INET6 + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); + if (scope_id) + *scope_id = address.v6.sin6_scope_id; + ec = asio::error_code(); + } + } + + // Windows may not set an error code on failure. + if (result == socket_error_retval && !ec) + ec = asio::error::invalid_argument; + + if (result != socket_error_retval) + ec = asio::error_code(); + + return result == socket_error_retval ? -1 : 1; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For strchr, memcpy and atoi. + + // On some platforms, inet_pton fails if an address string contains a scope + // id. Detect and remove the scope id before passing the string to inet_pton. + const bool is_v6 = (af == ASIO_OS_DEF(AF_INET6)); + const char* if_name = is_v6 ? strchr(src, '%') : 0; + char src_buf[max_addr_v6_str_len + 1]; + const char* src_ptr = src; + if (if_name != 0) + { + if (if_name - src > max_addr_v6_str_len) + { + ec = asio::error::invalid_argument; + return 0; + } + memcpy(src_buf, src, if_name - src); + src_buf[if_name - src] = 0; + src_ptr = src_buf; + } + + int result = error_wrapper(::inet_pton(af, src_ptr, dest), ec); + if (result <= 0 && !ec) + ec = asio::error::invalid_argument; + if (result > 0 && is_v6 && scope_id) + { + using namespace std; // For strchr and atoi. + *scope_id = 0; + if (if_name != 0) + { + in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest); + bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) + && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); + bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff) + && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02)); + if (is_link_local || is_multicast_link_local) + *scope_id = if_nametoindex(if_name + 1); + if (*scope_id == 0) + *scope_id = atoi(if_name + 1); + } + } + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +int gethostname(char* name, int namelen, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS_RUNTIME) + try + { + using namespace Windows::Foundation::Collections; + using namespace Windows::Networking; + using namespace Windows::Networking::Connectivity; + IVectorView<HostName^>^ hostnames = NetworkInformation::GetHostNames(); + for (unsigned i = 0; i < hostnames->Size; ++i) + { + HostName^ hostname = hostnames->GetAt(i); + if (hostname->Type == HostNameType::DomainName) + { + std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; + std::string raw_name = converter.to_bytes(hostname->RawName->Data()); + if (namelen > 0 && raw_name.size() < static_cast<std::size_t>(namelen)) + { + strcpy_s(name, namelen, raw_name.c_str()); + return 0; + } + } + } + return -1; + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + return -1; + } +#else // defined(ASIO_WINDOWS_RUNTIME) + int result = error_wrapper(::gethostname(name, namelen), ec); +# if defined(ASIO_WINDOWS) + if (result == 0) + ec = asio::error_code(); +# endif // defined(ASIO_WINDOWS) + return result; +#endif // defined(ASIO_WINDOWS_RUNTIME) +} + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#if !defined(ASIO_HAS_GETADDRINFO) + +// The following functions are only needed for emulation of getaddrinfo and +// getnameinfo. + +inline asio::error_code translate_netdb_error(int error) +{ + switch (error) + { + case 0: + return asio::error_code(); + case HOST_NOT_FOUND: + return asio::error::host_not_found; + case TRY_AGAIN: + return asio::error::host_not_found_try_again; + case NO_RECOVERY: + return asio::error::no_recovery; + case NO_DATA: + return asio::error::no_data; + default: + ASIO_ASSERT(false); + return asio::error::invalid_argument; + } +} + +inline hostent* gethostbyaddr(const char* addr, int length, int af, + hostent* result, char* buffer, int buflength, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); + if (!retval) + return 0; + ec = asio::error_code(); + *result = *retval; + return retval; +#elif defined(__sun) || defined(__QNX__) + int error = 0; + hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, + buffer, buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyaddr( + addr, length, af, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, + buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline hostent* gethostbyname(const char* name, int af, struct hostent* result, + char* buffer, int buflength, int ai_flags, asio::error_code& ec) +{ + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + (void)(ai_flags); + if (af != ASIO_OS_DEF(AF_INET)) + { + ec = asio::error::address_family_not_supported; + return 0; + } + hostent* retval = error_wrapper(::gethostbyname(name), ec); + if (!retval) + return 0; + ec = asio::error_code(); + *result = *retval; + return result; +#elif defined(__sun) || defined(__QNX__) + (void)(ai_flags); + if (af != ASIO_OS_DEF(AF_INET)) + { + ec = asio::error::address_family_not_supported; + return 0; + } + int error = 0; + hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, + buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyname( + name, af, ai_flags, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + (void)(ai_flags); + if (af != ASIO_OS_DEF(AF_INET)) + { + ec = asio::error::address_family_not_supported; + return 0; + } + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyname_r(name, result, + buffer, buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline void freehostent(hostent* h) +{ +#if defined(__MACH__) && defined(__APPLE__) + if (h) + ::freehostent(h); +#else + (void)(h); +#endif +} + +// Emulation of getaddrinfo based on implementation in: +// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. + +struct gai_search +{ + const char* host; + int family; +}; + +inline int gai_nsearch(const char* host, + const addrinfo_type* hints, gai_search (&search)[2]) +{ + int search_count = 0; + if (host == 0 || host[0] == '\0') + { + if (hints->ai_flags & AI_PASSIVE) + { + // No host and AI_PASSIVE implies wildcard bind. + switch (hints->ai_family) + { + case ASIO_OS_DEF(AF_INET): + search[search_count].host = "0.0.0.0"; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + case ASIO_OS_DEF(AF_INET6): + search[search_count].host = "0::0"; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + break; + case ASIO_OS_DEF(AF_UNSPEC): + search[search_count].host = "0::0"; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + search[search_count].host = "0.0.0.0"; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + default: + break; + } + } + else + { + // No host and not AI_PASSIVE means connect to local host. + switch (hints->ai_family) + { + case ASIO_OS_DEF(AF_INET): + search[search_count].host = "localhost"; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + case ASIO_OS_DEF(AF_INET6): + search[search_count].host = "localhost"; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + break; + case ASIO_OS_DEF(AF_UNSPEC): + search[search_count].host = "localhost"; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + search[search_count].host = "localhost"; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + default: + break; + } + } + } + else + { + // Host is specified. + switch (hints->ai_family) + { + case ASIO_OS_DEF(AF_INET): + search[search_count].host = host; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + case ASIO_OS_DEF(AF_INET6): + search[search_count].host = host; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + break; + case ASIO_OS_DEF(AF_UNSPEC): + search[search_count].host = host; + search[search_count].family = ASIO_OS_DEF(AF_INET6); + ++search_count; + search[search_count].host = host; + search[search_count].family = ASIO_OS_DEF(AF_INET); + ++search_count; + break; + default: + break; + } + } + return search_count; +} + +template <typename T> +inline T* gai_alloc(std::size_t size = sizeof(T)) +{ + using namespace std; + T* p = static_cast<T*>(::operator new(size, std::nothrow)); + if (p) + memset(p, 0, size); + return p; +} + +inline void gai_free(void* p) +{ + ::operator delete(p); +} + +inline void gai_strcpy(char* target, const char* source, std::size_t max_size) +{ + using namespace std; +#if defined(ASIO_HAS_SECURE_RTL) + strcpy_s(target, max_size, source); +#else // defined(ASIO_HAS_SECURE_RTL) + *target = 0; + if (max_size > 0) + strncat(target, source, max_size - 1); +#endif // defined(ASIO_HAS_SECURE_RTL) +} + +enum { gai_clone_flag = 1 << 30 }; + +inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, + const void* addr, int family) +{ + using namespace std; + + addrinfo_type* ai = gai_alloc<addrinfo_type>(); + if (ai == 0) + return EAI_MEMORY; + + ai->ai_next = 0; + **next = ai; + *next = &ai->ai_next; + + ai->ai_canonname = 0; + ai->ai_socktype = hints->ai_socktype; + if (ai->ai_socktype == 0) + ai->ai_flags |= gai_clone_flag; + ai->ai_protocol = hints->ai_protocol; + ai->ai_family = family; + + switch (ai->ai_family) + { + case ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>(); + if (sinptr == 0) + return EAI_MEMORY; + sinptr->sin_family = ASIO_OS_DEF(AF_INET); + memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); + ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr); + ai->ai_addrlen = sizeof(sockaddr_in4_type); + break; + } + case ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>(); + if (sin6ptr == 0) + return EAI_MEMORY; + sin6ptr->sin6_family = ASIO_OS_DEF(AF_INET6); + memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); + ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr); + ai->ai_addrlen = sizeof(sockaddr_in6_type); + break; + } + default: + break; + } + + return 0; +} + +inline addrinfo_type* gai_clone(addrinfo_type* ai) +{ + using namespace std; + + addrinfo_type* new_ai = gai_alloc<addrinfo_type>(); + if (new_ai == 0) + return new_ai; + + new_ai->ai_next = ai->ai_next; + ai->ai_next = new_ai; + + new_ai->ai_flags = 0; + new_ai->ai_family = ai->ai_family; + new_ai->ai_socktype = ai->ai_socktype; + new_ai->ai_protocol = ai->ai_protocol; + new_ai->ai_canonname = 0; + new_ai->ai_addrlen = ai->ai_addrlen; + new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen); + memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); + + return new_ai; +} + +inline int gai_port(addrinfo_type* aihead, int port, int socktype) +{ + int num_found = 0; + + for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) + { + if (ai->ai_flags & gai_clone_flag) + { + if (ai->ai_socktype != 0) + { + ai = gai_clone(ai); + if (ai == 0) + return -1; + // ai now points to newly cloned entry. + } + } + else if (ai->ai_socktype != socktype) + { + // Ignore if mismatch on socket type. + continue; + } + + ai->ai_socktype = socktype; + + switch (ai->ai_family) + { + case ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = + reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr); + sinptr->sin_port = port; + ++num_found; + break; + } + case ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr); + sin6ptr->sin6_port = port; + ++num_found; + break; + } + default: + break; + } + } + + return num_found; +} + +inline int gai_serv(addrinfo_type* aihead, + const addrinfo_type* hints, const char* serv) +{ + using namespace std; + + int num_found = 0; + + if ( +#if defined(AI_NUMERICSERV) + (hints->ai_flags & AI_NUMERICSERV) || +#endif + isdigit(static_cast<unsigned char>(serv[0]))) + { + int port = htons(atoi(serv)); + if (hints->ai_socktype) + { + // Caller specifies socket type. + int rc = gai_port(aihead, port, hints->ai_socktype); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + else + { + // Caller does not specify socket type. + int rc = gai_port(aihead, port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + rc = gai_port(aihead, port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + else + { + // Try service name with TCP first, then UDP. + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) + { + servent* sptr = getservbyname(serv, "tcp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) + { + servent* sptr = getservbyname(serv, "udp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + } + + if (num_found == 0) + { + if (hints->ai_socktype == 0) + { + // All calls to getservbyname() failed. + return EAI_NONAME; + } + else + { + // Service not supported for socket type. + return EAI_SERVICE; + } + } + + return 0; +} + +inline int gai_echeck(const char* host, const char* service, + int flags, int family, int socktype, int protocol) +{ + (void)(flags); + (void)(protocol); + + // Host or service must be specified. + if (host == 0 || host[0] == '\0') + if (service == 0 || service[0] == '\0') + return EAI_NONAME; + + // Check combination of family and socket type. + switch (family) + { + case ASIO_OS_DEF(AF_UNSPEC): + break; + case ASIO_OS_DEF(AF_INET): + case ASIO_OS_DEF(AF_INET6): + if (service != 0 && service[0] != '\0') + if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) + return EAI_SOCKTYPE; + break; + default: + return EAI_FAMILY; + } + + return 0; +} + +inline void freeaddrinfo_emulation(addrinfo_type* aihead) +{ + addrinfo_type* ai = aihead; + while (ai) + { + gai_free(ai->ai_addr); + gai_free(ai->ai_canonname); + addrinfo_type* ainext = ai->ai_next; + gai_free(ai); + ai = ainext; + } +} + +inline int getaddrinfo_emulation(const char* host, const char* service, + const addrinfo_type* hintsp, addrinfo_type** result) +{ + // Set up linked list of addrinfo structures. + addrinfo_type* aihead = 0; + addrinfo_type** ainext = &aihead; + char* canon = 0; + + // Supply default hints if not specified by caller. + addrinfo_type hints = addrinfo_type(); + hints.ai_family = ASIO_OS_DEF(AF_UNSPEC); + if (hintsp) + hints = *hintsp; + + // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED + // and AI_ALL flags. +#if defined(AI_V4MAPPED) + if (hints.ai_family != ASIO_OS_DEF(AF_INET6)) + hints.ai_flags &= ~AI_V4MAPPED; +#endif +#if defined(AI_ALL) + if (hints.ai_family != ASIO_OS_DEF(AF_INET6)) + hints.ai_flags &= ~AI_ALL; +#endif + + // Basic error checking. + int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, + hints.ai_socktype, hints.ai_protocol); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + + gai_search search[2]; + int search_count = gai_nsearch(host, &hints, search); + for (gai_search* sptr = search; sptr < search + search_count; ++sptr) + { + // Check for IPv4 dotted decimal string. + in4_addr_type inaddr; + asio::error_code ec; + if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET), + sptr->host, &inaddr, 0, ec) == 1) + { + if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC) + && hints.ai_family != ASIO_OS_DEF(AF_INET)) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == ASIO_OS_DEF(AF_INET)) + { + rc = gai_aistruct(&ainext, &hints, &inaddr, ASIO_OS_DEF(AF_INET)); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Check for IPv6 hex string. + in6_addr_type in6addr; + if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6), + sptr->host, &in6addr, 0, ec) == 1) + { + if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC) + && hints.ai_family != ASIO_OS_DEF(AF_INET6)) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == ASIO_OS_DEF(AF_INET6)) + { + rc = gai_aistruct(&ainext, &hints, &in6addr, + ASIO_OS_DEF(AF_INET6)); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Look up hostname. + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyname(sptr->host, + sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); + if (hptr == 0) + { + if (search_count == 2) + { + // Failure is OK if there are multiple searches. + continue; + } + freeaddrinfo_emulation(aihead); + gai_free(canon); + if (ec == asio::error::host_not_found) + return EAI_NONAME; + if (ec == asio::error::host_not_found_try_again) + return EAI_AGAIN; + if (ec == asio::error::no_recovery) + return EAI_FAIL; + if (ec == asio::error::no_data) + return EAI_NONAME; + return EAI_NONAME; + } + + // Check for address family mismatch if one was specified. + if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC) + && hints.ai_family != hptr->h_addrtype) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + + // Save canonical name first time. + if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] + && (hints.ai_flags & AI_CANONNAME) && canon == 0) + { + std::size_t canon_len = strlen(hptr->h_name) + 1; + canon = gai_alloc<char>(canon_len); + if (canon == 0) + { + freeaddrinfo_emulation(aihead); + socket_ops::freehostent(hptr); + return EAI_MEMORY; + } + gai_strcpy(canon, hptr->h_name, canon_len); + } + + // Create an addrinfo structure for each returned address. + for (char** ap = hptr->h_addr_list; *ap; ++ap) + { + rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + } + + socket_ops::freehostent(hptr); + } + + // Check if we found anything. + if (aihead == 0) + { + gai_free(canon); + return EAI_NONAME; + } + + // Return canonical name in first entry. + if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) + { + if (canon) + { + aihead->ai_canonname = canon; + canon = 0; + } + else + { + std::size_t canonname_len = strlen(search[0].host) + 1; + aihead->ai_canonname = gai_alloc<char>(canonname_len); + if (aihead->ai_canonname == 0) + { + freeaddrinfo_emulation(aihead); + return EAI_MEMORY; + } + gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); + } + } + gai_free(canon); + + // Process the service name. + if (service != 0 && service[0] != '\0') + { + rc = gai_serv(aihead, &hints, service); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + } + + // Return result to caller. + *result = aihead; + return 0; +} + +inline asio::error_code getnameinfo_emulation( + const socket_addr_type* sa, std::size_t salen, char* host, + std::size_t hostlen, char* serv, std::size_t servlen, int flags, + asio::error_code& ec) +{ + using namespace std; + + const char* addr; + size_t addr_len; + unsigned short port; + switch (sa->sa_family) + { + case ASIO_OS_DEF(AF_INET): + if (salen != sizeof(sockaddr_in4_type)) + { + return ec = asio::error::invalid_argument; + } + addr = reinterpret_cast<const char*>( + &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr); + addr_len = sizeof(in4_addr_type); + port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port; + break; + case ASIO_OS_DEF(AF_INET6): + if (salen != sizeof(sockaddr_in6_type)) + { + return ec = asio::error::invalid_argument; + } + addr = reinterpret_cast<const char*>( + &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr); + addr_len = sizeof(in6_addr_type); + port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port; + break; + default: + return ec = asio::error::address_family_not_supported; + } + + if (host && hostlen > 0) + { + if (flags & NI_NUMERICHOST) + { + if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + else + { + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyaddr(addr, + static_cast<int>(addr_len), sa->sa_family, + &hent, hbuf, sizeof(hbuf), ec); + if (hptr && hptr->h_name && hptr->h_name[0] != '\0') + { + if (flags & NI_NOFQDN) + { + char* dot = strchr(hptr->h_name, '.'); + if (dot) + { + *dot = 0; + } + } + gai_strcpy(host, hptr->h_name, hostlen); + socket_ops::freehostent(hptr); + } + else + { + socket_ops::freehostent(hptr); + if (flags & NI_NAMEREQD) + { + return ec = asio::error::host_not_found; + } + if (socket_ops::inet_ntop(sa->sa_family, + addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + } + } + + if (serv && servlen > 0) + { + if (flags & NI_NUMERICSERV) + { + if (servlen < 6) + { + return ec = asio::error::no_buffer_space; + } +#if defined(ASIO_HAS_SECURE_RTL) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else // defined(ASIO_HAS_SECURE_RTL) + sprintf(serv, "%u", ntohs(port)); +#endif // defined(ASIO_HAS_SECURE_RTL) + } + else + { +#if defined(ASIO_HAS_PTHREADS) + static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + ::pthread_mutex_lock(&mutex); +#endif // defined(ASIO_HAS_PTHREADS) + servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); + if (sptr && sptr->s_name && sptr->s_name[0] != '\0') + { + gai_strcpy(serv, sptr->s_name, servlen); + } + else + { + if (servlen < 6) + { + return ec = asio::error::no_buffer_space; + } +#if defined(ASIO_HAS_SECURE_RTL) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else // defined(ASIO_HAS_SECURE_RTL) + sprintf(serv, "%u", ntohs(port)); +#endif // defined(ASIO_HAS_SECURE_RTL) + } +#if defined(ASIO_HAS_PTHREADS) + ::pthread_mutex_unlock(&mutex); +#endif // defined(ASIO_HAS_PTHREADS) + } + } + + ec = asio::error_code(); + return ec; +} + +#endif // !defined(ASIO_HAS_GETADDRINFO) + +inline asio::error_code translate_addrinfo_error(int error) +{ + switch (error) + { + case 0: + return asio::error_code(); + case EAI_AGAIN: + return asio::error::host_not_found_try_again; + case EAI_BADFLAGS: + return asio::error::invalid_argument; + case EAI_FAIL: + return asio::error::no_recovery; + case EAI_FAMILY: + return asio::error::address_family_not_supported; + case EAI_MEMORY: + return asio::error::no_memory; + case EAI_NONAME: +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: +#endif +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif + return asio::error::host_not_found; + case EAI_SERVICE: + return asio::error::service_not_found; + case EAI_SOCKTYPE: + return asio::error::socket_type_not_supported; + default: // Possibly the non-portable EAI_SYSTEM. +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + return asio::error_code( + WSAGetLastError(), asio::error::get_system_category()); +#else + return asio::error_code( + errno, asio::error::get_system_category()); +#endif + } +} + +asio::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec) +{ + host = (host && *host) ? host : 0; + service = (service && *service) ? service : 0; + clear_last_error(); +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(ASIO_HAS_GETADDRINFO) + // Building for Windows XP, Windows Server 2003, or later. + int error = ::getaddrinfo(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gai_t)(const char*, + const char*, const addrinfo_type*, addrinfo_type**); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) + { + int error = gai(host, service, &hints, result); + return ec = translate_addrinfo_error(error); + } + } + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# endif +#elif !defined(ASIO_HAS_GETADDRINFO) + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +#else + int error = ::getaddrinfo(host, service, &hints, result); +#if defined(__MACH__) && defined(__APPLE__) + using namespace std; // For isdigit and atoi. + if (error == 0 && service && isdigit(static_cast<unsigned char>(service[0]))) + { + u_short_type port = host_to_network_short(atoi(service)); + for (addrinfo_type* ai = *result; ai; ai = ai->ai_next) + { + switch (ai->ai_family) + { + case ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = + reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr); + if (sinptr->sin_port == 0) + sinptr->sin_port = port; + break; + } + case ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr); + if (sin6ptr->sin6_port == 0) + sin6ptr->sin6_port = port; + break; + } + default: + break; + } + } + } +#endif + return ec = translate_addrinfo_error(error); +#endif +} + +asio::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec) +{ + if (cancel_token.expired()) + ec = asio::error::operation_aborted; + else + socket_ops::getaddrinfo(host, service, hints, result, ec); + return ec; +} + +void freeaddrinfo(addrinfo_type* ai) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(ASIO_HAS_GETADDRINFO) + // Building for Windows XP, Windows Server 2003, or later. + ::freeaddrinfo(ai); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *fai_t)(addrinfo_type*); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) + { + fai(ai); + return; + } + } + freeaddrinfo_emulation(ai); +# endif +#elif !defined(ASIO_HAS_GETADDRINFO) + freeaddrinfo_emulation(ai); +#else + ::freeaddrinfo(ai); +#endif +} + +asio::error_code getnameinfo(const socket_addr_type* addr, + std::size_t addrlen, char* host, std::size_t hostlen, + char* serv, std::size_t servlen, int flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(ASIO_HAS_GETADDRINFO) + // Building for Windows XP, Windows Server 2003, or later. + clear_last_error(); + int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen), + host, static_cast<DWORD>(hostlen), + serv, static_cast<DWORD>(servlen), flags); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gni_t)(const socket_addr_type*, + int, char*, DWORD, char*, DWORD, int); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) + { + clear_last_error(); + int error = gni(addr, static_cast<int>(addrlen), + host, static_cast<DWORD>(hostlen), + serv, static_cast<DWORD>(servlen), flags); + return ec = translate_addrinfo_error(error); + } + } + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +# endif +#elif !defined(ASIO_HAS_GETADDRINFO) + using namespace std; // For memcpy. + sockaddr_storage_type tmp_addr; + memcpy(&tmp_addr, addr, addrlen); + addr = reinterpret_cast<socket_addr_type*>(&tmp_addr); + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +#else + clear_last_error(); + int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); + return ec = translate_addrinfo_error(error); +#endif +} + +asio::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec) +{ + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + + return ec; +} + +asio::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec) +{ + if (cancel_token.expired()) + { + ec = asio::error::operation_aborted; + } + else + { + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + } + + return ec; +} + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +u_long_type network_to_host_long(u_long_type value) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + unsigned char* value_p = reinterpret_cast<unsigned char*>(&value); + u_long_type result = (static_cast<u_long_type>(value_p[0]) << 24) + | (static_cast<u_long_type>(value_p[1]) << 16) + | (static_cast<u_long_type>(value_p[2]) << 8) + | static_cast<u_long_type>(value_p[3]); + return result; +#else // defined(ASIO_WINDOWS_RUNTIME) + return ntohl(value); +#endif // defined(ASIO_WINDOWS_RUNTIME) +} + +u_long_type host_to_network_long(u_long_type value) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + u_long_type result; + unsigned char* result_p = reinterpret_cast<unsigned char*>(&result); + result_p[0] = static_cast<unsigned char>((value >> 24) & 0xFF); + result_p[1] = static_cast<unsigned char>((value >> 16) & 0xFF); + result_p[2] = static_cast<unsigned char>((value >> 8) & 0xFF); + result_p[3] = static_cast<unsigned char>(value & 0xFF); + return result; +#else // defined(ASIO_WINDOWS_RUNTIME) + return htonl(value); +#endif // defined(ASIO_WINDOWS_RUNTIME) +} + +u_short_type network_to_host_short(u_short_type value) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + unsigned char* value_p = reinterpret_cast<unsigned char*>(&value); + u_short_type result = (static_cast<u_short_type>(value_p[0]) << 8) + | static_cast<u_short_type>(value_p[1]); + return result; +#else // defined(ASIO_WINDOWS_RUNTIME) + return ntohs(value); +#endif // defined(ASIO_WINDOWS_RUNTIME) +} + +u_short_type host_to_network_short(u_short_type value) +{ +#if defined(ASIO_WINDOWS_RUNTIME) + u_short_type result; + unsigned char* result_p = reinterpret_cast<unsigned char*>(&result); + result_p[0] = static_cast<unsigned char>((value >> 8) & 0xFF); + result_p[1] = static_cast<unsigned char>(value & 0xFF); + return result; +#else // defined(ASIO_WINDOWS_RUNTIME) + return htons(value); +#endif // defined(ASIO_WINDOWS_RUNTIME) +} + +} // namespace socket_ops +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SOCKET_OPS_IPP diff --git a/lib/asio/detail/impl/socket_select_interrupter.ipp b/lib/asio/detail/impl/socket_select_interrupter.ipp new file mode 100644 index 0000000..052f2a7 --- /dev/null +++ b/lib/asio/detail/impl/socket_select_interrupter.ipp @@ -0,0 +1,176 @@ +// +// detail/impl/socket_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP +#define ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include <cstdlib> +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_select_interrupter.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +socket_select_interrupter::socket_select_interrupter() +{ + open_descriptors(); +} + +void socket_select_interrupter::open_descriptors() +{ + asio::error_code ec; + socket_holder acceptor(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (acceptor.get() == invalid_socket) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + int opt = 1; + socket_ops::state_type acceptor_state = 0; + socket_ops::setsockopt(acceptor.get(), acceptor_state, + SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); + + using namespace std; // For memset. + sockaddr_in4_type addr; + std::size_t addr_len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK); + addr.sin_port = 0; + if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, + &addr_len, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + // Some broken firewalls on Windows will intermittently cause getsockname to + // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We + // explicitly specify the target address here to work around this problem. + if (addr.sin_addr.s_addr == socket_ops::host_to_network_long(INADDR_ANY)) + addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK); + + if (socket_ops::listen(acceptor.get(), + SOMAXCONN, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder client(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (client.get() == invalid_socket) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); + if (server.get() == invalid_socket) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + ioctl_arg_type non_blocking = 1; + socket_ops::state_type client_state = 0; + if (socket_ops::ioctl(client.get(), client_state, + FIONBIO, &non_blocking, ec)) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(client.get(), client_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + non_blocking = 1; + socket_ops::state_type server_state = 0; + if (socket_ops::ioctl(server.get(), server_state, + FIONBIO, &non_blocking, ec)) + asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(server.get(), server_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + read_descriptor_ = server.release(); + write_descriptor_ = client.release(); +} + +socket_select_interrupter::~socket_select_interrupter() +{ + close_descriptors(); +} + +void socket_select_interrupter::close_descriptors() +{ + asio::error_code ec; + socket_ops::state_type state = socket_ops::internal_non_blocking; + if (read_descriptor_ != invalid_socket) + socket_ops::close(read_descriptor_, state, true, ec); + if (write_descriptor_ != invalid_socket) + socket_ops::close(write_descriptor_, state, true, ec); +} + +void socket_select_interrupter::recreate() +{ + close_descriptors(); + + write_descriptor_ = invalid_socket; + read_descriptor_ = invalid_socket; + + open_descriptors(); +} + +void socket_select_interrupter::interrupt() +{ + char byte = 0; + socket_ops::buf b; + socket_ops::init_buf(b, &byte, 1); + asio::error_code ec; + socket_ops::send(write_descriptor_, &b, 1, 0, ec); +} + +bool socket_select_interrupter::reset() +{ + char data[1024]; + socket_ops::buf b; + socket_ops::init_buf(b, data, sizeof(data)); + asio::error_code ec; + int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + return was_interrupted; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP diff --git a/lib/asio/detail/impl/strand_executor_service.hpp b/lib/asio/detail/impl/strand_executor_service.hpp new file mode 100644 index 0000000..0e18ca0 --- /dev/null +++ b/lib/asio/detail/impl/strand_executor_service.hpp @@ -0,0 +1,179 @@ +// +// detail/impl/strand_executor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP +#define ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/call_stack.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/executor_work_guard.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Executor> +class strand_executor_service::invoker +{ +public: + invoker(const implementation_type& impl, Executor& ex) + : impl_(impl), + work_(ex) + { + } + + invoker(const invoker& other) + : impl_(other.impl_), + work_(other.work_) + { + } + +#if defined(ASIO_HAS_MOVE) + invoker(invoker&& other) + : impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)), + work_(ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + struct on_invoker_exit + { + invoker* this_; + + ~on_invoker_exit() + { + this_->impl_->mutex_->lock(); + this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_); + bool more_handlers = this_->impl_->locked_ = + !this_->impl_->ready_queue_.empty(); + this_->impl_->mutex_->unlock(); + + if (more_handlers) + { + Executor ex(this_->work_.get_executor()); + recycling_allocator<void> allocator; + ex.post(ASIO_MOVE_CAST(invoker)(*this_), allocator); + } + } + }; + + void operator()() + { + // Indicate that this strand is executing on the current thread. + call_stack<strand_impl>::context ctx(impl_.get()); + + // Ensure the next handler, if any, is scheduled on block exit. + on_invoker_exit on_exit = { this }; + (void)on_exit; + + // Run all ready handlers. No lock is required since the ready queue is + // accessed only within the strand. + asio::error_code ec; + while (scheduler_operation* o = impl_->ready_queue_.front()) + { + impl_->ready_queue_.pop(); + o->complete(impl_.get(), ec, 0); + } + } + +private: + implementation_type impl_; + executor_work_guard<Executor> work_; +}; + +template <typename Executor, typename Function, typename Allocator> +void strand_executor_service::dispatch(const implementation_type& impl, + Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay<Function>::type function_type; + + // If we are already in the strand then the function can run immediately. + if (call_stack<strand_impl>::contains(impl.get())) + { + // Make a local, non-const copy of the function. + function_type tmp(ASIO_MOVE_CAST(Function)(function)); + + fenced_block b(fenced_block::full); + asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a); + + ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "dispatch")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + ex.dispatch(invoker<Executor>(impl, ex), a); +} + +// Request invocation of the given function and return immediately. +template <typename Executor, typename Function, typename Allocator> +void strand_executor_service::post(const implementation_type& impl, + Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a); + + ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "post")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + ex.post(invoker<Executor>(impl, ex), a); +} + +// Request invocation of the given function and return immediately. +template <typename Executor, typename Function, typename Allocator> +void strand_executor_service::defer(const implementation_type& impl, + Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a); + + ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "defer")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + ex.defer(invoker<Executor>(impl, ex), a); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP diff --git a/lib/asio/detail/impl/strand_executor_service.ipp b/lib/asio/detail/impl/strand_executor_service.ipp new file mode 100644 index 0000000..365652e --- /dev/null +++ b/lib/asio/detail/impl/strand_executor_service.ipp @@ -0,0 +1,134 @@ +// +// detail/impl/strand_executor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP +#define ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/strand_executor_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +strand_executor_service::strand_executor_service(execution_context& ctx) + : execution_context_service_base<strand_executor_service>(ctx), + mutex_(), + salt_(0), + impl_list_(0) +{ +} + +void strand_executor_service::shutdown() +{ + op_queue<scheduler_operation> ops; + + asio::detail::mutex::scoped_lock lock(mutex_); + + strand_impl* impl = impl_list_; + while (impl) + { + impl->mutex_->lock(); + impl->shutdown_ = true; + ops.push(impl->waiting_queue_); + ops.push(impl->ready_queue_); + impl->mutex_->unlock(); + impl = impl->next_; + } +} + +strand_executor_service::implementation_type +strand_executor_service::create_implementation() +{ + implementation_type new_impl(new strand_impl); + new_impl->locked_ = false; + new_impl->shutdown_ = false; + + asio::detail::mutex::scoped_lock lock(mutex_); + + // Select a mutex from the pool of shared mutexes. + std::size_t salt = salt_++; + std::size_t mutex_index = reinterpret_cast<std::size_t>(new_impl.get()); + mutex_index += (reinterpret_cast<std::size_t>(new_impl.get()) >> 3); + mutex_index ^= salt + 0x9e3779b9 + (mutex_index << 6) + (mutex_index >> 2); + mutex_index = mutex_index % num_mutexes; + if (!mutexes_[mutex_index].get()) + mutexes_[mutex_index].reset(new mutex); + new_impl->mutex_ = mutexes_[mutex_index].get(); + + // Insert implementation into linked list of all implementations. + new_impl->next_ = impl_list_; + new_impl->prev_ = 0; + if (impl_list_) + impl_list_->prev_ = new_impl.get(); + impl_list_ = new_impl.get(); + new_impl->service_ = this; + + return new_impl; +} + +strand_executor_service::strand_impl::~strand_impl() +{ + asio::detail::mutex::scoped_lock lock(service_->mutex_); + + // Remove implementation from linked list of all implementations. + if (service_->impl_list_ == this) + service_->impl_list_ = next_; + if (prev_) + prev_->next_ = next_; + if (next_) + next_->prev_= prev_; +} + +bool strand_executor_service::enqueue(const implementation_type& impl, + scheduler_operation* op) +{ + impl->mutex_->lock(); + if (impl->shutdown_) + { + impl->mutex_->unlock(); + op->destroy(); + return false; + } + else if (impl->locked_) + { + // Some other function already holds the strand lock. Enqueue for later. + impl->waiting_queue_.push(op); + impl->mutex_->unlock(); + return false; + } + else + { + // The function is acquiring the strand lock and so is responsible for + // scheduling the strand. + impl->locked_ = true; + impl->mutex_->unlock(); + impl->ready_queue_.push(op); + return true; + } +} + +bool strand_executor_service::running_in_this_thread( + const implementation_type& impl) +{ + return !!call_stack<strand_impl>::contains(impl.get()); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP diff --git a/lib/asio/detail/impl/strand_service.hpp b/lib/asio/detail/impl/strand_service.hpp new file mode 100644 index 0000000..da5b716 --- /dev/null +++ b/lib/asio/detail/impl/strand_service.hpp @@ -0,0 +1,118 @@ +// +// detail/impl/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP +#define ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/call_stack.hpp" +#include "asio/detail/completion_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +inline strand_service::strand_impl::strand_impl() + : operation(&strand_service::do_complete), + locked_(false) +{ +} + +struct strand_service::on_dispatch_exit +{ + io_context_impl* io_context_; + strand_impl* impl_; + + ~on_dispatch_exit() + { + impl_->mutex_.lock(); + impl_->ready_queue_.push(impl_->waiting_queue_); + bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty(); + impl_->mutex_.unlock(); + + if (more_handlers) + io_context_->post_immediate_completion(impl_, false); + } +}; + +template <typename Handler> +void strand_service::dispatch(strand_service::implementation_type& impl, + Handler& handler) +{ + // If we are already in the strand then the handler can run immediately. + if (call_stack<strand_impl>::contains(impl)) + { + fenced_block b(fenced_block::full); + asio_handler_invoke_helpers::invoke(handler, handler); + return; + } + + // Allocate and construct an operation to wrap the handler. + typedef completion_handler<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((this->context(), + *p.p, "strand", impl, 0, "dispatch")); + + bool dispatch_immediately = do_dispatch(impl, p.p); + operation* o = p.p; + p.v = p.p = 0; + + if (dispatch_immediately) + { + // Indicate that this strand is executing on the current thread. + call_stack<strand_impl>::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_dispatch_exit on_exit = { &io_context_, impl }; + (void)on_exit; + + completion_handler<Handler>::do_complete( + &io_context_, o, asio::error_code(), 0); + } +} + +// Request the io_context to invoke the given handler and return immediately. +template <typename Handler> +void strand_service::post(strand_service::implementation_type& impl, + Handler& handler) +{ + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef completion_handler<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((this->context(), + *p.p, "strand", impl, 0, "post")); + + do_post(impl, p.p, is_continuation); + p.v = p.p = 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP diff --git a/lib/asio/detail/impl/strand_service.ipp b/lib/asio/detail/impl/strand_service.ipp new file mode 100644 index 0000000..cbaf25b --- /dev/null +++ b/lib/asio/detail/impl/strand_service.ipp @@ -0,0 +1,177 @@ +// +// detail/impl/strand_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP +#define ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/call_stack.hpp" +#include "asio/detail/strand_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct strand_service::on_do_complete_exit +{ + io_context_impl* owner_; + strand_impl* impl_; + + ~on_do_complete_exit() + { + impl_->mutex_.lock(); + impl_->ready_queue_.push(impl_->waiting_queue_); + bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty(); + impl_->mutex_.unlock(); + + if (more_handlers) + owner_->post_immediate_completion(impl_, true); + } +}; + +strand_service::strand_service(asio::io_context& io_context) + : asio::detail::service_base<strand_service>(io_context), + io_context_(asio::use_service<io_context_impl>(io_context)), + mutex_(), + salt_(0) +{ +} + +void strand_service::shutdown() +{ + op_queue<operation> ops; + + asio::detail::mutex::scoped_lock lock(mutex_); + + for (std::size_t i = 0; i < num_implementations; ++i) + { + if (strand_impl* impl = implementations_[i].get()) + { + ops.push(impl->waiting_queue_); + ops.push(impl->ready_queue_); + } + } +} + +void strand_service::construct(strand_service::implementation_type& impl) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + std::size_t salt = salt_++; +#if defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) + std::size_t index = salt; +#else // defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) + std::size_t index = reinterpret_cast<std::size_t>(&impl); + index += (reinterpret_cast<std::size_t>(&impl) >> 3); + index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2); +#endif // defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) + index = index % num_implementations; + + if (!implementations_[index].get()) + implementations_[index].reset(new strand_impl); + impl = implementations_[index].get(); +} + +bool strand_service::running_in_this_thread( + const implementation_type& impl) const +{ + return call_stack<strand_impl>::contains(impl) != 0; +} + +bool strand_service::do_dispatch(implementation_type& impl, operation* op) +{ + // If we are running inside the io_context, and no other handler already + // holds the strand lock, then the handler can run immediately. + bool can_dispatch = io_context_.can_dispatch(); + impl->mutex_.lock(); + if (can_dispatch && !impl->locked_) + { + // Immediate invocation is allowed. + impl->locked_ = true; + impl->mutex_.unlock(); + return true; + } + + if (impl->locked_) + { + // Some other handler already holds the strand lock. Enqueue for later. + impl->waiting_queue_.push(op); + impl->mutex_.unlock(); + } + else + { + // The handler is acquiring the strand lock and so is responsible for + // scheduling the strand. + impl->locked_ = true; + impl->mutex_.unlock(); + impl->ready_queue_.push(op); + io_context_.post_immediate_completion(impl, false); + } + + return false; +} + +void strand_service::do_post(implementation_type& impl, + operation* op, bool is_continuation) +{ + impl->mutex_.lock(); + if (impl->locked_) + { + // Some other handler already holds the strand lock. Enqueue for later. + impl->waiting_queue_.push(op); + impl->mutex_.unlock(); + } + else + { + // The handler is acquiring the strand lock and so is responsible for + // scheduling the strand. + impl->locked_ = true; + impl->mutex_.unlock(); + impl->ready_queue_.push(op); + io_context_.post_immediate_completion(impl, is_continuation); + } +} + +void strand_service::do_complete(void* owner, operation* base, + const asio::error_code& ec, std::size_t /*bytes_transferred*/) +{ + if (owner) + { + strand_impl* impl = static_cast<strand_impl*>(base); + + // Indicate that this strand is executing on the current thread. + call_stack<strand_impl>::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_do_complete_exit on_exit; + on_exit.owner_ = static_cast<io_context_impl*>(owner); + on_exit.impl_ = impl; + + // Run all ready handlers. No lock is required since the ready queue is + // accessed only within the strand. + while (operation* o = impl->ready_queue_.front()) + { + impl->ready_queue_.pop(); + o->complete(owner, ec, 0); + } + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP diff --git a/lib/asio/detail/impl/throw_error.ipp b/lib/asio/detail/impl/throw_error.ipp new file mode 100644 index 0000000..a540cd2 --- /dev/null +++ b/lib/asio/detail/impl/throw_error.ipp @@ -0,0 +1,60 @@ +// +// detail/impl/throw_error.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_THROW_ERROR_IPP +#define ASIO_DETAIL_IMPL_THROW_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/throw_exception.hpp" +#include "asio/system_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void do_throw_error(const asio::error_code& err) +{ + asio::system_error e(err); + asio::detail::throw_exception(e); +} + +void do_throw_error(const asio::error_code& err, const char* location) +{ + // boostify: non-boost code starts here +#if defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR) + // Microsoft's implementation of std::system_error is non-conformant in that + // it ignores the error code's message when a "what" string is supplied. We'll + // work around this by explicitly formatting the "what" string. + std::string what_msg = location; + what_msg += ": "; + what_msg += err.message(); + asio::system_error e(err, what_msg); + asio::detail::throw_exception(e); +#else // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR) + // boostify: non-boost code ends here + asio::system_error e(err, location); + asio::detail::throw_exception(e); + // boostify: non-boost code starts here +#endif // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR) + // boostify: non-boost code ends here +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_THROW_ERROR_IPP diff --git a/lib/asio/detail/impl/timer_queue_ptime.ipp b/lib/asio/detail/impl/timer_queue_ptime.ipp new file mode 100644 index 0000000..742837f --- /dev/null +++ b/lib/asio/detail/impl/timer_queue_ptime.ipp @@ -0,0 +1,91 @@ +// +// detail/impl/timer_queue_ptime.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP +#define ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) + +#include "asio/detail/timer_queue_ptime.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +timer_queue<time_traits<boost::posix_time::ptime> >::timer_queue() +{ +} + +timer_queue<time_traits<boost::posix_time::ptime> >::~timer_queue() +{ +} + +bool timer_queue<time_traits<boost::posix_time::ptime> >::enqueue_timer( + const time_type& time, per_timer_data& timer, wait_op* op) +{ + return impl_.enqueue_timer(time, timer, op); +} + +bool timer_queue<time_traits<boost::posix_time::ptime> >::empty() const +{ + return impl_.empty(); +} + +long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_msec( + long max_duration) const +{ + return impl_.wait_duration_msec(max_duration); +} + +long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_usec( + long max_duration) const +{ + return impl_.wait_duration_usec(max_duration); +} + +void timer_queue<time_traits<boost::posix_time::ptime> >::get_ready_timers( + op_queue<operation>& ops) +{ + impl_.get_ready_timers(ops); +} + +void timer_queue<time_traits<boost::posix_time::ptime> >::get_all_timers( + op_queue<operation>& ops) +{ + impl_.get_all_timers(ops); +} + +std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer( + per_timer_data& timer, op_queue<operation>& ops, std::size_t max_cancelled) +{ + return impl_.cancel_timer(timer, ops, max_cancelled); +} + +void timer_queue<time_traits<boost::posix_time::ptime> >::move_timer( + per_timer_data& target, per_timer_data& source) +{ + impl_.move_timer(target, source); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + +#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP diff --git a/lib/asio/detail/impl/timer_queue_set.ipp b/lib/asio/detail/impl/timer_queue_set.ipp new file mode 100644 index 0000000..b516548 --- /dev/null +++ b/lib/asio/detail/impl/timer_queue_set.ipp @@ -0,0 +1,101 @@ +// +// detail/impl/timer_queue_set.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP +#define ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/timer_queue_set.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +timer_queue_set::timer_queue_set() + : first_(0) +{ +} + +void timer_queue_set::insert(timer_queue_base* q) +{ + q->next_ = first_; + first_ = q; +} + +void timer_queue_set::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; + } + } + } +} + +bool timer_queue_set::all_empty() const +{ + for (timer_queue_base* p = first_; p; p = p->next_) + if (!p->empty()) + return false; + return true; +} + +long timer_queue_set::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; +} + +long timer_queue_set::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; +} + +void timer_queue_set::get_ready_timers(op_queue<operation>& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_ready_timers(ops); +} + +void timer_queue_set::get_all_timers(op_queue<operation>& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_all_timers(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP diff --git a/lib/asio/detail/impl/win_event.ipp b/lib/asio/detail/impl/win_event.ipp new file mode 100644 index 0000000..6f74649 --- /dev/null +++ b/lib/asio/detail/impl/win_event.ipp @@ -0,0 +1,76 @@ +// +// detail/win_event.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_EVENT_IPP +#define ASIO_DETAIL_IMPL_WIN_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_event.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_event::win_event() + : state_(0) +{ +#if defined(ASIO_WINDOWS_APP) + events_[0] = ::CreateEventExW(0, 0, + CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); +#else // defined(ASIO_WINDOWS_APP) + events_[0] = ::CreateEventW(0, true, false, 0); +#endif // defined(ASIO_WINDOWS_APP) + if (!events_[0]) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "event"); + } + +#if defined(ASIO_WINDOWS_APP) + events_[1] = ::CreateEventExW(0, 0, 0, EVENT_ALL_ACCESS); +#else // defined(ASIO_WINDOWS_APP) + events_[1] = ::CreateEventW(0, false, false, 0); +#endif // defined(ASIO_WINDOWS_APP) + if (!events_[1]) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(events_[0]); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "event"); + } +} + +win_event::~win_event() +{ + ::CloseHandle(events_[0]); + ::CloseHandle(events_[1]); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_EVENT_IPP diff --git a/lib/asio/detail/impl/win_iocp_handle_service.ipp b/lib/asio/detail/impl/win_iocp_handle_service.ipp new file mode 100644 index 0000000..9cba2b0 --- /dev/null +++ b/lib/asio/detail/impl/win_iocp_handle_service.ipp @@ -0,0 +1,525 @@ +// +// detail/impl/win_iocp_handle_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/win_iocp_handle_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_handle_service::overlapped_wrapper + : public OVERLAPPED +{ +public: + explicit overlapped_wrapper(asio::error_code& ec) + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + + // Create a non-signalled manual-reset event, for GetOverlappedResult. + hEvent = ::CreateEventW(0, TRUE, FALSE, 0); + if (hEvent) + { + // As documented in GetQueuedCompletionStatus, setting the low order + // bit of this event prevents our synchronous writes from being treated + // as completion port events. + DWORD_PTR tmp = reinterpret_cast<DWORD_PTR>(hEvent); + hEvent = reinterpret_cast<HANDLE>(tmp | 1); + } + else + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + } + + ~overlapped_wrapper() + { + if (hEvent) + { + ::CloseHandle(hEvent); + } + } +}; + +win_iocp_handle_service::win_iocp_handle_service( + asio::io_context& io_context) + : service_base<win_iocp_handle_service>(io_context), + iocp_service_(asio::use_service<win_iocp_io_context>(io_context)), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_handle_service::shutdown() +{ + // Close all implementations, causing all operations to complete. + asio::detail::mutex::scoped_lock lock(mutex_); + implementation_type* impl = impl_list_; + while (impl) + { + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_handle_service::construct( + win_iocp_handle_service::implementation_type& impl) +{ + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_handle_service::move_construct( + win_iocp_handle_service::implementation_type& impl, + win_iocp_handle_service::implementation_type& other_impl) +{ + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_handle_service::move_assign( + win_iocp_handle_service::implementation_type& impl, + win_iocp_handle_service& other_service, + win_iocp_handle_service::implementation_type& other_impl) +{ + close_for_destruction(impl); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(other_service.mutex_); + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } +} + +void win_iocp_handle_service::destroy( + win_iocp_handle_service::implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +asio::error_code win_iocp_handle_service::assign( + win_iocp_handle_service::implementation_type& impl, + const native_handle_type& handle, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + if (iocp_service_.register_handle(handle, ec)) + return ec; + + impl.handle_ = handle; + ec = asio::error_code(); + return ec; +} + +asio::error_code win_iocp_handle_service::close( + win_iocp_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close")); + + if (!::CloseHandle(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } + else + { + ec = asio::error_code(); + } + + return ec; +} + +asio::error_code win_iocp_handle_service::cancel( + win_iocp_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast<uintmax_t>(impl.handle_), "cancel")); + + if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; + if (!cancel_io_ex(impl.handle_, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = asio::error_code(); + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + } + else + { + ec = asio::error_code(); + } + } + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = asio::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + if (!::CancelIo(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = asio::error::operation_not_supported; + } + + return ec; +} + +size_t win_iocp_handle_service::do_write( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const asio::const_buffer& buffer, asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a handle is a no-op. + if (buffer.size() == 0) + { + ec = asio::error_code(); + return 0; + } + + overlapped_wrapper overlapped(ec); + if (ec) + { + return 0; + } + + // Write the data. + overlapped.Offset = offset & 0xFFFFFFFF; + overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, buffer.data(), + static_cast<DWORD>(buffer.size()), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING) + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + } + + // Wait for the operation to complete. + DWORD bytes_transferred = 0; + ok = ::GetOverlappedResult(impl.handle_, + &overlapped, &bytes_transferred, TRUE); + if (!ok) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + + ec = asio::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_write_op( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const asio::const_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, asio::error::bad_descriptor); + } + else if (buffer.size() == 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_, buffer.data(), + static_cast<DWORD>(buffer.size()), + &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); + } + } +} + +size_t win_iocp_handle_service::do_read( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const asio::mutable_buffer& buffer, asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream handle is a no-op. + if (buffer.size() == 0) + { + ec = asio::error_code(); + return 0; + } + + overlapped_wrapper overlapped(ec); + if (ec) + { + return 0; + } + + // Read some data. + overlapped.Offset = offset & 0xFFFFFFFF; + overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, buffer.data(), + static_cast<DWORD>(buffer.size()), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) + { + if (last_error == ERROR_HANDLE_EOF) + { + ec = asio::error::eof; + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + return 0; + } + } + + // Wait for the operation to complete. + DWORD bytes_transferred = 0; + ok = ::GetOverlappedResult(impl.handle_, + &overlapped, &bytes_transferred, TRUE); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_HANDLE_EOF) + { + ec = asio::error::eof; + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0; + } + + ec = asio::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_read_op( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const asio::mutable_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, asio::error::bad_descriptor); + } + else if (buffer.size() == 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_, buffer.data(), + static_cast<DWORD>(buffer.size()), + &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); + } + } +} + +void win_iocp_handle_service::update_cancellation_thread_id( + win_iocp_handle_service::implementation_type& impl) +{ + 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); +} + +void win_iocp_handle_service::close_for_destruction(implementation_type& impl) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close")); + + ::CloseHandle(impl.handle_); + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP diff --git a/lib/asio/detail/impl/win_iocp_io_context.hpp b/lib/asio/detail/impl/win_iocp_io_context.hpp new file mode 100644 index 0000000..44887d7 --- /dev/null +++ b/lib/asio/detail/impl/win_iocp_io_context.hpp @@ -0,0 +1,103 @@ +// +// detail/impl/win_iocp_io_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/completion_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +void win_iocp_io_context::add_timer_queue( + timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +template <typename Time_Traits> +void win_iocp_io_context::remove_timer_queue( + timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void win_iocp_io_context::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op) +{ + // If the service has been shut down we silently discard the timer. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + { + post_immediate_completion(op, false); + return; + } + + mutex::scoped_lock lock(dispatch_mutex_); + + bool earliest = queue.enqueue_timer(time, timer, op); + work_started(); + if (earliest) + update_timeout(); +} + +template <typename Time_Traits> +std::size_t win_iocp_io_context::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled) +{ + // If the service has been shut down we silently ignore the cancellation. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return 0; + + mutex::scoped_lock lock(dispatch_mutex_); + op_queue<win_iocp_operation> ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + post_deferred_completions(ops); + return n; +} + +template <typename Time_Traits> +void win_iocp_io_context::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from) +{ + asio::detail::mutex::scoped_lock lock(dispatch_mutex_); + op_queue<operation> ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP diff --git a/lib/asio/detail/impl/win_iocp_io_context.ipp b/lib/asio/detail/impl/win_iocp_io_context.ipp new file mode 100644 index 0000000..c371b86 --- /dev/null +++ b/lib/asio/detail/impl/win_iocp_io_context.ipp @@ -0,0 +1,554 @@ +// +// detail/impl/win_iocp_io_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include "asio/detail/cstdint.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_iocp_io_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct win_iocp_io_context::work_finished_on_block_exit +{ + ~work_finished_on_block_exit() + { + io_context_->work_finished(); + } + + win_iocp_io_context* io_context_; +}; + +struct win_iocp_io_context::timer_thread_function +{ + void operator()() + { + while (::InterlockedExchangeAdd(&io_context_->shutdown_, 0) == 0) + { + if (::WaitForSingleObject(io_context_->waitable_timer_.handle, + INFINITE) == WAIT_OBJECT_0) + { + ::InterlockedExchange(&io_context_->dispatch_required_, 1); + ::PostQueuedCompletionStatus(io_context_->iocp_.handle, + 0, wake_for_dispatch, 0); + } + } + } + + win_iocp_io_context* io_context_; +}; + +win_iocp_io_context::win_iocp_io_context( + asio::execution_context& ctx, int concurrency_hint) + : execution_context_service_base<win_iocp_io_context>(ctx), + iocp_(), + outstanding_work_(0), + stopped_(0), + stop_event_posted_(0), + shutdown_(0), + gqcs_timeout_(get_gqcs_timeout()), + dispatch_required_(0), + concurrency_hint_(concurrency_hint) +{ + ASIO_HANDLER_TRACKING_INIT; + + iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, + static_cast<DWORD>(concurrency_hint >= 0 ? concurrency_hint : DWORD(~0))); + if (!iocp_.handle) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "iocp"); + } +} + +void win_iocp_io_context::shutdown() +{ + ::InterlockedExchange(&shutdown_, 1); + + if (timer_thread_.get()) + { + LARGE_INTEGER timeout; + timeout.QuadPart = 1; + ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE); + } + + while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) + { + op_queue<win_iocp_operation> ops; + timer_queues_.get_all_timers(ops); + ops.push(completed_ops_); + if (!ops.empty()) + { + while (win_iocp_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, gqcs_timeout_); + if (overlapped) + { + ::InterlockedDecrement(&outstanding_work_); + static_cast<win_iocp_operation*>(overlapped)->destroy(); + } + } + } + + if (timer_thread_.get()) + timer_thread_->join(); +} + +asio::error_code win_iocp_io_context::register_handle( + HANDLE handle, asio::error_code& ec) +{ + if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + return ec; +} + +size_t win_iocp_io_context::run(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + size_t n = 0; + while (do_one(INFINITE, ec)) + if (n != (std::numeric_limits<size_t>::max)()) + ++n; + return n; +} + +size_t win_iocp_io_context::run_one(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + return do_one(INFINITE, ec); +} + +size_t win_iocp_io_context::wait_one(long usec, asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), ec); +} + +size_t win_iocp_io_context::poll(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + size_t n = 0; + while (do_one(0, ec)) + if (n != (std::numeric_limits<size_t>::max)()) + ++n; + return n; +} + +size_t win_iocp_io_context::poll_one(asio::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = asio::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + return do_one(0, ec); +} + +void win_iocp_io_context::stop() +{ + if (::InterlockedExchange(&stopped_, 1) == 0) + { + if (::InterlockedExchange(&stop_event_posted_, 1) == 0) + { + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "pqcs"); + } + } + } +} + +void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op) +{ + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_context::post_deferred_completions( + op_queue<win_iocp_operation>& ops) +{ + while (win_iocp_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, 0, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + completed_ops_.push(ops); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_context::abandon_operations( + op_queue<win_iocp_operation>& ops) +{ + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + ::InterlockedDecrement(&outstanding_work_); + op->destroy(); + } +} + +void win_iocp_io_context::on_pending(win_iocp_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. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_context::on_completion(win_iocp_operation* op, + DWORD last_error, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast<ulong_ptr_t>( + &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, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_context::on_completion(win_iocp_operation* op, + const asio::error_code& ec, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast<ulong_ptr_t>(&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. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +size_t win_iocp_io_context::do_one(DWORD msec, asio::error_code& ec) +{ + for (;;) + { + // Try to acquire responsibility for dispatching timers and completed ops. + if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1) + { + mutex::scoped_lock lock(dispatch_mutex_); + + // Dispatch pending timers and operations. + op_queue<win_iocp_operation> ops; + ops.push(completed_ops_); + timer_queues_.get_ready_timers(ops); + post_deferred_completions(ops); + update_timeout(); + } + + // Get the next operation from the queue. + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::SetLastError(0); + BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, + &bytes_transferred, &completion_key, &overlapped, + msec < gqcs_timeout_ ? msec : gqcs_timeout_); + DWORD last_error = ::GetLastError(); + + if (overlapped) + { + win_iocp_operation* op = static_cast<win_iocp_operation*>(overlapped); + asio::error_code result_ec(last_error, + asio::error::get_system_category()); + + // We may have been passed the last_error and bytes_transferred in the + // OVERLAPPED structure itself. + if (completion_key == overlapped_contains_result) + { + result_ec = asio::error_code(static_cast<int>(op->Offset), + *reinterpret_cast<asio::error_category*>(op->Internal)); + bytes_transferred = op->OffsetHigh; + } + + // Otherwise ensure any result has been saved into the OVERLAPPED + // structure. + else + { + op->Internal = reinterpret_cast<ulong_ptr_t>(&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 = asio::error_code(); + return 1; + } + } + else if (!ok) + { + if (last_error != WAIT_TIMEOUT) + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + + // If we're waiting indefinitely we need to keep going until we get a + // real handler. + if (msec == INFINITE) + continue; + + ec = asio::error_code(); + return 0; + } + else if (completion_key == wake_for_dispatch) + { + // We have been woken up to try to acquire responsibility for dispatching + // timers and completed operations. + } + else + { + // Indicate that there is no longer an in-flight stop event. + ::InterlockedExchange(&stop_event_posted_, 0); + + // The stopped_ flag is always checked to ensure that any leftover + // stop events from a previous run invocation are ignored. + if (::InterlockedExchangeAdd(&stopped_, 0) != 0) + { + // Wake up next thread that is blocked on GetQueuedCompletionStatus. + if (::InterlockedExchange(&stop_event_posted_, 1) == 0) + { + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return 0; + } + } + + ec = asio::error_code(); + return 0; + } + } + } +} + +DWORD win_iocp_io_context::get_gqcs_timeout() +{ + OSVERSIONINFOEX osvi; + ZeroMemory(&osvi, sizeof(osvi)); + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = 6ul; + + const uint64_t condition_mask = ::VerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL); + + if (!!::VerifyVersionInfo(&osvi, VER_MAJORVERSION, condition_mask)) + return INFINITE; + + return default_gqcs_timeout; +} + +void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.insert(&queue); + + if (!waitable_timer_.handle) + { + waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0); + if (waitable_timer_.handle == 0) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "timer"); + } + + LARGE_INTEGER timeout; + timeout.QuadPart = -max_timeout_usec; + timeout.QuadPart *= 10; + ::SetWaitableTimer(waitable_timer_.handle, + &timeout, max_timeout_msec, 0, 0, FALSE); + } + + if (!timer_thread_.get()) + { + timer_thread_function thread_function = { this }; + timer_thread_.reset(new thread(thread_function, 65536)); + } +} + +void win_iocp_io_context::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.erase(&queue); +} + +void win_iocp_io_context::update_timeout() +{ + if (timer_thread_.get()) + { + // There's no point updating the waitable timer if the new timeout period + // exceeds the maximum timeout. In that case, we might as well wait for the + // existing period of the timer to expire. + long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec); + if (timeout_usec < max_timeout_usec) + { + LARGE_INTEGER timeout; + timeout.QuadPart = -timeout_usec; + timeout.QuadPart *= 10; + ::SetWaitableTimer(waitable_timer_.handle, + &timeout, max_timeout_msec, 0, 0, FALSE); + } + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP diff --git a/lib/asio/detail/impl/win_iocp_serial_port_service.ipp b/lib/asio/detail/impl/win_iocp_serial_port_service.ipp new file mode 100644 index 0000000..4a9b8cd --- /dev/null +++ b/lib/asio/detail/impl/win_iocp_serial_port_service.ipp @@ -0,0 +1,181 @@ +// +// detail/impl/win_iocp_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + +#include <cstring> +#include "asio/detail/win_iocp_serial_port_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_iocp_serial_port_service::win_iocp_serial_port_service( + asio::io_context& io_context) + : service_base<win_iocp_serial_port_service>(io_context), + handle_service_(io_context) +{ +} + +void win_iocp_serial_port_service::shutdown() +{ +} + +asio::error_code win_iocp_serial_port_service::open( + win_iocp_serial_port_service::implementation_type& impl, + const std::string& device, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + // For convenience, add a leading \\.\ sequence if not already present. + std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device; + + // Open a handle to the serial port. + ::HANDLE handle = ::CreateFileA(name.c_str(), + GENERIC_READ | GENERIC_WRITE, 0, 0, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (handle == INVALID_HANDLE_VALUE) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // Determine the initial serial port parameters. + using namespace std; // For memset. + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // Set some default serial port parameters. This implementation does not + // support changing these, so they might as well be in a known state. + dcb.fBinary = TRUE; // Win32 only supports binary mode. + dcb.fDsrSensitivity = FALSE; + dcb.fNull = FALSE; // Do not ignore NULL characters. + dcb.fAbortOnError = FALSE; // Ignore serial framing errors. + if (!::SetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // Set up timeouts so that the serial port will behave similarly to a + // network socket. Reads wait for at least one byte, then return with + // whatever they have. Writes return once everything is out the door. + ::COMMTIMEOUTS timeouts; + timeouts.ReadIntervalTimeout = 1; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + if (!::SetCommTimeouts(handle, &timeouts)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + // We're done. Take ownership of the serial port handle. + if (handle_service_.assign(impl, handle, ec)) + ::CloseHandle(handle); + return ec; +} + +asio::error_code win_iocp_serial_port_service::do_set_option( + win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::store_function_type store, + const void* option, asio::error_code& ec) +{ + using namespace std; // For memcpy. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native_handle(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + if (store(option, dcb, ec)) + return ec; + + if (!::SetCommState(handle_service_.native_handle(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + ec = asio::error_code(); + return ec; +} + +asio::error_code win_iocp_serial_port_service::do_get_option( + const win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::load_function_type load, + void* option, asio::error_code& ec) const +{ + using namespace std; // For memset. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native_handle(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + return ec; + } + + return load(option, dcb, ec); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP diff --git a/lib/asio/detail/impl/win_iocp_socket_service_base.ipp b/lib/asio/detail/impl/win_iocp_socket_service_base.ipp new file mode 100644 index 0000000..6c478cd --- /dev/null +++ b/lib/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -0,0 +1,799 @@ +// +// detail/impl/win_iocp_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/win_iocp_socket_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_iocp_socket_service_base::win_iocp_socket_service_base( + asio::io_context& io_context) + : io_context_(io_context), + iocp_service_(use_service<win_iocp_io_context>(io_context)), + reactor_(0), + connect_ex_(0), + nt_set_info_(0), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_socket_service_base::base_shutdown() +{ + // Close all implementations, causing all operations to complete. + asio::detail::mutex::scoped_lock lock(mutex_); + base_implementation_type* impl = impl_list_; + while (impl) + { + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_socket_service_base::construct( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_socket_service_base::base_move_construct( + win_iocp_socket_service_base::base_implementation_type& impl, + win_iocp_socket_service_base::base_implementation_type& other_impl) +{ + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + impl.cancel_token_ = other_impl.cancel_token_; + other_impl.cancel_token_.reset(); + +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_socket_service_base::base_move_assign( + win_iocp_socket_service_base::base_implementation_type& impl, + win_iocp_socket_service_base& other_service, + win_iocp_socket_service_base::base_implementation_type& other_impl) +{ + close_for_destruction(impl); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + impl.cancel_token_ = other_impl.cancel_token_; + other_impl.cancel_token_.reset(); + +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(other_service.mutex_); + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } +} + +void win_iocp_socket_service_base::destroy( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +asio::error_code win_iocp_socket_service_base::close( + win_iocp_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "close")); + + // 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. + select_reactor* r = static_cast<select_reactor*>( + interlocked_compare_exchange_pointer( + reinterpret_cast<void**>(&reactor_), 0, 0)); + if (r) + r->deregister_descriptor(impl.socket_, impl.reactor_data_, true); + + socket_ops::close(impl.socket_, impl.state_, false, ec); + + if (r) + r->cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = asio::error_code(); + } + + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) + + return ec; +} + +socket_type win_iocp_socket_service_base::release( + win_iocp_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + return invalid_socket; + + cancel(impl, ec); + if (ec) + return invalid_socket; + + nt_set_info_fn fn = get_nt_set_info(); + if (fn == 0) + { + ec = asio::error::operation_not_supported; + return invalid_socket; + } + + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(impl.socket_); + ULONG_PTR iosb[2] = { 0, 0 }; + void* info[2] = { 0, 0 }; + if (fn(sock_as_handle, iosb, &info, sizeof(info), + 61 /* FileReplaceCompletionInformation */)) + { + ec = asio::error::operation_not_supported; + return invalid_socket; + } + + socket_type tmp = impl.socket_; + impl.socket_ = invalid_socket; + return tmp; +} + +asio::error_code win_iocp_socket_service_base::cancel( + win_iocp_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "cancel")); + + if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock); + if (!cancel_io_ex(sock_as_handle, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = asio::error_code(); + } + else + { + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + } + else + { + ec = asio::error_code(); + } + } +#if defined(ASIO_ENABLE_CANCELIO) + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = asio::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock); + if (!::CancelIo(sock_as_handle)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + else + { + ec = asio::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = asio::error::operation_not_supported; + } +#else // defined(ASIO_ENABLE_CANCELIO) + else + { + // Cancellation is not supported as CancelIo may not be used. + ec = asio::error::operation_not_supported; + } +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Cancel any operations started via the reactor. + if (!ec) + { + select_reactor* r = static_cast<select_reactor*>( + interlocked_compare_exchange_pointer( + reinterpret_cast<void**>(&reactor_), 0, 0)); + if (r) + r->cancel_ops(impl.socket_, impl.reactor_data_); + } + + return ec; +} + +asio::error_code win_iocp_socket_service_base::do_open( + win_iocp_socket_service_base::base_implementation_type& impl, + int family, int type, int protocol, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(family, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get()); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter()); + ec = asio::error_code(); + return ec; +} + +asio::error_code win_iocp_socket_service_base::do_assign( + win_iocp_socket_service_base::base_implementation_type& impl, + int type, socket_type native_socket, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(native_socket); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter()); + ec = asio::error_code(); + return ec; +} + +void win_iocp_socket_service_base::start_send_op( + win_iocp_socket_service_base::base_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, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASend(impl.socket_, buffers, + static_cast<DWORD>(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); + } +} + +void win_iocp_socket_service_base::start_send_to_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + 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, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASendTo(impl.socket_, buffers, + static_cast<DWORD>(buffer_count), + &bytes_transferred, flags, addr, addrlen, 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); + } +} + +void win_iocp_socket_service_base::start_receive_op( + win_iocp_socket_service_base::base_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, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(impl.socket_, buffers, + static_cast<DWORD>(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); + } +} + +void win_iocp_socket_service_base::start_null_buffers_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op) +{ + if ((impl.state_ & socket_ops::stream_oriented) != 0) + { + // For stream sockets on Windows, we may issue a 0-byte overlapped + // WSARecv to wait until there is data available on the socket. + ::WSABUF buf = { 0, 0 }; + start_receive_op(impl, &buf, 1, flags, false, op); + } + else + { + start_reactor_op(impl, + (flags & socket_base::message_out_of_band) + ? select_reactor::except_op : select_reactor::read_op, + op); + } +} + +void win_iocp_socket_service_base::start_receive_from_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecvFrom(impl.socket_, buffers, + static_cast<DWORD>(buffer_count), + &bytes_transferred, &recv_flags, addr, addrlen, 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); + } +} + +void win_iocp_socket_service_base::start_accept_op( + win_iocp_socket_service_base::base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, asio::error::bad_descriptor); + else if (peer_is_open) + iocp_service_.on_completion(op, asio::error::already_open); + else + { + asio::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + 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); + } + } +} + +void win_iocp_socket_service_base::restart_accept_op( + socket_type s, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + new_socket.reset(); + iocp_service_.work_started(); + + asio::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(s, 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); + } +} + +void win_iocp_socket_service_base::start_reactor_op( + win_iocp_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op) +{ + select_reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if (is_open(impl)) + { + r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false, false); + return; + } + else + op->ec_ = asio::error::bad_descriptor; + + iocp_service_.post_immediate_completion(op, false); +} + +void win_iocp_socket_service_base::start_connect_op( + win_iocp_socket_service_base::base_implementation_type& impl, + int family, int type, const socket_addr_type* addr, + std::size_t addrlen, win_iocp_socket_connect_op_base* op) +{ + // If ConnectEx is available, use that. + if (family == ASIO_OS_DEF(AF_INET) + || family == ASIO_OS_DEF(AF_INET6)) + { + if (connect_ex_fn connect_ex = get_connect_ex(impl, type)) + { + union address_union + { + socket_addr_type base; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } a; + + using namespace std; // For memset. + memset(&a, 0, sizeof(a)); + a.base.sa_family = family; + + socket_ops::bind(impl.socket_, &a.base, + family == ASIO_OS_DEF(AF_INET) + ? sizeof(a.v4) : sizeof(a.v6), op->ec_); + if (op->ec_ && op->ec_ != asio::error::invalid_argument) + { + iocp_service_.post_immediate_completion(op, false); + return; + } + + op->connect_ex_ = true; + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + BOOL result = connect_ex(impl.socket_, + addr, static_cast<int>(addrlen), 0, 0, 0, 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); + return; + } + } + + // Otherwise, fall back to a reactor-based implementation. + select_reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if ((impl.state_ & socket_ops::non_blocking) != 0 + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, true, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == asio::error::in_progress + || op->ec_ == asio::error::would_block) + { + op->ec_ = asio::error_code(); + r.start_op(select_reactor::connect_op, impl.socket_, + impl.reactor_data_, op, false, false); + return; + } + } + } + + r.post_immediate_completion(op, false); +} + +void win_iocp_socket_service_base::close_for_destruction( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "close")); + + // 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. + select_reactor* r = static_cast<select_reactor*>( + interlocked_compare_exchange_pointer( + reinterpret_cast<void**>(&reactor_), 0, 0)); + if (r) + r->deregister_descriptor(impl.socket_, impl.reactor_data_, true); + + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + + if (r) + r->cleanup_descriptor_data(impl.reactor_data_); + } + + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(ASIO_ENABLE_CANCELIO) +} + +void win_iocp_socket_service_base::update_cancellation_thread_id( + win_iocp_socket_service_base::base_implementation_type& impl) +{ +#if defined(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(ASIO_ENABLE_CANCELIO) + (void)impl; +#endif // defined(ASIO_ENABLE_CANCELIO) +} + +select_reactor& win_iocp_socket_service_base::get_reactor() +{ + select_reactor* r = static_cast<select_reactor*>( + interlocked_compare_exchange_pointer( + reinterpret_cast<void**>(&reactor_), 0, 0)); + if (!r) + { + r = &(use_service<select_reactor>(io_context_)); + interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r); + } + return *r; +} + +win_iocp_socket_service_base::connect_ex_fn +win_iocp_socket_service_base::get_connect_ex( + win_iocp_socket_service_base::base_implementation_type& impl, int type) +{ +#if defined(ASIO_DISABLE_CONNECTEX) + (void)impl; + (void)type; + return 0; +#else // defined(ASIO_DISABLE_CONNECTEX) + if (type != ASIO_OS_DEF(SOCK_STREAM) + && type != ASIO_OS_DEF(SOCK_SEQPACKET)) + return 0; + + void* ptr = interlocked_compare_exchange_pointer(&connect_ex_, 0, 0); + if (!ptr) + { + GUID guid = { 0x25a207b9, 0xddf3, 0x4660, + { 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e } }; + + DWORD bytes = 0; + if (::WSAIoctl(impl.socket_, SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, sizeof(guid), &ptr, sizeof(ptr), &bytes, 0, 0) != 0) + { + // Set connect_ex_ to a special value to indicate that ConnectEx is + // unavailable. That way we won't bother trying to look it up again. + ptr = this; + } + + interlocked_exchange_pointer(&connect_ex_, ptr); + } + + return reinterpret_cast<connect_ex_fn>(ptr == this ? 0 : ptr); +#endif // defined(ASIO_DISABLE_CONNECTEX) +} + +win_iocp_socket_service_base::nt_set_info_fn +win_iocp_socket_service_base::get_nt_set_info() +{ + void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0); + if (!ptr) + { + if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL")) + ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile")); + + // On failure, set nt_set_info_ to a special value to indicate that the + // NtSetInformationFile function is unavailable. That way we won't bother + // trying to look it up again. + interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this); + } + + return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr); +} + +void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp) +{ +#if defined(_M_IX86) + return reinterpret_cast<void*>(InterlockedCompareExchange( + reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch), + reinterpret_cast<LONG>(cmp))); +#else + return InterlockedCompareExchangePointer(dest, exch, cmp); +#endif +} + +void* win_iocp_socket_service_base::interlocked_exchange_pointer( + void** dest, void* val) +{ +#if defined(_M_IX86) + return reinterpret_cast<void*>(InterlockedExchange( + reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val))); +#else + return InterlockedExchangePointer(dest, val); +#endif +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP diff --git a/lib/asio/detail/impl/win_mutex.ipp b/lib/asio/detail/impl/win_mutex.ipp new file mode 100644 index 0000000..dc58a12 --- /dev/null +++ b/lib/asio/detail/impl/win_mutex.ipp @@ -0,0 +1,84 @@ +// +// detail/impl/win_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_MUTEX_IPP +#define ASIO_DETAIL_IMPL_WIN_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_mutex.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_mutex::win_mutex() +{ + int error = do_init(); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "mutex"); +} + +int win_mutex::do_init() +{ +#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_); +# elif defined(ASIO_WINDOWS_APP) + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + return ::GetLastError(); +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + return ::GetLastError(); +# endif + return 0; +#else + __try + { +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# elif defined(ASIO_WINDOWS_APP) + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + return ::GetLastError(); +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + return ::GetLastError(); +# endif + } + __except(GetExceptionCode() == STATUS_NO_MEMORY + ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + return ERROR_OUTOFMEMORY; + } + + return 0; +#endif +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_MUTEX_IPP diff --git a/lib/asio/detail/impl/win_object_handle_service.ipp b/lib/asio/detail/impl/win_object_handle_service.ipp new file mode 100644 index 0000000..c5e59d1 --- /dev/null +++ b/lib/asio/detail/impl/win_object_handle_service.ipp @@ -0,0 +1,449 @@ +// +// detail/impl/win_object_handle_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2011 Boris Schaeling (boris@highscore.de) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP +#define ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#include "asio/detail/win_object_handle_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_object_handle_service::win_object_handle_service( + asio::io_context& io_context) + : service_base<win_object_handle_service>(io_context), + io_context_(asio::use_service<io_context_impl>(io_context)), + mutex_(), + impl_list_(0), + shutdown_(false) +{ +} + +void win_object_handle_service::shutdown() +{ + mutex::scoped_lock lock(mutex_); + + // Setting this flag to true prevents new objects from being registered, and + // new asynchronous wait operations from being started. We only need to worry + // about cleaning up the operations that are currently in progress. + shutdown_ = true; + + op_queue<operation> ops; + for (implementation_type* impl = impl_list_; impl; impl = impl->next_) + ops.push(impl->op_queue_); + + lock.unlock(); + + io_context_.abandon_operations(ops); +} + +void win_object_handle_service::construct( + win_object_handle_service::implementation_type& impl) +{ + impl.handle_ = INVALID_HANDLE_VALUE; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + impl.owner_ = this; + + // Insert implementation into linked list of all implementations. + mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; + } +} + +void win_object_handle_service::move_construct( + win_object_handle_service::implementation_type& impl, + win_object_handle_service::implementation_type& other_impl) +{ + mutex::scoped_lock lock(mutex_); + + // Insert implementation into linked list of all implementations. + if (!shutdown_) + { + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; + } + + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + impl.wait_handle_ = other_impl.wait_handle_; + other_impl.wait_handle_ = INVALID_HANDLE_VALUE; + impl.op_queue_.push(other_impl.op_queue_); + impl.owner_ = this; + + // We must not hold the lock while calling UnregisterWaitEx. This is because + // the registered callback function might be invoked while we are waiting for + // UnregisterWaitEx to complete. + lock.unlock(); + + if (impl.wait_handle_ != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE); + + if (!impl.op_queue_.empty()) + register_wait_callback(impl, lock); +} + +void win_object_handle_service::move_assign( + win_object_handle_service::implementation_type& impl, + win_object_handle_service& other_service, + win_object_handle_service::implementation_type& other_impl) +{ + asio::error_code ignored_ec; + close(impl, ignored_ec); + + mutex::scoped_lock lock(mutex_); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + impl.wait_handle_ = other_impl.wait_handle_; + other_impl.wait_handle_ = INVALID_HANDLE_VALUE; + impl.op_queue_.push(other_impl.op_queue_); + impl.owner_ = this; + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } + + // We must not hold the lock while calling UnregisterWaitEx. This is because + // the registered callback function might be invoked while we are waiting for + // UnregisterWaitEx to complete. + lock.unlock(); + + if (impl.wait_handle_ != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE); + + if (!impl.op_queue_.empty()) + register_wait_callback(impl, lock); +} + +void win_object_handle_service::destroy( + win_object_handle_service::implementation_type& impl) +{ + mutex::scoped_lock lock(mutex_); + + // Remove implementation from linked list of all implementations. + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle", + &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close")); + + HANDLE wait_handle = impl.wait_handle_; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + + op_queue<operation> ops; + while (wait_op* op = impl.op_queue_.front()) + { + op->ec_ = asio::error::operation_aborted; + impl.op_queue_.pop(); + ops.push(op); + } + + // We must not hold the lock while calling UnregisterWaitEx. This is + // because the registered callback function might be invoked while we are + // waiting for UnregisterWaitEx to complete. + lock.unlock(); + + if (wait_handle != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE); + + ::CloseHandle(impl.handle_); + impl.handle_ = INVALID_HANDLE_VALUE; + + io_context_.post_deferred_completions(ops); + } +} + +asio::error_code win_object_handle_service::assign( + win_object_handle_service::implementation_type& impl, + const native_handle_type& handle, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + impl.handle_ = handle; + ec = asio::error_code(); + return ec; +} + +asio::error_code win_object_handle_service::close( + win_object_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle", + &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close")); + + mutex::scoped_lock lock(mutex_); + + HANDLE wait_handle = impl.wait_handle_; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + + op_queue<operation> completed_ops; + while (wait_op* op = impl.op_queue_.front()) + { + impl.op_queue_.pop(); + op->ec_ = asio::error::operation_aborted; + completed_ops.push(op); + } + + // We must not hold the lock while calling UnregisterWaitEx. This is + // because the registered callback function might be invoked while we are + // waiting for UnregisterWaitEx to complete. + lock.unlock(); + + if (wait_handle != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE); + + if (::CloseHandle(impl.handle_)) + { + impl.handle_ = INVALID_HANDLE_VALUE; + ec = asio::error_code(); + } + else + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + } + + io_context_.post_deferred_completions(completed_ops); + } + else + { + ec = asio::error_code(); + } + + return ec; +} + +asio::error_code win_object_handle_service::cancel( + win_object_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle", + &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel")); + + mutex::scoped_lock lock(mutex_); + + HANDLE wait_handle = impl.wait_handle_; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + + op_queue<operation> completed_ops; + while (wait_op* op = impl.op_queue_.front()) + { + op->ec_ = asio::error::operation_aborted; + impl.op_queue_.pop(); + completed_ops.push(op); + } + + // We must not hold the lock while calling UnregisterWaitEx. This is + // because the registered callback function might be invoked while we are + // waiting for UnregisterWaitEx to complete. + lock.unlock(); + + if (wait_handle != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE); + + ec = asio::error_code(); + + io_context_.post_deferred_completions(completed_ops); + } + else + { + ec = asio::error::bad_descriptor; + } + + return ec; +} + +void win_object_handle_service::wait( + win_object_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + switch (::WaitForSingleObject(impl.handle_, INFINITE)) + { + case WAIT_FAILED: + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, + asio::error::get_system_category()); + break; + } + case WAIT_OBJECT_0: + case WAIT_ABANDONED: + default: + ec = asio::error_code(); + break; + } +} + +void win_object_handle_service::start_wait_op( + win_object_handle_service::implementation_type& impl, wait_op* op) +{ + io_context_.work_started(); + + if (is_open(impl)) + { + mutex::scoped_lock lock(mutex_); + + if (!shutdown_) + { + impl.op_queue_.push(op); + + // Only the first operation to be queued gets to register a wait callback. + // Subsequent operations have to wait for the first to finish. + if (impl.op_queue_.front() == op) + register_wait_callback(impl, lock); + } + else + { + lock.unlock(); + io_context_.post_deferred_completion(op); + } + } + else + { + op->ec_ = asio::error::bad_descriptor; + io_context_.post_deferred_completion(op); + } +} + +void win_object_handle_service::register_wait_callback( + win_object_handle_service::implementation_type& impl, + mutex::scoped_lock& lock) +{ + lock.lock(); + + if (!RegisterWaitForSingleObject(&impl.wait_handle_, + impl.handle_, &win_object_handle_service::wait_callback, + &impl, INFINITE, WT_EXECUTEONLYONCE)) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + + op_queue<operation> completed_ops; + while (wait_op* op = impl.op_queue_.front()) + { + op->ec_ = ec; + impl.op_queue_.pop(); + completed_ops.push(op); + } + + lock.unlock(); + io_context_.post_deferred_completions(completed_ops); + } +} + +void win_object_handle_service::wait_callback(PVOID param, BOOLEAN) +{ + implementation_type* impl = static_cast<implementation_type*>(param); + mutex::scoped_lock lock(impl->owner_->mutex_); + + if (impl->wait_handle_ != INVALID_HANDLE_VALUE) + { + ::UnregisterWaitEx(impl->wait_handle_, NULL); + impl->wait_handle_ = INVALID_HANDLE_VALUE; + } + + if (wait_op* op = impl->op_queue_.front()) + { + op_queue<operation> completed_ops; + + op->ec_ = asio::error_code(); + impl->op_queue_.pop(); + completed_ops.push(op); + + if (!impl->op_queue_.empty()) + { + if (!RegisterWaitForSingleObject(&impl->wait_handle_, + impl->handle_, &win_object_handle_service::wait_callback, + param, INFINITE, WT_EXECUTEONLYONCE)) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + + while ((op = impl->op_queue_.front()) != 0) + { + op->ec_ = ec; + impl->op_queue_.pop(); + completed_ops.push(op); + } + } + } + + io_context_impl& ioc = impl->owner_->io_context_; + lock.unlock(); + ioc.post_deferred_completions(completed_ops); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#endif // ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP diff --git a/lib/asio/detail/impl/win_static_mutex.ipp b/lib/asio/detail/impl/win_static_mutex.ipp new file mode 100644 index 0000000..42089bd --- /dev/null +++ b/lib/asio/detail/impl/win_static_mutex.ipp @@ -0,0 +1,136 @@ +// +// detail/impl/win_static_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP +#define ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include <cstdio> +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_static_mutex.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void win_static_mutex::init() +{ + int error = do_init(); + asio::error_code ec(error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "static_mutex"); +} + +int win_static_mutex::do_init() +{ + using namespace std; // For sprintf. + wchar_t mutex_name[128]; +#if defined(ASIO_HAS_SECURE_RTL) + swprintf_s( +#else // defined(ASIO_HAS_SECURE_RTL) + _snwprintf( +#endif // defined(ASIO_HAS_SECURE_RTL) + mutex_name, 128, L"asio-58CCDC44-6264-4842-90C2-F3C545CB8AA7-%u-%p", + static_cast<unsigned int>(::GetCurrentProcessId()), this); + +#if defined(ASIO_WINDOWS_APP) + HANDLE mutex = ::CreateMutexExW(0, mutex_name, CREATE_MUTEX_INITIAL_OWNER, 0); +#else // defined(ASIO_WINDOWS_APP) + HANDLE mutex = ::CreateMutexW(0, TRUE, mutex_name); +#endif // defined(ASIO_WINDOWS_APP) + DWORD last_error = ::GetLastError(); + if (mutex == 0) + return ::GetLastError(); + + if (last_error == ERROR_ALREADY_EXISTS) + { +#if defined(ASIO_WINDOWS_APP) + ::WaitForSingleObjectEx(mutex, INFINITE, false); +#else // defined(ASIO_WINDOWS_APP) + ::WaitForSingleObject(mutex, INFINITE); +#endif // defined(ASIO_WINDOWS_APP) + } + + if (initialised_) + { + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return 0; + } + +#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 + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + { + last_error = ::GetLastError(); + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return last_error; + } +# endif +#else + __try + { +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# elif defined(ASIO_WINDOWS_APP) + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + { + last_error = ::GetLastError(); + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return last_error; + } +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + { + last_error = ::GetLastError(); + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return last_error; + } +# endif + } + __except(GetExceptionCode() == STATUS_NO_MEMORY + ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return ERROR_OUTOFMEMORY; + } +#endif + + initialised_ = true; + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP diff --git a/lib/asio/detail/impl/win_thread.ipp b/lib/asio/detail/impl/win_thread.ipp new file mode 100644 index 0000000..ed6dbaf --- /dev/null +++ b/lib/asio/detail/impl/win_thread.ipp @@ -0,0 +1,150 @@ +// +// detail/impl/win_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_THREAD_IPP +#define ASIO_DETAIL_IMPL_WIN_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_APP) \ + && !defined(UNDER_CE) + +#include <process.h> +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_thread.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_thread::~win_thread() +{ + ::CloseHandle(thread_); + + // The exit_event_ handle is deliberately allowed to leak here since it + // is an error for the owner of an internal thread not to join() it. +} + +void win_thread::join() +{ + HANDLE handles[2] = { exit_event_, thread_ }; + ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); + ::CloseHandle(exit_event_); + if (terminate_threads()) + { + ::TerminateThread(thread_, 0); + } + else + { + ::QueueUserAPC(apc_function, thread_, 0); + ::WaitForSingleObject(thread_, INFINITE); + } +} + +std::size_t win_thread::hardware_concurrency() +{ + SYSTEM_INFO system_info; + ::GetSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; +} + +void win_thread::start_thread(func_base* arg, unsigned int stack_size) +{ + ::HANDLE entry_event = 0; + arg->entry_event_ = entry_event = ::CreateEventW(0, true, false, 0); + if (!entry_event) + { + DWORD last_error = ::GetLastError(); + delete arg; + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread.entry_event"); + } + + arg->exit_event_ = exit_event_ = ::CreateEventW(0, true, false, 0); + if (!exit_event_) + { + DWORD last_error = ::GetLastError(); + delete arg; + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread.exit_event"); + } + + unsigned int thread_id = 0; + thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, + stack_size, win_thread_function, arg, 0, &thread_id)); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + delete arg; + if (entry_event) + ::CloseHandle(entry_event); + if (exit_event_) + ::CloseHandle(exit_event_); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); + } + + if (entry_event) + { + ::WaitForSingleObject(entry_event, INFINITE); + ::CloseHandle(entry_event); + } +} + +unsigned int __stdcall win_thread_function(void* arg) +{ + win_thread::auto_func_base_ptr func = { + static_cast<win_thread::func_base*>(arg) }; + + ::SetEvent(func.ptr->entry_event_); + + func.ptr->run(); + + // Signal that the thread has finished its work, but rather than returning go + // to sleep to put the thread into a well known state. If the thread is being + // joined during global object destruction then it may be killed using + // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx + // call will be interrupted using QueueUserAPC and the thread will shut down + // cleanly. + HANDLE exit_event = func.ptr->exit_event_; + delete func.ptr; + func.ptr = 0; + ::SetEvent(exit_event); + ::SleepEx(INFINITE, TRUE); + + return 0; +} + +#if defined(WINVER) && (WINVER < 0x0500) +void __stdcall apc_function(ULONG) {} +#else +void __stdcall apc_function(ULONG_PTR) {} +#endif + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_APP) + // && !defined(UNDER_CE) + +#endif // ASIO_DETAIL_IMPL_WIN_THREAD_IPP diff --git a/lib/asio/detail/impl/win_tss_ptr.ipp b/lib/asio/detail/impl/win_tss_ptr.ipp new file mode 100644 index 0000000..61df0ce --- /dev/null +++ b/lib/asio/detail/impl/win_tss_ptr.ipp @@ -0,0 +1,57 @@ +// +// detail/impl/win_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP +#define ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_tss_ptr.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +DWORD win_tss_ptr_create() +{ +#if defined(UNDER_CE) + const DWORD out_of_indexes = 0xFFFFFFFF; +#else + const DWORD out_of_indexes = TLS_OUT_OF_INDEXES; +#endif + + DWORD tss_key = ::TlsAlloc(); + if (tss_key == out_of_indexes) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "tss"); + } + return tss_key; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP diff --git a/lib/asio/detail/impl/winrt_ssocket_service_base.ipp b/lib/asio/detail/impl/winrt_ssocket_service_base.ipp new file mode 100644 index 0000000..288ca8b --- /dev/null +++ b/lib/asio/detail/impl/winrt_ssocket_service_base.ipp @@ -0,0 +1,629 @@ +// +// detail/impl/winrt_ssocket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include <cstring> +#include "asio/detail/winrt_ssocket_service_base.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/detail/winrt_utils.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +winrt_ssocket_service_base::winrt_ssocket_service_base( + asio::io_context& io_context) + : io_context_(use_service<io_context_impl>(io_context)), + async_manager_(use_service<winrt_async_manager>(io_context)), + mutex_(), + impl_list_(0) +{ +} + +void winrt_ssocket_service_base::base_shutdown() +{ + // Close all implementations, causing all operations to complete. + asio::detail::mutex::scoped_lock lock(mutex_); + base_implementation_type* impl = impl_list_; + while (impl) + { + asio::error_code ignored_ec; + close(*impl, ignored_ec); + impl = impl->next_; + } +} + +void winrt_ssocket_service_base::construct( + winrt_ssocket_service_base::base_implementation_type& impl) +{ + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void winrt_ssocket_service_base::base_move_construct( + winrt_ssocket_service_base::base_implementation_type& impl, + winrt_ssocket_service_base::base_implementation_type& other_impl) +{ + impl.socket_ = other_impl.socket_; + other_impl.socket_ = nullptr; + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void winrt_ssocket_service_base::base_move_assign( + winrt_ssocket_service_base::base_implementation_type& impl, + winrt_ssocket_service_base& other_service, + winrt_ssocket_service_base::base_implementation_type& other_impl) +{ + asio::error_code ignored_ec; + close(impl, ignored_ec); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.socket_ = other_impl.socket_; + other_impl.socket_ = nullptr; + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(other_service.mutex_); + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } +} + +void winrt_ssocket_service_base::destroy( + winrt_ssocket_service_base::base_implementation_type& impl) +{ + asio::error_code ignored_ec; + close(impl, ignored_ec); + + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +asio::error_code winrt_ssocket_service_base::close( + winrt_ssocket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (impl.socket_) + { + delete impl.socket_; + impl.socket_ = nullptr; + } + + ec = asio::error_code(); + return ec; +} + +winrt_ssocket_service_base::native_handle_type +winrt_ssocket_service_base::release( + winrt_ssocket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + return nullptr; + + cancel(impl, ec); + if (ec) + return nullptr; + + native_handle_type tmp = impl.socket_; + impl.socket_ = nullptr; + return tmp; +} + +std::size_t winrt_ssocket_service_base::do_get_endpoint( + const base_implementation_type& impl, bool local, + void* addr, std::size_t addr_len, asio::error_code& ec) const +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return addr_len; + } + + try + { + std::string addr_string = winrt_utils::string(local + ? impl.socket_->Information->LocalAddress->CanonicalName + : impl.socket_->Information->RemoteAddress->CanonicalName); + unsigned short port = winrt_utils::integer(local + ? impl.socket_->Information->LocalPort + : impl.socket_->Information->RemotePort); + unsigned long scope = 0; + + switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family) + { + case ASIO_OS_DEF(AF_INET): + if (addr_len < sizeof(sockaddr_in4_type)) + { + ec = asio::error::invalid_argument; + return addr_len; + } + else + { + socket_ops::inet_pton(ASIO_OS_DEF(AF_INET), addr_string.c_str(), + &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec); + reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port + = socket_ops::host_to_network_short(port); + ec = asio::error_code(); + return sizeof(sockaddr_in4_type); + } + case ASIO_OS_DEF(AF_INET6): + if (addr_len < sizeof(sockaddr_in6_type)) + { + ec = asio::error::invalid_argument; + return addr_len; + } + else + { + socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6), addr_string.c_str(), + &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec); + reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port + = socket_ops::host_to_network_short(port); + ec = asio::error_code(); + return sizeof(sockaddr_in6_type); + } + default: + ec = asio::error::address_family_not_supported; + return addr_len; + } + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + return addr_len; + } +} + +asio::error_code winrt_ssocket_service_base::do_set_option( + winrt_ssocket_service_base::base_implementation_type& impl, + int level, int optname, const void* optval, + std::size_t optlen, asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + try + { + if (level == ASIO_OS_DEF(SOL_SOCKET) + && optname == ASIO_OS_DEF(SO_KEEPALIVE)) + { + if (optlen == sizeof(int)) + { + int value = 0; + std::memcpy(&value, optval, optlen); + impl.socket_->Control->KeepAlive = !!value; + ec = asio::error_code(); + } + else + { + ec = asio::error::invalid_argument; + } + } + else if (level == ASIO_OS_DEF(IPPROTO_TCP) + && optname == ASIO_OS_DEF(TCP_NODELAY)) + { + if (optlen == sizeof(int)) + { + int value = 0; + std::memcpy(&value, optval, optlen); + impl.socket_->Control->NoDelay = !!value; + ec = asio::error_code(); + } + else + { + ec = asio::error::invalid_argument; + } + } + else + { + ec = asio::error::invalid_argument; + } + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + } + + return ec; +} + +void winrt_ssocket_service_base::do_get_option( + const winrt_ssocket_service_base::base_implementation_type& impl, + int level, int optname, void* optval, + std::size_t* optlen, asio::error_code& ec) const +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return; + } + + try + { + if (level == ASIO_OS_DEF(SOL_SOCKET) + && optname == ASIO_OS_DEF(SO_KEEPALIVE)) + { + if (*optlen >= sizeof(int)) + { + int value = impl.socket_->Control->KeepAlive ? 1 : 0; + std::memcpy(optval, &value, sizeof(int)); + *optlen = sizeof(int); + ec = asio::error_code(); + } + else + { + ec = asio::error::invalid_argument; + } + } + else if (level == ASIO_OS_DEF(IPPROTO_TCP) + && optname == ASIO_OS_DEF(TCP_NODELAY)) + { + if (*optlen >= sizeof(int)) + { + int value = impl.socket_->Control->NoDelay ? 1 : 0; + std::memcpy(optval, &value, sizeof(int)); + *optlen = sizeof(int); + ec = asio::error_code(); + } + else + { + ec = asio::error::invalid_argument; + } + } + else + { + ec = asio::error::invalid_argument; + } + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + } +} + +asio::error_code winrt_ssocket_service_base::do_connect( + winrt_ssocket_service_base::base_implementation_type& impl, + const void* addr, asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + char addr_string[max_addr_v6_str_len]; + unsigned short port; + switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family) + { + case ASIO_OS_DEF(AF_INET): + socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET), + &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr, + addr_string, sizeof(addr_string), 0, ec); + port = socket_ops::network_to_host_short( + reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port); + break; + case ASIO_OS_DEF(AF_INET6): + socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6), + &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr, + addr_string, sizeof(addr_string), 0, ec); + port = socket_ops::network_to_host_short( + reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port); + break; + default: + ec = asio::error::address_family_not_supported; + return ec; + } + + if (!ec) try + { + async_manager_.sync(impl.socket_->ConnectAsync( + ref new Windows::Networking::HostName( + winrt_utils::string(addr_string)), + winrt_utils::string(port)), ec); + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + } + + return ec; +} + +void winrt_ssocket_service_base::start_connect_op( + winrt_ssocket_service_base::base_implementation_type& impl, + const void* addr, winrt_async_op<void>* op, bool is_continuation) +{ + if (!is_open(impl)) + { + op->ec_ = asio::error::bad_descriptor; + io_context_.post_immediate_completion(op, is_continuation); + return; + } + + char addr_string[max_addr_v6_str_len]; + unsigned short port = 0; + switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family) + { + case ASIO_OS_DEF(AF_INET): + socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET), + &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr, + addr_string, sizeof(addr_string), 0, op->ec_); + port = socket_ops::network_to_host_short( + reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port); + break; + case ASIO_OS_DEF(AF_INET6): + socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6), + &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr, + addr_string, sizeof(addr_string), 0, op->ec_); + port = socket_ops::network_to_host_short( + reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port); + break; + default: + op->ec_ = asio::error::address_family_not_supported; + break; + } + + if (op->ec_) + { + io_context_.post_immediate_completion(op, is_continuation); + return; + } + + try + { + async_manager_.async(impl.socket_->ConnectAsync( + ref new Windows::Networking::HostName( + winrt_utils::string(addr_string)), + winrt_utils::string(port)), op); + } + catch (Platform::Exception^ e) + { + op->ec_ = asio::error_code( + e->HResult, asio::system_category()); + io_context_.post_immediate_completion(op, is_continuation); + } +} + +std::size_t winrt_ssocket_service_base::do_send( + winrt_ssocket_service_base::base_implementation_type& impl, + const asio::const_buffer& data, + socket_base::message_flags flags, asio::error_code& ec) +{ + if (flags) + { + ec = asio::error::operation_not_supported; + return 0; + } + + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + try + { + buffer_sequence_adapter<asio::const_buffer, + asio::const_buffer> bufs(asio::buffer(data)); + + if (bufs.all_empty()) + { + ec = asio::error_code(); + return 0; + } + + return async_manager_.sync( + impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec); + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + return 0; + } +} + +void winrt_ssocket_service_base::start_send_op( + winrt_ssocket_service_base::base_implementation_type& impl, + const asio::const_buffer& data, socket_base::message_flags flags, + winrt_async_op<unsigned int>* op, bool is_continuation) +{ + if (flags) + { + op->ec_ = asio::error::operation_not_supported; + io_context_.post_immediate_completion(op, is_continuation); + return; + } + + if (!is_open(impl)) + { + op->ec_ = asio::error::bad_descriptor; + io_context_.post_immediate_completion(op, is_continuation); + return; + } + + try + { + buffer_sequence_adapter<asio::const_buffer, + asio::const_buffer> bufs(asio::buffer(data)); + + if (bufs.all_empty()) + { + io_context_.post_immediate_completion(op, is_continuation); + return; + } + + async_manager_.async( + impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op); + } + catch (Platform::Exception^ e) + { + op->ec_ = asio::error_code(e->HResult, + asio::system_category()); + io_context_.post_immediate_completion(op, is_continuation); + } +} + +std::size_t winrt_ssocket_service_base::do_receive( + winrt_ssocket_service_base::base_implementation_type& impl, + const asio::mutable_buffer& data, + socket_base::message_flags flags, asio::error_code& ec) +{ + if (flags) + { + ec = asio::error::operation_not_supported; + return 0; + } + + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + try + { + buffer_sequence_adapter<asio::mutable_buffer, + asio::mutable_buffer> bufs(asio::buffer(data)); + + if (bufs.all_empty()) + { + ec = asio::error_code(); + return 0; + } + + async_manager_.sync( + impl.socket_->InputStream->ReadAsync( + bufs.buffers()[0], bufs.buffers()[0]->Capacity, + Windows::Storage::Streams::InputStreamOptions::Partial), ec); + + std::size_t bytes_transferred = bufs.buffers()[0]->Length; + if (bytes_transferred == 0 && !ec) + { + ec = asio::error::eof; + } + + return bytes_transferred; + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + return 0; + } +} + +void winrt_ssocket_service_base::start_receive_op( + winrt_ssocket_service_base::base_implementation_type& impl, + const asio::mutable_buffer& data, socket_base::message_flags flags, + winrt_async_op<Windows::Storage::Streams::IBuffer^>* op, + bool is_continuation) +{ + if (flags) + { + op->ec_ = asio::error::operation_not_supported; + io_context_.post_immediate_completion(op, is_continuation); + return; + } + + if (!is_open(impl)) + { + op->ec_ = asio::error::bad_descriptor; + io_context_.post_immediate_completion(op, is_continuation); + return; + } + + try + { + buffer_sequence_adapter<asio::mutable_buffer, + asio::mutable_buffer> bufs(asio::buffer(data)); + + if (bufs.all_empty()) + { + io_context_.post_immediate_completion(op, is_continuation); + return; + } + + async_manager_.async( + impl.socket_->InputStream->ReadAsync( + bufs.buffers()[0], bufs.buffers()[0]->Capacity, + Windows::Storage::Streams::InputStreamOptions::Partial), op); + } + catch (Platform::Exception^ e) + { + op->ec_ = asio::error_code(e->HResult, + asio::system_category()); + io_context_.post_immediate_completion(op, is_continuation); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP diff --git a/lib/asio/detail/impl/winrt_timer_scheduler.hpp b/lib/asio/detail/impl/winrt_timer_scheduler.hpp new file mode 100644 index 0000000..856378f --- /dev/null +++ b/lib/asio/detail/impl/winrt_timer_scheduler.hpp @@ -0,0 +1,92 @@ +// +// detail/impl/winrt_timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP +#define ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +void winrt_timer_scheduler::add_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template <typename Time_Traits> +void winrt_timer_scheduler::remove_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void winrt_timer_scheduler::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + io_context_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + io_context_.work_started(); + if (earliest) + event_.signal(lock); +} + +template <typename Time_Traits> +std::size_t winrt_timer_scheduler::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + io_context_.post_deferred_completions(ops); + return n; +} + +template <typename Time_Traits> +void winrt_timer_scheduler::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP diff --git a/lib/asio/detail/impl/winrt_timer_scheduler.ipp b/lib/asio/detail/impl/winrt_timer_scheduler.ipp new file mode 100644 index 0000000..ef21399 --- /dev/null +++ b/lib/asio/detail/impl/winrt_timer_scheduler.ipp @@ -0,0 +1,122 @@ +// +// detail/impl/winrt_timer_scheduler.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP +#define ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/winrt_timer_scheduler.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +winrt_timer_scheduler::winrt_timer_scheduler( + asio::io_context& io_context) + : asio::detail::service_base<winrt_timer_scheduler>(io_context), + io_context_(use_service<io_context_impl>(io_context)), + mutex_(), + event_(), + timer_queues_(), + thread_(0), + stop_thread_(false), + shutdown_(false) +{ + thread_ = new asio::detail::thread( + bind_handler(&winrt_timer_scheduler::call_run_thread, this)); +} + +winrt_timer_scheduler::~winrt_timer_scheduler() +{ + shutdown(); +} + +void winrt_timer_scheduler::shutdown() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_thread_ = true; + event_.signal(lock); + lock.unlock(); + + if (thread_) + { + thread_->join(); + delete thread_; + thread_ = 0; + } + + op_queue<operation> ops; + timer_queues_.get_all_timers(ops); + io_context_.abandon_operations(ops); +} + +void winrt_timer_scheduler::notify_fork(asio::io_context::fork_event) +{ +} + +void winrt_timer_scheduler::init_task() +{ +} + +void winrt_timer_scheduler::run_thread() +{ + asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + const long max_wait_duration = 5 * 60 * 1000000; + long wait_duration = timer_queues_.wait_duration_usec(max_wait_duration); + event_.wait_for_usec(lock, wait_duration); + event_.clear(lock); + op_queue<operation> ops; + timer_queues_.get_ready_timers(ops); + if (!ops.empty()) + { + lock.unlock(); + io_context_.post_deferred_completions(ops); + lock.lock(); + } + } +} + +void winrt_timer_scheduler::call_run_thread(winrt_timer_scheduler* scheduler) +{ + scheduler->run_thread(); +} + +void winrt_timer_scheduler::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void winrt_timer_scheduler::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP diff --git a/lib/asio/detail/impl/winsock_init.ipp b/lib/asio/detail/impl/winsock_init.ipp new file mode 100644 index 0000000..da4b0c0 --- /dev/null +++ b/lib/asio/detail/impl/winsock_init.ipp @@ -0,0 +1,82 @@ +// +// detail/impl/winsock_init.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP +#define ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/socket_types.hpp" +#include "asio/detail/winsock_init.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void winsock_init_base::startup(data& d, + unsigned char major, unsigned char minor) +{ + if (::InterlockedIncrement(&d.init_count_) == 1) + { + WSADATA wsa_data; + long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); + ::InterlockedExchange(&d.result_, result); + } +} + +void winsock_init_base::manual_startup(data& d) +{ + if (::InterlockedIncrement(&d.init_count_) == 1) + { + ::InterlockedExchange(&d.result_, 0); + } +} + +void winsock_init_base::cleanup(data& d) +{ + if (::InterlockedDecrement(&d.init_count_) == 0) + { + ::WSACleanup(); + } +} + +void winsock_init_base::manual_cleanup(data& d) +{ + ::InterlockedDecrement(&d.init_count_); +} + +void winsock_init_base::throw_on_error(data& d) +{ + long result = ::InterlockedExchangeAdd(&d.result_, 0); + if (result != 0) + { + asio::error_code ec(result, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "winsock"); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP diff --git a/lib/asio/detail/io_control.hpp b/lib/asio/detail/io_control.hpp new file mode 100644 index 0000000..12f35e0 --- /dev/null +++ b/lib/asio/detail/io_control.hpp @@ -0,0 +1,84 @@ +// +// detail/io_control.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IO_CONTROL_HPP +#define ASIO_DETAIL_IO_CONTROL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cstddef> +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace io_control { + +// I/O control command for getting number of bytes available. +class bytes_readable +{ +public: + // Default constructor. + bytes_readable() + : value_(0) + { + } + + // Construct with a specific command value. + bytes_readable(std::size_t value) + : value_(static_cast<detail::ioctl_arg_type>(value)) + { + } + + // Get the name of the IO control command. + int name() const + { + return static_cast<int>(ASIO_OS_DEF(FIONREAD)); + } + + // Set the value of the I/O control command. + void set(std::size_t value) + { + value_ = static_cast<detail::ioctl_arg_type>(value); + } + + // Get the current value of the I/O control command. + std::size_t get() const + { + return static_cast<std::size_t>(value_); + } + + // Get the address of the command data. + detail::ioctl_arg_type* data() + { + return &value_; + } + + // Get the address of the command data. + const detail::ioctl_arg_type* data() const + { + return &value_; + } + +private: + detail::ioctl_arg_type value_; +}; + +} // namespace io_control +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IO_CONTROL_HPP diff --git a/lib/asio/detail/is_buffer_sequence.hpp b/lib/asio/detail/is_buffer_sequence.hpp new file mode 100644 index 0000000..42ad0eb --- /dev/null +++ b/lib/asio/detail/is_buffer_sequence.hpp @@ -0,0 +1,239 @@ +// +// detail/is_buffer_sequence.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP +#define ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +class mutable_buffer; +class const_buffer; + +namespace detail { + +struct buffer_sequence_memfns_base +{ + void begin(); + void end(); + void size(); + void max_size(); + void capacity(); + void data(); + void prepare(); + void commit(); + void consume(); +}; + +template <typename T> +struct buffer_sequence_memfns_derived + : T, buffer_sequence_memfns_base +{ +}; + +template <typename T, T> +struct buffer_sequence_memfns_check +{ +}; + +template <typename> +char (&begin_memfn_helper(...))[2]; + +template <typename T> +char begin_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::begin>*); + +template <typename> +char (&end_memfn_helper(...))[2]; + +template <typename T> +char end_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::end>*); + +template <typename> +char (&size_memfn_helper(...))[2]; + +template <typename T> +char size_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::size>*); + +template <typename> +char (&max_size_memfn_helper(...))[2]; + +template <typename T> +char max_size_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::max_size>*); + +template <typename> +char (&capacity_memfn_helper(...))[2]; + +template <typename T> +char capacity_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::capacity>*); + +template <typename> +char (&data_memfn_helper(...))[2]; + +template <typename T> +char data_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::data>*); + +template <typename> +char (&prepare_memfn_helper(...))[2]; + +template <typename T> +char prepare_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::prepare>*); + +template <typename> +char (&commit_memfn_helper(...))[2]; + +template <typename T> +char commit_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::commit>*); + +template <typename> +char (&consume_memfn_helper(...))[2]; + +template <typename T> +char consume_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::consume>*); + +template <typename, typename> +char (&buffer_element_type_helper(...))[2]; + +#if defined(ASIO_HAS_DECL_TYPE) + +template <typename T, typename Buffer> +char buffer_element_type_helper(T* t, + typename enable_if<is_convertible< + decltype(*buffer_sequence_begin(*t)), + Buffer>::value>::type*); + +#else // defined(ASIO_HAS_DECL_TYPE) + +template <typename T, typename Buffer> +char buffer_element_type_helper( + typename T::const_iterator*, + typename enable_if<is_convertible< + typename T::value_type, Buffer>::value>::type*); + +#endif // defined(ASIO_HAS_DECL_TYPE) + +template <typename> +char (&const_buffers_type_typedef_helper(...))[2]; + +template <typename T> +char const_buffers_type_typedef_helper( + typename T::const_buffers_type*); + +template <typename> +char (&mutable_buffers_type_typedef_helper(...))[2]; + +template <typename T> +char mutable_buffers_type_typedef_helper( + typename T::mutable_buffers_type*); + +template <typename T, typename Buffer> +struct is_buffer_sequence_class + : integral_constant<bool, + sizeof(begin_memfn_helper<T>(0)) != 1 && + sizeof(end_memfn_helper<T>(0)) != 1 && + sizeof(buffer_element_type_helper<T, Buffer>(0, 0)) == 1> +{ +}; + +template <typename T, typename Buffer> +struct is_buffer_sequence + : conditional<is_class<T>::value, + is_buffer_sequence_class<T, Buffer>, + false_type>::type +{ +}; + +template <> +struct is_buffer_sequence<mutable_buffer, mutable_buffer> + : true_type +{ +}; + +template <> +struct is_buffer_sequence<mutable_buffer, const_buffer> + : true_type +{ +}; + +template <> +struct is_buffer_sequence<const_buffer, const_buffer> + : true_type +{ +}; + +template <> +struct is_buffer_sequence<const_buffer, mutable_buffer> + : false_type +{ +}; + +template <typename T> +struct is_dynamic_buffer_class + : integral_constant<bool, + sizeof(size_memfn_helper<T>(0)) != 1 && + sizeof(max_size_memfn_helper<T>(0)) != 1 && + sizeof(capacity_memfn_helper<T>(0)) != 1 && + sizeof(data_memfn_helper<T>(0)) != 1 && + sizeof(consume_memfn_helper<T>(0)) != 1 && + sizeof(prepare_memfn_helper<T>(0)) != 1 && + sizeof(commit_memfn_helper<T>(0)) != 1 && + sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 && + sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1> +{ +}; + +template <typename T> +struct is_dynamic_buffer + : conditional<is_class<T>::value, + is_dynamic_buffer_class<T>, + false_type>::type +{ +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP diff --git a/lib/asio/detail/is_executor.hpp b/lib/asio/detail/is_executor.hpp new file mode 100644 index 0000000..4584dd0 --- /dev/null +++ b/lib/asio/detail/is_executor.hpp @@ -0,0 +1,126 @@ +// +// detail/is_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_IS_EXECUTOR_HPP +#define ASIO_DETAIL_IS_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct executor_memfns_base +{ + void context(); + void on_work_started(); + void on_work_finished(); + void dispatch(); + void post(); + void defer(); +}; + +template <typename T> +struct executor_memfns_derived + : T, executor_memfns_base +{ +}; + +template <typename T, T> +struct executor_memfns_check +{ +}; + +template <typename> +char (&context_memfn_helper(...))[2]; + +template <typename T> +char context_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::context>*); + +template <typename> +char (&on_work_started_memfn_helper(...))[2]; + +template <typename T> +char on_work_started_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::on_work_started>*); + +template <typename> +char (&on_work_finished_memfn_helper(...))[2]; + +template <typename T> +char on_work_finished_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::on_work_finished>*); + +template <typename> +char (&dispatch_memfn_helper(...))[2]; + +template <typename T> +char dispatch_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::dispatch>*); + +template <typename> +char (&post_memfn_helper(...))[2]; + +template <typename T> +char post_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::post>*); + +template <typename> +char (&defer_memfn_helper(...))[2]; + +template <typename T> +char defer_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::defer>*); + +template <typename T> +struct is_executor_class + : integral_constant<bool, + sizeof(context_memfn_helper<T>(0)) != 1 && + sizeof(on_work_started_memfn_helper<T>(0)) != 1 && + sizeof(on_work_finished_memfn_helper<T>(0)) != 1 && + sizeof(dispatch_memfn_helper<T>(0)) != 1 && + sizeof(post_memfn_helper<T>(0)) != 1 && + sizeof(defer_memfn_helper<T>(0)) != 1> +{ +}; + +template <typename T> +struct is_executor + : conditional<is_class<T>::value, + is_executor_class<T>, + false_type>::type +{ +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IS_EXECUTOR_HPP diff --git a/lib/asio/detail/keyword_tss_ptr.hpp b/lib/asio/detail/keyword_tss_ptr.hpp new file mode 100644 index 0000000..2ae651a --- /dev/null +++ b/lib/asio/detail/keyword_tss_ptr.hpp @@ -0,0 +1,70 @@ +// +// detail/keyword_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_KEYWORD_TSS_PTR_HPP +#define ASIO_DETAIL_KEYWORD_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +class keyword_tss_ptr + : private noncopyable +{ +public: + // Constructor. + keyword_tss_ptr() + { + } + + // Destructor. + ~keyword_tss_ptr() + { + } + + // Get the value. + operator T*() const + { + return value_; + } + + // Set the value. + void operator=(T* value) + { + value_ = value; + } + +private: + static ASIO_THREAD_KEYWORD T* value_; +}; + +template <typename T> +ASIO_THREAD_KEYWORD T* keyword_tss_ptr<T>::value_; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) + +#endif // ASIO_DETAIL_KEYWORD_TSS_PTR_HPP diff --git a/lib/asio/detail/kqueue_reactor.hpp b/lib/asio/detail/kqueue_reactor.hpp new file mode 100644 index 0000000..43cb9f9 --- /dev/null +++ b/lib/asio/detail/kqueue_reactor.hpp @@ -0,0 +1,242 @@ +// +// detail/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_KQUEUE_REACTOR_HPP +#define ASIO_DETAIL_KQUEUE_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_KQUEUE) + +#include <cstddef> +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> +#include "asio/detail/limits.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/object_pool.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/select_interrupter.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" + +// Older versions of Mac OS X may not define EV_OOBAND. +#if !defined(EV_OOBAND) +# define EV_OOBAND EV_FLAG1 +#endif // !defined(EV_OOBAND) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class scheduler; + +class kqueue_reactor + : public execution_context_service_base<kqueue_reactor> +{ +private: + // The mutex type used by this reactor. + typedef conditionally_enabled_mutex mutex; + +public: + enum op_types { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor queues. + struct descriptor_state + { + descriptor_state(bool locking) : mutex_(locking) {} + + friend class kqueue_reactor; + friend class object_pool_access; + + descriptor_state* next_; + descriptor_state* prev_; + + mutex mutex_; + int descriptor_; + int num_kevents_; // 1 == read only, 2 == read and write + op_queue<reactor_op> op_queue_[max_ops]; + bool shutdown_; + }; + + // Per-descriptor data. + typedef descriptor_state* per_descriptor_data; + + // Constructor. + ASIO_DECL kqueue_reactor(asio::execution_context& ctx); + + // Destructor. + ASIO_DECL ~kqueue_reactor(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + ASIO_DECL void notify_fork( + asio::execution_context::fork_event fork_ev); + + // Initialise the task. + ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Move descriptor registration from one descriptor_data object to another. + ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data& descriptor_data); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data( + per_descriptor_data& descriptor_data); + + // Add a new timer queue to the reactor. + template <typename Time_Traits> + void add_timer_queue(timer_queue<Time_Traits>& queue); + + // Remove a timer queue from the reactor. + template <typename Time_Traits> + void remove_timer_queue(timer_queue<Time_Traits>& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template <typename Time_Traits> + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template <typename Time_Traits> + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source); + + // Run the kqueue loop. + ASIO_DECL void run(long usec, op_queue<operation>& ops); + + // Interrupt the kqueue loop. + ASIO_DECL void interrupt(); + +private: + // Create the kqueue file descriptor. Throws an exception if the descriptor + // cannot be created. + ASIO_DECL static int do_kqueue_create(); + + // Allocate a new descriptor state object. + ASIO_DECL descriptor_state* allocate_descriptor_state(); + + // Free an existing descriptor state object. + ASIO_DECL void free_descriptor_state(descriptor_state* s); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Get the timeout value for the kevent call. + ASIO_DECL timespec* get_timeout(long usec, timespec& ts); + + // The scheduler used to post completions. + scheduler& scheduler_; + + // Mutex to protect access to internal data. + mutex mutex_; + + // The kqueue file descriptor. + int kqueue_fd_; + + // The interrupter is used to break a blocking kevent call. + select_interrupter interrupter_; + + // The timer queues. + timer_queue_set timer_queues_; + + // Whether the service has been shut down. + bool shutdown_; + + // Mutex to protect access to the registered descriptors. + mutex registered_descriptors_mutex_; + + // Keep track of all registered descriptors. + object_pool<descriptor_state> registered_descriptors_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/kqueue_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/kqueue_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_KQUEUE) + +#endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP diff --git a/lib/asio/detail/limits.hpp b/lib/asio/detail/limits.hpp new file mode 100644 index 0000000..d32470d --- /dev/null +++ b/lib/asio/detail/limits.hpp @@ -0,0 +1,26 @@ +// +// detail/limits.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_LIMITS_HPP +#define ASIO_DETAIL_LIMITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_LIMITS) +# include <boost/limits.hpp> +#else // defined(ASIO_HAS_BOOST_LIMITS) +# include <limits> +#endif // defined(ASIO_HAS_BOOST_LIMITS) + +#endif // ASIO_DETAIL_LIMITS_HPP diff --git a/lib/asio/detail/local_free_on_block_exit.hpp b/lib/asio/detail/local_free_on_block_exit.hpp new file mode 100644 index 0000000..eba6b77 --- /dev/null +++ b/lib/asio/detail/local_free_on_block_exit.hpp @@ -0,0 +1,59 @@ +// +// detail/local_free_on_block_exit.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP +#define ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +#if !defined(ASIO_WINDOWS_APP) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class local_free_on_block_exit + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + explicit local_free_on_block_exit(void* p) + : p_(p) + { + } + + // Destructor restores the previous signal mask. + ~local_free_on_block_exit() + { + ::LocalFree(p_); + } + +private: + void* p_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS_APP) +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP diff --git a/lib/asio/detail/macos_fenced_block.hpp b/lib/asio/detail/macos_fenced_block.hpp new file mode 100644 index 0000000..bbac270 --- /dev/null +++ b/lib/asio/detail/macos_fenced_block.hpp @@ -0,0 +1,62 @@ +// +// detail/macos_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP +#define ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__MACH__) && defined(__APPLE__) + +#include <libkern/OSAtomic.h> +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class macos_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit macos_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit macos_fenced_block(full_t) + { + OSMemoryBarrier(); + } + + // Destructor. + ~macos_fenced_block() + { + OSMemoryBarrier(); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__MACH__) && defined(__APPLE__) + +#endif // ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP diff --git a/lib/asio/detail/memory.hpp b/lib/asio/detail/memory.hpp new file mode 100644 index 0000000..b1ec497 --- /dev/null +++ b/lib/asio/detail/memory.hpp @@ -0,0 +1,70 @@ +// +// detail/memory.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_MEMORY_HPP +#define ASIO_DETAIL_MEMORY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <memory> + +#if !defined(ASIO_HAS_STD_SHARED_PTR) +# include <boost/shared_ptr.hpp> +# include <boost/weak_ptr.hpp> +#endif // !defined(ASIO_HAS_STD_SHARED_PTR) + +#if !defined(ASIO_HAS_STD_ADDRESSOF) +# include <boost/utility/addressof.hpp> +#endif // !defined(ASIO_HAS_STD_ADDRESSOF) + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_SHARED_PTR) +using std::shared_ptr; +using std::weak_ptr; +#else // defined(ASIO_HAS_STD_SHARED_PTR) +using boost::shared_ptr; +using boost::weak_ptr; +#endif // defined(ASIO_HAS_STD_SHARED_PTR) + +#if defined(ASIO_HAS_STD_ADDRESSOF) +using std::addressof; +#else // defined(ASIO_HAS_STD_ADDRESSOF) +using boost::addressof; +#endif // defined(ASIO_HAS_STD_ADDRESSOF) + +} // namespace detail + +#if defined(ASIO_HAS_CXX11_ALLOCATORS) +using std::allocator_arg_t; +# define ASIO_USES_ALLOCATOR(t) \ + namespace std { \ + template <typename Allocator> \ + struct uses_allocator<t, Allocator> : true_type {}; \ + } \ + /**/ +# define ASIO_REBIND_ALLOC(alloc, t) \ + typename std::allocator_traits<alloc>::template rebind_alloc<t> + /**/ +#else // defined(ASIO_HAS_CXX11_ALLOCATORS) +struct allocator_arg_t {}; +# define ASIO_USES_ALLOCATOR(t) +# define ASIO_REBIND_ALLOC(alloc, t) \ + typename alloc::template rebind<t>::other + /**/ +#endif // defined(ASIO_HAS_CXX11_ALLOCATORS) + +} // namespace asio + +#endif // ASIO_DETAIL_MEMORY_HPP diff --git a/lib/asio/detail/mutex.hpp b/lib/asio/detail/mutex.hpp new file mode 100644 index 0000000..2f8f0b1 --- /dev/null +++ b/lib/asio/detail/mutex.hpp @@ -0,0 +1,48 @@ +// +// detail/mutex.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_MUTEX_HPP +#define ASIO_DETAIL_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_mutex.hpp" +#elif defined(ASIO_WINDOWS) +# include "asio/detail/win_mutex.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_mutex.hpp" +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# include "asio/detail/std_mutex.hpp" +#else +# error Only Windows, POSIX and std::mutex are supported! +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) +typedef null_mutex mutex; +#elif defined(ASIO_WINDOWS) +typedef win_mutex mutex; +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_mutex mutex; +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +typedef std_mutex mutex; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_MUTEX_HPP diff --git a/lib/asio/detail/noncopyable.hpp b/lib/asio/detail/noncopyable.hpp new file mode 100644 index 0000000..0c038e1 --- /dev/null +++ b/lib/asio/detail/noncopyable.hpp @@ -0,0 +1,43 @@ +// +// detail/noncopyable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NONCOPYABLE_HPP +#define ASIO_DETAIL_NONCOPYABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class noncopyable +{ +protected: + noncopyable() {} + ~noncopyable() {} +private: + noncopyable(const noncopyable&); + const noncopyable& operator=(const noncopyable&); +}; + +} // namespace detail + +using asio::detail::noncopyable; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_NONCOPYABLE_HPP diff --git a/lib/asio/detail/null_event.hpp b/lib/asio/detail/null_event.hpp new file mode 100644 index 0000000..5686a41 --- /dev/null +++ b/lib/asio/detail/null_event.hpp @@ -0,0 +1,100 @@ +// +// detail/null_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NULL_EVENT_HPP +#define ASIO_DETAIL_NULL_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_event + : private noncopyable +{ +public: + // Constructor. + null_event() + { + } + + // Destructor. + ~null_event() + { + } + + // Signal the event. (Retained for backward compatibility.) + template <typename Lock> + void signal(Lock&) + { + } + + // Signal all waiters. + template <typename Lock> + void signal_all(Lock&) + { + } + + // Unlock the mutex and signal one waiter. + template <typename Lock> + void unlock_and_signal_one(Lock&) + { + } + + // If there's a waiter, unlock the mutex and signal it. + template <typename Lock> + bool maybe_unlock_and_signal_one(Lock&) + { + return false; + } + + // Reset the event. + template <typename Lock> + void clear(Lock&) + { + } + + // Wait for the event to become signalled. + template <typename Lock> + void wait(Lock&) + { + do_wait(); + } + + // Timed wait for the event to become signalled. + template <typename Lock> + bool wait_for_usec(Lock&, long usec) + { + do_wait_for_usec(usec); + return true; + } + +private: + ASIO_DECL static void do_wait(); + ASIO_DECL static void do_wait_for_usec(long usec); +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/null_event.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_NULL_EVENT_HPP diff --git a/lib/asio/detail/null_fenced_block.hpp b/lib/asio/detail/null_fenced_block.hpp new file mode 100644 index 0000000..0275326 --- /dev/null +++ b/lib/asio/detail/null_fenced_block.hpp @@ -0,0 +1,47 @@ +// +// detail/null_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NULL_FENCED_BLOCK_HPP +#define ASIO_DETAIL_NULL_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_fenced_block + : private noncopyable +{ +public: + enum half_or_full_t { half, full }; + + // Constructor. + explicit null_fenced_block(half_or_full_t) + { + } + + // Destructor. + ~null_fenced_block() + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_NULL_FENCED_BLOCK_HPP diff --git a/lib/asio/detail/null_global.hpp b/lib/asio/detail/null_global.hpp new file mode 100644 index 0000000..727dd3f --- /dev/null +++ b/lib/asio/detail/null_global.hpp @@ -0,0 +1,59 @@ +// +// detail/null_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NULL_GLOBAL_HPP +#define ASIO_DETAIL_NULL_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +struct null_global_impl +{ + null_global_impl() + : ptr_(0) + { + } + + // Destructor automatically cleans up the global. + ~null_global_impl() + { + delete ptr_; + } + + static null_global_impl instance_; + T* ptr_; +}; + +template <typename T> +null_global_impl<T> null_global_impl<T>::instance_; + +template <typename T> +T& null_global() +{ + if (null_global_impl<T>::instance_.ptr_ == 0) + null_global_impl<T>::instance_.ptr_ = new T; + return *null_global_impl<T>::instance_.ptr_; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_NULL_GLOBAL_HPP diff --git a/lib/asio/detail/null_mutex.hpp b/lib/asio/detail/null_mutex.hpp new file mode 100644 index 0000000..afe3fc0 --- /dev/null +++ b/lib/asio/detail/null_mutex.hpp @@ -0,0 +1,64 @@ +// +// detail/null_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NULL_MUTEX_HPP +#define ASIO_DETAIL_NULL_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_mutex + : private noncopyable +{ +public: + typedef asio::detail::scoped_lock<null_mutex> scoped_lock; + + // Constructor. + null_mutex() + { + } + + // Destructor. + ~null_mutex() + { + } + + // Lock the mutex. + void lock() + { + } + + // Unlock the mutex. + void unlock() + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_THREADS) + +#endif // ASIO_DETAIL_NULL_MUTEX_HPP diff --git a/lib/asio/detail/null_reactor.hpp b/lib/asio/detail/null_reactor.hpp new file mode 100644 index 0000000..ca3c5fd --- /dev/null +++ b/lib/asio/detail/null_reactor.hpp @@ -0,0 +1,68 @@ +// +// detail/null_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NULL_REACTOR_HPP +#define ASIO_DETAIL_NULL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/scheduler_operation.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_reactor + : public execution_context_service_base<null_reactor> +{ +public: + // Constructor. + null_reactor(asio::execution_context& ctx) + : execution_context_service_base<null_reactor>(ctx) + { + } + + // Destructor. + ~null_reactor() + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // No-op because should never be called. + void run(long /*usec*/, op_queue<scheduler_operation>& /*ops*/) + { + } + + // No-op. + void interrupt() + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_NULL_REACTOR_HPP diff --git a/lib/asio/detail/null_signal_blocker.hpp b/lib/asio/detail/null_signal_blocker.hpp new file mode 100644 index 0000000..edfe820 --- /dev/null +++ b/lib/asio/detail/null_signal_blocker.hpp @@ -0,0 +1,69 @@ +// +// detail/null_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP +#define ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) \ + || defined(ASIO_WINDOWS) \ + || defined(ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_signal_blocker + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + null_signal_blocker() + { + } + + // Destructor restores the previous signal mask. + ~null_signal_blocker() + { + } + + // Block all signals for the calling thread. + void block() + { + } + + // Restore the previous signal mask. + void unblock() + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_THREADS) + // || defined(ASIO_WINDOWS) + // || defined(ASIO_WINDOWS_RUNTIME) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP diff --git a/lib/asio/detail/null_socket_service.hpp b/lib/asio/detail/null_socket_service.hpp new file mode 100644 index 0000000..109c6c7 --- /dev/null +++ b/lib/asio/detail/null_socket_service.hpp @@ -0,0 +1,508 @@ +// +// detail/null_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP +#define ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/bind_handler.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol> +class null_socket_service : + public service_base<null_socket_service<Protocol> > +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + typedef int native_handle_type; + + // The implementation type of the socket. + struct implementation_type + { + }; + + // Constructor. + null_socket_service(asio::io_context& io_context) + : service_base<null_socket_service<Protocol> >(io_context), + io_context_(io_context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // Construct a new socket implementation. + void construct(implementation_type&) + { + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type&, implementation_type&) + { + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type&, + null_socket_service&, implementation_type&) + { + } + + // Move-construct a new socket implementation from another protocol type. + template <typename Protocol1> + void converting_move_construct(implementation_type&, + null_socket_service<Protocol1>&, + typename null_socket_service<Protocol1>::implementation_type&) + { + } + + // Destroy a socket implementation. + void destroy(implementation_type&) + { + } + + // Open a new socket implementation. + asio::error_code open(implementation_type&, + const protocol_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Assign a native socket to a socket implementation. + asio::error_code assign(implementation_type&, const protocol_type&, + const native_handle_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Determine whether the socket is open. + bool is_open(const implementation_type&) const + { + return false; + } + + // Destroy a socket implementation. + asio::error_code close(implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Release ownership of the socket. + native_handle_type release(implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Get the native socket representation. + native_handle_type native_handle(implementation_type&) + { + return 0; + } + + // Cancel all operations associated with the socket. + asio::error_code cancel(implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return false; + } + + // Determine the number of bytes available for reading. + std::size_t available(const implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Place the socket into the state where it will listen for new connections. + asio::error_code listen(implementation_type&, + int, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Perform an IO control command on the socket. + template <typename IO_Control_Command> + asio::error_code io_control(implementation_type&, + IO_Control_Command&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const implementation_type&) const + { + return false; + } + + // Sets the non-blocking mode of the socket. + asio::error_code non_blocking(implementation_type&, + bool, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const implementation_type&) const + { + return false; + } + + // Sets the non-blocking mode of the native socket implementation. + asio::error_code native_non_blocking(implementation_type&, + bool, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Disable sends or receives on the socket. + asio::error_code shutdown(implementation_type&, + socket_base::shutdown_type, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Bind the socket to the specified local endpoint. + asio::error_code bind(implementation_type&, + const endpoint_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Set a socket option. + template <typename Option> + asio::error_code set_option(implementation_type&, + const Option&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Set a socket option. + template <typename Option> + asio::error_code get_option(const implementation_type&, + Option&, asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return endpoint_type(); + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return endpoint_type(); + } + + // Send the given data to the peer. + template <typename ConstBufferSequence> + std::size_t send(implementation_type&, const ConstBufferSequence&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be sent without blocking. + std::size_t send(implementation_type&, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_send(implementation_type&, const ConstBufferSequence&, + socket_base::message_flags, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler> + void async_send(implementation_type&, const null_buffers&, + socket_base::message_flags, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Receive some data from the peer. Returns the number of bytes received. + template <typename MutableBufferSequence> + std::size_t receive(implementation_type&, const MutableBufferSequence&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be received without blocking. + std::size_t receive(implementation_type&, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_receive(implementation_type&, const MutableBufferSequence&, + socket_base::message_flags, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive(implementation_type&, const null_buffers&, + socket_base::message_flags, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Receive some data with associated flags. Returns the number of bytes + // received. + template <typename MutableBufferSequence> + std::size_t receive_with_flags(implementation_type&, + const MutableBufferSequence&, socket_base::message_flags, + socket_base::message_flags&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be received without blocking. + std::size_t receive_with_flags(implementation_type&, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_receive_with_flags(implementation_type&, + const MutableBufferSequence&, socket_base::message_flags, + socket_base::message_flags&, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive_with_flags(implementation_type&, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags&, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template <typename ConstBufferSequence> + std::size_t send_to(implementation_type&, const ConstBufferSequence&, + const endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be sent without blocking. + std::size_t send_to(implementation_type&, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_send_to(implementation_type&, const ConstBufferSequence&, + const endpoint_type&, socket_base::message_flags, + Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler> + void async_send_to(implementation_type&, const null_buffers&, + const endpoint_type&, socket_base::message_flags, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template <typename MutableBufferSequence> + std::size_t receive_from(implementation_type&, const MutableBufferSequence&, + endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be received without blocking. + std::size_t receive_from(implementation_type&, const null_buffers&, + endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // 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 <typename MutableBufferSequence, typename Handler> + void async_receive_from(implementation_type&, + const MutableBufferSequence&, endpoint_type&, + socket_base::message_flags, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive_from(implementation_type&, + const null_buffers&, endpoint_type&, + socket_base::message_flags, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Accept a new connection. + template <typename Socket> + asio::error_code accept(implementation_type&, + Socket&, endpoint_type*, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template <typename Socket, typename Handler> + void async_accept(implementation_type&, Socket&, + endpoint_type*, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + io_context_.post(detail::bind_handler(handler, ec)); + } + + // Connect the socket to the specified endpoint. + asio::error_code connect(implementation_type&, + const endpoint_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Start an asynchronous connect. + template <typename Handler> + void async_connect(implementation_type&, + const endpoint_type&, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + io_context_.post(detail::bind_handler(handler, ec)); + } + +private: + asio::io_context& io_context_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP diff --git a/lib/asio/detail/null_static_mutex.hpp b/lib/asio/detail/null_static_mutex.hpp new file mode 100644 index 0000000..36ec04f --- /dev/null +++ b/lib/asio/detail/null_static_mutex.hpp @@ -0,0 +1,60 @@ +// +// detail/null_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NULL_STATIC_MUTEX_HPP +#define ASIO_DETAIL_NULL_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) + +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct null_static_mutex +{ + typedef asio::detail::scoped_lock<null_static_mutex> scoped_lock; + + // Initialise the mutex. + void init() + { + } + + // Lock the mutex. + void lock() + { + } + + // Unlock the mutex. + void unlock() + { + } + + int unused_; +}; + +#define ASIO_NULL_STATIC_MUTEX_INIT { 0 } + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_THREADS) + +#endif // ASIO_DETAIL_NULL_STATIC_MUTEX_HPP diff --git a/lib/asio/detail/null_thread.hpp b/lib/asio/detail/null_thread.hpp new file mode 100644 index 0000000..7291ba3 --- /dev/null +++ b/lib/asio/detail/null_thread.hpp @@ -0,0 +1,67 @@ +// +// detail/null_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NULL_THREAD_HPP +#define ASIO_DETAIL_NULL_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class null_thread + : private noncopyable +{ +public: + // Constructor. + template <typename Function> + null_thread(Function, unsigned int = 0) + { + asio::detail::throw_error( + asio::error::operation_not_supported, "thread"); + } + + // Destructor. + ~null_thread() + { + } + + // Wait for the thread to exit. + void join() + { + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + return 1; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_THREADS) + +#endif // ASIO_DETAIL_NULL_THREAD_HPP diff --git a/lib/asio/detail/null_tss_ptr.hpp b/lib/asio/detail/null_tss_ptr.hpp new file mode 100644 index 0000000..323967d --- /dev/null +++ b/lib/asio/detail/null_tss_ptr.hpp @@ -0,0 +1,68 @@ +// +// detail/null_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_NULL_TSS_PTR_HPP +#define ASIO_DETAIL_NULL_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +class null_tss_ptr + : private noncopyable +{ +public: + // Constructor. + null_tss_ptr() + : value_(0) + { + } + + // Destructor. + ~null_tss_ptr() + { + } + + // Get the value. + operator T*() const + { + return value_; + } + + // Set the value. + void operator=(T* value) + { + value_ = value; + } + +private: + T* value_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_THREADS) + +#endif // ASIO_DETAIL_NULL_TSS_PTR_HPP diff --git a/lib/asio/detail/object_pool.hpp b/lib/asio/detail/object_pool.hpp new file mode 100644 index 0000000..e1a3c54 --- /dev/null +++ b/lib/asio/detail/object_pool.hpp @@ -0,0 +1,171 @@ +// +// detail/object_pool.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_OBJECT_POOL_HPP +#define ASIO_DETAIL_OBJECT_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Object> +class object_pool; + +class object_pool_access +{ +public: + template <typename Object> + static Object* create() + { + return new Object; + } + + template <typename Object, typename Arg> + static Object* create(Arg arg) + { + return new Object(arg); + } + + template <typename Object> + static void destroy(Object* o) + { + delete o; + } + + template <typename Object> + static Object*& next(Object* o) + { + return o->next_; + } + + template <typename Object> + static Object*& prev(Object* o) + { + return o->prev_; + } +}; + +template <typename Object> +class object_pool + : private noncopyable +{ +public: + // Constructor. + object_pool() + : live_list_(0), + free_list_(0) + { + } + + // Destructor destroys all objects. + ~object_pool() + { + destroy_list(live_list_); + destroy_list(free_list_); + } + + // Get the object at the start of the live list. + Object* first() + { + return live_list_; + } + + // Allocate a new object. + Object* alloc() + { + Object* o = free_list_; + if (o) + free_list_ = object_pool_access::next(free_list_); + else + o = object_pool_access::create<Object>(); + + object_pool_access::next(o) = live_list_; + object_pool_access::prev(o) = 0; + if (live_list_) + object_pool_access::prev(live_list_) = o; + live_list_ = o; + + return o; + } + + // Allocate a new object with an argument. + template <typename Arg> + Object* alloc(Arg arg) + { + Object* o = free_list_; + if (o) + free_list_ = object_pool_access::next(free_list_); + else + o = object_pool_access::create<Object>(arg); + + object_pool_access::next(o) = live_list_; + object_pool_access::prev(o) = 0; + if (live_list_) + object_pool_access::prev(live_list_) = o; + live_list_ = o; + + return o; + } + + // Free an object. Moves it to the free list. No destructors are run. + void free(Object* o) + { + if (live_list_ == o) + live_list_ = object_pool_access::next(o); + + if (object_pool_access::prev(o)) + { + object_pool_access::next(object_pool_access::prev(o)) + = object_pool_access::next(o); + } + + if (object_pool_access::next(o)) + { + object_pool_access::prev(object_pool_access::next(o)) + = object_pool_access::prev(o); + } + + object_pool_access::next(o) = free_list_; + object_pool_access::prev(o) = 0; + free_list_ = o; + } + +private: + // Helper function to destroy all elements in a list. + void destroy_list(Object* list) + { + while (list) + { + Object* o = list; + list = object_pool_access::next(o); + object_pool_access::destroy(o); + } + } + + // The list of live objects. + Object* live_list_; + + // The free list. + Object* free_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_OBJECT_POOL_HPP diff --git a/lib/asio/detail/old_win_sdk_compat.hpp b/lib/asio/detail/old_win_sdk_compat.hpp new file mode 100644 index 0000000..bfb109e --- /dev/null +++ b/lib/asio/detail/old_win_sdk_compat.hpp @@ -0,0 +1,214 @@ +// +// detail/old_win_sdk_compat.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP +#define ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +// Guess whether we are building against on old Platform SDK. +#if !defined(IN6ADDR_ANY_INIT) +#define ASIO_HAS_OLD_WIN_SDK 1 +#endif // !defined(IN6ADDR_ANY_INIT) + +#if defined(ASIO_HAS_OLD_WIN_SDK) + +// Emulation of types that are missing from old Platform SDKs. +// +// N.B. this emulation is also used if building for a Windows 2000 target with +// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support +// in that case. + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +enum +{ + sockaddr_storage_maxsize = 128, // Maximum size. + sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment. + sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)), + sockaddr_storage_pad2size = (sockaddr_storage_maxsize - + (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize)) +}; + +struct sockaddr_storage_emulation +{ + short ss_family; + char __ss_pad1[sockaddr_storage_pad1size]; + __int64 __ss_align; + char __ss_pad2[sockaddr_storage_pad2size]; +}; + +struct in6_addr_emulation +{ + union + { + u_char Byte[16]; + u_short Word[8]; + } u; +}; + +#if !defined(s6_addr) +# define _S6_un u +# define _S6_u8 Byte +# define s6_addr _S6_un._S6_u8 +#endif // !defined(s6_addr) + +struct sockaddr_in6_emulation +{ + short sin6_family; + u_short sin6_port; + u_long sin6_flowinfo; + in6_addr_emulation sin6_addr; + u_long sin6_scope_id; +}; + +struct ipv6_mreq_emulation +{ + in6_addr_emulation ipv6mr_multiaddr; + unsigned int ipv6mr_interface; +}; + +struct addrinfo_emulation +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char* ai_canonname; + sockaddr* ai_addr; + addrinfo_emulation* ai_next; +}; + +#if !defined(AI_PASSIVE) +# define AI_PASSIVE 0x1 +#endif + +#if !defined(AI_CANONNAME) +# define AI_CANONNAME 0x2 +#endif + +#if !defined(AI_NUMERICHOST) +# define AI_NUMERICHOST 0x4 +#endif + +#if !defined(EAI_AGAIN) +# define EAI_AGAIN WSATRY_AGAIN +#endif + +#if !defined(EAI_BADFLAGS) +# define EAI_BADFLAGS WSAEINVAL +#endif + +#if !defined(EAI_FAIL) +# define EAI_FAIL WSANO_RECOVERY +#endif + +#if !defined(EAI_FAMILY) +# define EAI_FAMILY WSAEAFNOSUPPORT +#endif + +#if !defined(EAI_MEMORY) +# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY +#endif + +#if !defined(EAI_NODATA) +# define EAI_NODATA WSANO_DATA +#endif + +#if !defined(EAI_NONAME) +# define EAI_NONAME WSAHOST_NOT_FOUND +#endif + +#if !defined(EAI_SERVICE) +# define EAI_SERVICE WSATYPE_NOT_FOUND +#endif + +#if !defined(EAI_SOCKTYPE) +# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT +#endif + +#if !defined(NI_NOFQDN) +# define NI_NOFQDN 0x01 +#endif + +#if !defined(NI_NUMERICHOST) +# define NI_NUMERICHOST 0x02 +#endif + +#if !defined(NI_NAMEREQD) +# define NI_NAMEREQD 0x04 +#endif + +#if !defined(NI_NUMERICSERV) +# define NI_NUMERICSERV 0x08 +#endif + +#if !defined(NI_DGRAM) +# define NI_DGRAM 0x10 +#endif + +#if !defined(IPPROTO_IPV6) +# define IPPROTO_IPV6 41 +#endif + +#if !defined(IPV6_UNICAST_HOPS) +# define IPV6_UNICAST_HOPS 4 +#endif + +#if !defined(IPV6_MULTICAST_IF) +# define IPV6_MULTICAST_IF 9 +#endif + +#if !defined(IPV6_MULTICAST_HOPS) +# define IPV6_MULTICAST_HOPS 10 +#endif + +#if !defined(IPV6_MULTICAST_LOOP) +# define IPV6_MULTICAST_LOOP 11 +#endif + +#if !defined(IPV6_JOIN_GROUP) +# define IPV6_JOIN_GROUP 12 +#endif + +#if !defined(IPV6_LEAVE_GROUP) +# define IPV6_LEAVE_GROUP 13 +#endif + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_OLD_WIN_SDK) + +// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. +#if !defined(IPV6_V6ONLY) +# define IPV6_V6ONLY 27 +#endif + +// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6. +#if !defined(IPPROTO_ICMPV6) +# define IPPROTO_ICMPV6 58 +#endif + +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP diff --git a/lib/asio/detail/op_queue.hpp b/lib/asio/detail/op_queue.hpp new file mode 100644 index 0000000..6219f79 --- /dev/null +++ b/lib/asio/detail/op_queue.hpp @@ -0,0 +1,162 @@ +// +// detail/op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_OP_QUEUE_HPP +#define ASIO_DETAIL_OP_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Operation> +class op_queue; + +class op_queue_access +{ +public: + template <typename Operation> + static Operation* next(Operation* o) + { + return static_cast<Operation*>(o->next_); + } + + template <typename Operation1, typename Operation2> + static void next(Operation1*& o1, Operation2* o2) + { + o1->next_ = o2; + } + + template <typename Operation> + static void destroy(Operation* o) + { + o->destroy(); + } + + template <typename Operation> + static Operation*& front(op_queue<Operation>& q) + { + return q.front_; + } + + template <typename Operation> + static Operation*& back(op_queue<Operation>& q) + { + return q.back_; + } +}; + +template <typename Operation> +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<Operation*>(0)); + } + } + + // Push an operation on to the back of the queue. + void push(Operation* h) + { + op_queue_access::next(h, static_cast<Operation*>(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 <typename OtherOperation> + void push(op_queue<OtherOperation>& 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; + } + + // Test whether an operation is already enqueued. + bool is_enqueued(Operation* o) const + { + return op_queue_access::next(o) != 0 || back_ == o; + } + +private: + friend class op_queue_access; + + // The front of the queue. + Operation* front_; + + // The back of the queue. + Operation* back_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_OP_QUEUE_HPP diff --git a/lib/asio/detail/operation.hpp b/lib/asio/detail/operation.hpp new file mode 100644 index 0000000..811e54d --- /dev/null +++ b/lib/asio/detail/operation.hpp @@ -0,0 +1,38 @@ +// +// detail/operation.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_OPERATION_HPP +#define ASIO_DETAIL_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_operation.hpp" +#else +# include "asio/detail/scheduler_operation.hpp" +#endif + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_IOCP) +typedef win_iocp_operation operation; +#else +typedef scheduler_operation operation; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_OPERATION_HPP diff --git a/lib/asio/detail/pipe_select_interrupter.hpp b/lib/asio/detail/pipe_select_interrupter.hpp new file mode 100644 index 0000000..55d7db4 --- /dev/null +++ b/lib/asio/detail/pipe_select_interrupter.hpp @@ -0,0 +1,89 @@ +// +// detail/pipe_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP +#define ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) +#if !defined(ASIO_WINDOWS_RUNTIME) +#if !defined(__CYGWIN__) +#if !defined(__SYMBIAN32__) +#if !defined(ASIO_HAS_EVENTFD) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class pipe_select_interrupter +{ +public: + // Constructor. + ASIO_DECL pipe_select_interrupter(); + + // Destructor. + ASIO_DECL ~pipe_select_interrupter(); + + // Recreate the interrupter's descriptors. Used after a fork. + ASIO_DECL void recreate(); + + // Interrupt the select call. + ASIO_DECL void interrupt(); + + // Reset the select interrupt. Returns true if the call was interrupted. + ASIO_DECL bool reset(); + + // Get the read descriptor to be passed to select. + int read_descriptor() const + { + return read_descriptor_; + } + +private: + // Open the descriptors. Throws on error. + ASIO_DECL void open_descriptors(); + + // Close the descriptors. + ASIO_DECL void close_descriptors(); + + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // byte will be written on the other end of the connection and this + // descriptor will become readable. + int read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // byte may be written to this to wake up the select which is waiting for the + // other end to become readable. + int write_descriptor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/pipe_select_interrupter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_HAS_EVENTFD) +#endif // !defined(__SYMBIAN32__) +#endif // !defined(__CYGWIN__) +#endif // !defined(ASIO_WINDOWS_RUNTIME) +#endif // !defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP diff --git a/lib/asio/detail/pop_options.hpp b/lib/asio/detail/pop_options.hpp new file mode 100644 index 0000000..1045612 --- /dev/null +++ b/lib/asio/detail/pop_options.hpp @@ -0,0 +1,135 @@ +// +// detail/pop_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 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) +// + +// No header guard + +#if defined(__COMO__) + +// Comeau C++ + +#elif defined(__DMC__) + +// Digital Mars C++ + +#elif defined(__INTEL_COMPILER) || defined(__ICL) \ + || defined(__ICC) || defined(__ECC) + +// Intel C++ + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility pop +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +#elif defined(__clang__) + +// Clang + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if defined(ASIO_OBJC_WORKAROUND) +# undef Protocol +# undef id +# undef ASIO_OBJC_WORKAROUND +# endif +# endif +# endif + +# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) +# pragma GCC visibility pop +# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) + +#elif defined(__GNUC__) + +// GNU C++ + +# if defined(__MINGW32__) || defined(__CYGWIN__) +# pragma pack (pop) +# endif + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if defined(ASIO_OBJC_WORKAROUND) +# undef Protocol +# undef id +# undef ASIO_OBJC_WORKAROUND +# endif +# endif +# endif + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility pop +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +# if (__GNUC__ >= 7) +# pragma GCC diagnostic pop +# endif // (__GNUC__ >= 7) + +#elif defined(__KCC) + +// Kai C++ + +#elif defined(__sgi) + +// SGI MIPSpro C++ + +#elif defined(__DECCXX) + +// Compaq Tru64 Unix cxx + +#elif defined(__ghs) + +// Greenhills C++ + +#elif defined(__BORLANDC__) + +// Borland C++ + +# pragma option pop +# pragma nopushoptwarn +# pragma nopackwarning + +#elif defined(__MWERKS__) + +// Metrowerks CodeWarrior + +#elif defined(__SUNPRO_CC) + +// Sun Workshop Compiler C++ + +#elif defined(__HP_aCC) + +// HP aCC + +#elif defined(__MRC__) || defined(__SC__) + +// MPW MrCpp or SCpp + +#elif defined(__IBMCPP__) + +// IBM Visual Age + +#elif defined(_MSC_VER) + +// Microsoft Visual C++ +// +// Must remain the last #elif since some other vendors (Metrowerks, for example) +// also #define _MSC_VER + +# pragma warning (pop) +# pragma pack (pop) + +# if defined(__cplusplus_cli) || defined(__cplusplus_winrt) +# if defined(ASIO_CLR_WORKAROUND) +# undef generic +# undef ASIO_CLR_WORKAROUND +# endif +# endif + +#endif diff --git a/lib/asio/detail/posix_event.hpp b/lib/asio/detail/posix_event.hpp new file mode 100644 index 0000000..121065e --- /dev/null +++ b/lib/asio/detail/posix_event.hpp @@ -0,0 +1,162 @@ +// +// detail/posix_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_POSIX_EVENT_HPP +#define ASIO_DETAIL_POSIX_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include <pthread.h> +#include "asio/detail/assert.hpp" +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class posix_event + : private noncopyable +{ +public: + // Constructor. + ASIO_DECL posix_event(); + + // Destructor. + ~posix_event() + { + ::pthread_cond_destroy(&cond_); + } + + // Signal the event. (Retained for backward compatibility.) + template <typename Lock> + void signal(Lock& lock) + { + this->signal_all(lock); + } + + // Signal all waiters. + template <typename Lock> + void signal_all(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + state_ |= 1; + ::pthread_cond_broadcast(&cond_); // Ignore EINVAL. + } + + // Unlock the mutex and signal one waiter. + template <typename Lock> + void unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + lock.unlock(); + if (have_waiters) + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + } + + // If there's a waiter, unlock the mutex and signal it. + template <typename Lock> + bool maybe_unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + if (state_ > 1) + { + lock.unlock(); + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + return true; + } + return false; + } + + // Reset the event. + template <typename Lock> + void clear(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + state_ &= ~std::size_t(1); + } + + // Wait for the event to become signalled. + template <typename Lock> + void wait(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + while ((state_ & 1) == 0) + { + state_ += 2; + ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL. + state_ -= 2; + } + } + + // Timed wait for the event to become signalled. + template <typename Lock> + bool wait_for_usec(Lock& lock, long usec) + { + ASIO_ASSERT(lock.locked()); + if ((state_ & 1) == 0) + { + state_ += 2; + timespec ts; +#if (defined(__MACH__) && defined(__APPLE__)) \ + || (defined(__ANDROID__) && (__ANDROID_API__ < 21) \ + && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + ::pthread_cond_timedwait_relative_np( + &cond_, &lock.mutex().mutex_, &ts); // Ignore EINVAL. +#else // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21) + // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) + if (::clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + ts.tv_sec += usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + ts.tv_sec += ts.tv_nsec / 1000000000; + ts.tv_nsec = ts.tv_nsec % 1000000000; + ::pthread_cond_timedwait(&cond_, + &lock.mutex().mutex_, &ts); // Ignore EINVAL. + } +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21) + // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) + state_ -= 2; + } + return (state_ & 1) != 0; + } + +private: + ::pthread_cond_t cond_; + std::size_t state_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_event.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_EVENT_HPP diff --git a/lib/asio/detail/posix_fd_set_adapter.hpp b/lib/asio/detail/posix_fd_set_adapter.hpp new file mode 100644 index 0000000..95042d6 --- /dev/null +++ b/lib/asio/detail/posix_fd_set_adapter.hpp @@ -0,0 +1,118 @@ +// +// detail/posix_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP +#define ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) \ + && !defined(__CYGWIN__) \ + && !defined(ASIO_WINDOWS_RUNTIME) + +#include <cstring> +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements. +class posix_fd_set_adapter : noncopyable +{ +public: + posix_fd_set_adapter() + : max_descriptor_(invalid_socket) + { + using namespace std; // Needed for memset on Solaris. + FD_ZERO(&fd_set_); + } + + void reset() + { + using namespace std; // Needed for memset on Solaris. + FD_ZERO(&fd_set_); + } + + bool set(socket_type descriptor) + { + if (descriptor < (socket_type)FD_SETSIZE) + { + if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_) + max_descriptor_ = descriptor; + FD_SET(descriptor, &fd_set_); + return true; + } + return false; + } + + void set(reactor_op_queue<socket_type>& operations, op_queue<operation>& ops) + { + reactor_op_queue<socket_type>::iterator i = operations.begin(); + while (i != operations.end()) + { + reactor_op_queue<socket_type>::iterator op_iter = i++; + if (!set(op_iter->first)) + { + asio::error_code ec(error::fd_set_failure); + operations.cancel_operations(op_iter, ops, ec); + } + } + } + + bool is_set(socket_type descriptor) const + { + return FD_ISSET(descriptor, &fd_set_) != 0; + } + + operator fd_set*() + { + return &fd_set_; + } + + socket_type max_descriptor() const + { + return max_descriptor_; + } + + void perform(reactor_op_queue<socket_type>& operations, + op_queue<operation>& ops) const + { + reactor_op_queue<socket_type>::iterator i = operations.begin(); + while (i != operations.end()) + { + reactor_op_queue<socket_type>::iterator op_iter = i++; + if (is_set(op_iter->first)) + operations.perform_operations(op_iter, ops); + } + } + +private: + mutable fd_set fd_set_; + socket_type max_descriptor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) + // && !defined(__CYGWIN__) + // && !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP diff --git a/lib/asio/detail/posix_global.hpp b/lib/asio/detail/posix_global.hpp new file mode 100644 index 0000000..7ee0a71 --- /dev/null +++ b/lib/asio/detail/posix_global.hpp @@ -0,0 +1,80 @@ +// +// detail/posix_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_POSIX_GLOBAL_HPP +#define ASIO_DETAIL_POSIX_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include <exception> +#include <pthread.h> + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +struct posix_global_impl +{ + // Helper function to perform initialisation. + static void do_init() + { + instance_.static_ptr_ = instance_.ptr_ = new T; + } + + // Destructor automatically cleans up the global. + ~posix_global_impl() + { + delete static_ptr_; + } + + static ::pthread_once_t init_once_; + static T* static_ptr_; + static posix_global_impl instance_; + T* ptr_; +}; + +template <typename T> +::pthread_once_t posix_global_impl<T>::init_once_ = PTHREAD_ONCE_INIT; + +template <typename T> +T* posix_global_impl<T>::static_ptr_ = 0; + +template <typename T> +posix_global_impl<T> posix_global_impl<T>::instance_; + +template <typename T> +T& posix_global() +{ + int result = ::pthread_once( + &posix_global_impl<T>::init_once_, + &posix_global_impl<T>::do_init); + + if (result != 0) + std::terminate(); + + return *posix_global_impl<T>::instance_.ptr_; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_GLOBAL_HPP diff --git a/lib/asio/detail/posix_mutex.hpp b/lib/asio/detail/posix_mutex.hpp new file mode 100644 index 0000000..c0d9fc9 --- /dev/null +++ b/lib/asio/detail/posix_mutex.hpp @@ -0,0 +1,76 @@ +// +// detail/posix_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_POSIX_MUTEX_HPP +#define ASIO_DETAIL_POSIX_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include <pthread.h> +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class posix_event; + +class posix_mutex + : private noncopyable +{ +public: + typedef asio::detail::scoped_lock<posix_mutex> scoped_lock; + + // Constructor. + ASIO_DECL posix_mutex(); + + // Destructor. + ~posix_mutex() + { + ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY. + } + + // Lock the mutex. + void lock() + { + (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL. + } + + // Unlock the mutex. + void unlock() + { + (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL. + } + +private: + friend class posix_event; + ::pthread_mutex_t mutex_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_mutex.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_MUTEX_HPP diff --git a/lib/asio/detail/posix_signal_blocker.hpp b/lib/asio/detail/posix_signal_blocker.hpp new file mode 100644 index 0000000..fab5eb1 --- /dev/null +++ b/lib/asio/detail/posix_signal_blocker.hpp @@ -0,0 +1,85 @@ +// +// detail/posix_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP +#define ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include <csignal> +#include <pthread.h> +#include <signal.h> +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class posix_signal_blocker + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + posix_signal_blocker() + : blocked_(false) + { + sigset_t new_mask; + sigfillset(&new_mask); + blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0); + } + + // Destructor restores the previous signal mask. + ~posix_signal_blocker() + { + if (blocked_) + pthread_sigmask(SIG_SETMASK, &old_mask_, 0); + } + + // Block all signals for the calling thread. + void block() + { + if (!blocked_) + { + sigset_t new_mask; + sigfillset(&new_mask); + blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0); + } + } + + // Restore the previous signal mask. + void unblock() + { + if (blocked_) + blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0); + } + +private: + // Have signals been blocked. + bool blocked_; + + // The previous signal mask. + sigset_t old_mask_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP diff --git a/lib/asio/detail/posix_static_mutex.hpp b/lib/asio/detail/posix_static_mutex.hpp new file mode 100644 index 0000000..59b86c1 --- /dev/null +++ b/lib/asio/detail/posix_static_mutex.hpp @@ -0,0 +1,64 @@ +// +// detail/posix_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP +#define ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include <pthread.h> +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct posix_static_mutex +{ + typedef asio::detail::scoped_lock<posix_static_mutex> scoped_lock; + + // Initialise the mutex. + void init() + { + // Nothing to do. + } + + // Lock the mutex. + void lock() + { + (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL. + } + + // Unlock the mutex. + void unlock() + { + (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL. + } + + ::pthread_mutex_t mutex_; +}; + +#define ASIO_POSIX_STATIC_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER } + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP diff --git a/lib/asio/detail/posix_thread.hpp b/lib/asio/detail/posix_thread.hpp new file mode 100644 index 0000000..1817af2 --- /dev/null +++ b/lib/asio/detail/posix_thread.hpp @@ -0,0 +1,109 @@ +// +// detail/posix_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_POSIX_THREAD_HPP +#define ASIO_DETAIL_POSIX_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include <cstddef> +#include <pthread.h> +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +extern "C" +{ + ASIO_DECL void* asio_detail_posix_thread_function(void* arg); +} + +class posix_thread + : private noncopyable +{ +public: + // Constructor. + template <typename Function> + posix_thread(Function f, unsigned int = 0) + : joined_(false) + { + start_thread(new func<Function>(f)); + } + + // Destructor. + ASIO_DECL ~posix_thread(); + + // Wait for the thread to exit. + ASIO_DECL void join(); + + // Get number of CPUs. + ASIO_DECL static std::size_t hardware_concurrency(); + +private: + friend void* asio_detail_posix_thread_function(void* arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + + template <typename Function> + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ASIO_DECL void start_thread(func_base* arg); + + ::pthread_t thread_; + bool joined_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_thread.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_THREAD_HPP diff --git a/lib/asio/detail/posix_tss_ptr.hpp b/lib/asio/detail/posix_tss_ptr.hpp new file mode 100644 index 0000000..a3096b4 --- /dev/null +++ b/lib/asio/detail/posix_tss_ptr.hpp @@ -0,0 +1,79 @@ +// +// detail/posix_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_POSIX_TSS_PTR_HPP +#define ASIO_DETAIL_POSIX_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PTHREADS) + +#include <pthread.h> +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper function to create thread-specific storage. +ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key); + +template <typename T> +class posix_tss_ptr + : private noncopyable +{ +public: + // Constructor. + posix_tss_ptr() + { + posix_tss_ptr_create(tss_key_); + } + + // Destructor. + ~posix_tss_ptr() + { + ::pthread_key_delete(tss_key_); + } + + // Get the value. + operator T*() const + { + return static_cast<T*>(::pthread_getspecific(tss_key_)); + } + + // Set the value. + void operator=(T* value) + { + ::pthread_setspecific(tss_key_, value); + } + +private: + // Thread-specific storage to allow unlocked access to determine whether a + // thread is a member of the pool. + pthread_key_t tss_key_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/posix_tss_ptr.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_PTHREADS) + +#endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP diff --git a/lib/asio/detail/push_options.hpp b/lib/asio/detail/push_options.hpp new file mode 100644 index 0000000..0a3e979 --- /dev/null +++ b/lib/asio/detail/push_options.hpp @@ -0,0 +1,175 @@ +// +// detail/push_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 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) +// + +// No header guard + +#if defined(__COMO__) + +// Comeau C++ + +#elif defined(__DMC__) + +// Digital Mars C++ + +#elif defined(__INTEL_COMPILER) || defined(__ICL) \ + || defined(__ICC) || defined(__ECC) + +// Intel C++ + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility push (default) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +#elif defined(__clang__) + +// Clang + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if !defined(ASIO_DISABLE_OBJC_WORKAROUND) +# if !defined(Protocol) && !defined(id) +# define Protocol cpp_Protocol +# define id cpp_id +# define ASIO_OBJC_WORKAROUND +# endif +# endif +# endif +# endif + +# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) +# pragma GCC visibility push (default) +# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) + +#elif defined(__GNUC__) + +// GNU C++ + +# if defined(__MINGW32__) || defined(__CYGWIN__) +# pragma pack (push, 8) +# endif + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if !defined(ASIO_DISABLE_OBJC_WORKAROUND) +# if !defined(Protocol) && !defined(id) +# define Protocol cpp_Protocol +# define id cpp_id +# define ASIO_OBJC_WORKAROUND +# endif +# endif +# endif +# endif + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility push (default) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +# if (__GNUC__ >= 7) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +# endif // (__GNUC__ >= 7) + +#elif defined(__KCC) + +// Kai C++ + +#elif defined(__sgi) + +// SGI MIPSpro C++ + +#elif defined(__DECCXX) + +// Compaq Tru64 Unix cxx + +#elif defined(__ghs) + +// Greenhills C++ + +#elif defined(__BORLANDC__) + +// Borland C++ + +# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi- +# pragma nopushoptwarn +# pragma nopackwarning +# if !defined(__MT__) +# error Multithreaded RTL must be selected. +# endif // !defined(__MT__) + +#elif defined(__MWERKS__) + +// Metrowerks CodeWarrior + +#elif defined(__SUNPRO_CC) + +// Sun Workshop Compiler C++ + +#elif defined(__HP_aCC) + +// HP aCC + +#elif defined(__MRC__) || defined(__SC__) + +// MPW MrCpp or SCpp + +#elif defined(__IBMCPP__) + +// IBM Visual Age + +#elif defined(_MSC_VER) + +// Microsoft Visual C++ +// +// Must remain the last #elif since some other vendors (Metrowerks, for example) +// also #define _MSC_VER + +# pragma warning (disable:4103) +# pragma warning (push) +# pragma warning (disable:4127) +# pragma warning (disable:4180) +# pragma warning (disable:4244) +# pragma warning (disable:4355) +# pragma warning (disable:4510) +# pragma warning (disable:4512) +# pragma warning (disable:4610) +# pragma warning (disable:4675) +# if (_MSC_VER < 1600) +// Visual Studio 2008 generates spurious warnings about unused parameters. +# pragma warning (disable:4100) +# endif // (_MSC_VER < 1600) +# if defined(_M_IX86) && defined(_Wp64) +// The /Wp64 option is broken. If you want to check 64 bit portability, use a +// 64 bit compiler! +# pragma warning (disable:4311) +# pragma warning (disable:4312) +# endif // defined(_M_IX86) && defined(_Wp64) +# pragma pack (push, 8) +// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler +// has a tendency to incorrectly optimise away some calls to member template +// functions, even though those functions contain code that should not be +// optimised away! Therefore we will always disable this optimisation option +// for the MSVC6 compiler. +# if (_MSC_VER < 1300) +# pragma optimize ("g", off) +# endif +# if !defined(_MT) +# error Multithreaded RTL must be selected. +# endif // !defined(_MT) + +# if defined(__cplusplus_cli) || defined(__cplusplus_winrt) +# if !defined(ASIO_DISABLE_CLR_WORKAROUND) +# if !defined(generic) +# define generic cpp_generic +# define ASIO_CLR_WORKAROUND +# endif +# endif +# endif + +#endif diff --git a/lib/asio/detail/reactive_descriptor_service.hpp b/lib/asio/detail/reactive_descriptor_service.hpp new file mode 100644 index 0000000..e866863 --- /dev/null +++ b/lib/asio/detail/reactive_descriptor_service.hpp @@ -0,0 +1,388 @@ +// +// detail/reactive_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP +#define ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include "asio/buffer.hpp" +#include "asio/io_context.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/descriptor_read_op.hpp" +#include "asio/detail/descriptor_write_op.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/reactive_null_buffers_op.hpp" +#include "asio/detail/reactive_wait_op.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/posix/descriptor_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class reactive_descriptor_service : + public service_base<reactive_descriptor_service> +{ +public: + // The native type of a descriptor. + typedef int native_handle_type; + + // The implementation type of the descriptor. + class implementation_type + : private asio::detail::noncopyable + { + public: + // Default constructor. + implementation_type() + : descriptor_(-1), + state_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class reactive_descriptor_service; + + // The native descriptor representation. + int descriptor_; + + // The current state of the descriptor. + descriptor_ops::state_type state_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + }; + + // Constructor. + ASIO_DECL reactive_descriptor_service( + asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new descriptor implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Move-construct a new descriptor implementation. + ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another descriptor implementation. + ASIO_DECL void move_assign(implementation_type& impl, + reactive_descriptor_service& other_service, + implementation_type& other_impl); + + // Destroy a descriptor implementation. + ASIO_DECL void destroy(implementation_type& impl); + + // Assign a native descriptor to a descriptor implementation. + ASIO_DECL asio::error_code assign(implementation_type& impl, + const native_handle_type& native_descriptor, + asio::error_code& ec); + + // Determine whether the descriptor is open. + bool is_open(const implementation_type& impl) const + { + return impl.descriptor_ != -1; + } + + // Destroy a descriptor implementation. + ASIO_DECL asio::error_code close(implementation_type& impl, + asio::error_code& ec); + + // Get the native descriptor representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return impl.descriptor_; + } + + // Release ownership of the native descriptor representation. + ASIO_DECL native_handle_type release(implementation_type& impl); + + // Cancel all operations associated with the descriptor. + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); + + // Perform an IO control command on the descriptor. + template <typename IO_Control_Command> + asio::error_code io_control(implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + descriptor_ops::ioctl(impl.descriptor_, impl.state_, + command.name(), static_cast<ioctl_arg_type*>(command.data()), ec); + return ec; + } + + // Gets the non-blocking mode of the descriptor. + bool non_blocking(const implementation_type& impl) const + { + return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the descriptor. + asio::error_code non_blocking(implementation_type& impl, + bool mode, asio::error_code& ec) + { + descriptor_ops::set_user_non_blocking( + impl.descriptor_, impl.state_, mode, ec); + return ec; + } + + // Gets the non-blocking mode of the native descriptor implementation. + bool native_non_blocking(const implementation_type& impl) const + { + return (impl.state_ & descriptor_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native descriptor implementation. + asio::error_code native_non_blocking(implementation_type& impl, + bool mode, asio::error_code& ec) + { + descriptor_ops::set_internal_non_blocking( + impl.descriptor_, impl.state_, mode, ec); + return ec; + } + + // Wait for the descriptor to become ready to read, ready to write, or to have + // pending error conditions. + asio::error_code wait(implementation_type& impl, + posix::descriptor_base::wait_type w, asio::error_code& ec) + { + switch (w) + { + case posix::descriptor_base::wait_read: + descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); + break; + case posix::descriptor_base::wait_write: + descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); + break; + case posix::descriptor_base::wait_error: + descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec); + break; + default: + ec = asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the descriptor to become ready to read, ready to + // write, or to have pending error conditions. + template <typename Handler> + void async_wait(implementation_type& impl, + posix::descriptor_base::wait_type w, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_wait_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_wait")); + + int op_type; + switch (w) + { + case posix::descriptor_base::wait_read: + op_type = reactor::read_op; + break; + case posix::descriptor_base::wait_write: + op_type = reactor::write_op; + break; + case posix::descriptor_base::wait_error: + op_type = reactor::except_op; + break; + default: + p.p->ec_ = asio::error::invalid_argument; + reactor_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + return; + } + + start_op(impl, op_type, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Write some data to the descriptor. + template <typename ConstBufferSequence> + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(buffers); + + return descriptor_ops::sync_write(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + + // Wait until data can be written without blocking. + size_t write_some(implementation_type& impl, + const null_buffers&, asio::error_code& ec) + { + // Wait for descriptor to become ready. + descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); + + return 0; + } + + // Start an asynchronous write. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef descriptor_write_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.descriptor_, buffers, handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_write_some")); + + start_op(impl, reactor::write_op, p.p, is_continuation, true, + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::all_empty(buffers)); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be written without blocking. + template <typename Handler> + void async_write_some(implementation_type& impl, + const null_buffers&, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_write_some(null_buffers)")); + + start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Read some data from the stream. Returns the number of bytes read. + template <typename MutableBufferSequence> + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + return descriptor_ops::sync_read(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + + // Wait until data can be read without blocking. + size_t read_some(implementation_type& impl, + const null_buffers&, asio::error_code& ec) + { + // Wait for descriptor to become ready. + descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); + + return 0; + } + + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef descriptor_read_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.descriptor_, buffers, handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_read_some")); + + start_op(impl, reactor::read_op, p.p, is_continuation, true, + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::all_empty(buffers)); + p.v = p.p = 0; + } + + // Wait until data can be read without blocking. + template <typename Handler> + void async_read_some(implementation_type& impl, + const null_buffers&, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_read_some(null_buffers)")); + + start_op(impl, reactor::read_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + +private: + // Start the asynchronous operation. + ASIO_DECL void start_op(implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); + + // The selector that performs event demultiplexing for the service. + reactor& reactor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/reactive_descriptor_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP diff --git a/lib/asio/detail/reactive_null_buffers_op.hpp b/lib/asio/detail/reactive_null_buffers_op.hpp new file mode 100644 index 0000000..7408269 --- /dev/null +++ b/lib/asio/detail/reactive_null_buffers_op.hpp @@ -0,0 +1,90 @@ +// +// detail/reactive_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP +#define ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class reactive_null_buffers_op : public reactor_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); + + reactive_null_buffers_op(Handler& handler) + : reactor_op(&reactive_null_buffers_op::do_perform, + &reactive_null_buffers_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP diff --git a/lib/asio/detail/reactive_serial_port_service.hpp b/lib/asio/detail/reactive_serial_port_service.hpp new file mode 100644 index 0000000..6fddd9f --- /dev/null +++ b/lib/asio/detail/reactive_serial_port_service.hpp @@ -0,0 +1,236 @@ +// +// detail/reactive_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP +#define ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SERIAL_PORT) +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include <string> +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/serial_port_base.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/reactive_descriptor_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Extend reactive_descriptor_service to provide serial port support. +class reactive_serial_port_service : + public service_base<reactive_serial_port_service> +{ +public: + // The native type of a serial port. + typedef reactive_descriptor_service::native_handle_type native_handle_type; + + // The implementation type of the serial port. + typedef reactive_descriptor_service::implementation_type implementation_type; + + ASIO_DECL reactive_serial_port_service( + asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new serial port implementation. + void construct(implementation_type& impl) + { + descriptor_service_.construct(impl); + } + + // Move-construct a new serial port implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + descriptor_service_.move_construct(impl, other_impl); + } + + // Move-assign from another serial port implementation. + void move_assign(implementation_type& impl, + reactive_serial_port_service& other_service, + implementation_type& other_impl) + { + descriptor_service_.move_assign(impl, + other_service.descriptor_service_, other_impl); + } + + // Destroy a serial port implementation. + void destroy(implementation_type& impl) + { + descriptor_service_.destroy(impl); + } + + // Open the serial port using the specified device name. + ASIO_DECL asio::error_code open(implementation_type& impl, + const std::string& device, asio::error_code& ec); + + // Assign a native descriptor to a serial port implementation. + asio::error_code assign(implementation_type& impl, + const native_handle_type& native_descriptor, + asio::error_code& ec) + { + return descriptor_service_.assign(impl, native_descriptor, ec); + } + + // Determine whether the serial port is open. + bool is_open(const implementation_type& impl) const + { + return descriptor_service_.is_open(impl); + } + + // Destroy a serial port implementation. + asio::error_code close(implementation_type& impl, + asio::error_code& ec) + { + return descriptor_service_.close(impl, ec); + } + + // Get the native serial port representation. + native_handle_type native_handle(implementation_type& impl) + { + return descriptor_service_.native_handle(impl); + } + + // Cancel all operations associated with the serial port. + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) + { + return descriptor_service_.cancel(impl, ec); + } + + // Set an option on the serial port. + template <typename SettableSerialPortOption> + asio::error_code set_option(implementation_type& impl, + const SettableSerialPortOption& option, asio::error_code& ec) + { + return do_set_option(impl, + &reactive_serial_port_service::store_option<SettableSerialPortOption>, + &option, ec); + } + + // Get an option from the serial port. + template <typename GettableSerialPortOption> + asio::error_code get_option(const implementation_type& impl, + GettableSerialPortOption& option, asio::error_code& ec) const + { + return do_get_option(impl, + &reactive_serial_port_service::load_option<GettableSerialPortOption>, + &option, ec); + } + + // Send a break sequence to the serial port. + asio::error_code send_break(implementation_type& impl, + asio::error_code& ec) + { + errno = 0; + descriptor_ops::error_wrapper(::tcsendbreak( + descriptor_service_.native_handle(impl), 0), ec); + return ec; + } + + // Write the given data. Returns the number of bytes sent. + template <typename ConstBufferSequence> + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return descriptor_service_.write_some(impl, buffers, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, Handler& handler) + { + descriptor_service_.async_write_some(impl, buffers, handler); + } + + // Read some data. Returns the number of bytes received. + template <typename MutableBufferSequence> + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return descriptor_service_.read_some(impl, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being received must be + // valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, Handler& handler) + { + descriptor_service_.async_read_some(impl, buffers, handler); + } + +private: + // Function pointer type for storing a serial port option. + typedef asio::error_code (*store_function_type)( + const void*, termios&, asio::error_code&); + + // Helper function template to store a serial port option. + template <typename SettableSerialPortOption> + static asio::error_code store_option(const void* option, + termios& storage, asio::error_code& ec) + { + static_cast<const SettableSerialPortOption*>(option)->store(storage, ec); + return ec; + } + + // Helper function to set a serial port option. + ASIO_DECL asio::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, asio::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef asio::error_code (*load_function_type)( + void*, const termios&, asio::error_code&); + + // Helper function template to load a serial port option. + template <typename GettableSerialPortOption> + static asio::error_code load_option(void* option, + const termios& storage, asio::error_code& ec) + { + static_cast<GettableSerialPortOption*>(option)->load(storage, ec); + return ec; + } + + // Helper function to get a serial port option. + ASIO_DECL asio::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, asio::error_code& ec) const; + + // The implementation used for initiating asynchronous operations. + reactive_descriptor_service descriptor_service_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/reactive_serial_port_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP diff --git a/lib/asio/detail/reactive_socket_accept_op.hpp b/lib/asio/detail/reactive_socket_accept_op.hpp new file mode 100644 index 0000000..4a98f04 --- /dev/null +++ b/lib/asio/detail/reactive_socket_accept_op.hpp @@ -0,0 +1,217 @@ +// +// detail/reactive_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Socket, typename Protocol> +class reactive_socket_accept_op_base : public reactor_op +{ +public: + reactive_socket_accept_op_base(socket_type socket, + socket_ops::state_type state, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, func_type complete_func) + : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_accept_op_base* o( + static_cast<reactive_socket_accept_op_base*>(base)); + + socket_type new_socket = invalid_socket; + status result = socket_ops::non_blocking_accept(o->socket_, + o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, + o->peer_endpoint_ ? &o->addrlen_ : 0, o->ec_, new_socket) + ? done : not_done; + o->new_socket_.reset(new_socket); + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_accept", o->ec_)); + + return result; + } + + void do_assign() + { + if (new_socket_.get() != invalid_socket) + { + if (peer_endpoint_) + peer_endpoint_->resize(addrlen_); + peer_.assign(protocol_, new_socket_.get(), ec_); + if (!ec_) + new_socket_.release(); + } + } + +private: + socket_type socket_; + socket_ops::state_type state_; + socket_holder new_socket_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + std::size_t addrlen_; +}; + +template <typename Socket, typename Protocol, typename Handler> +class reactive_socket_accept_op : + public reactive_socket_accept_op_base<Socket, Protocol> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); + + reactive_socket_accept_op(socket_type socket, + socket_ops::state_type state, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler& handler) + : reactive_socket_accept_op_base<Socket, Protocol>(socket, state, peer, + protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + // On success, assign new connection to peer socket object. + if (owner) + o->do_assign(); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code> + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +#if defined(ASIO_HAS_MOVE) + +template <typename Protocol, typename Handler> +class reactive_socket_move_accept_op : + private Protocol::socket, + public reactive_socket_accept_op_base<typename Protocol::socket, Protocol> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op); + + reactive_socket_move_accept_op(io_context& ioc, socket_type socket, + socket_ops::state_type state, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler& handler) + : Protocol::socket(ioc), + reactive_socket_accept_op_base<typename Protocol::socket, Protocol>( + socket, state, *this, protocol, peer_endpoint, + &reactive_socket_move_accept_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_move_accept_op* o( + static_cast<reactive_socket_move_accept_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + // On success, assign new connection to peer socket object. + if (owner) + o->do_assign(); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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::move_binder2<Handler, + asio::error_code, typename Protocol::socket> + handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_, + ASIO_MOVE_CAST(typename Protocol::socket)(*o)); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +#endif // defined(ASIO_HAS_MOVE) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP diff --git a/lib/asio/detail/reactive_socket_connect_op.hpp b/lib/asio/detail/reactive_socket_connect_op.hpp new file mode 100644 index 0000000..76164b2 --- /dev/null +++ b/lib/asio/detail/reactive_socket_connect_op.hpp @@ -0,0 +1,113 @@ +// +// detail/reactive_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class reactive_socket_connect_op_base : public reactor_op +{ +public: + reactive_socket_connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func), + socket_(socket) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_connect_op_base* o( + static_cast<reactive_socket_connect_op_base*>(base)); + + status result = socket_ops::non_blocking_connect( + o->socket_, o->ec_) ? done : not_done; + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_connect", o->ec_)); + + return result; + } + +private: + socket_type socket_; +}; + +template <typename Handler> +class reactive_socket_connect_op : public reactive_socket_connect_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); + + reactive_socket_connect_op(socket_type socket, Handler& handler) + : reactive_socket_connect_op_base(socket, + &reactive_socket_connect_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_connect_op* o + (static_cast<reactive_socket_connect_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code> + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP diff --git a/lib/asio/detail/reactive_socket_recv_op.hpp b/lib/asio/detail/reactive_socket_recv_op.hpp new file mode 100644 index 0000000..04bd266 --- /dev/null +++ b/lib/asio/detail/reactive_socket_recv_op.hpp @@ -0,0 +1,135 @@ +// +// detail/reactive_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence> +class reactive_socket_recv_op_base : public reactor_op +{ +public: + reactive_socket_recv_op_base(socket_type socket, + socket_ops::state_type state, const MutableBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_recv_op_base* o( + static_cast<reactive_socket_recv_op_base*>(base)); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(o->buffers_); + + status result = socket_ops::non_blocking_recv(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + (o->state_ & socket_ops::stream_oriented) != 0, + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ == 0) + result = done_and_exhausted; + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recv", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + MutableBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template <typename MutableBufferSequence, typename Handler> +class reactive_socket_recv_op : + public reactive_socket_recv_op_base<MutableBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); + + reactive_socket_recv_op(socket_type socket, + socket_ops::state_type state, const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler& handler) + : reactive_socket_recv_op_base<MutableBufferSequence>(socket, state, + buffers, flags, &reactive_socket_recv_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP diff --git a/lib/asio/detail/reactive_socket_recvfrom_op.hpp b/lib/asio/detail/reactive_socket_recvfrom_op.hpp new file mode 100644 index 0000000..3d4fa4c --- /dev/null +++ b/lib/asio/detail/reactive_socket_recvfrom_op.hpp @@ -0,0 +1,138 @@ +// +// detail/reactive_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Endpoint> +class reactive_socket_recvfrom_op_base : public reactor_op +{ +public: + reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_recvfrom_op_base::do_perform, complete_func), + socket_(socket), + protocol_type_(protocol_type), + buffers_(buffers), + sender_endpoint_(endpoint), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_recvfrom_op_base* o( + static_cast<reactive_socket_recvfrom_op_base*>(base)); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(o->buffers_); + + std::size_t addr_len = o->sender_endpoint_.capacity(); + status result = socket_ops::non_blocking_recvfrom(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result && !o->ec_) + o->sender_endpoint_.resize(addr_len); + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvfrom", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + int protocol_type_; + MutableBufferSequence buffers_; + Endpoint& sender_endpoint_; + socket_base::message_flags flags_; +}; + +template <typename MutableBufferSequence, typename Endpoint, typename Handler> +class reactive_socket_recvfrom_op : + public reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); + + reactive_socket_recvfrom_op(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, Handler& handler) + : reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>( + socket, protocol_type, buffers, endpoint, flags, + &reactive_socket_recvfrom_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recvfrom_op* o( + static_cast<reactive_socket_recvfrom_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP diff --git a/lib/asio/detail/reactive_socket_recvmsg_op.hpp b/lib/asio/detail/reactive_socket_recvmsg_op.hpp new file mode 100644 index 0000000..f473274 --- /dev/null +++ b/lib/asio/detail/reactive_socket_recvmsg_op.hpp @@ -0,0 +1,132 @@ +// +// detail/reactive_socket_recvmsg_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/socket_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence> +class reactive_socket_recvmsg_op_base : public reactor_op +{ +public: + reactive_socket_recvmsg_op_base(socket_type socket, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, func_type complete_func) + : reactor_op(&reactive_socket_recvmsg_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + in_flags_(in_flags), + out_flags_(out_flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_recvmsg_op_base* o( + static_cast<reactive_socket_recvmsg_op_base*>(base)); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(o->buffers_); + + status result = socket_ops::non_blocking_recvmsg(o->socket_, + bufs.buffers(), bufs.count(), + o->in_flags_, o->out_flags_, + o->ec_, o->bytes_transferred_) ? done : not_done; + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvmsg", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + MutableBufferSequence buffers_; + socket_base::message_flags in_flags_; + socket_base::message_flags& out_flags_; +}; + +template <typename MutableBufferSequence, typename Handler> +class reactive_socket_recvmsg_op : + public reactive_socket_recvmsg_op_base<MutableBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op); + + reactive_socket_recvmsg_op(socket_type socket, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler) + : reactive_socket_recvmsg_op_base<MutableBufferSequence>(socket, buffers, + in_flags, out_flags, &reactive_socket_recvmsg_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recvmsg_op* o( + static_cast<reactive_socket_recvmsg_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP diff --git a/lib/asio/detail/reactive_socket_send_op.hpp b/lib/asio/detail/reactive_socket_send_op.hpp new file mode 100644 index 0000000..bd550d9 --- /dev/null +++ b/lib/asio/detail/reactive_socket_send_op.hpp @@ -0,0 +1,134 @@ +// +// detail/reactive_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence> +class reactive_socket_send_op_base : public reactor_op +{ +public: + reactive_socket_send_op_base(socket_type socket, + socket_ops::state_type state, const ConstBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_send_op_base* o( + static_cast<reactive_socket_send_op_base*>(base)); + + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(o->buffers_); + + status result = socket_ops::non_blocking_send(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ < bufs.total_size()) + result = done_and_exhausted; + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_send", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + ConstBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template <typename ConstBufferSequence, typename Handler> +class reactive_socket_send_op : + public reactive_socket_send_op_base<ConstBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); + + reactive_socket_send_op(socket_type socket, + socket_ops::state_type state, const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler& handler) + : reactive_socket_send_op_base<ConstBufferSequence>(socket, + state, buffers, flags, &reactive_socket_send_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP diff --git a/lib/asio/detail/reactive_socket_sendto_op.hpp b/lib/asio/detail/reactive_socket_sendto_op.hpp new file mode 100644 index 0000000..c97554d --- /dev/null +++ b/lib/asio/detail/reactive_socket_sendto_op.hpp @@ -0,0 +1,130 @@ +// +// detail/reactive_socket_sendto_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence, typename Endpoint> +class reactive_socket_sendto_op_base : public reactor_op +{ +public: + reactive_socket_sendto_op_base(socket_type socket, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + destination_(endpoint), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_sendto_op_base* o( + static_cast<reactive_socket_sendto_op_base*>(base)); + + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(o->buffers_); + + status result = socket_ops::non_blocking_sendto(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + + ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_sendto", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + ConstBufferSequence buffers_; + Endpoint destination_; + socket_base::message_flags flags_; +}; + +template <typename ConstBufferSequence, typename Endpoint, typename Handler> +class reactive_socket_sendto_op : + public reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); + + reactive_socket_sendto_op(socket_type socket, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, Handler& handler) + : reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>(socket, + buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP diff --git a/lib/asio/detail/reactive_socket_service.hpp b/lib/asio/detail/reactive_socket_service.hpp new file mode 100644 index 0000000..15a4fdb --- /dev/null +++ b/lib/asio/detail/reactive_socket_service.hpp @@ -0,0 +1,526 @@ +// +// detail/reactive_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) + +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/reactive_null_buffers_op.hpp" +#include "asio/detail/reactive_socket_accept_op.hpp" +#include "asio/detail/reactive_socket_connect_op.hpp" +#include "asio/detail/reactive_socket_recvfrom_op.hpp" +#include "asio/detail/reactive_socket_sendto_op.hpp" +#include "asio/detail/reactive_socket_service_base.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol> +class reactive_socket_service : + public service_base<reactive_socket_service<Protocol> >, + public reactive_socket_service_base +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + typedef socket_type native_handle_type; + + // The implementation type of the socket. + struct implementation_type : + reactive_socket_service_base::base_implementation_type + { + // Default constructor. + implementation_type() + : protocol_(endpoint_type().protocol()) + { + } + + // The protocol associated with the socket. + protocol_type protocol_; + }; + + // Constructor. + reactive_socket_service(asio::io_context& io_context) + : service_base<reactive_socket_service<Protocol> >(io_context), + reactive_socket_service_base(io_context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type& impl, + reactive_socket_service_base& other_service, + implementation_type& other_impl) + { + this->base_move_assign(impl, other_service, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-construct a new socket implementation from another protocol type. + template <typename Protocol1> + void converting_move_construct(implementation_type& impl, + reactive_socket_service<Protocol1>&, + typename reactive_socket_service< + Protocol1>::implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = protocol_type(other_impl.protocol_); + other_impl.protocol_ = typename Protocol1::endpoint().protocol(); + } + + // Open a new socket implementation. + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) + { + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) + impl.protocol_ = protocol; + return ec; + } + + // Assign a native socket to a socket implementation. + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_handle_type& native_socket, + asio::error_code& ec) + { + if (!do_assign(impl, protocol.type(), native_socket, ec)) + impl.protocol_ = protocol; + return ec; + } + + // Get the native socket representation. + native_handle_type native_handle(implementation_type& impl) + { + return impl.socket_; + } + + // Bind the socket to the specified local endpoint. + asio::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) + { + socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + return ec; + } + + // Set a socket option. + template <typename Option> + asio::error_code set_option(implementation_type& impl, + const Option& option, asio::error_code& ec) + { + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; + } + + // Set a socket option. + template <typename Option> + asio::error_code get_option(const implementation_type& impl, + Option& option, asio::error_code& ec) const + { + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, + endpoint.data(), &addr_len, false, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Disable sends or receives on the socket. + asio::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template <typename ConstBufferSequence> + size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + asio::error_code& ec) + { + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(buffers); + + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); + } + + // Wait until data can be sent without blocking. + size_t send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_sendto_op<ConstBufferSequence, + endpoint_type, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send_to")); + + start_op(impl, reactor::write_op, p.p, is_continuation, true, false); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler> + void async_send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send_to(null_buffers)")); + + start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template <typename MutableBufferSequence> + size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + asio::error_code& ec) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); + + if (!ec) + sender_endpoint.resize(addr_len); + + return bytes_recvd; + } + + // Wait until data can be received without blocking. + size_t receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags, + asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + return 0; + } + + // 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 <typename MutableBufferSequence, typename Handler> + void async_receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, + socket_base::message_flags flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recvfrom_op<MutableBufferSequence, + endpoint_type, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + int protocol = impl.protocol_.type(); + p.p = new (p.v) op(impl.socket_, protocol, + buffers, sender_endpoint, flags, handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_from")); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, true, false); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive_from(implementation_type& impl, + const null_buffers&, endpoint_type& sender_endpoint, + socket_base::message_flags flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_from(null_buffers)")); + + // 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, + p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Accept a new connection. + template <typename Socket> + asio::error_code accept(implementation_type& impl, + Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec) + { + // We cannot accept a socket that is already open. + if (peer.is_open()) + { + ec = asio::error::already_open; + return ec; + } + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return ec; + } + +#if defined(ASIO_HAS_MOVE) + // Accept a new connection. + typename Protocol::socket accept(implementation_type& impl, + io_context* peer_io_context, endpoint_type* peer_endpoint, + asio::error_code& ec) + { + typename Protocol::socket peer( + peer_io_context ? *peer_io_context : io_context_); + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return peer; + } +#endif // defined(ASIO_HAS_MOVE) + + // Start an asynchronous accept. The peer and peer_endpoint objects must be + // valid until the accept's handler is invoked. + template <typename Socket, typename Handler> + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_accept_op<Socket, Protocol, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, peer, + impl.protocol_, peer_endpoint, handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, p.p, is_continuation, peer.is_open()); + p.v = p.p = 0; + } + +#if defined(ASIO_HAS_MOVE) + // Start an asynchronous accept. The peer_endpoint object must be valid until + // the accept's handler is invoked. + template <typename Handler> + void async_accept(implementation_type& impl, + asio::io_context* peer_io_context, + endpoint_type* peer_endpoint, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_move_accept_op<Protocol, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(peer_io_context ? *peer_io_context : io_context_, + impl.socket_, impl.state_, impl.protocol_, peer_endpoint, handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, p.p, is_continuation, false); + p.v = p.p = 0; + } +#endif // defined(ASIO_HAS_MOVE) + + // Connect the socket to the specified endpoint. + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) + { + socket_ops::sync_connect(impl.socket_, + peer_endpoint.data(), peer_endpoint.size(), ec); + return ec; + } + + // Start an asynchronous connect. + template <typename Handler> + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_connect_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_connect")); + + start_connect_op(impl, p.p, is_continuation, + peer_endpoint.data(), peer_endpoint.size()); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP diff --git a/lib/asio/detail/reactive_socket_service_base.hpp b/lib/asio/detail/reactive_socket_service_base.hpp new file mode 100644 index 0000000..ccd497e --- /dev/null +++ b/lib/asio/detail/reactive_socket_service_base.hpp @@ -0,0 +1,511 @@ +// +// detail/reactive_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP +#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_IOCP) \ + && !defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactive_null_buffers_op.hpp" +#include "asio/detail/reactive_socket_recv_op.hpp" +#include "asio/detail/reactive_socket_recvmsg_op.hpp" +#include "asio/detail/reactive_socket_send_op.hpp" +#include "asio/detail/reactive_wait_op.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class reactive_socket_service_base +{ +public: + // The native type of a socket. + typedef socket_type native_handle_type; + + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + }; + + // Constructor. + ASIO_DECL reactive_socket_service_base( + asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void base_shutdown(); + + // Construct a new socket implementation. + ASIO_DECL void construct(base_implementation_type& impl); + + // Move-construct a new socket implementation. + ASIO_DECL void base_move_construct(base_implementation_type& impl, + base_implementation_type& other_impl); + + // Move-assign from another socket implementation. + ASIO_DECL void base_move_assign(base_implementation_type& impl, + reactive_socket_service_base& other_service, + base_implementation_type& other_impl); + + // Destroy a socket implementation. + ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + ASIO_DECL asio::error_code close( + base_implementation_type& impl, asio::error_code& ec); + + // Release ownership of the socket. + ASIO_DECL socket_type release( + base_implementation_type& impl, asio::error_code& ec); + + // Get the native socket representation. + native_handle_type native_handle(base_implementation_type& impl) + { + return impl.socket_; + } + + // Cancel all operations associated with the socket. + ASIO_DECL asio::error_code cancel( + base_implementation_type& impl, asio::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + asio::error_code listen(base_implementation_type& impl, + int backlog, asio::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template <typename IO_Control_Command> + asio::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast<ioctl_arg_type*>(command.data()), ec); + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the socket. + asio::error_code non_blocking(base_implementation_type& impl, + bool mode, asio::error_code& ec) + { + socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native socket implementation. + asio::error_code native_non_blocking(base_implementation_type& impl, + bool mode, asio::error_code& ec) + { + socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Wait for the socket to become ready to read, ready to write, or to have + // pending error conditions. + asio::error_code wait(base_implementation_type& impl, + socket_base::wait_type w, asio::error_code& ec) + { + switch (w) + { + case socket_base::wait_read: + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_write: + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_error: + socket_ops::poll_error(impl.socket_, impl.state_, -1, ec); + break; + default: + ec = asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the socket to become ready to read, ready to + // write, or to have pending error conditions. + template <typename Handler> + void async_wait(base_implementation_type& impl, + socket_base::wait_type w, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_wait_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_wait")); + + int op_type; + switch (w) + { + case socket_base::wait_read: + op_type = reactor::read_op; + break; + case socket_base::wait_write: + op_type = reactor::write_op; + break; + case socket_base::wait_error: + op_type = reactor::except_op; + break; + default: + p.p->ec_ = asio::error::invalid_argument; + reactor_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + return; + } + + start_op(impl, op_type, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Send the given data to the peer. + template <typename ConstBufferSequence> + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_send_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send")); + + start_op(impl, reactor::write_op, p.p, is_continuation, true, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::all_empty(buffers))); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler> + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send(null_buffers)")); + + start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template <typename MutableBufferSequence> + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive")); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, + (flags & socket_base::message_out_of_band) == 0, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::all_empty(buffers))); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive(null_buffers)")); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Receive some data with associated flags. Returns the number of bytes + // received. + template <typename MutableBufferSequence> + size_t receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + return socket_ops::sync_recvmsg(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), in_flags, out_flags, ec); + } + + // Wait until data can be received without blocking. + size_t receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recvmsg_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, buffers, in_flags, out_flags, handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags")); + + start_op(impl, + (in_flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, + (in_flags & socket_base::message_out_of_band) == 0, false); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + start_op(impl, + (in_flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, false, false); + p.v = p.p = 0; + } + +protected: + // Open a new socket implementation. + ASIO_DECL asio::error_code do_open( + base_implementation_type& impl, int af, + int type, int protocol, asio::error_code& ec); + + // Assign a native socket to a socket implementation. + ASIO_DECL asio::error_code do_assign( + base_implementation_type& impl, int type, + const native_handle_type& native_socket, asio::error_code& ec); + + // Start the asynchronous read or write operation. + ASIO_DECL void start_op(base_implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); + + // Start the asynchronous accept operation. + ASIO_DECL void start_accept_op(base_implementation_type& impl, + reactor_op* op, bool is_continuation, bool peer_is_open); + + // Start the asynchronous connect operation. + ASIO_DECL void start_connect_op(base_implementation_type& impl, + reactor_op* op, bool is_continuation, + const socket_addr_type* addr, size_t addrlen); + + // The io_context that owns this socket service. + io_context& io_context_; + + // The selector that performs event demultiplexing for the service. + reactor& reactor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/reactive_socket_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // !defined(ASIO_HAS_IOCP) + // && !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP diff --git a/lib/asio/detail/reactive_wait_op.hpp b/lib/asio/detail/reactive_wait_op.hpp new file mode 100644 index 0000000..616d8b1 --- /dev/null +++ b/lib/asio/detail/reactive_wait_op.hpp @@ -0,0 +1,90 @@ +// +// detail/reactive_wait_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_WAIT_OP_HPP +#define ASIO_DETAIL_REACTIVE_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class reactive_wait_op : public reactor_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_wait_op); + + reactive_wait_op(Handler& handler) + : reactor_op(&reactive_wait_op::do_perform, + &reactive_wait_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_wait_op* o(static_cast<reactive_wait_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code> + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_WAIT_OP_HPP diff --git a/lib/asio/detail/reactor.hpp b/lib/asio/detail/reactor.hpp new file mode 100644 index 0000000..4750276 --- /dev/null +++ b/lib/asio/detail/reactor.hpp @@ -0,0 +1,32 @@ +// +// detail/reactor.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTOR_HPP +#define ASIO_DETAIL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/reactor_fwd.hpp" + +#if defined(ASIO_HAS_EPOLL) +# include "asio/detail/epoll_reactor.hpp" +#elif defined(ASIO_HAS_KQUEUE) +# include "asio/detail/kqueue_reactor.hpp" +#elif defined(ASIO_HAS_DEV_POLL) +# include "asio/detail/dev_poll_reactor.hpp" +#elif defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/null_reactor.hpp" +#else +# include "asio/detail/select_reactor.hpp" +#endif + +#endif // ASIO_DETAIL_REACTOR_HPP diff --git a/lib/asio/detail/reactor_fwd.hpp b/lib/asio/detail/reactor_fwd.hpp new file mode 100644 index 0000000..a4555c3 --- /dev/null +++ b/lib/asio/detail/reactor_fwd.hpp @@ -0,0 +1,40 @@ +// +// detail/reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTOR_FWD_HPP +#define ASIO_DETAIL_REACTOR_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) +typedef class null_reactor reactor; +#elif defined(ASIO_HAS_IOCP) +typedef class select_reactor reactor; +#elif defined(ASIO_HAS_EPOLL) +typedef class epoll_reactor reactor; +#elif defined(ASIO_HAS_KQUEUE) +typedef class kqueue_reactor reactor; +#elif defined(ASIO_HAS_DEV_POLL) +typedef class dev_poll_reactor reactor; +#else +typedef class select_reactor reactor; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_REACTOR_FWD_HPP diff --git a/lib/asio/detail/reactor_op.hpp b/lib/asio/detail/reactor_op.hpp new file mode 100644 index 0000000..faad1a7 --- /dev/null +++ b/lib/asio/detail/reactor_op.hpp @@ -0,0 +1,65 @@ +// +// detail/reactor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTOR_OP_HPP +#define ASIO_DETAIL_REACTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class reactor_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + + // The number of bytes transferred, to be passed to the completion handler. + std::size_t bytes_transferred_; + + // Status returned by perform function. May be used to decide whether it is + // worth performing more operations on the descriptor immediately. + enum status { not_done, done, done_and_exhausted }; + + // Perform the operation. Returns true if it is finished. + status perform() + { + return perform_func_(this); + } + +protected: + typedef status (*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 + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTOR_OP_HPP diff --git a/lib/asio/detail/reactor_op_queue.hpp b/lib/asio/detail/reactor_op_queue.hpp new file mode 100644 index 0000000..898f31d --- /dev/null +++ b/lib/asio/detail/reactor_op_queue.hpp @@ -0,0 +1,168 @@ +// +// detail/reactor_op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTOR_OP_QUEUE_HPP +#define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/hash_map.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Descriptor> +class reactor_op_queue + : private noncopyable +{ +public: + typedef Descriptor key_type; + + struct mapped_type : op_queue<reactor_op> + { + mapped_type() {} + mapped_type(const mapped_type&) {} + void operator=(const mapped_type&) {} + }; + + typedef typename hash_map<key_type, mapped_type>::value_type value_type; + typedef typename hash_map<key_type, mapped_type>::iterator iterator; + + // Constructor. + reactor_op_queue() + : operations_() + { + } + + // Obtain iterators to all registered descriptors. + iterator begin() { return operations_.begin(); } + iterator end() { return operations_.end(); } + + // 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. + bool enqueue_operation(Descriptor descriptor, reactor_op* op) + { + std::pair<iterator, bool> entry = + operations_.insert(value_type(descriptor, mapped_type())); + entry.first->second.push(op); + return entry.second; + } + + // Cancel all operations associated with the descriptor identified by the + // supplied iterator. Any operations pending for the descriptor will be + // cancelled. 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(iterator i, op_queue<operation>& ops, + const asio::error_code& ec = + asio::error::operation_aborted) + { + if (i != operations_.end()) + { + while (reactor_op* op = i->second.front()) + { + op->ec_ = ec; + i->second.pop(); + ops.push(op); + } + operations_.erase(i); + return true; + } + + return false; + } + + // Cancel all operations associated with the descriptor. Any operations + // pending for the descriptor will be cancelled. 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, op_queue<operation>& ops, + const asio::error_code& ec = + asio::error::operation_aborted) + { + return this->cancel_operations(operations_.find(descriptor), ops, ec); + } + + // Whether there are no operations in the queue. + bool empty() const + { + return operations_.empty(); + } + + // Determine whether there are any operations associated with the descriptor. + bool has_operation(Descriptor descriptor) const + { + return operations_.find(descriptor) != operations_.end(); + } + + // Perform the operations corresponding to the descriptor identified by the + // supplied iterator. Returns true if there are still unfinished operations + // queued for the descriptor. + bool perform_operations(iterator i, op_queue<operation>& ops) + { + if (i != operations_.end()) + { + while (reactor_op* op = i->second.front()) + { + if (op->perform()) + { + i->second.pop(); + ops.push(op); + } + else + { + return true; + } + } + operations_.erase(i); + } + return false; + } + + // 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<operation>& ops) + { + return this->perform_operations(operations_.find(descriptor), ops); + } + + // Get all operations owned by the queue. + void get_all_operations(op_queue<operation>& ops) + { + iterator i = operations_.begin(); + while (i != operations_.end()) + { + iterator op_iter = i++; + ops.push(op_iter->second); + operations_.erase(op_iter); + } + } + +private: + // The operations that are currently executing asynchronously. + hash_map<key_type, mapped_type> operations_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP diff --git a/lib/asio/detail/recycling_allocator.hpp b/lib/asio/detail/recycling_allocator.hpp new file mode 100644 index 0000000..964af1d --- /dev/null +++ b/lib/asio/detail/recycling_allocator.hpp @@ -0,0 +1,104 @@ +// +// detail/recycling_allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP +#define ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/thread_context.hpp" +#include "asio/detail/thread_info_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +class recycling_allocator +{ +public: + typedef T value_type; + + template <typename U> + struct rebind + { + typedef recycling_allocator<U> other; + }; + + recycling_allocator() + { + } + + template <typename U> + recycling_allocator(const recycling_allocator<U>&) + { + } + + T* allocate(std::size_t n) + { + typedef thread_context::thread_call_stack call_stack; + void* p = thread_info_base::allocate(call_stack::top(), sizeof(T) * n); + return static_cast<T*>(p); + } + + void deallocate(T* p, std::size_t n) + { + typedef thread_context::thread_call_stack call_stack; + thread_info_base::deallocate(call_stack::top(), p, sizeof(T) * n); + } +}; + +template <> +class recycling_allocator<void> +{ +public: + typedef void value_type; + + template <typename U> + struct rebind + { + typedef recycling_allocator<U> other; + }; + + recycling_allocator() + { + } + + template <typename U> + recycling_allocator(const recycling_allocator<U>&) + { + } +}; + +template <typename Allocator> +struct get_recycling_allocator +{ + typedef Allocator type; + static type get(const Allocator& a) { return a; } +}; + +template <typename T> +struct get_recycling_allocator<std::allocator<T> > +{ + typedef recycling_allocator<T> type; + static type get(const std::allocator<T>&) { return type(); } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP diff --git a/lib/asio/detail/regex_fwd.hpp b/lib/asio/detail/regex_fwd.hpp new file mode 100644 index 0000000..dcf7d06 --- /dev/null +++ b/lib/asio/detail/regex_fwd.hpp @@ -0,0 +1,35 @@ +// +// detail/regex_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REGEX_FWD_HPP +#define ASIO_DETAIL_REGEX_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(ASIO_HAS_BOOST_REGEX) + +#include <boost/regex_fwd.hpp> +#include <boost/regex/v4/match_flags.hpp> + +namespace boost { + +template <class BidiIterator> +struct sub_match; + +template <class BidiIterator, class Allocator> +class match_results; + +} // namespace boost + +#endif // defined(ASIO_HAS_BOOST_REGEX) + +#endif // ASIO_DETAIL_REGEX_FWD_HPP diff --git a/lib/asio/detail/resolve_endpoint_op.hpp b/lib/asio/detail/resolve_endpoint_op.hpp new file mode 100644 index 0000000..8eee2f9 --- /dev/null +++ b/lib/asio/detail/resolve_endpoint_op.hpp @@ -0,0 +1,122 @@ +// +// detail/resolve_endpoint_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP +#define ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/ip/basic_resolver_results.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/resolve_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol, typename Handler> +class resolve_endpoint_op : public resolve_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op); + + typedef typename Protocol::endpoint endpoint_type; + typedef asio::ip::basic_resolver_results<Protocol> results_type; + + resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token, + const endpoint_type& endpoint, io_context_impl& ioc, Handler& handler) + : resolve_op(&resolve_endpoint_op::do_complete), + cancel_token_(cancel_token), + endpoint_(endpoint), + io_context_impl_(ioc), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + if (owner && owner != &o->io_context_impl_) + { + // The operation is being run on the worker io_context. Time to perform + // the resolver operation. + + // Perform the blocking endpoint resolution operation. + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(), + o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV, + o->endpoint_.protocol().type(), o->ec_); + o->results_ = results_type::create(o->endpoint_, host_name, service_name); + + // Pass operation back to main io_context for completion. + o->io_context_impl_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_context. The completion + // handler is ready to be delivered. + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, results_type> + handler(o->handler_, o->ec_, o->results_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + endpoint_type endpoint_; + io_context_impl& io_context_impl_; + Handler handler_; + results_type results_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP diff --git a/lib/asio/detail/resolve_op.hpp b/lib/asio/detail/resolve_op.hpp new file mode 100644 index 0000000..a528aa8 --- /dev/null +++ b/lib/asio/detail/resolve_op.hpp @@ -0,0 +1,45 @@ +// +// detail/resolve_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_RESOLVE_OP_HPP +#define ASIO_DETAIL_RESOLVE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class resolve_op : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + +protected: + resolve_op(func_type complete_func) + : operation(complete_func) + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_RESOLVE_OP_HPP diff --git a/lib/asio/detail/resolve_query_op.hpp b/lib/asio/detail/resolve_query_op.hpp new file mode 100644 index 0000000..0ec5a32 --- /dev/null +++ b/lib/asio/detail/resolve_query_op.hpp @@ -0,0 +1,134 @@ +// +// detail/resolve_query_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_RESOLVE_QUERY_OP_HPP +#define ASIO_DETAIL_RESOLVE_QUERY_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/ip/basic_resolver_results.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/resolve_op.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol, typename Handler> +class resolve_query_op : public resolve_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(resolve_query_op); + + typedef asio::ip::basic_resolver_query<Protocol> query_type; + typedef asio::ip::basic_resolver_results<Protocol> results_type; + + resolve_query_op(socket_ops::weak_cancel_token_type cancel_token, + const query_type& query, io_context_impl& ioc, Handler& handler) + : resolve_op(&resolve_query_op::do_complete), + cancel_token_(cancel_token), + query_(query), + io_context_impl_(ioc), + handler_(ASIO_MOVE_CAST(Handler)(handler)), + addrinfo_(0) + { + handler_work<Handler>::start(handler_); + } + + ~resolve_query_op() + { + if (addrinfo_) + socket_ops::freeaddrinfo(addrinfo_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_query_op* o(static_cast<resolve_query_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + if (owner && owner != &o->io_context_impl_) + { + // The operation is being run on the worker io_context. Time to perform + // the resolver operation. + + // Perform the blocking host resolution operation. + socket_ops::background_getaddrinfo(o->cancel_token_, + o->query_.host_name().c_str(), o->query_.service_name().c_str(), + o->query_.hints(), &o->addrinfo_, o->ec_); + + // Pass operation back to main io_context for completion. + o->io_context_impl_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_context. The completion + // handler is ready to be delivered. + + // Take ownership of the operation's outstanding work. + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, results_type> + handler(o->handler_, o->ec_, results_type()); + p.h = asio::detail::addressof(handler.handler_); + if (o->addrinfo_) + { + handler.arg2_ = results_type::create(o->addrinfo_, + o->query_.host_name(), o->query_.service_name()); + } + p.reset(); + + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + query_type query_; + io_context_impl& io_context_impl_; + Handler handler_; + asio::detail::addrinfo_type* addrinfo_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_RESOLVE_QUERY_OP_HPP diff --git a/lib/asio/detail/resolver_service.hpp b/lib/asio/detail/resolver_service.hpp new file mode 100644 index 0000000..11a94d1 --- /dev/null +++ b/lib/asio/detail/resolver_service.hpp @@ -0,0 +1,145 @@ +// +// detail/resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_RESOLVER_SERVICE_HPP +#define ASIO_DETAIL_RESOLVER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/ip/basic_resolver_results.hpp" +#include "asio/detail/concurrency_hint.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/resolve_endpoint_op.hpp" +#include "asio/detail/resolve_query_op.hpp" +#include "asio/detail/resolver_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol> +class resolver_service : + public service_base<resolver_service<Protocol> >, + public resolver_service_base +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The query type. + typedef asio::ip::basic_resolver_query<Protocol> query_type; + + // The results type. + typedef asio::ip::basic_resolver_results<Protocol> results_type; + + // Constructor. + resolver_service(asio::io_context& io_context) + : service_base<resolver_service<Protocol> >(io_context), + resolver_service_base(io_context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Perform any fork-related housekeeping. + void notify_fork(asio::io_context::fork_event fork_ev) + { + this->base_notify_fork(fork_ev); + } + + // Resolve a query to a list of entries. + results_type resolve(implementation_type&, const query_type& query, + asio::error_code& ec) + { + asio::detail::addrinfo_type* address_info = 0; + + socket_ops::getaddrinfo(query.host_name().c_str(), + query.service_name().c_str(), query.hints(), &address_info, ec); + auto_addrinfo auto_address_info(address_info); + + return ec ? results_type() : results_type::create( + address_info, query.host_name(), query.service_name()); + } + + // Asynchronously resolve a query to a list of entries. + template <typename Handler> + void async_resolve(implementation_type& impl, + const query_type& query, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef resolve_query_op<Protocol, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl, query, io_context_impl_, handler); + + ASIO_HANDLER_CREATION((io_context_impl_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); + + start_resolve_op(p.p); + p.v = p.p = 0; + } + + // Resolve an endpoint to a list of entries. + results_type resolve(implementation_type&, + const endpoint_type& endpoint, asio::error_code& ec) + { + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, + endpoint.protocol().type(), ec); + + return ec ? results_type() : results_type::create( + endpoint, host_name, service_name); + } + + // Asynchronously resolve an endpoint to a list of entries. + template <typename Handler> + 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<Protocol, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl, endpoint, io_context_impl_, handler); + + ASIO_HANDLER_CREATION((io_context_impl_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); + + start_resolve_op(p.p); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP diff --git a/lib/asio/detail/resolver_service_base.hpp b/lib/asio/detail/resolver_service_base.hpp new file mode 100644 index 0000000..10a7922 --- /dev/null +++ b/lib/asio/detail/resolver_service_base.hpp @@ -0,0 +1,140 @@ +// +// detail/resolver_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP +#define ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/io_context.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/resolve_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/thread.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class resolver_service_base +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // Constructor. + ASIO_DECL resolver_service_base(asio::io_context& io_context); + + // Destructor. + ASIO_DECL ~resolver_service_base(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void base_shutdown(); + + // Perform any fork-related housekeeping. + ASIO_DECL void base_notify_fork( + asio::io_context::fork_event fork_ev); + + // Construct a new resolver implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Destroy a resolver implementation. + ASIO_DECL void destroy(implementation_type&); + + // Move-construct a new resolver implementation. + ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another resolver implementation. + ASIO_DECL void move_assign(implementation_type& impl, + resolver_service_base& other_service, + implementation_type& other_impl); + + // Cancel pending asynchronous operations. + ASIO_DECL void cancel(implementation_type& impl); + +protected: + // Helper function to start an asynchronous resolve operation. + ASIO_DECL void start_resolve_op(resolve_op* op); + +#if !defined(ASIO_WINDOWS_RUNTIME) + // Helper class to perform exception-safe cleanup of addrinfo objects. + class auto_addrinfo + : private asio::detail::noncopyable + { + public: + explicit auto_addrinfo(asio::detail::addrinfo_type* ai) + : ai_(ai) + { + } + + ~auto_addrinfo() + { + if (ai_) + socket_ops::freeaddrinfo(ai_); + } + + operator asio::detail::addrinfo_type*() + { + return ai_; + } + + private: + asio::detail::addrinfo_type* ai_; + }; +#endif // !defined(ASIO_WINDOWS_RUNTIME) + + // Helper class to run the work io_context in a thread. + class work_io_context_runner; + + // Start the work thread if it's not already running. + ASIO_DECL void start_work_thread(); + + // The io_context implementation used to post completions. + io_context_impl& io_context_impl_; + +private: + // Mutex to protect access to internal data. + asio::detail::mutex mutex_; + + // Private io_context used for performing asynchronous host resolution. + asio::detail::scoped_ptr<asio::io_context> work_io_context_; + + // The work io_context implementation used to post completions. + io_context_impl& work_io_context_impl_; + + // Work for the private io_context to perform. + asio::executor_work_guard< + asio::io_context::executor_type> work_; + + // Thread used for running the work io_context's run loop. + asio::detail::scoped_ptr<asio::detail::thread> work_thread_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/resolver_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP diff --git a/lib/asio/detail/scheduler.hpp b/lib/asio/detail/scheduler.hpp new file mode 100644 index 0000000..10c29b7 --- /dev/null +++ b/lib/asio/detail/scheduler.hpp @@ -0,0 +1,213 @@ +// +// detail/scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SCHEDULER_HPP +#define ASIO_DETAIL_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/error_code.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/conditionally_enabled_event.hpp" +#include "asio/detail/conditionally_enabled_mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_fwd.hpp" +#include "asio/detail/scheduler_operation.hpp" +#include "asio/detail/thread_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct scheduler_thread_info; + +class scheduler + : public execution_context_service_base<scheduler>, + public thread_context +{ +public: + typedef scheduler_operation operation; + + // Constructor. Specifies the number of concurrent threads that are likely to + // run the scheduler. If set to 1 certain optimisation are performed. + ASIO_DECL scheduler(asio::execution_context& ctx, + int concurrency_hint = 0); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Initialise the task, if required. + ASIO_DECL void init_task(); + + // Run the event loop until interrupted or no more work. + ASIO_DECL std::size_t run(asio::error_code& ec); + + // Run until interrupted or one operation is performed. + ASIO_DECL std::size_t run_one(asio::error_code& ec); + + // Run until timeout, interrupted, or one operation is performed. + ASIO_DECL std::size_t wait_one( + long usec, asio::error_code& ec); + + // Poll for operations without blocking. + ASIO_DECL std::size_t poll(asio::error_code& ec); + + // Poll for one operation without blocking. + ASIO_DECL std::size_t poll_one(asio::error_code& ec); + + // Interrupt the event processing loop. + ASIO_DECL void stop(); + + // Determine whether the scheduler is stopped. + ASIO_DECL bool stopped() const; + + // Restart in preparation for a subsequent run invocation. + ASIO_DECL void restart(); + + // Notify that some work has started. + void work_started() + { + ++outstanding_work_; + } + + // Used to compensate for a forthcoming work_finished call. Must be called + // from within a scheduler-owned thread. + ASIO_DECL void compensating_work_started(); + + // Notify that some work has finished. + void work_finished() + { + if (--outstanding_work_ == 0) + stop(); + } + + // Return whether a handler can be dispatched immediately. + bool can_dispatch() + { + return thread_call_stack::contains(this) != 0; + } + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() has not yet been called for the operation. + ASIO_DECL void post_immediate_completion( + operation* op, bool is_continuation); + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operation. + ASIO_DECL void post_deferred_completion(operation* op); + + // Request invocation of the given operations and return immediately. Assumes + // that work_started() was previously called for each operation. + ASIO_DECL void post_deferred_completions(op_queue<operation>& ops); + + // Enqueue the given operation following a failed attempt to dispatch the + // operation for immediate invocation. + ASIO_DECL void do_dispatch(operation* op); + + // Process unfinished operations as part of a shutdownoperation. Assumes that + // work_started() was previously called for the operations. + ASIO_DECL void abandon_operations(op_queue<operation>& ops); + + // Get the concurrency hint that was used to initialise the scheduler. + int concurrency_hint() const + { + return concurrency_hint_; + } + +private: + // The mutex type used by this scheduler. + typedef conditionally_enabled_mutex mutex; + + // The event type used by this scheduler. + typedef conditionally_enabled_event event; + + // Structure containing thread-specific data. + typedef scheduler_thread_info thread_info; + + // Run at most one operation. May block. + ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock, + thread_info& this_thread, const asio::error_code& ec); + + // Run at most one operation with a timeout. May block. + ASIO_DECL std::size_t do_wait_one(mutex::scoped_lock& lock, + thread_info& this_thread, long usec, const asio::error_code& ec); + + // Poll for at most one operation. + ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock, + thread_info& this_thread, const asio::error_code& ec); + + // Stop the task and all idle threads. + ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock); + + // Wake a single idle thread, or the task, and always unlock the mutex. + ASIO_DECL void wake_one_thread_and_unlock( + mutex::scoped_lock& lock); + + // Helper class to perform task-related operations on block exit. + struct task_cleanup; + friend struct task_cleanup; + + // Helper class to call work-related operations on block exit. + struct work_cleanup; + friend struct work_cleanup; + + // Whether to optimise for single-threaded use cases. + const bool one_thread_; + + // Mutex to protect access to internal data. + mutable mutex mutex_; + + // Event to wake up blocked threads. + event wakeup_event_; + + // The task to be run by this service. + reactor* task_; + + // Operation object to represent the position of the task in the queue. + struct task_operation : operation + { + task_operation() : operation(0) {} + } task_operation_; + + // Whether the task has been interrupted. + bool task_interrupted_; + + // The count of unfinished work. + atomic_count outstanding_work_; + + // The queue of handlers that are ready to be delivered. + op_queue<operation> op_queue_; + + // Flag to indicate that the dispatcher has been stopped. + bool stopped_; + + // Flag to indicate that the dispatcher has been shut down. + bool shutdown_; + + // The concurrency hint used to initialise the scheduler. + const int concurrency_hint_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/scheduler.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_SCHEDULER_HPP diff --git a/lib/asio/detail/scheduler_operation.hpp b/lib/asio/detail/scheduler_operation.hpp new file mode 100644 index 0000000..1c2ce02 --- /dev/null +++ b/lib/asio/detail/scheduler_operation.hpp @@ -0,0 +1,78 @@ +// +// detail/scheduler_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SCHEDULER_OPERATION_HPP +#define ASIO_DETAIL_SCHEDULER_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/error_code.hpp" +#include "asio/detail/handler_tracking.hpp" +#include "asio/detail/op_queue.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class scheduler; + +// Base class for all operations. A function pointer is used instead of virtual +// functions to avoid the associated overhead. +class scheduler_operation ASIO_INHERIT_TRACKED_HANDLER +{ +public: + typedef scheduler_operation operation_type; + + void complete(void* owner, const asio::error_code& ec, + std::size_t bytes_transferred) + { + func_(owner, this, ec, bytes_transferred); + } + + void destroy() + { + func_(0, this, asio::error_code(), 0); + } + +protected: + typedef void (*func_type)(void*, + scheduler_operation*, + const asio::error_code&, std::size_t); + + scheduler_operation(func_type func) + : next_(0), + func_(func), + task_result_(0) + { + } + + // Prevents deletion through this type. + ~scheduler_operation() + { + } + +private: + friend class op_queue_access; + scheduler_operation* next_; + func_type func_; +protected: + friend class scheduler; + unsigned int task_result_; // Passed into bytes transferred. +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SCHEDULER_OPERATION_HPP diff --git a/lib/asio/detail/scheduler_thread_info.hpp b/lib/asio/detail/scheduler_thread_info.hpp new file mode 100644 index 0000000..2ffe013 --- /dev/null +++ b/lib/asio/detail/scheduler_thread_info.hpp @@ -0,0 +1,40 @@ +// +// detail/scheduler_thread_info.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP +#define ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/op_queue.hpp" +#include "asio/detail/thread_info_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class scheduler; +class scheduler_operation; + +struct scheduler_thread_info : public thread_info_base +{ + op_queue<scheduler_operation> private_op_queue; + long private_outstanding_work; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP diff --git a/lib/asio/detail/scoped_lock.hpp b/lib/asio/detail/scoped_lock.hpp new file mode 100644 index 0000000..6cbce38 --- /dev/null +++ b/lib/asio/detail/scoped_lock.hpp @@ -0,0 +1,101 @@ +// +// detail/scoped_lock.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SCOPED_LOCK_HPP +#define ASIO_DETAIL_SCOPED_LOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper class to lock and unlock a mutex automatically. +template <typename Mutex> +class scoped_lock + : private noncopyable +{ +public: + // Tag type used to distinguish constructors. + enum adopt_lock_t { adopt_lock }; + + // Constructor adopts a lock that is already held. + scoped_lock(Mutex& m, adopt_lock_t) + : mutex_(m), + locked_(true) + { + } + + // Constructor acquires the lock. + explicit scoped_lock(Mutex& m) + : mutex_(m) + { + mutex_.lock(); + locked_ = true; + } + + // Destructor releases the lock. + ~scoped_lock() + { + if (locked_) + mutex_.unlock(); + } + + // Explicitly acquire the lock. + void lock() + { + if (!locked_) + { + mutex_.lock(); + locked_ = true; + } + } + + // Explicitly release the lock. + void unlock() + { + if (locked_) + { + mutex_.unlock(); + locked_ = false; + } + } + + // Test whether the lock is held. + bool locked() const + { + return locked_; + } + + // Get the underlying mutex. + Mutex& mutex() + { + return mutex_; + } + +private: + // The underlying mutex. + Mutex& mutex_; + + // Whether the mutex is currently locked or unlocked. + bool locked_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SCOPED_LOCK_HPP diff --git a/lib/asio/detail/scoped_ptr.hpp b/lib/asio/detail/scoped_ptr.hpp new file mode 100644 index 0000000..3449c53 --- /dev/null +++ b/lib/asio/detail/scoped_ptr.hpp @@ -0,0 +1,87 @@ +// +// detail/scoped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SCOPED_PTR_HPP +#define ASIO_DETAIL_SCOPED_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +class scoped_ptr +{ +public: + // Constructor. + explicit scoped_ptr(T* p = 0) + : p_(p) + { + } + + // Destructor. + ~scoped_ptr() + { + delete p_; + } + + // Access. + T* get() + { + return p_; + } + + // Access. + T* operator->() + { + return p_; + } + + // Dereference. + T& operator*() + { + return *p_; + } + + // Reset pointer. + void reset(T* p = 0) + { + delete p_; + p_ = p; + } + + // Release ownership of the pointer. + T* release() + { + T* tmp = p_; + p_ = 0; + return tmp; + } + +private: + // Disallow copying and assignment. + scoped_ptr(const scoped_ptr&); + scoped_ptr& operator=(const scoped_ptr&); + + T* p_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SCOPED_PTR_HPP diff --git a/lib/asio/detail/select_interrupter.hpp b/lib/asio/detail/select_interrupter.hpp new file mode 100644 index 0000000..1a07599 --- /dev/null +++ b/lib/asio/detail/select_interrupter.hpp @@ -0,0 +1,46 @@ +// +// detail/select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SELECT_INTERRUPTER_HPP +#define ASIO_DETAIL_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) +# include "asio/detail/socket_select_interrupter.hpp" +#elif defined(ASIO_HAS_EVENTFD) +# include "asio/detail/eventfd_select_interrupter.hpp" +#else +# include "asio/detail/pipe_select_interrupter.hpp" +#endif + +namespace asio { +namespace detail { + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) +typedef socket_select_interrupter select_interrupter; +#elif defined(ASIO_HAS_EVENTFD) +typedef eventfd_select_interrupter select_interrupter; +#else +typedef pipe_select_interrupter select_interrupter; +#endif + +} // namespace detail +} // namespace asio + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP diff --git a/lib/asio/detail/select_reactor.hpp b/lib/asio/detail/select_reactor.hpp new file mode 100644 index 0000000..0996549 --- /dev/null +++ b/lib/asio/detail/select_reactor.hpp @@ -0,0 +1,238 @@ +// +// detail/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SELECT_REACTOR_HPP +#define ASIO_DETAIL_SELECT_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) \ + || (!defined(ASIO_HAS_DEV_POLL) \ + && !defined(ASIO_HAS_EPOLL) \ + && !defined(ASIO_HAS_KQUEUE) \ + && !defined(ASIO_WINDOWS_RUNTIME)) + +#include <cstddef> +#include "asio/detail/fd_set_adapter.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/select_interrupter.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/execution_context.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/thread.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class select_reactor + : public execution_context_service_base<select_reactor> +{ +public: +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + enum op_types { read_op = 0, write_op = 1, except_op = 2, + max_select_ops = 3, connect_op = 3, max_ops = 4 }; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + enum op_types { read_op = 0, write_op = 1, except_op = 2, + max_select_ops = 3, connect_op = 1, max_ops = 3 }; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + + // Per-descriptor data. + struct per_descriptor_data + { + }; + + // Constructor. + ASIO_DECL select_reactor(asio::execution_context& ctx); + + // Destructor. + ASIO_DECL ~select_reactor(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + ASIO_DECL void notify_fork( + asio::execution_context::fork_event fork_ev); + + // Initialise the task, but only if the reactor is not in its own thread. + ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool is_continuation, bool); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data&, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data&); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&); + + // Move descriptor registration from one descriptor_data object to another. + ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Add a new timer queue to the reactor. + template <typename Time_Traits> + void add_timer_queue(timer_queue<Time_Traits>& queue); + + // Remove a timer queue from the reactor. + template <typename Time_Traits> + void remove_timer_queue(timer_queue<Time_Traits>& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template <typename Time_Traits> + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template <typename Time_Traits> + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source); + + // Run select once until interrupted or events are ready to be dispatched. + ASIO_DECL void run(long usec, op_queue<operation>& ops); + + // Interrupt the select loop. + ASIO_DECL void interrupt(); + +private: +#if defined(ASIO_HAS_IOCP) + // Run the select loop in the thread. + ASIO_DECL void run_thread(); +#endif // defined(ASIO_HAS_IOCP) + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Get the timeout value for the select call. + ASIO_DECL timeval* get_timeout(long usec, timeval& tv); + + // Cancel all operations associated with the given descriptor. This function + // does not acquire the select_reactor's mutex. + ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const asio::error_code& ec); + + // The scheduler implementation used to post completions. +# if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_type; +# else // defined(ASIO_HAS_IOCP) + typedef class scheduler scheduler_type; +# endif // defined(ASIO_HAS_IOCP) + scheduler_type& scheduler_; + + // Mutex to protect access to internal data. + asio::detail::mutex mutex_; + + // The interrupter is used to break a blocking select call. + select_interrupter interrupter_; + + // The queues of read, write and except operations. + reactor_op_queue<socket_type> op_queue_[max_ops]; + + // The file descriptor sets to be passed to the select system call. + fd_set_adapter fd_sets_[max_select_ops]; + + // The timer queues. + timer_queue_set timer_queues_; + +#if defined(ASIO_HAS_IOCP) + // Helper class to run the reactor loop in a thread. + class thread_function; + friend class thread_function; + + // Does the reactor loop thread need to stop. + bool stop_thread_; + + // The thread that is running the reactor loop. + asio::detail::thread* thread_; +#endif // defined(ASIO_HAS_IOCP) + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/select_reactor.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/select_reactor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + // || (!defined(ASIO_HAS_DEV_POLL) + // && !defined(ASIO_HAS_EPOLL) + // && !defined(ASIO_HAS_KQUEUE) + // && !defined(ASIO_WINDOWS_RUNTIME)) + +#endif // ASIO_DETAIL_SELECT_REACTOR_HPP diff --git a/lib/asio/detail/service_registry.hpp b/lib/asio/detail/service_registry.hpp new file mode 100644 index 0000000..cda6307 --- /dev/null +++ b/lib/asio/detail/service_registry.hpp @@ -0,0 +1,164 @@ +// +// detail/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SERVICE_REGISTRY_HPP +#define ASIO_DETAIL_SERVICE_REGISTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <typeinfo> +#include "asio/detail/mutex.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +class io_context; + +namespace detail { + +template <typename T> +class typeid_wrapper {}; + +class service_registry + : private noncopyable +{ +public: + // Constructor. + ASIO_DECL service_registry(execution_context& owner); + + // Destructor. + ASIO_DECL ~service_registry(); + + // Shutdown all services. + ASIO_DECL void shutdown_services(); + + // Destroy all services. + ASIO_DECL void destroy_services(); + + // Notify all services of a fork event. + ASIO_DECL void notify_fork(execution_context::fork_event fork_ev); + + // Get the service object corresponding to the specified service type. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. + template <typename Service> + Service& use_service(); + + // Get the service object corresponding to the specified service type. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. + // This overload is used for backwards compatibility with services that + // inherit from io_context::service. + template <typename Service> + Service& use_service(io_context& owner); + + // Add a service object. Throws on error, in which case ownership of the + // object is retained by the caller. + template <typename Service> + void add_service(Service* new_service); + + // Check whether a service object of the specified type already exists. + template <typename Service> + bool has_service() const; + +private: + // Initalise a service's key when the key_type typedef is not available. + template <typename Service> + static void init_key(execution_context::service::key& key, ...); + +#if !defined(ASIO_NO_TYPEID) + // Initalise a service's key when the key_type typedef is available. + template <typename Service> + static void init_key(execution_context::service::key& key, + typename enable_if< + is_base_of<typename Service::key_type, Service>::value>::type*); +#endif // !defined(ASIO_NO_TYPEID) + + // Initialise a service's key based on its id. + ASIO_DECL static void init_key_from_id( + execution_context::service::key& key, + const execution_context::id& id); + +#if !defined(ASIO_NO_TYPEID) + // Initialise a service's key based on its id. + template <typename Service> + static void init_key_from_id(execution_context::service::key& key, + const service_id<Service>& /*id*/); +#endif // !defined(ASIO_NO_TYPEID) + + // Check if a service matches the given id. + ASIO_DECL static bool keys_match( + const execution_context::service::key& key1, + const execution_context::service::key& key2); + + // The type of a factory function used for creating a service instance. + typedef execution_context::service*(*factory_type)(void*); + + // Factory function for creating a service instance. + template <typename Service, typename Owner> + static execution_context::service* create(void* owner); + + // Destroy a service instance. + ASIO_DECL static void destroy(execution_context::service* service); + + // Helper class to manage service pointers. + struct auto_service_ptr; + friend struct auto_service_ptr; + struct auto_service_ptr + { + execution_context::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. + ASIO_DECL execution_context::service* do_use_service( + const execution_context::service::key& key, + factory_type factory, void* owner); + + // Add a service object. Throws on error, in which case ownership of the + // object is retained by the caller. + ASIO_DECL void do_add_service( + const execution_context::service::key& key, + execution_context::service* new_service); + + // Check whether a service object with the specified key already exists. + ASIO_DECL bool do_has_service( + const execution_context::service::key& key) const; + + // Mutex to protect access to internal data. + mutable asio::detail::mutex mutex_; + + // The owner of this service registry and the services it contains. + execution_context& owner_; + + // The first service in the list of contained services. + execution_context::service* first_service_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/service_registry.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/service_registry.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP diff --git a/lib/asio/detail/signal_blocker.hpp b/lib/asio/detail/signal_blocker.hpp new file mode 100644 index 0000000..b684295 --- /dev/null +++ b/lib/asio/detail/signal_blocker.hpp @@ -0,0 +1,44 @@ +// +// detail/signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SIGNAL_BLOCKER_HPP +#define ASIO_DETAIL_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) || defined(ASIO_WINDOWS) \ + || defined(ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) || defined(__SYMBIAN32__) +# include "asio/detail/null_signal_blocker.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_signal_blocker.hpp" +#else +# error Only Windows and POSIX are supported! +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) || defined(ASIO_WINDOWS) \ + || defined(ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) || defined(__SYMBIAN32__) +typedef null_signal_blocker signal_blocker; +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_signal_blocker signal_blocker; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP diff --git a/lib/asio/detail/signal_handler.hpp b/lib/asio/detail/signal_handler.hpp new file mode 100644 index 0000000..d1c9910 --- /dev/null +++ b/lib/asio/detail/signal_handler.hpp @@ -0,0 +1,86 @@ +// +// detail/signal_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SIGNAL_HANDLER_HPP +#define ASIO_DETAIL_SIGNAL_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/signal_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class signal_handler : public signal_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(signal_handler); + + signal_handler(Handler& h) + : signal_op(&signal_handler::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(h)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + signal_handler* h(static_cast<signal_handler*>(base)); + ptr p = { asio::detail::addressof(h->handler_), h, h }; + handler_work<Handler> w(h->handler_); + + ASIO_HANDLER_COMPLETION((*h)); + + // 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, asio::error_code, int> + handler(h->handler_, h->ec_, h->signal_number_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SIGNAL_HANDLER_HPP diff --git a/lib/asio/detail/signal_init.hpp b/lib/asio/detail/signal_init.hpp new file mode 100644 index 0000000..814ff51 --- /dev/null +++ b/lib/asio/detail/signal_init.hpp @@ -0,0 +1,47 @@ +// +// detail/signal_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SIGNAL_INIT_HPP +#define ASIO_DETAIL_SIGNAL_INIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include <csignal> + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <int Signal = SIGPIPE> +class signal_init +{ +public: + // Constructor. + signal_init() + { + std::signal(Signal, SIG_IGN); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#endif // ASIO_DETAIL_SIGNAL_INIT_HPP diff --git a/lib/asio/detail/signal_op.hpp b/lib/asio/detail/signal_op.hpp new file mode 100644 index 0000000..c4e364c --- /dev/null +++ b/lib/asio/detail/signal_op.hpp @@ -0,0 +1,49 @@ +// +// detail/signal_op.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SIGNAL_OP_HPP +#define ASIO_DETAIL_SIGNAL_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class signal_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + + // The signal number to be passed to the completion handler. + int signal_number_; + +protected: + signal_op(func_type func) + : operation(func), + signal_number_(0) + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SIGNAL_OP_HPP diff --git a/lib/asio/detail/signal_set_service.hpp b/lib/asio/detail/signal_set_service.hpp new file mode 100644 index 0000000..a18ab70 --- /dev/null +++ b/lib/asio/detail/signal_set_service.hpp @@ -0,0 +1,217 @@ +// +// detail/signal_set_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP +#define ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <cstddef> +#include <signal.h> +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/signal_handler.hpp" +#include "asio/detail/signal_op.hpp" +#include "asio/detail/socket_types.hpp" + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) +# include "asio/detail/reactor.hpp" +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(NSIG) && (NSIG > 0) +enum { max_signal_number = NSIG }; +#else +enum { max_signal_number = 128 }; +#endif + +extern ASIO_DECL struct signal_state* get_signal_state(); + +extern "C" ASIO_DECL void asio_signal_handler(int signal_number); + +class signal_set_service : + public service_base<signal_set_service> +{ +public: + // Type used for tracking an individual signal registration. + class registration + { + public: + // Default constructor. + registration() + : signal_number_(0), + queue_(0), + undelivered_(0), + next_in_table_(0), + prev_in_table_(0), + next_in_set_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class signal_set_service; + + // The signal number that is registered. + int signal_number_; + + // The waiting signal handlers. + op_queue<signal_op>* queue_; + + // The number of undelivered signals. + std::size_t undelivered_; + + // Pointers to adjacent registrations in the registrations_ table. + registration* next_in_table_; + registration* prev_in_table_; + + // Link to next registration in the signal set. + registration* next_in_set_; + }; + + // The implementation type of the signal_set. + class implementation_type + { + public: + // Default constructor. + implementation_type() + : signals_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class signal_set_service; + + // The pending signal handlers. + op_queue<signal_op> queue_; + + // Linked list of registered signals. + registration* signals_; + }; + + // Constructor. + ASIO_DECL signal_set_service(asio::io_context& io_context); + + // Destructor. + ASIO_DECL ~signal_set_service(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Perform fork-related housekeeping. + ASIO_DECL void notify_fork( + asio::io_context::fork_event fork_ev); + + // Construct a new signal_set implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Destroy a signal_set implementation. + ASIO_DECL void destroy(implementation_type& impl); + + // Add a signal to a signal_set. + ASIO_DECL asio::error_code add(implementation_type& impl, + int signal_number, asio::error_code& ec); + + // Remove a signal to a signal_set. + ASIO_DECL asio::error_code remove(implementation_type& impl, + int signal_number, asio::error_code& ec); + + // Remove all signals from a signal_set. + ASIO_DECL asio::error_code clear(implementation_type& impl, + asio::error_code& ec); + + // Cancel all operations associated with the signal set. + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); + + // Start an asynchronous operation to wait for a signal to be delivered. + template <typename Handler> + void async_wait(implementation_type& impl, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef signal_handler<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((io_context_.context(), + *p.p, "signal_set", &impl, 0, "async_wait")); + + start_wait_op(impl, p.p); + p.v = p.p = 0; + } + + // Deliver notification that a particular signal occurred. + ASIO_DECL static void deliver_signal(int signal_number); + +private: + // Helper function to add a service to the global signal state. + ASIO_DECL static void add_service(signal_set_service* service); + + // Helper function to remove a service from the global signal state. + ASIO_DECL static void remove_service(signal_set_service* service); + + // Helper function to create the pipe descriptors. + ASIO_DECL static void open_descriptors(); + + // Helper function to close the pipe descriptors. + ASIO_DECL static void close_descriptors(); + + // Helper function to start a wait operation. + ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op); + + // The io_context instance used for dispatching handlers. + io_context_impl& io_context_; + +#if !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + // The type used for registering for pipe reactor notifications. + class pipe_read_op; + + // The reactor used for waiting for pipe readiness. + reactor& reactor_; + + // The per-descriptor reactor data used for the pipe. + reactor::per_descriptor_data reactor_data_; +#endif // !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + + // A mapping from signal number to the registered signal sets. + registration* registrations_[max_signal_number]; + + // Pointers to adjacent services in linked list. + signal_set_service* next_; + signal_set_service* prev_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/signal_set_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP diff --git a/lib/asio/detail/socket_holder.hpp b/lib/asio/detail/socket_holder.hpp new file mode 100644 index 0000000..99b081f --- /dev/null +++ b/lib/asio/detail/socket_holder.hpp @@ -0,0 +1,98 @@ +// +// detail/socket_holder.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SOCKET_HOLDER_HPP +#define ASIO_DETAIL_SOCKET_HOLDER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Implement the resource acquisition is initialisation idiom for sockets. +class socket_holder + : private noncopyable +{ +public: + // Construct as an uninitialised socket. + socket_holder() + : socket_(invalid_socket) + { + } + + // Construct to take ownership of the specified socket. + explicit socket_holder(socket_type s) + : socket_(s) + { + } + + // Destructor. + ~socket_holder() + { + if (socket_ != invalid_socket) + { + asio::error_code ec; + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); + } + } + + // Get the underlying socket. + socket_type get() const + { + return socket_; + } + + // Reset to an uninitialised socket. + void reset() + { + if (socket_ != invalid_socket) + { + asio::error_code ec; + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); + socket_ = invalid_socket; + } + } + + // Reset to take ownership of the specified socket. + void reset(socket_type s) + { + reset(); + socket_ = s; + } + + // Release ownership of the socket. + socket_type release() + { + socket_type tmp = socket_; + socket_ = invalid_socket; + return tmp; + } + +private: + // The underlying socket. + socket_type socket_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SOCKET_HOLDER_HPP diff --git a/lib/asio/detail/socket_ops.hpp b/lib/asio/detail/socket_ops.hpp new file mode 100644 index 0000000..815b0d1 --- /dev/null +++ b/lib/asio/detail/socket_ops.hpp @@ -0,0 +1,337 @@ +// +// detail/socket_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SOCKET_OPS_HPP +#define ASIO_DETAIL_SOCKET_OPS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/error_code.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace socket_ops { + +// Socket state bits. +enum +{ + // The user wants a non-blocking socket. + user_set_non_blocking = 1, + + // The socket has been set non-blocking. + internal_non_blocking = 2, + + // Helper "state" used to determine whether the socket is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, + + // 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. + user_set_linger = 8, + + // The socket is stream-oriented. + stream_oriented = 16, + + // The socket is datagram-oriented. + datagram_oriented = 32, + + // The socket may have been dup()-ed. + possible_dup = 64 +}; + +typedef unsigned char state_type; + +struct noop_deleter { void operator()(void*) {} }; +typedef shared_ptr<void> shared_cancel_token_type; +typedef weak_ptr<void> weak_cancel_token_type; + +#if !defined(ASIO_WINDOWS_RUNTIME) + +ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL socket_type sync_accept(socket_type s, + state_type state, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, socket_type& new_socket); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL int close(socket_type s, state_type& state, + bool destruction, asio::error_code& ec); + +ASIO_DECL bool set_user_non_blocking(socket_type s, + state_type& state, bool value, asio::error_code& ec); + +ASIO_DECL bool set_internal_non_blocking(socket_type s, + state_type& state, bool value, asio::error_code& ec); + +ASIO_DECL int shutdown(socket_type s, + int what, asio::error_code& ec); + +ASIO_DECL int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_connect(socket_type s, + asio::error_code& ec); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_connect(socket_type s, + asio::error_code& ec); + +ASIO_DECL int socketpair(int af, int type, int protocol, + socket_type sv[2], asio::error_code& ec); + +ASIO_DECL bool sockatmark(socket_type s, asio::error_code& ec); + +ASIO_DECL size_t available(socket_type s, asio::error_code& ec); + +ASIO_DECL int listen(socket_type s, + int backlog, asio::error_code& ec); + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef WSABUF buf; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef iovec buf; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +ASIO_DECL void init_buf(buf& b, void* data, size_t size); + +ASIO_DECL void init_buf(buf& b, const void* data, size_t size); + +ASIO_DECL signed_size_type recv(socket_type s, buf* bufs, + size_t count, int flags, asio::error_code& ec); + +ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + asio::error_code& ec, size_t bytes_transferred); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs, + size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state, + buf* bufs, size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL signed_size_type recvmsg(socket_type s, buf* bufs, + size_t count, int in_flags, int& out_flags, + asio::error_code& ec); + +ASIO_DECL size_t sync_recvmsg(socket_type s, state_type state, + buf* bufs, size_t count, int in_flags, int& out_flags, + asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_recvmsg( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_recvmsg(socket_type s, + buf* bufs, size_t count, int in_flags, int& out_flags, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL signed_size_type send(socket_type s, const buf* bufs, + size_t count, int flags, asio::error_code& ec); + +ASIO_DECL size_t sync_send(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, + bool all_empty, asio::error_code& ec); + +#if defined(ASIO_HAS_IOCP) + +ASIO_DECL void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + asio::error_code& ec); + +#else // defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL signed_size_type sendto(socket_type s, const buf* bufs, + size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL size_t sync_sendto(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec); + +#if !defined(ASIO_HAS_IOCP) + +ASIO_DECL bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec, size_t& bytes_transferred); + +#endif // !defined(ASIO_HAS_IOCP) + +ASIO_DECL socket_type socket(int af, int type, int protocol, + asio::error_code& ec); + +ASIO_DECL int setsockopt(socket_type s, state_type& state, + int level, int optname, const void* optval, + std::size_t optlen, asio::error_code& ec); + +ASIO_DECL int getsockopt(socket_type s, state_type state, + int level, int optname, void* optval, + size_t* optlen, asio::error_code& ec); + +ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, asio::error_code& ec); + +ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL int ioctl(socket_type s, state_type& state, + int cmd, ioctl_arg_type* arg, asio::error_code& ec); + +ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, asio::error_code& ec); + +ASIO_DECL int poll_read(socket_type s, + state_type state, int msec, asio::error_code& ec); + +ASIO_DECL int poll_write(socket_type s, + state_type state, int msec, asio::error_code& ec); + +ASIO_DECL int poll_error(socket_type s, + state_type state, int msec, asio::error_code& ec); + +ASIO_DECL int poll_connect(socket_type s, + int msec, asio::error_code& ec); + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest, + size_t length, unsigned long scope_id, asio::error_code& ec); + +ASIO_DECL int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, asio::error_code& ec); + +ASIO_DECL int gethostname(char* name, + int namelen, asio::error_code& ec); + +#if !defined(ASIO_WINDOWS_RUNTIME) + +ASIO_DECL asio::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec); + +ASIO_DECL asio::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, asio::error_code& ec); + +ASIO_DECL void freeaddrinfo(addrinfo_type* ai); + +ASIO_DECL asio::error_code getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int flags, asio::error_code& ec); + +ASIO_DECL asio::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec); + +ASIO_DECL asio::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, asio::error_code& ec); + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +ASIO_DECL u_long_type network_to_host_long(u_long_type value); + +ASIO_DECL u_long_type host_to_network_long(u_long_type value); + +ASIO_DECL u_short_type network_to_host_short(u_short_type value); + +ASIO_DECL u_short_type host_to_network_short(u_short_type value); + +} // namespace socket_ops +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/socket_ops.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_SOCKET_OPS_HPP diff --git a/lib/asio/detail/socket_option.hpp b/lib/asio/detail/socket_option.hpp new file mode 100644 index 0000000..6852d56 --- /dev/null +++ b/lib/asio/detail/socket_option.hpp @@ -0,0 +1,316 @@ +// +// detail/socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SOCKET_OPTION_HPP +#define ASIO_DETAIL_SOCKET_OPTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cstddef> +#include <stdexcept> +#include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_exception.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace socket_option { + +// Helper template for implementing boolean-based options. +template <int Level, int Name> +class boolean +{ +public: + // Default constructor. + boolean() + : value_(0) + { + } + + // Construct with a specific option value. + explicit boolean(bool v) + : value_(v ? 1 : 0) + { + } + + // Set the current value of the boolean. + boolean& operator=(bool v) + { + value_ = v ? 1 : 0; + return *this; + } + + // Get the current value of the boolean. + bool value() const + { + return !!value_; + } + + // Convert to bool. + operator bool() const + { + return !!value_; + } + + // Test for false. + bool operator!() const + { + return !value_; + } + + // Get the level of the socket option. + template <typename Protocol> + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template <typename Protocol> + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the boolean data. + template <typename Protocol> + int* data(const Protocol&) + { + return &value_; + } + + // Get the address of the boolean data. + template <typename Protocol> + const int* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the boolean data. + template <typename Protocol> + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the boolean data. + template <typename Protocol> + void resize(const Protocol&, std::size_t s) + { + // On some platforms (e.g. Windows Vista), the getsockopt function will + // return the size of a boolean socket option as one byte, even though a + // four byte integer was passed in. + switch (s) + { + case sizeof(char): + value_ = *reinterpret_cast<char*>(&value_) ? 1 : 0; + break; + case sizeof(value_): + break; + default: + { + std::length_error ex("boolean socket option resize"); + asio::detail::throw_exception(ex); + } + } + } + +private: + int value_; +}; + +// Helper template for implementing integer options. +template <int Level, int Name> +class integer +{ +public: + // Default constructor. + integer() + : value_(0) + { + } + + // Construct with a specific option value. + explicit integer(int v) + : value_(v) + { + } + + // Set the value of the int option. + integer& operator=(int v) + { + value_ = v; + return *this; + } + + // Get the current value of the int option. + int value() const + { + return value_; + } + + // Get the level of the socket option. + template <typename Protocol> + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template <typename Protocol> + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the int data. + template <typename Protocol> + int* data(const Protocol&) + { + return &value_; + } + + // Get the address of the int data. + template <typename Protocol> + const int* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the int data. + template <typename Protocol> + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the int data. + template <typename Protocol> + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + { + std::length_error ex("integer socket option resize"); + asio::detail::throw_exception(ex); + } + } + +private: + int value_; +}; + +// Helper template for implementing linger options. +template <int Level, int Name> +class linger +{ +public: + // Default constructor. + linger() + { + value_.l_onoff = 0; + value_.l_linger = 0; + } + + // Construct with specific option values. + linger(bool e, int t) + { + enabled(e); + timeout ASIO_PREVENT_MACRO_SUBSTITUTION(t); + } + + // Set the value for whether linger is enabled. + void enabled(bool value) + { + value_.l_onoff = value ? 1 : 0; + } + + // Get the value for whether linger is enabled. + bool enabled() const + { + return value_.l_onoff != 0; + } + + // Set the value for the linger timeout. + void timeout ASIO_PREVENT_MACRO_SUBSTITUTION(int value) + { +#if defined(WIN32) + value_.l_linger = static_cast<u_short>(value); +#else + value_.l_linger = value; +#endif + } + + // Get the value for the linger timeout. + int timeout ASIO_PREVENT_MACRO_SUBSTITUTION() const + { + return static_cast<int>(value_.l_linger); + } + + // Get the level of the socket option. + template <typename Protocol> + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template <typename Protocol> + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the linger data. + template <typename Protocol> + detail::linger_type* data(const Protocol&) + { + return &value_; + } + + // Get the address of the linger data. + template <typename Protocol> + const detail::linger_type* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the linger data. + template <typename Protocol> + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the int data. + template <typename Protocol> + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + { + std::length_error ex("linger socket option resize"); + asio::detail::throw_exception(ex); + } + } + +private: + detail::linger_type value_; +}; + +} // namespace socket_option +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SOCKET_OPTION_HPP diff --git a/lib/asio/detail/socket_select_interrupter.hpp b/lib/asio/detail/socket_select_interrupter.hpp new file mode 100644 index 0000000..7351070 --- /dev/null +++ b/lib/asio/detail/socket_select_interrupter.hpp @@ -0,0 +1,91 @@ +// +// detail/socket_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP +#define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_WINDOWS_RUNTIME) + +#if defined(ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class socket_select_interrupter +{ +public: + // Constructor. + ASIO_DECL socket_select_interrupter(); + + // Destructor. + ASIO_DECL ~socket_select_interrupter(); + + // Recreate the interrupter's descriptors. Used after a fork. + ASIO_DECL void recreate(); + + // Interrupt the select call. + ASIO_DECL void interrupt(); + + // Reset the select interrupt. Returns true if the call was interrupted. + ASIO_DECL bool reset(); + + // Get the read descriptor to be passed to select. + socket_type read_descriptor() const + { + return read_descriptor_; + } + +private: + // Open the descriptors. Throws on error. + ASIO_DECL void open_descriptors(); + + // Close the descriptors. + ASIO_DECL void close_descriptors(); + + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // byte will be written on the other end of the connection and this + // descriptor will become readable. + socket_type read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // byte may be written to this to wake up the select which is waiting for the + // other end to become readable. + socket_type write_descriptor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/socket_select_interrupter.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // !defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP diff --git a/lib/asio/detail/socket_types.hpp b/lib/asio/detail/socket_types.hpp new file mode 100644 index 0000000..d354343 --- /dev/null +++ b/lib/asio/detail/socket_types.hpp @@ -0,0 +1,416 @@ +// +// detail/socket_types.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SOCKET_TYPES_HPP +#define ASIO_DETAIL_SOCKET_TYPES_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +// Empty. +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) +# error WinSock.h has already been included +# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) +# if defined(__BORLANDC__) +# include <stdlib.h> // Needed for __errno +# if !defined(_WSPIAPI_H_) +# define _WSPIAPI_H_ +# define ASIO_WSPIAPI_H_DEFINED +# endif // !defined(_WSPIAPI_H_) +# endif // defined(__BORLANDC__) +# include <winsock2.h> +# include <ws2tcpip.h> +# if defined(WINAPI_FAMILY) +# if ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0) +# include <windows.h> +# endif // ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0) +# endif // defined(WINAPI_FAMILY) +# if !defined(ASIO_WINDOWS_APP) +# include <mswsock.h> +# endif // !defined(ASIO_WINDOWS_APP) +# if defined(ASIO_WSPIAPI_H_DEFINED) +# undef _WSPIAPI_H_ +# undef ASIO_WSPIAPI_H_DEFINED +# endif // defined(ASIO_WSPIAPI_H_DEFINED) +# if !defined(ASIO_NO_DEFAULT_LINKED_LIBS) +# if defined(UNDER_CE) +# pragma comment(lib, "ws2.lib") +# elif defined(_MSC_VER) || defined(__BORLANDC__) +# pragma comment(lib, "ws2_32.lib") +# if !defined(ASIO_WINDOWS_APP) +# pragma comment(lib, "mswsock.lib") +# endif // !defined(ASIO_WINDOWS_APP) +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# endif // !defined(ASIO_NO_DEFAULT_LINKED_LIBS) +# include "asio/detail/old_win_sdk_compat.hpp" +#else +# include <sys/ioctl.h> +# if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) || defined(__NetBSD__) \ + || defined(__OpenBSD__) || defined(__linux__) \ + || defined(__EMSCRIPTEN__) +# include <poll.h> +# elif !defined(__SYMBIAN32__) +# include <sys/poll.h> +# endif +# include <sys/types.h> +# include <sys/stat.h> +# include <fcntl.h> +# if defined(__hpux) +# include <sys/time.h> +# endif +# if !defined(__hpux) || defined(__SELECT) +# include <sys/select.h> +# endif +# include <sys/socket.h> +# include <sys/uio.h> +# include <sys/un.h> +# include <netinet/in.h> +# if !defined(__SYMBIAN32__) +# include <netinet/tcp.h> +# endif +# include <arpa/inet.h> +# include <netdb.h> +# include <net/if.h> +# include <limits.h> +# if defined(__sun) +# include <sys/filio.h> +# include <sys/sockio.h> +# endif +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_WINDOWS_RUNTIME) +const int max_addr_v4_str_len = 256; +const int max_addr_v6_str_len = 256; +typedef unsigned __int32 u_long_type; +typedef unsigned __int16 u_short_type; +struct in4_addr_type { u_long_type s_addr; }; +struct in4_mreq_type { in4_addr_type imr_multiaddr, imr_interface; }; +struct in6_addr_type { unsigned char s6_addr[16]; }; +struct in6_mreq_type { in6_addr_type ipv6mr_multiaddr; + unsigned long ipv6mr_interface; }; +struct socket_addr_type { int sa_family; }; +struct sockaddr_in4_type { int sin_family; + in4_addr_type sin_addr; u_short_type sin_port; }; +struct sockaddr_in6_type { int sin6_family; + in6_addr_type sin6_addr; u_short_type sin6_port; + u_long_type sin6_flowinfo; u_long_type sin6_scope_id; }; +struct sockaddr_storage_type { int ss_family; + unsigned char ss_bytes[128 - sizeof(int)]; }; +struct addrinfo_type { int ai_flags; + int ai_family, ai_socktype, ai_protocol; + int ai_addrlen; const void* ai_addr; + const char* ai_canonname; addrinfo_type* ai_next; }; +struct linger_type { u_short_type l_onoff, l_linger; }; +typedef u_long_type ioctl_arg_type; +typedef int signed_size_type; +# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c +# define ASIO_OS_DEF_AF_UNSPEC 0 +# define ASIO_OS_DEF_AF_INET 2 +# define ASIO_OS_DEF_AF_INET6 23 +# define ASIO_OS_DEF_SOCK_STREAM 1 +# define ASIO_OS_DEF_SOCK_DGRAM 2 +# define ASIO_OS_DEF_SOCK_RAW 3 +# define ASIO_OS_DEF_SOCK_SEQPACKET 5 +# define ASIO_OS_DEF_IPPROTO_IP 0 +# define ASIO_OS_DEF_IPPROTO_IPV6 41 +# define ASIO_OS_DEF_IPPROTO_TCP 6 +# define ASIO_OS_DEF_IPPROTO_UDP 17 +# define ASIO_OS_DEF_IPPROTO_ICMP 1 +# define ASIO_OS_DEF_IPPROTO_ICMPV6 58 +# define ASIO_OS_DEF_FIONBIO 1 +# define ASIO_OS_DEF_FIONREAD 2 +# define ASIO_OS_DEF_INADDR_ANY 0 +# define ASIO_OS_DEF_MSG_OOB 0x1 +# define ASIO_OS_DEF_MSG_PEEK 0x2 +# define ASIO_OS_DEF_MSG_DONTROUTE 0x4 +# define ASIO_OS_DEF_MSG_EOR 0 // Not supported. +# define ASIO_OS_DEF_SHUT_RD 0x0 +# define ASIO_OS_DEF_SHUT_WR 0x1 +# define ASIO_OS_DEF_SHUT_RDWR 0x2 +# define ASIO_OS_DEF_SOMAXCONN 0x7fffffff +# define ASIO_OS_DEF_SOL_SOCKET 0xffff +# define ASIO_OS_DEF_SO_BROADCAST 0x20 +# define ASIO_OS_DEF_SO_DEBUG 0x1 +# define ASIO_OS_DEF_SO_DONTROUTE 0x10 +# define ASIO_OS_DEF_SO_KEEPALIVE 0x8 +# define ASIO_OS_DEF_SO_LINGER 0x80 +# define ASIO_OS_DEF_SO_OOBINLINE 0x100 +# define ASIO_OS_DEF_SO_SNDBUF 0x1001 +# define ASIO_OS_DEF_SO_RCVBUF 0x1002 +# define ASIO_OS_DEF_SO_SNDLOWAT 0x1003 +# define ASIO_OS_DEF_SO_RCVLOWAT 0x1004 +# define ASIO_OS_DEF_SO_REUSEADDR 0x4 +# define ASIO_OS_DEF_TCP_NODELAY 0x1 +# define ASIO_OS_DEF_IP_MULTICAST_IF 2 +# define ASIO_OS_DEF_IP_MULTICAST_TTL 3 +# define ASIO_OS_DEF_IP_MULTICAST_LOOP 4 +# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP 5 +# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP 6 +# define ASIO_OS_DEF_IP_TTL 7 +# define ASIO_OS_DEF_IPV6_UNICAST_HOPS 4 +# define ASIO_OS_DEF_IPV6_MULTICAST_IF 9 +# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS 10 +# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP 11 +# define ASIO_OS_DEF_IPV6_JOIN_GROUP 12 +# define ASIO_OS_DEF_IPV6_LEAVE_GROUP 13 +# define ASIO_OS_DEF_AI_CANONNAME 0x2 +# define ASIO_OS_DEF_AI_PASSIVE 0x1 +# define ASIO_OS_DEF_AI_NUMERICHOST 0x4 +# define ASIO_OS_DEF_AI_NUMERICSERV 0x8 +# define ASIO_OS_DEF_AI_V4MAPPED 0x800 +# define ASIO_OS_DEF_AI_ALL 0x100 +# define ASIO_OS_DEF_AI_ADDRCONFIG 0x400 +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) +typedef SOCKET socket_type; +const SOCKET invalid_socket = INVALID_SOCKET; +const int socket_error_retval = SOCKET_ERROR; +const int max_addr_v4_str_len = 256; +const int max_addr_v6_str_len = 256; +typedef sockaddr socket_addr_type; +typedef in_addr in4_addr_type; +typedef ip_mreq in4_mreq_type; +typedef sockaddr_in sockaddr_in4_type; +# if defined(ASIO_HAS_OLD_WIN_SDK) +typedef in6_addr_emulation in6_addr_type; +typedef ipv6_mreq_emulation in6_mreq_type; +typedef sockaddr_in6_emulation sockaddr_in6_type; +typedef sockaddr_storage_emulation sockaddr_storage_type; +typedef addrinfo_emulation addrinfo_type; +# else +typedef in6_addr in6_addr_type; +typedef ipv6_mreq in6_mreq_type; +typedef sockaddr_in6 sockaddr_in6_type; +typedef sockaddr_storage sockaddr_storage_type; +typedef addrinfo addrinfo_type; +# endif +typedef ::linger linger_type; +typedef unsigned long ioctl_arg_type; +typedef u_long u_long_type; +typedef u_short u_short_type; +typedef int signed_size_type; +# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c +# define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC +# define ASIO_OS_DEF_AF_INET AF_INET +# define ASIO_OS_DEF_AF_INET6 AF_INET6 +# define ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM +# define ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM +# define ASIO_OS_DEF_SOCK_RAW SOCK_RAW +# define ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET +# define ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP +# define ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6 +# define ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP +# define ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP +# define ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP +# define ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6 +# define ASIO_OS_DEF_FIONBIO FIONBIO +# define ASIO_OS_DEF_FIONREAD FIONREAD +# define ASIO_OS_DEF_INADDR_ANY INADDR_ANY +# define ASIO_OS_DEF_MSG_OOB MSG_OOB +# define ASIO_OS_DEF_MSG_PEEK MSG_PEEK +# define ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE +# define ASIO_OS_DEF_MSG_EOR 0 // Not supported on Windows. +# define ASIO_OS_DEF_SHUT_RD SD_RECEIVE +# define ASIO_OS_DEF_SHUT_WR SD_SEND +# define ASIO_OS_DEF_SHUT_RDWR SD_BOTH +# define ASIO_OS_DEF_SOMAXCONN SOMAXCONN +# define ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET +# define ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST +# define ASIO_OS_DEF_SO_DEBUG SO_DEBUG +# define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE +# define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE +# define ASIO_OS_DEF_SO_LINGER SO_LINGER +# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE +# define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF +# define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF +# define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT +# define ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT +# define ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR +# define ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY +# define ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF +# define ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL +# define ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP +# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP +# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP +# define ASIO_OS_DEF_IP_TTL IP_TTL +# define ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS +# define ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF +# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS +# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP +# define ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP +# define ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP +# define ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME +# define ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE +# define ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST +# if defined(AI_NUMERICSERV) +# define ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV +# else +# define ASIO_OS_DEF_AI_NUMERICSERV 0 +# endif +# if defined(AI_V4MAPPED) +# define ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED +# else +# define ASIO_OS_DEF_AI_V4MAPPED 0 +# endif +# if defined(AI_ALL) +# define ASIO_OS_DEF_AI_ALL AI_ALL +# else +# define ASIO_OS_DEF_AI_ALL 0 +# endif +# if defined(AI_ADDRCONFIG) +# define ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG +# else +# define ASIO_OS_DEF_AI_ADDRCONFIG 0 +# endif +# if defined (_WIN32_WINNT) +const int max_iov_len = 64; +# else +const int max_iov_len = 16; +# endif +#else +typedef int socket_type; +const int invalid_socket = -1; +const int socket_error_retval = -1; +const int max_addr_v4_str_len = INET_ADDRSTRLEN; +#if defined(INET6_ADDRSTRLEN) +const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; +#else // defined(INET6_ADDRSTRLEN) +const int max_addr_v6_str_len = 256; +#endif // defined(INET6_ADDRSTRLEN) +typedef sockaddr socket_addr_type; +typedef in_addr in4_addr_type; +# if defined(__hpux) +// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined. +struct in4_mreq_type +{ + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; +# else +typedef ip_mreq in4_mreq_type; +# endif +typedef sockaddr_in sockaddr_in4_type; +typedef in6_addr in6_addr_type; +typedef ipv6_mreq in6_mreq_type; +typedef sockaddr_in6 sockaddr_in6_type; +typedef sockaddr_storage sockaddr_storage_type; +typedef sockaddr_un sockaddr_un_type; +typedef addrinfo addrinfo_type; +typedef ::linger linger_type; +typedef int ioctl_arg_type; +typedef uint32_t u_long_type; +typedef uint16_t u_short_type; +#if defined(ASIO_HAS_SSIZE_T) +typedef ssize_t signed_size_type; +#else // defined(ASIO_HAS_SSIZE_T) +typedef int signed_size_type; +#endif // defined(ASIO_HAS_SSIZE_T) +# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c +# define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC +# define ASIO_OS_DEF_AF_INET AF_INET +# define ASIO_OS_DEF_AF_INET6 AF_INET6 +# define ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM +# define ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM +# define ASIO_OS_DEF_SOCK_RAW SOCK_RAW +# define ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET +# define ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP +# define ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6 +# define ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP +# define ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP +# define ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP +# define ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6 +# define ASIO_OS_DEF_FIONBIO FIONBIO +# define ASIO_OS_DEF_FIONREAD FIONREAD +# define ASIO_OS_DEF_INADDR_ANY INADDR_ANY +# define ASIO_OS_DEF_MSG_OOB MSG_OOB +# define ASIO_OS_DEF_MSG_PEEK MSG_PEEK +# define ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE +# define ASIO_OS_DEF_MSG_EOR MSG_EOR +# define ASIO_OS_DEF_SHUT_RD SHUT_RD +# define ASIO_OS_DEF_SHUT_WR SHUT_WR +# define ASIO_OS_DEF_SHUT_RDWR SHUT_RDWR +# define ASIO_OS_DEF_SOMAXCONN SOMAXCONN +# define ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET +# define ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST +# define ASIO_OS_DEF_SO_DEBUG SO_DEBUG +# define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE +# define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE +# define ASIO_OS_DEF_SO_LINGER SO_LINGER +# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE +# define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF +# define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF +# define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT +# define ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT +# define ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR +# define ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY +# define ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF +# define ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL +# define ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP +# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP +# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP +# define ASIO_OS_DEF_IP_TTL IP_TTL +# define ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS +# define ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF +# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS +# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP +# define ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP +# define ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP +# define ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME +# define ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE +# define ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST +# if defined(AI_NUMERICSERV) +# define ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV +# else +# define ASIO_OS_DEF_AI_NUMERICSERV 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. +# if defined(AI_V4MAPPED) && !defined(__QNXNTO__) +# define ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED +# else +# define ASIO_OS_DEF_AI_V4MAPPED 0 +# endif +# if defined(AI_ALL) && !defined(__QNXNTO__) +# define ASIO_OS_DEF_AI_ALL AI_ALL +# else +# define ASIO_OS_DEF_AI_ALL 0 +# endif +# if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__) +# define ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG +# else +# define ASIO_OS_DEF_AI_ADDRCONFIG 0 +# endif +# if defined(IOV_MAX) +const int max_iov_len = IOV_MAX; +# else +// POSIX platforms are not required to define IOV_MAX. +const int max_iov_len = 16; +# endif +#endif +const int custom_socket_option_level = 0xA5100000; +const int enable_connection_aborted_option = 1; +const int always_fail_option = 2; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SOCKET_TYPES_HPP diff --git a/lib/asio/detail/solaris_fenced_block.hpp b/lib/asio/detail/solaris_fenced_block.hpp new file mode 100644 index 0000000..d48f6a3 --- /dev/null +++ b/lib/asio/detail/solaris_fenced_block.hpp @@ -0,0 +1,62 @@ +// +// detail/solaris_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP +#define ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(__sun) + +#include <atomic.h> +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class solaris_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit solaris_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit solaris_fenced_block(full_t) + { + membar_consumer(); + } + + // Destructor. + ~solaris_fenced_block() + { + membar_producer(); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(__sun) + +#endif // ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP diff --git a/lib/asio/detail/static_mutex.hpp b/lib/asio/detail/static_mutex.hpp new file mode 100644 index 0000000..8f2bc02 --- /dev/null +++ b/lib/asio/detail/static_mutex.hpp @@ -0,0 +1,52 @@ +// +// detail/static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_STATIC_MUTEX_HPP +#define ASIO_DETAIL_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_static_mutex.hpp" +#elif defined(ASIO_WINDOWS) +# include "asio/detail/win_static_mutex.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_static_mutex.hpp" +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# include "asio/detail/std_static_mutex.hpp" +#else +# error Only Windows and POSIX are supported! +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) +typedef null_static_mutex static_mutex; +# define ASIO_STATIC_MUTEX_INIT ASIO_NULL_STATIC_MUTEX_INIT +#elif defined(ASIO_WINDOWS) +typedef win_static_mutex static_mutex; +# define ASIO_STATIC_MUTEX_INIT ASIO_WIN_STATIC_MUTEX_INIT +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_static_mutex static_mutex; +# define ASIO_STATIC_MUTEX_INIT ASIO_POSIX_STATIC_MUTEX_INIT +#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +typedef std_static_mutex static_mutex; +# define ASIO_STATIC_MUTEX_INIT ASIO_STD_STATIC_MUTEX_INIT +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_STATIC_MUTEX_HPP diff --git a/lib/asio/detail/std_event.hpp b/lib/asio/detail/std_event.hpp new file mode 100644 index 0000000..5639ecd --- /dev/null +++ b/lib/asio/detail/std_event.hpp @@ -0,0 +1,176 @@ +// +// detail/std_event.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_STD_EVENT_HPP +#define ASIO_DETAIL_STD_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#include <chrono> +#include <condition_variable> +#include "asio/detail/assert.hpp" +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class std_event + : private noncopyable +{ +public: + // Constructor. + std_event() + : state_(0) + { + } + + // Destructor. + ~std_event() + { + } + + // Signal the event. (Retained for backward compatibility.) + template <typename Lock> + void signal(Lock& lock) + { + this->signal_all(lock); + } + + // Signal all waiters. + template <typename Lock> + void signal_all(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + state_ |= 1; + cond_.notify_all(); + } + + // Unlock the mutex and signal one waiter. + template <typename Lock> + void unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + lock.unlock(); + if (have_waiters) + cond_.notify_one(); + } + + // If there's a waiter, unlock the mutex and signal it. + template <typename Lock> + bool maybe_unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + if (state_ > 1) + { + lock.unlock(); + cond_.notify_one(); + return true; + } + return false; + } + + // Reset the event. + template <typename Lock> + void clear(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + state_ &= ~std::size_t(1); + } + + // Wait for the event to become signalled. + template <typename Lock> + void wait(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + unique_lock_adapter u_lock(lock); + while ((state_ & 1) == 0) + { + waiter w(state_); + cond_.wait(u_lock.unique_lock_); + } + } + + // Timed wait for the event to become signalled. + template <typename Lock> + bool wait_for_usec(Lock& lock, long usec) + { + ASIO_ASSERT(lock.locked()); + unique_lock_adapter u_lock(lock); + if ((state_ & 1) == 0) + { + waiter w(state_); + cond_.wait_for(u_lock.unique_lock_, std::chrono::microseconds(usec)); + } + return (state_ & 1) != 0; + } + +private: + // Helper class to temporarily adapt a scoped_lock into a unique_lock so that + // it can be passed to std::condition_variable::wait(). + struct unique_lock_adapter + { + template <typename Lock> + explicit unique_lock_adapter(Lock& lock) + : unique_lock_(lock.mutex().mutex_, std::adopt_lock) + { + } + + ~unique_lock_adapter() + { + unique_lock_.release(); + } + + std::unique_lock<std::mutex> unique_lock_; + }; + + // Helper to increment and decrement the state to track outstanding waiters. + class waiter + { + public: + explicit waiter(std::size_t& state) + : state_(state) + { + state_ += 2; + } + + ~waiter() + { + state_ -= 2; + } + + private: + std::size_t& state_; + }; + + std::condition_variable cond_; + std::size_t state_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#endif // ASIO_DETAIL_STD_EVENT_HPP diff --git a/lib/asio/detail/std_fenced_block.hpp b/lib/asio/detail/std_fenced_block.hpp new file mode 100644 index 0000000..0d8ade0 --- /dev/null +++ b/lib/asio/detail/std_fenced_block.hpp @@ -0,0 +1,62 @@ +// +// detail/std_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_STD_FENCED_BLOCK_HPP +#define ASIO_DETAIL_STD_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_ATOMIC) + +#include <atomic> +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class std_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit std_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit std_fenced_block(full_t) + { + std::atomic_thread_fence(std::memory_order_acquire); + } + + // Destructor. + ~std_fenced_block() + { + std::atomic_thread_fence(std::memory_order_release); + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_ATOMIC) + +#endif // ASIO_DETAIL_STD_FENCED_BLOCK_HPP diff --git a/lib/asio/detail/std_global.hpp b/lib/asio/detail/std_global.hpp new file mode 100644 index 0000000..0c5173e --- /dev/null +++ b/lib/asio/detail/std_global.hpp @@ -0,0 +1,70 @@ +// +// detail/std_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_STD_GLOBAL_HPP +#define ASIO_DETAIL_STD_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_CALL_ONCE) + +#include <exception> +#include <mutex> + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +struct std_global_impl +{ + // Helper function to perform initialisation. + static void do_init() + { + instance_.ptr_ = new T; + } + + // Destructor automatically cleans up the global. + ~std_global_impl() + { + delete ptr_; + } + + static std::once_flag init_once_; + static std_global_impl instance_; + T* ptr_; +}; + +template <typename T> +std::once_flag std_global_impl<T>::init_once_; + +template <typename T> +std_global_impl<T> std_global_impl<T>::instance_; + +template <typename T> +T& std_global() +{ + std::call_once(std_global_impl<T>::init_once_, &std_global_impl<T>::do_init); + return *std_global_impl<T>::instance_.ptr_; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_CALL_ONCE) + +#endif // ASIO_DETAIL_STD_GLOBAL_HPP diff --git a/lib/asio/detail/std_mutex.hpp b/lib/asio/detail/std_mutex.hpp new file mode 100644 index 0000000..159049e --- /dev/null +++ b/lib/asio/detail/std_mutex.hpp @@ -0,0 +1,73 @@ +// +// detail/std_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_STD_MUTEX_HPP +#define ASIO_DETAIL_STD_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#include <mutex> +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class std_event; + +class std_mutex + : private noncopyable +{ +public: + typedef asio::detail::scoped_lock<std_mutex> scoped_lock; + + // Constructor. + std_mutex() + { + } + + // Destructor. + ~std_mutex() + { + } + + // Lock the mutex. + void lock() + { + mutex_.lock(); + } + + // Unlock the mutex. + void unlock() + { + mutex_.unlock(); + } + +private: + friend class std_event; + std::mutex mutex_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#endif // ASIO_DETAIL_STD_MUTEX_HPP diff --git a/lib/asio/detail/std_static_mutex.hpp b/lib/asio/detail/std_static_mutex.hpp new file mode 100644 index 0000000..e9c9dc5 --- /dev/null +++ b/lib/asio/detail/std_static_mutex.hpp @@ -0,0 +1,81 @@ +// +// detail/std_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_STD_STATIC_MUTEX_HPP +#define ASIO_DETAIL_STD_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#include <mutex> +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class std_event; + +class std_static_mutex + : private noncopyable +{ +public: + typedef asio::detail::scoped_lock<std_static_mutex> scoped_lock; + + // Constructor. + std_static_mutex(int) + { + } + + // Destructor. + ~std_static_mutex() + { + } + + // Initialise the mutex. + void init() + { + // Nothing to do. + } + + // Lock the mutex. + void lock() + { + mutex_.lock(); + } + + // Unlock the mutex. + void unlock() + { + mutex_.unlock(); + } + +private: + friend class std_event; + std::mutex mutex_; +}; + +#define ASIO_STD_STATIC_MUTEX_INIT 0 + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#endif // ASIO_DETAIL_STD_STATIC_MUTEX_HPP diff --git a/lib/asio/detail/std_thread.hpp b/lib/asio/detail/std_thread.hpp new file mode 100644 index 0000000..a240308 --- /dev/null +++ b/lib/asio/detail/std_thread.hpp @@ -0,0 +1,71 @@ +// +// detail/std_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_STD_THREAD_HPP +#define ASIO_DETAIL_STD_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_THREAD) + +#include <thread> +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class std_thread + : private noncopyable +{ +public: + // Constructor. + template <typename Function> + std_thread(Function f, unsigned int = 0) + : thread_(f) + { + } + + // Destructor. + ~std_thread() + { + join(); + } + + // Wait for the thread to exit. + void join() + { + if (thread_.joinable()) + thread_.join(); + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + return std::thread::hardware_concurrency(); + } + +private: + std::thread thread_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_STD_THREAD) + +#endif // ASIO_DETAIL_STD_THREAD_HPP diff --git a/lib/asio/detail/strand_executor_service.hpp b/lib/asio/detail/strand_executor_service.hpp new file mode 100644 index 0000000..67e8427 --- /dev/null +++ b/lib/asio/detail/strand_executor_service.hpp @@ -0,0 +1,142 @@ +// +// detail/strand_executor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP +#define ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/executor_op.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/scheduler_operation.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Default service implementation for a strand. +class strand_executor_service + : public execution_context_service_base<strand_executor_service> +{ +public: + // The underlying implementation of a strand. + class strand_impl + { + public: + ASIO_DECL ~strand_impl(); + + private: + friend class strand_executor_service; + + // Mutex to protect access to internal data. + mutex* mutex_; + + // Indicates whether the strand is currently "locked" by a handler. This + // means that there is a handler upcall in progress, or that the strand + // itself has been scheduled in order to invoke some pending handlers. + bool locked_; + + // Indicates that the strand has been shut down and will accept no further + // handlers. + bool shutdown_; + + // The handlers that are waiting on the strand but should not be run until + // after the next time the strand is scheduled. This queue must only be + // modified while the mutex is locked. + op_queue<scheduler_operation> waiting_queue_; + + // The handlers that are ready to be run. Logically speaking, these are the + // handlers that hold the strand's lock. The ready queue is only modified + // from within the strand and so may be accessed without locking the mutex. + op_queue<scheduler_operation> ready_queue_; + + // Pointers to adjacent handle implementations in linked list. + strand_impl* next_; + strand_impl* prev_; + + // The strand service in where the implementation is held. + strand_executor_service* service_; + }; + + typedef shared_ptr<strand_impl> implementation_type; + + // Construct a new strand service for the specified context. + ASIO_DECL explicit strand_executor_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Create a new strand_executor implementation. + ASIO_DECL implementation_type create_implementation(); + + // Request invocation of the given function. + template <typename Executor, typename Function, typename Allocator> + static void dispatch(const implementation_type& impl, Executor& ex, + ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Request invocation of the given function and return immediately. + template <typename Executor, typename Function, typename Allocator> + static void post(const implementation_type& impl, Executor& ex, + ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Request invocation of the given function and return immediately. + template <typename Executor, typename Function, typename Allocator> + static void defer(const implementation_type& impl, Executor& ex, + ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Determine whether the strand is running in the current thread. + ASIO_DECL static bool running_in_this_thread( + const implementation_type& impl); + +private: + friend class strand_impl; + template <typename Executor> class invoker; + + // Adds a function to the strand. Returns true if it acquires the lock. + ASIO_DECL static bool enqueue(const implementation_type& impl, + scheduler_operation* op); + + // Mutex to protect access to the service-wide state. + mutex mutex_; + + // Number of mutexes shared between all strand objects. + enum { num_mutexes = 193 }; + + // Pool of mutexes. + scoped_ptr<mutex> mutexes_[num_mutexes]; + + // Extra value used when hashing to prevent recycled memory locations from + // getting the same mutex. + std::size_t salt_; + + // The head of a linked list of all implementations. + strand_impl* impl_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/strand_executor_service.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/strand_executor_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP diff --git a/lib/asio/detail/strand_service.hpp b/lib/asio/detail/strand_service.hpp new file mode 100644 index 0000000..edc14a0 --- /dev/null +++ b/lib/asio/detail/strand_service.hpp @@ -0,0 +1,142 @@ +// +// detail/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_STRAND_SERVICE_HPP +#define ASIO_DETAIL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/io_context.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/scoped_ptr.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Default service implementation for a strand. +class strand_service + : public asio::detail::service_base<strand_service> +{ +private: + // Helper class to re-post the strand on exit. + struct on_do_complete_exit; + + // Helper class to re-post the strand on exit. + struct on_dispatch_exit; + +public: + + // The underlying implementation of a strand. + class strand_impl + : public operation + { + public: + strand_impl(); + + private: + // Only this service will have access to the internal values. + friend class strand_service; + friend struct on_do_complete_exit; + friend struct on_dispatch_exit; + + // Mutex to protect access to internal data. + asio::detail::mutex mutex_; + + // Indicates whether the strand is currently "locked" by a handler. This + // means that there is a handler upcall in progress, or that the strand + // itself has been scheduled in order to invoke some pending handlers. + bool locked_; + + // The handlers that are waiting on the strand but should not be run until + // after the next time the strand is scheduled. This queue must only be + // modified while the mutex is locked. + op_queue<operation> waiting_queue_; + + // The handlers that are ready to be run. Logically speaking, these are the + // handlers that hold the strand's lock. The ready queue is only modified + // from within the strand and so may be accessed without locking the mutex. + op_queue<operation> ready_queue_; + }; + + typedef strand_impl* implementation_type; + + // Construct a new strand service for the specified io_context. + ASIO_DECL explicit strand_service(asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new strand implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Request the io_context to invoke the given handler. + template <typename Handler> + void dispatch(implementation_type& impl, Handler& handler); + + // Request the io_context to invoke the given handler and return immediately. + template <typename Handler> + void post(implementation_type& impl, Handler& handler); + + // Determine whether the strand is running in the current thread. + ASIO_DECL bool running_in_this_thread( + const implementation_type& impl) const; + +private: + // Helper function to dispatch a handler. Returns true if the handler should + // be dispatched immediately. + ASIO_DECL bool do_dispatch(implementation_type& impl, operation* op); + + // Helper fiunction to post a handler. + ASIO_DECL void do_post(implementation_type& impl, + operation* op, bool is_continuation); + + ASIO_DECL static void do_complete(void* owner, + operation* base, const asio::error_code& ec, + std::size_t bytes_transferred); + + // The io_context implementation used to post completions. + io_context_impl& io_context_; + + // Mutex to protect access to the array of implementations. + asio::detail::mutex mutex_; + + // Number of implementations shared between all strand objects. +#if defined(ASIO_STRAND_IMPLEMENTATIONS) + enum { num_implementations = ASIO_STRAND_IMPLEMENTATIONS }; +#else // defined(ASIO_STRAND_IMPLEMENTATIONS) + enum { num_implementations = 193 }; +#endif // defined(ASIO_STRAND_IMPLEMENTATIONS) + + // Pool of implementations. + scoped_ptr<strand_impl> implementations_[num_implementations]; + + // Extra value used when hashing to prevent recycled memory locations from + // getting the same strand implementation. + std::size_t salt_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/strand_service.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/strand_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_STRAND_SERVICE_HPP diff --git a/lib/asio/detail/string_view.hpp b/lib/asio/detail/string_view.hpp new file mode 100644 index 0000000..f09cebc --- /dev/null +++ b/lib/asio/detail/string_view.hpp @@ -0,0 +1,47 @@ +// +// detail/string_view.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_STRING_VIEW_HPP +#define ASIO_DETAIL_STRING_VIEW_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STRING_VIEW) + +#if defined(ASIO_HAS_STD_STRING_VIEW) +# include <string_view> +#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# include <experimental/string_view> +#else // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# error ASIO_HAS_STRING_VIEW is set but no string_view is available +#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +namespace asio { + +#if defined(ASIO_HAS_STD_STRING_VIEW) +using std::basic_string_view; +using std::string_view; +#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +using std::experimental::basic_string_view; +using std::experimental::string_view; +#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +} // namespace asio + +# define ASIO_STRING_VIEW_PARAM asio::string_view +#else // defined(ASIO_HAS_STRING_VIEW) +# define ASIO_STRING_VIEW_PARAM const std::string& +#endif // defined(ASIO_HAS_STRING_VIEW) + +#endif // ASIO_DETAIL_STRING_VIEW_HPP diff --git a/lib/asio/detail/thread.hpp b/lib/asio/detail/thread.hpp new file mode 100644 index 0000000..ea556db --- /dev/null +++ b/lib/asio/detail/thread.hpp @@ -0,0 +1,60 @@ +// +// detail/thread.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_THREAD_HPP +#define ASIO_DETAIL_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_thread.hpp" +#elif defined(ASIO_WINDOWS) +# if defined(UNDER_CE) +# include "asio/detail/wince_thread.hpp" +# elif defined(ASIO_WINDOWS_APP) +# include "asio/detail/winapp_thread.hpp" +# else +# include "asio/detail/win_thread.hpp" +# endif +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_thread.hpp" +#elif defined(ASIO_HAS_STD_THREAD) +# include "asio/detail/std_thread.hpp" +#else +# error Only Windows, POSIX and std::thread are supported! +#endif + +namespace asio { +namespace detail { + +#if !defined(ASIO_HAS_THREADS) +typedef null_thread thread; +#elif defined(ASIO_WINDOWS) +# if defined(UNDER_CE) +typedef wince_thread thread; +# elif defined(ASIO_WINDOWS_APP) +typedef winapp_thread thread; +# else +typedef win_thread thread; +# endif +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_thread thread; +#elif defined(ASIO_HAS_STD_THREAD) +typedef std_thread thread; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_THREAD_HPP diff --git a/lib/asio/detail/thread_context.hpp b/lib/asio/detail/thread_context.hpp new file mode 100644 index 0000000..88b4f31 --- /dev/null +++ b/lib/asio/detail/thread_context.hpp @@ -0,0 +1,42 @@ +// +// detail/thread_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_THREAD_CONTEXT_HPP +#define ASIO_DETAIL_THREAD_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <climits> +#include <cstddef> +#include "asio/detail/call_stack.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class thread_info_base; + +// Base class for things that manage threads (scheduler, win_iocp_io_context). +class thread_context +{ +public: + // Per-thread call stack to track the state of each thread in the context. + typedef call_stack<thread_context, thread_info_base> thread_call_stack; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_THREAD_CONTEXT_HPP diff --git a/lib/asio/detail/thread_group.hpp b/lib/asio/detail/thread_group.hpp new file mode 100644 index 0000000..1e400b0 --- /dev/null +++ b/lib/asio/detail/thread_group.hpp @@ -0,0 +1,89 @@ +// +// detail/thread_group.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_THREAD_GROUP_HPP +#define ASIO_DETAIL_THREAD_GROUP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/thread.hpp" + +namespace asio { +namespace detail { + +class thread_group +{ +public: + // Constructor initialises an empty thread group. + thread_group() + : first_(0) + { + } + + // Destructor joins any remaining threads in the group. + ~thread_group() + { + join(); + } + + // Create a new thread in the group. + template <typename Function> + void create_thread(Function f) + { + first_ = new item(f, first_); + } + + // Create new threads in the group. + template <typename Function> + void create_threads(Function f, std::size_t num_threads) + { + for (std::size_t i = 0; i < num_threads; ++i) + create_thread(f); + } + + // Wait for all threads in the group to exit. + void join() + { + while (first_) + { + first_->thread_.join(); + item* tmp = first_; + first_ = first_->next_; + delete tmp; + } + } + +private: + // Structure used to track a single thread in the group. + struct item + { + template <typename Function> + explicit item(Function f, item* next) + : thread_(f), + next_(next) + { + } + + asio::detail::thread thread_; + item* next_; + }; + + // The first thread in the group. + item* first_; +}; + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_THREAD_GROUP_HPP diff --git a/lib/asio/detail/thread_info_base.hpp b/lib/asio/detail/thread_info_base.hpp new file mode 100644 index 0000000..1b22207 --- /dev/null +++ b/lib/asio/detail/thread_info_base.hpp @@ -0,0 +1,121 @@ +// +// detail/thread_info_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_THREAD_INFO_BASE_HPP +#define ASIO_DETAIL_THREAD_INFO_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <climits> +#include <cstddef> +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class thread_info_base + : private noncopyable +{ +public: + struct default_tag + { + enum { mem_index = 0 }; + }; + + struct awaitee_tag + { + enum { mem_index = 1 }; + }; + + thread_info_base() + { + for (int i = 0; i < max_mem_index; ++i) + reusable_memory_[i] = 0; + } + + ~thread_info_base() + { + for (int i = 0; i < max_mem_index; ++i) + if (reusable_memory_[i]) + ::operator delete(reusable_memory_[i]); + } + + static void* allocate(thread_info_base* this_thread, std::size_t size) + { + return allocate(default_tag(), this_thread, size); + } + + static void deallocate(thread_info_base* this_thread, + void* pointer, std::size_t size) + { + deallocate(default_tag(), this_thread, pointer, size); + } + + template <typename Purpose> + static void* allocate(Purpose, thread_info_base* this_thread, + std::size_t size) + { + std::size_t chunks = (size + chunk_size - 1) / chunk_size; + + if (this_thread && this_thread->reusable_memory_[Purpose::mem_index]) + { + void* const pointer = this_thread->reusable_memory_[Purpose::mem_index]; + this_thread->reusable_memory_[Purpose::mem_index] = 0; + + unsigned char* const mem = static_cast<unsigned char*>(pointer); + if (static_cast<std::size_t>(mem[0]) >= chunks) + { + mem[size] = mem[0]; + return pointer; + } + + ::operator delete(pointer); + } + + void* const pointer = ::operator new(chunks * chunk_size + 1); + unsigned char* const mem = static_cast<unsigned char*>(pointer); + mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0; + return pointer; + } + + template <typename Purpose> + static void deallocate(Purpose, thread_info_base* this_thread, + void* pointer, std::size_t size) + { + if (size <= chunk_size * UCHAR_MAX) + { + if (this_thread && this_thread->reusable_memory_[Purpose::mem_index] == 0) + { + unsigned char* const mem = static_cast<unsigned char*>(pointer); + mem[0] = mem[size]; + this_thread->reusable_memory_[Purpose::mem_index] = pointer; + return; + } + } + + ::operator delete(pointer); + } + +private: + enum { chunk_size = 4 }; + enum { max_mem_index = 2 }; + void* reusable_memory_[max_mem_index]; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_THREAD_INFO_BASE_HPP diff --git a/lib/asio/detail/throw_error.hpp b/lib/asio/detail/throw_error.hpp new file mode 100644 index 0000000..5dd8785 --- /dev/null +++ b/lib/asio/detail/throw_error.hpp @@ -0,0 +1,53 @@ +// +// detail/throw_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_THROW_ERROR_HPP +#define ASIO_DETAIL_THROW_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +ASIO_DECL void do_throw_error(const asio::error_code& err); + +ASIO_DECL void do_throw_error(const asio::error_code& err, + const char* location); + +inline void throw_error(const asio::error_code& err) +{ + if (err) + do_throw_error(err); +} + +inline void throw_error(const asio::error_code& err, + const char* location) +{ + if (err) + do_throw_error(err, location); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/throw_error.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_THROW_ERROR_HPP diff --git a/lib/asio/detail/throw_exception.hpp b/lib/asio/detail/throw_exception.hpp new file mode 100644 index 0000000..f9f7bfb --- /dev/null +++ b/lib/asio/detail/throw_exception.hpp @@ -0,0 +1,51 @@ +// +// detail/throw_exception.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_THROW_EXCEPTION_HPP +#define ASIO_DETAIL_THROW_EXCEPTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_THROW_EXCEPTION) +# include <boost/throw_exception.hpp> +#endif // defined(ASIO_BOOST_THROW_EXCEPTION) + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_BOOST_THROW_EXCEPTION) +using boost::throw_exception; +#else // defined(ASIO_HAS_BOOST_THROW_EXCEPTION) + +// Declare the throw_exception function for all targets. +template <typename Exception> +void throw_exception(const Exception& e); + +// Only define the throw_exception function when exceptions are enabled. +// Otherwise, it is up to the application to provide a definition of this +// function. +# if !defined(ASIO_NO_EXCEPTIONS) +template <typename Exception> +void throw_exception(const Exception& e) +{ + throw e; +} +# endif // !defined(ASIO_NO_EXCEPTIONS) + +#endif // defined(ASIO_HAS_BOOST_THROW_EXCEPTION) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_THROW_EXCEPTION_HPP diff --git a/lib/asio/detail/timer_queue.hpp b/lib/asio/detail/timer_queue.hpp new file mode 100644 index 0000000..380e779 --- /dev/null +++ b/lib/asio/detail/timer_queue.hpp @@ -0,0 +1,358 @@ +// +// detail/timer_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_TIMER_QUEUE_HPP +#define ASIO_DETAIL_TIMER_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cstddef> +#include <vector> +#include "asio/detail/cstdint.hpp" +#include "asio/detail/date_time_fwd.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Time_Traits> +class timer_queue + : public timer_queue_base +{ +public: + // The time type. + typedef typename Time_Traits::time_type time_type; + + // The duration type. + typedef typename Time_Traits::duration_type duration_type; + + // Per-timer data. + class per_timer_data + { + public: + per_timer_data() : + heap_index_((std::numeric_limits<std::size_t>::max)()), + next_(0), prev_(0) + { + } + + private: + friend class timer_queue; + + // The operations waiting on the timer. + op_queue<wait_op> op_queue_; + + // The index of the timer in the heap. + std::size_t heap_index_; + + // Pointers to adjacent timers in a linked list. + per_timer_data* next_; + per_timer_data* prev_; + }; + + // Constructor. + timer_queue() + : timers_(), + 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. + bool enqueue_timer(const time_type& time, per_timer_data& timer, wait_op* op) + { + // Enqueue the timer object. + if (timer.prev_ == 0 && &timer != timers_) + { + if (this->is_positive_infinity(time)) + { + // No heap entry is required for timers that never expire. + timer.heap_index_ = (std::numeric_limits<std::size_t>::max)(); + } + else + { + // Put the new timer at the correct position in the heap. This is done + // first since push_back() can throw due to allocation failure. + timer.heap_index_ = heap_.size(); + heap_entry entry = { time, &timer }; + heap_.push_back(entry); + up_heap(heap_.size() - 1); + } + + // Insert the new timer into the linked list of active timers. + timer.next_ = timers_; + timer.prev_ = 0; + if (timers_) + timers_->prev_ = &timer; + timers_ = &timer; + } + + // Enqueue the individual timer operation. + timer.op_queue_.push(op); + + // Interrupt reactor only if newly added timer is first to expire. + return timer.heap_index_ == 0 && timer.op_queue_.front() == op; + } + + // Whether there are no timers in the queue. + virtual bool empty() const + { + return timers_ == 0; + } + + // Get the time for the timer that is earliest in the queue. + virtual long wait_duration_msec(long max_duration) const + { + if (heap_.empty()) + return max_duration; + + return this->to_msec( + Time_Traits::to_posix_duration( + Time_Traits::subtract(heap_[0].time_, Time_Traits::now())), + max_duration); + } + + // Get the time for the timer that is earliest in the queue. + virtual long wait_duration_usec(long max_duration) const + { + if (heap_.empty()) + return max_duration; + + return this->to_usec( + Time_Traits::to_posix_duration( + Time_Traits::subtract(heap_[0].time_, Time_Traits::now())), + max_duration); + } + + // Dequeue all timers not later than the current time. + virtual void get_ready_timers(op_queue<operation>& ops) + { + if (!heap_.empty()) + { + const time_type now = Time_Traits::now(); + while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_)) + { + per_timer_data* timer = heap_[0].timer_; + ops.push(timer->op_queue_); + remove_timer(*timer); + } + } + } + + // Dequeue all timers. + virtual void get_all_timers(op_queue<operation>& ops) + { + while (timers_) + { + per_timer_data* timer = timers_; + timers_ = timers_->next_; + ops.push(timer->op_queue_); + timer->next_ = 0; + timer->prev_ = 0; + } + + heap_.clear(); + } + + // Cancel and dequeue operations for the given timer. + std::size_t cancel_timer(per_timer_data& timer, op_queue<operation>& ops, + std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()) + { + std::size_t num_cancelled = 0; + if (timer.prev_ != 0 || &timer == timers_) + { + while (wait_op* op = (num_cancelled != max_cancelled) + ? timer.op_queue_.front() : 0) + { + op->ec_ = asio::error::operation_aborted; + timer.op_queue_.pop(); + ops.push(op); + ++num_cancelled; + } + if (timer.op_queue_.empty()) + remove_timer(timer); + } + return num_cancelled; + } + + // Move operations from one timer to another, empty timer. + void move_timer(per_timer_data& target, per_timer_data& source) + { + target.op_queue_.push(source.op_queue_); + + target.heap_index_ = source.heap_index_; + source.heap_index_ = (std::numeric_limits<std::size_t>::max)(); + + if (target.heap_index_ < heap_.size()) + heap_[target.heap_index_].timer_ = ⌖ + + if (timers_ == &source) + timers_ = ⌖ + if (source.prev_) + source.prev_->next_ = ⌖ + if (source.next_) + source.next_->prev_= ⌖ + target.next_ = source.next_; + target.prev_ = source.prev_; + source.next_ = 0; + source.prev_ = 0; + } + +private: + // Move the item at the given index up the heap to its correct position. + void up_heap(std::size_t index) + { + while (index > 0) + { + std::size_t parent = (index - 1) / 2; + if (!Time_Traits::less_than(heap_[index].time_, heap_[parent].time_)) + break; + swap_heap(index, parent); + index = parent; + } + } + + // Move the item at the given index down the heap to its correct position. + void down_heap(std::size_t index) + { + std::size_t child = index * 2 + 1; + while (child < heap_.size()) + { + std::size_t min_child = (child + 1 == heap_.size() + || Time_Traits::less_than( + heap_[child].time_, heap_[child + 1].time_)) + ? child : child + 1; + if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_)) + break; + swap_heap(index, min_child); + index = min_child; + child = index * 2 + 1; + } + } + + // Swap two entries in the heap. + void swap_heap(std::size_t index1, std::size_t index2) + { + heap_entry tmp = heap_[index1]; + heap_[index1] = heap_[index2]; + heap_[index2] = tmp; + heap_[index1].timer_->heap_index_ = index1; + heap_[index2].timer_->heap_index_ = index2; + } + + // Remove a timer from the heap and list of timers. + void remove_timer(per_timer_data& timer) + { + // Remove the timer from the heap. + std::size_t index = timer.heap_index_; + if (!heap_.empty() && index < heap_.size()) + { + if (index == heap_.size() - 1) + { + heap_.pop_back(); + } + else + { + swap_heap(index, heap_.size() - 1); + heap_.pop_back(); + if (index > 0 && Time_Traits::less_than( + heap_[index].time_, heap_[(index - 1) / 2].time_)) + up_heap(index); + else + down_heap(index); + } + } + + // Remove the timer from the linked list of active timers. + if (timers_ == &timer) + timers_ = timer.next_; + if (timer.prev_) + timer.prev_->next_ = timer.next_; + if (timer.next_) + timer.next_->prev_= timer.prev_; + timer.next_ = 0; + timer.prev_ = 0; + } + + // Determine if the specified absolute time is positive infinity. + template <typename Time_Type> + static bool is_positive_infinity(const Time_Type&) + { + return false; + } + + // Determine if the specified absolute time is positive infinity. + template <typename T, typename TimeSystem> + static bool is_positive_infinity( + const boost::date_time::base_time<T, TimeSystem>& time) + { + return time.is_pos_infinity(); + } + + // Helper function to convert a duration into milliseconds. + template <typename Duration> + long to_msec(const Duration& d, long max_duration) const + { + if (d.ticks() <= 0) + return 0; + int64_t msec = d.total_milliseconds(); + if (msec == 0) + return 1; + if (msec > max_duration) + return max_duration; + return static_cast<long>(msec); + } + + // Helper function to convert a duration into microseconds. + template <typename Duration> + long to_usec(const Duration& d, long max_duration) const + { + if (d.ticks() <= 0) + return 0; + int64_t usec = d.total_microseconds(); + if (usec == 0) + return 1; + if (usec > max_duration) + return max_duration; + return static_cast<long>(usec); + } + + // The head of a linked list of all active timers. + per_timer_data* timers_; + + struct heap_entry + { + // The time when the timer should fire. + time_type time_; + + // The associated timer with enqueued operations. + per_timer_data* timer_; + }; + + // The heap of timers, with the earliest timer at the front. + std::vector<heap_entry> heap_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_TIMER_QUEUE_HPP diff --git a/lib/asio/detail/timer_queue_base.hpp b/lib/asio/detail/timer_queue_base.hpp new file mode 100644 index 0000000..4af995f --- /dev/null +++ b/lib/asio/detail/timer_queue_base.hpp @@ -0,0 +1,68 @@ +// +// detail/timer_queue_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_TIMER_QUEUE_BASE_HPP +#define ASIO_DETAIL_TIMER_QUEUE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class timer_queue_base + : private noncopyable +{ +public: + // Constructor. + timer_queue_base() : next_(0) {} + + // Destructor. + virtual ~timer_queue_base() {} + + // Whether there are no timers in the queue. + virtual bool empty() const = 0; + + // Get the time to wait until the next timer. + 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; + + // Dequeue all ready timers. + virtual void get_ready_timers(op_queue<operation>& ops) = 0; + + // Dequeue all timers. + virtual void get_all_timers(op_queue<operation>& ops) = 0; + +private: + friend class timer_queue_set; + + // Next timer queue in the set. + timer_queue_base* next_; +}; + +template <typename Time_Traits> +class timer_queue; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_TIMER_QUEUE_BASE_HPP diff --git a/lib/asio/detail/timer_queue_ptime.hpp b/lib/asio/detail/timer_queue_ptime.hpp new file mode 100644 index 0000000..84e8338 --- /dev/null +++ b/lib/asio/detail/timer_queue_ptime.hpp @@ -0,0 +1,99 @@ +// +// detail/timer_queue_ptime.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP +#define ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) + +#include "asio/time_traits.hpp" +#include "asio/detail/timer_queue.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct forwarding_posix_time_traits : time_traits<boost::posix_time::ptime> {}; + +// Template specialisation for the commonly used instantation. +template <> +class timer_queue<time_traits<boost::posix_time::ptime> > + : public timer_queue_base +{ +public: + // The time type. + typedef boost::posix_time::ptime time_type; + + // The duration type. + typedef boost::posix_time::time_duration duration_type; + + // Per-timer data. + typedef timer_queue<forwarding_posix_time_traits>::per_timer_data + per_timer_data; + + // Constructor. + ASIO_DECL timer_queue(); + + // Destructor. + ASIO_DECL virtual ~timer_queue(); + + // 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. + ASIO_DECL bool enqueue_timer(const time_type& time, + per_timer_data& timer, wait_op* op); + + // Whether there are no timers in the queue. + ASIO_DECL virtual bool empty() const; + + // Get the time for the timer that is earliest in the queue. + ASIO_DECL virtual long wait_duration_msec(long max_duration) const; + + // Get the time for the timer that is earliest in the queue. + ASIO_DECL virtual long wait_duration_usec(long max_duration) const; + + // Dequeue all timers not later than the current time. + ASIO_DECL virtual void get_ready_timers(op_queue<operation>& ops); + + // Dequeue all timers. + ASIO_DECL virtual void get_all_timers(op_queue<operation>& ops); + + // Cancel and dequeue operations for the given timer. + ASIO_DECL std::size_t cancel_timer( + per_timer_data& timer, op_queue<operation>& ops, + std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + + // Move operations from one timer to another, empty timer. + ASIO_DECL void move_timer(per_timer_data& target, + per_timer_data& source); + +private: + timer_queue<forwarding_posix_time_traits> impl_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/timer_queue_ptime.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + +#endif // ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP diff --git a/lib/asio/detail/timer_queue_set.hpp b/lib/asio/detail/timer_queue_set.hpp new file mode 100644 index 0000000..0ea372a --- /dev/null +++ b/lib/asio/detail/timer_queue_set.hpp @@ -0,0 +1,66 @@ +// +// detail/timer_queue_set.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_TIMER_QUEUE_SET_HPP +#define ASIO_DETAIL_TIMER_QUEUE_SET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/timer_queue_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class timer_queue_set +{ +public: + // Constructor. + ASIO_DECL timer_queue_set(); + + // Add a timer queue to the set. + ASIO_DECL void insert(timer_queue_base* q); + + // Remove a timer queue from the set. + ASIO_DECL void erase(timer_queue_base* q); + + // Determine whether all queues are empty. + ASIO_DECL bool all_empty() const; + + // Get the wait duration in milliseconds. + ASIO_DECL long wait_duration_msec(long max_duration) const; + + // Get the wait duration in microseconds. + ASIO_DECL long wait_duration_usec(long max_duration) const; + + // Dequeue all ready timers. + ASIO_DECL void get_ready_timers(op_queue<operation>& ops); + + // Dequeue all timers. + ASIO_DECL void get_all_timers(op_queue<operation>& ops); + +private: + timer_queue_base* first_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/timer_queue_set.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_DETAIL_TIMER_QUEUE_SET_HPP diff --git a/lib/asio/detail/timer_scheduler.hpp b/lib/asio/detail/timer_scheduler.hpp new file mode 100644 index 0000000..b1f8df4 --- /dev/null +++ b/lib/asio/detail/timer_scheduler.hpp @@ -0,0 +1,35 @@ +// +// detail/timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_TIMER_SCHEDULER_HPP +#define ASIO_DETAIL_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/timer_scheduler_fwd.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/winrt_timer_scheduler.hpp" +#elif defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#elif defined(ASIO_HAS_EPOLL) +# include "asio/detail/epoll_reactor.hpp" +#elif defined(ASIO_HAS_KQUEUE) +# include "asio/detail/kqueue_reactor.hpp" +#elif defined(ASIO_HAS_DEV_POLL) +# include "asio/detail/dev_poll_reactor.hpp" +#else +# include "asio/detail/select_reactor.hpp" +#endif + +#endif // ASIO_DETAIL_TIMER_SCHEDULER_HPP diff --git a/lib/asio/detail/timer_scheduler_fwd.hpp b/lib/asio/detail/timer_scheduler_fwd.hpp new file mode 100644 index 0000000..80bae50 --- /dev/null +++ b/lib/asio/detail/timer_scheduler_fwd.hpp @@ -0,0 +1,40 @@ +// +// detail/timer_scheduler_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP +#define ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_WINDOWS_RUNTIME) +typedef class winrt_timer_scheduler timer_scheduler; +#elif defined(ASIO_HAS_IOCP) +typedef class win_iocp_io_context timer_scheduler; +#elif defined(ASIO_HAS_EPOLL) +typedef class epoll_reactor timer_scheduler; +#elif defined(ASIO_HAS_KQUEUE) +typedef class kqueue_reactor timer_scheduler; +#elif defined(ASIO_HAS_DEV_POLL) +typedef class dev_poll_reactor timer_scheduler; +#else +typedef class select_reactor timer_scheduler; +#endif + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP diff --git a/lib/asio/detail/tss_ptr.hpp b/lib/asio/detail/tss_ptr.hpp new file mode 100644 index 0000000..e628abe --- /dev/null +++ b/lib/asio/detail/tss_ptr.hpp @@ -0,0 +1,69 @@ +// +// detail/tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_TSS_PTR_HPP +#define ASIO_DETAIL_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_THREADS) +# include "asio/detail/null_tss_ptr.hpp" +#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) +# include "asio/detail/keyword_tss_ptr.hpp" +#elif defined(ASIO_WINDOWS) +# include "asio/detail/win_tss_ptr.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_tss_ptr.hpp" +#else +# error Only Windows and POSIX are supported! +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +class tss_ptr +#if !defined(ASIO_HAS_THREADS) + : public null_tss_ptr<T> +#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) + : public keyword_tss_ptr<T> +#elif defined(ASIO_WINDOWS) + : public win_tss_ptr<T> +#elif defined(ASIO_HAS_PTHREADS) + : public posix_tss_ptr<T> +#endif +{ +public: + void operator=(T* value) + { +#if !defined(ASIO_HAS_THREADS) + null_tss_ptr<T>::operator=(value); +#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) + keyword_tss_ptr<T>::operator=(value); +#elif defined(ASIO_WINDOWS) + win_tss_ptr<T>::operator=(value); +#elif defined(ASIO_HAS_PTHREADS) + posix_tss_ptr<T>::operator=(value); +#endif + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_TSS_PTR_HPP diff --git a/lib/asio/detail/type_traits.hpp b/lib/asio/detail/type_traits.hpp new file mode 100644 index 0000000..edf0928 --- /dev/null +++ b/lib/asio/detail/type_traits.hpp @@ -0,0 +1,86 @@ +// +// detail/type_traits.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_TYPE_TRAITS_HPP +#define ASIO_DETAIL_TYPE_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_STD_TYPE_TRAITS) +# include <type_traits> +#else // defined(ASIO_HAS_TYPE_TRAITS) +# include <boost/type_traits/add_const.hpp> +# include <boost/type_traits/conditional.hpp> +# include <boost/type_traits/decay.hpp> +# include <boost/type_traits/integral_constant.hpp> +# include <boost/type_traits/is_base_of.hpp> +# include <boost/type_traits/is_class.hpp> +# include <boost/type_traits/is_const.hpp> +# include <boost/type_traits/is_convertible.hpp> +# include <boost/type_traits/is_function.hpp> +# include <boost/type_traits/is_same.hpp> +# include <boost/type_traits/remove_pointer.hpp> +# include <boost/type_traits/remove_reference.hpp> +# include <boost/utility/enable_if.hpp> +# include <boost/utility/result_of.hpp> +#endif // defined(ASIO_HAS_TYPE_TRAITS) + +namespace asio { + +#if defined(ASIO_HAS_STD_TYPE_TRAITS) +using std::add_const; +using std::conditional; +using std::decay; +using std::enable_if; +using std::false_type; +using std::integral_constant; +using std::is_base_of; +using std::is_class; +using std::is_const; +using std::is_convertible; +using std::is_function; +using std::is_same; +using std::remove_pointer; +using std::remove_reference; +#if defined(ASIO_HAS_STD_INVOKE_RESULT) +template <typename> struct result_of; +template <typename F, typename... Args> +struct result_of<F(Args...)> : std::invoke_result<F, Args...> {}; +#else // defined(ASIO_HAS_STD_INVOKE_RESULT) +using std::result_of; +#endif // defined(ASIO_HAS_STD_INVOKE_RESULT) +using std::true_type; +#else // defined(ASIO_HAS_STD_TYPE_TRAITS) +using boost::add_const; +template <bool Condition, typename Type = void> +struct enable_if : boost::enable_if_c<Condition, Type> {}; +using boost::conditional; +using boost::decay; +using boost::false_type; +using boost::integral_constant; +using boost::is_base_of; +using boost::is_class; +using boost::is_const; +using boost::is_convertible; +using boost::is_function; +using boost::is_same; +using boost::remove_pointer; +using boost::remove_reference; +using boost::result_of; +using boost::true_type; +#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) + +} // namespace asio + +#endif // ASIO_DETAIL_TYPE_TRAITS_HPP diff --git a/lib/asio/detail/variadic_templates.hpp b/lib/asio/detail/variadic_templates.hpp new file mode 100644 index 0000000..d54eb4e --- /dev/null +++ b/lib/asio/detail/variadic_templates.hpp @@ -0,0 +1,119 @@ +// +// detail/variadic_templates.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_VARIADIC_TEMPLATES_HPP +#define ASIO_DETAIL_VARIADIC_TEMPLATES_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +# define ASIO_VARIADIC_TPARAMS(n) ASIO_VARIADIC_TPARAMS_##n + +# define ASIO_VARIADIC_TPARAMS_1 \ + typename T1 +# define ASIO_VARIADIC_TPARAMS_2 \ + typename T1, typename T2 +# define ASIO_VARIADIC_TPARAMS_3 \ + typename T1, typename T2, typename T3 +# define ASIO_VARIADIC_TPARAMS_4 \ + typename T1, typename T2, typename T3, typename T4 +# define ASIO_VARIADIC_TPARAMS_5 \ + typename T1, typename T2, typename T3, typename T4, typename T5 + +# define ASIO_VARIADIC_TARGS(n) ASIO_VARIADIC_TARGS_##n + +# define ASIO_VARIADIC_TARGS_1 T1 +# define ASIO_VARIADIC_TARGS_2 T1, T2 +# define ASIO_VARIADIC_TARGS_3 T1, T2, T3 +# define ASIO_VARIADIC_TARGS_4 T1, T2, T3, T4 +# define ASIO_VARIADIC_TARGS_5 T1, T2, T3, T4, T5 + +# define ASIO_VARIADIC_BYVAL_PARAMS(n) \ + ASIO_VARIADIC_BYVAL_PARAMS_##n + +# define ASIO_VARIADIC_BYVAL_PARAMS_1 T1 x1 +# define ASIO_VARIADIC_BYVAL_PARAMS_2 T1 x1, T2 x2 +# define ASIO_VARIADIC_BYVAL_PARAMS_3 T1 x1, T2 x2, T3 x3 +# define ASIO_VARIADIC_BYVAL_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4 +# define ASIO_VARIADIC_BYVAL_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5 + +# define ASIO_VARIADIC_BYVAL_ARGS(n) \ + ASIO_VARIADIC_BYVAL_ARGS_##n + +# define ASIO_VARIADIC_BYVAL_ARGS_1 x1 +# define ASIO_VARIADIC_BYVAL_ARGS_2 x1, x2 +# define ASIO_VARIADIC_BYVAL_ARGS_3 x1, x2, x3 +# define ASIO_VARIADIC_BYVAL_ARGS_4 x1, x2, x3, x4 +# define ASIO_VARIADIC_BYVAL_ARGS_5 x1, x2, x3, x4, x5 + +# define ASIO_VARIADIC_MOVE_PARAMS(n) \ + ASIO_VARIADIC_MOVE_PARAMS_##n + +# define ASIO_VARIADIC_MOVE_PARAMS_1 \ + ASIO_MOVE_ARG(T1) x1 +# define ASIO_VARIADIC_MOVE_PARAMS_2 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2 +# define ASIO_VARIADIC_MOVE_PARAMS_3 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ + ASIO_MOVE_ARG(T3) x3 +# define ASIO_VARIADIC_MOVE_PARAMS_4 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ + ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4 +# define ASIO_VARIADIC_MOVE_PARAMS_5 \ + ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ + ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \ + ASIO_MOVE_ARG(T5) x5 + +# define ASIO_VARIADIC_MOVE_ARGS(n) \ + ASIO_VARIADIC_MOVE_ARGS_##n + +# define ASIO_VARIADIC_MOVE_ARGS_1 \ + ASIO_MOVE_CAST(T1)(x1) +# define ASIO_VARIADIC_MOVE_ARGS_2 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2) +# define ASIO_VARIADIC_MOVE_ARGS_3 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ + ASIO_MOVE_CAST(T3)(x3) +# define ASIO_VARIADIC_MOVE_ARGS_4 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ + ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4) +# define ASIO_VARIADIC_MOVE_ARGS_5 \ + ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ + ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \ + ASIO_MOVE_CAST(T5)(x5) + +# define ASIO_VARIADIC_DECAY(n) \ + ASIO_VARIADIC_DECAY_##n + +# define ASIO_VARIADIC_DECAY_1 \ + typename decay<T1>::type +# define ASIO_VARIADIC_DECAY_2 \ + typename decay<T1>::type, typename decay<T2>::type +# define ASIO_VARIADIC_DECAY_3 \ + typename decay<T1>::type, typename decay<T2>::type, \ + typename decay<T3>::type +# define ASIO_VARIADIC_DECAY_4 \ + typename decay<T1>::type, typename decay<T2>::type, \ + typename decay<T3>::type, typename decay<T4>::type +# define ASIO_VARIADIC_DECAY_5 \ + typename decay<T1>::type, typename decay<T2>::type, \ + typename decay<T3>::type, typename decay<T4>::type, \ + typename decay<T5>::type + +# define ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5) + +#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#endif // ASIO_DETAIL_VARIADIC_TEMPLATES_HPP diff --git a/lib/asio/detail/wait_handler.hpp b/lib/asio/detail/wait_handler.hpp new file mode 100644 index 0000000..bd3dc24 --- /dev/null +++ b/lib/asio/detail/wait_handler.hpp @@ -0,0 +1,85 @@ +// +// detail/wait_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WAIT_HANDLER_HPP +#define ASIO_DETAIL_WAIT_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/io_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class wait_handler : public wait_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(wait_handler); + + wait_handler(Handler& h) + : wait_op(&wait_handler::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(h)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + wait_handler* h(static_cast<wait_handler*>(base)); + ptr p = { asio::detail::addressof(h->handler_), h, h }; + handler_work<Handler> w(h->handler_); + + ASIO_HANDLER_COMPLETION((*h)); + + // 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, asio::error_code> + handler(h->handler_, h->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WAIT_HANDLER_HPP diff --git a/lib/asio/detail/wait_op.hpp b/lib/asio/detail/wait_op.hpp new file mode 100644 index 0000000..1a3017b --- /dev/null +++ b/lib/asio/detail/wait_op.hpp @@ -0,0 +1,45 @@ +// +// detail/wait_op.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WAIT_OP_HPP +#define ASIO_DETAIL_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class wait_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + +protected: + wait_op(func_type func) + : operation(func) + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WAIT_OP_HPP diff --git a/lib/asio/detail/win_event.hpp b/lib/asio/detail/win_event.hpp new file mode 100644 index 0000000..859cdee --- /dev/null +++ b/lib/asio/detail/win_event.hpp @@ -0,0 +1,151 @@ +// +// detail/win_event.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_EVENT_HPP +#define ASIO_DETAIL_WIN_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/assert.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_event + : private noncopyable +{ +public: + // Constructor. + ASIO_DECL win_event(); + + // Destructor. + ASIO_DECL ~win_event(); + + // Signal the event. (Retained for backward compatibility.) + template <typename Lock> + void signal(Lock& lock) + { + this->signal_all(lock); + } + + // Signal all waiters. + template <typename Lock> + void signal_all(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + state_ |= 1; + ::SetEvent(events_[0]); + } + + // Unlock the mutex and signal one waiter. + template <typename Lock> + void unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + lock.unlock(); + if (have_waiters) + ::SetEvent(events_[1]); + } + + // If there's a waiter, unlock the mutex and signal it. + template <typename Lock> + bool maybe_unlock_and_signal_one(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + if (state_ > 1) + { + lock.unlock(); + ::SetEvent(events_[1]); + return true; + } + return false; + } + + // Reset the event. + template <typename Lock> + void clear(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + (void)lock; + ::ResetEvent(events_[0]); + state_ &= ~std::size_t(1); + } + + // Wait for the event to become signalled. + template <typename Lock> + void wait(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + while ((state_ & 1) == 0) + { + state_ += 2; + lock.unlock(); +#if defined(ASIO_WINDOWS_APP) + ::WaitForMultipleObjectsEx(2, events_, false, INFINITE, false); +#else // defined(ASIO_WINDOWS_APP) + ::WaitForMultipleObjects(2, events_, false, INFINITE); +#endif // defined(ASIO_WINDOWS_APP) + lock.lock(); + state_ -= 2; + } + } + + // Timed wait for the event to become signalled. + template <typename Lock> + bool wait_for_usec(Lock& lock, long usec) + { + ASIO_ASSERT(lock.locked()); + if ((state_ & 1) == 0) + { + state_ += 2; + lock.unlock(); + DWORD msec = usec > 0 ? (usec < 1000 ? 1 : usec / 1000) : 0; +#if defined(ASIO_WINDOWS_APP) + ::WaitForMultipleObjectsEx(2, events_, false, msec, false); +#else // defined(ASIO_WINDOWS_APP) + ::WaitForMultipleObjects(2, events_, false, msec); +#endif // defined(ASIO_WINDOWS_APP) + lock.lock(); + state_ -= 2; + } + return (state_ & 1) != 0; + } + +private: + HANDLE events_[2]; + std::size_t state_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_event.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_WIN_EVENT_HPP diff --git a/lib/asio/detail/win_fd_set_adapter.hpp b/lib/asio/detail/win_fd_set_adapter.hpp new file mode 100644 index 0000000..8d5e700 --- /dev/null +++ b/lib/asio/detail/win_fd_set_adapter.hpp @@ -0,0 +1,149 @@ +// +// detail/win_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP +#define ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements. +class win_fd_set_adapter : noncopyable +{ +public: + enum { default_fd_set_size = 1024 }; + + win_fd_set_adapter() + : capacity_(default_fd_set_size), + max_descriptor_(invalid_socket) + { + fd_set_ = static_cast<win_fd_set*>(::operator new( + sizeof(win_fd_set) - sizeof(SOCKET) + + sizeof(SOCKET) * (capacity_))); + fd_set_->fd_count = 0; + } + + ~win_fd_set_adapter() + { + ::operator delete(fd_set_); + } + + void reset() + { + fd_set_->fd_count = 0; + max_descriptor_ = invalid_socket; + } + + bool set(socket_type descriptor) + { + for (u_int i = 0; i < fd_set_->fd_count; ++i) + if (fd_set_->fd_array[i] == descriptor) + return true; + + reserve(fd_set_->fd_count + 1); + fd_set_->fd_array[fd_set_->fd_count++] = descriptor; + return true; + } + + void set(reactor_op_queue<socket_type>& operations, op_queue<operation>&) + { + reactor_op_queue<socket_type>::iterator i = operations.begin(); + while (i != operations.end()) + { + reactor_op_queue<socket_type>::iterator op_iter = i++; + reserve(fd_set_->fd_count + 1); + fd_set_->fd_array[fd_set_->fd_count++] = op_iter->first; + } + } + + bool is_set(socket_type descriptor) const + { + return !!__WSAFDIsSet(descriptor, + const_cast<fd_set*>(reinterpret_cast<const fd_set*>(fd_set_))); + } + + operator fd_set*() + { + return reinterpret_cast<fd_set*>(fd_set_); + } + + socket_type max_descriptor() const + { + return max_descriptor_; + } + + void perform(reactor_op_queue<socket_type>& operations, + op_queue<operation>& ops) const + { + for (u_int i = 0; i < fd_set_->fd_count; ++i) + operations.perform_operations(fd_set_->fd_array[i], ops); + } + +private: + // This structure is defined to be compatible with the Windows API fd_set + // structure, but without being dependent on the value of FD_SETSIZE. We use + // the "struct hack" to allow the number of descriptors to be varied at + // runtime. + struct win_fd_set + { + u_int fd_count; + SOCKET fd_array[1]; + }; + + // Increase the fd_set_ capacity to at least the specified number of elements. + void reserve(u_int n) + { + if (n <= capacity_) + return; + + u_int new_capacity = capacity_ + capacity_ / 2; + if (new_capacity < n) + new_capacity = n; + + win_fd_set* new_fd_set = static_cast<win_fd_set*>(::operator new( + sizeof(win_fd_set) - sizeof(SOCKET) + + sizeof(SOCKET) * (new_capacity))); + + new_fd_set->fd_count = fd_set_->fd_count; + for (u_int i = 0; i < fd_set_->fd_count; ++i) + new_fd_set->fd_array[i] = fd_set_->fd_array[i]; + + ::operator delete(fd_set_); + fd_set_ = new_fd_set; + capacity_ = new_capacity; + } + + win_fd_set* fd_set_; + u_int capacity_; + socket_type max_descriptor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP diff --git a/lib/asio/detail/win_fenced_block.hpp b/lib/asio/detail/win_fenced_block.hpp new file mode 100644 index 0000000..1ce6e13 --- /dev/null +++ b/lib/asio/detail/win_fenced_block.hpp @@ -0,0 +1,90 @@ +// +// detail/win_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_FENCED_BLOCK_HPP +#define ASIO_DETAIL_WIN_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) && !defined(UNDER_CE) + +#include "asio/detail/socket_types.hpp" +#include "asio/detail/noncopyable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit win_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit win_fenced_block(full_t) + { +#if defined(__BORLANDC__) + LONG barrier = 0; + ::InterlockedExchange(&barrier, 1); +#elif defined(ASIO_MSVC) \ + && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier)) +# 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 + MemoryBarrier(); +#endif + } + + // Destructor. + ~win_fenced_block() + { +#if defined(__BORLANDC__) + LONG barrier = 0; + ::InterlockedExchange(&barrier, 1); +#elif defined(ASIO_MSVC) \ + && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier)) +# 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 + MemoryBarrier(); +#endif + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) && !defined(UNDER_CE) + +#endif // ASIO_DETAIL_WIN_FENCED_BLOCK_HPP diff --git a/lib/asio/detail/win_global.hpp b/lib/asio/detail/win_global.hpp new file mode 100644 index 0000000..3b15a32 --- /dev/null +++ b/lib/asio/detail/win_global.hpp @@ -0,0 +1,73 @@ +// +// detail/win_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_GLOBAL_HPP +#define ASIO_DETAIL_WIN_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/static_mutex.hpp" +#include "asio/detail/tss_ptr.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +struct win_global_impl +{ + // Destructor automatically cleans up the global. + ~win_global_impl() + { + delete ptr_; + } + + static win_global_impl instance_; + static static_mutex mutex_; + static T* ptr_; + static tss_ptr<T> tss_ptr_; +}; + +template <typename T> +win_global_impl<T> win_global_impl<T>::instance_ = { 0 }; + +template <typename T> +static_mutex win_global_impl<T>::mutex_ = ASIO_STATIC_MUTEX_INIT; + +template <typename T> +T* win_global_impl<T>::ptr_ = 0; + +template <typename T> +tss_ptr<T> win_global_impl<T>::tss_ptr_; + +template <typename T> +T& win_global() +{ + if (static_cast<T*>(win_global_impl<T>::tss_ptr_) == 0) + { + win_global_impl<T>::mutex_.init(); + static_mutex::scoped_lock lock(win_global_impl<T>::mutex_); + win_global_impl<T>::ptr_ = new T; + win_global_impl<T>::tss_ptr_ = win_global_impl<T>::ptr_; + } + + return *win_global_impl<T>::tss_ptr_; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WIN_GLOBAL_HPP diff --git a/lib/asio/detail/win_iocp_handle_read_op.hpp b/lib/asio/detail/win_iocp_handle_read_op.hpp new file mode 100644 index 0000000..88e3f6c --- /dev/null +++ b/lib/asio/detail/win_iocp_handle_read_op.hpp @@ -0,0 +1,111 @@ +// +// detail/win_iocp_handle_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Handler> +class win_iocp_handle_read_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op); + + win_iocp_handle_read_op( + const MutableBufferSequence& buffers, Handler& handler) + : operation(&win_iocp_handle_read_op::do_complete), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_HANDLE_EOF) + ec = asio::error::eof; + + // 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, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP diff --git a/lib/asio/detail/win_iocp_handle_service.hpp b/lib/asio/detail/win_iocp_handle_service.hpp new file mode 100644 index 0000000..849fe8f --- /dev/null +++ b/lib/asio/detail/win_iocp_handle_service.hpp @@ -0,0 +1,323 @@ +// +// detail/win_iocp_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP +#define ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/cstdint.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/win_iocp_handle_read_op.hpp" +#include "asio/detail/win_iocp_handle_write_op.hpp" +#include "asio/detail/win_iocp_io_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_handle_service : + public service_base<win_iocp_handle_service> +{ +public: + // The native type of a stream handle. + typedef HANDLE native_handle_type; + + // The implementation type of the stream handle. + class implementation_type + { + public: + // Default constructor. + implementation_type() + : handle_(INVALID_HANDLE_VALUE), + safe_cancellation_thread_id_(0), + next_(0), + prev_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class win_iocp_handle_service; + + // The native stream handle representation. + native_handle_type handle_; + + // The ID of the thread from which it is safe to cancel asynchronous + // operations. 0 means no asynchronous operations have been started yet. + // ~0 means asynchronous operations have been started from more than one + // thread, and cancellation is not supported for the handle. + DWORD safe_cancellation_thread_id_; + + // Pointers to adjacent handle implementations in linked list. + implementation_type* next_; + implementation_type* prev_; + }; + + ASIO_DECL win_iocp_handle_service(asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new handle implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Move-construct a new handle implementation. + ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another handle implementation. + ASIO_DECL void move_assign(implementation_type& impl, + win_iocp_handle_service& other_service, + implementation_type& other_impl); + + // Destroy a handle implementation. + ASIO_DECL void destroy(implementation_type& impl); + + // Assign a native handle to a handle implementation. + ASIO_DECL asio::error_code assign(implementation_type& impl, + const native_handle_type& handle, asio::error_code& ec); + + // Determine whether the handle is open. + bool is_open(const implementation_type& impl) const + { + return impl.handle_ != INVALID_HANDLE_VALUE; + } + + // Destroy a handle implementation. + ASIO_DECL asio::error_code close(implementation_type& impl, + asio::error_code& ec); + + // Get the native handle representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return impl.handle_; + } + + // Cancel all operations associated with the handle. + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); + + // Write the given data. Returns the number of bytes written. + template <typename ConstBufferSequence> + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return write_some_at(impl, 0, buffers, ec); + } + + // Write the given data at the specified offset. Returns the number of bytes + // written. + template <typename ConstBufferSequence> + size_t write_some_at(implementation_type& impl, uint64_t offset, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + asio::const_buffer buffer = + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::first(buffers); + + return do_write(impl, offset, buffer, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler); + + ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some")); + + start_write_op(impl, 0, + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::first(buffers), p.p); + p.v = p.p = 0; + } + + // Start an asynchronous write at a specified offset. The data being written + // must be valid for the lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_write_some_at(implementation_type& impl, uint64_t offset, + const ConstBufferSequence& buffers, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler); + + ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some_at")); + + start_write_op(impl, offset, + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::first(buffers), p.p); + p.v = p.p = 0; + } + + // Read some data. Returns the number of bytes received. + template <typename MutableBufferSequence> + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return read_some_at(impl, 0, buffers, ec); + } + + // Read some data at a specified offset. Returns the number of bytes received. + template <typename MutableBufferSequence> + size_t read_some_at(implementation_type& impl, uint64_t offset, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + asio::mutable_buffer buffer = + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::first(buffers); + + return do_read(impl, offset, buffer, ec); + } + + // Start an asynchronous read. The buffer for the data being received must be + // valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler); + + ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some")); + + start_read_op(impl, 0, + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::first(buffers), p.p); + p.v = p.p = 0; + } + + // Start an asynchronous read at a specified offset. The buffer for the data + // being received must be valid for the lifetime of the asynchronous + // operation. + template <typename MutableBufferSequence, typename Handler> + void async_read_some_at(implementation_type& impl, uint64_t offset, + const MutableBufferSequence& buffers, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler); + + ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some_at")); + + start_read_op(impl, offset, + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::first(buffers), p.p); + p.v = p.p = 0; + } + +private: + // Prevent the use of the null_buffers type with this service. + size_t write_some(implementation_type& impl, + const null_buffers& buffers, asio::error_code& ec); + size_t write_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, asio::error_code& ec); + template <typename Handler> + void async_write_some(implementation_type& impl, + const null_buffers& buffers, Handler& handler); + template <typename Handler> + void async_write_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, Handler& handler); + size_t read_some(implementation_type& impl, + const null_buffers& buffers, asio::error_code& ec); + size_t read_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, asio::error_code& ec); + template <typename Handler> + void async_read_some(implementation_type& impl, + const null_buffers& buffers, Handler& handler); + template <typename Handler> + void async_read_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, Handler& handler); + + // Helper class for waiting for synchronous operations to complete. + class overlapped_wrapper; + + // Helper function to perform a synchronous write operation. + ASIO_DECL size_t do_write(implementation_type& impl, + uint64_t offset, const asio::const_buffer& buffer, + asio::error_code& ec); + + // Helper function to start a write operation. + ASIO_DECL void start_write_op(implementation_type& impl, + uint64_t offset, const asio::const_buffer& buffer, + operation* op); + + // Helper function to perform a synchronous write operation. + ASIO_DECL size_t do_read(implementation_type& impl, + uint64_t offset, const asio::mutable_buffer& buffer, + asio::error_code& ec); + + // Helper function to start a read operation. + ASIO_DECL void start_read_op(implementation_type& impl, + uint64_t offset, const asio::mutable_buffer& buffer, + operation* op); + + // Update the ID of the thread from which cancellation is safe. + ASIO_DECL void update_cancellation_thread_id(implementation_type& impl); + + // Helper function to close a handle when the associated object is being + // destroyed. + ASIO_DECL void close_for_destruction(implementation_type& impl); + + // The IOCP service used for running asynchronous operations and dispatching + // handlers. + win_iocp_io_context& iocp_service_; + + // Mutex to protect access to the linked list of implementations. + mutex mutex_; + + // The head of a linked list of all implementations. + implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_handle_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP diff --git a/lib/asio/detail/win_iocp_handle_write_op.hpp b/lib/asio/detail/win_iocp_handle_write_op.hpp new file mode 100644 index 0000000..d7bb944 --- /dev/null +++ b/lib/asio/detail/win_iocp_handle_write_op.hpp @@ -0,0 +1,103 @@ +// +// detail/win_iocp_handle_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence, typename Handler> +class win_iocp_handle_write_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op); + + win_iocp_handle_write_op(const ConstBufferSequence& buffers, Handler& handler) + : operation(&win_iocp_handle_write_op::do_complete), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // 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, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + ConstBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP diff --git a/lib/asio/detail/win_iocp_io_context.hpp b/lib/asio/detail/win_iocp_io_context.hpp new file mode 100644 index 0000000..11bf58b --- /dev/null +++ b/lib/asio/detail/win_iocp_io_context.hpp @@ -0,0 +1,328 @@ +// +// detail/win_iocp_io_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP +#define ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/limits.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/thread.hpp" +#include "asio/detail/thread_context.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/detail/win_iocp_operation.hpp" +#include "asio/detail/win_iocp_thread_info.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class wait_op; + +class win_iocp_io_context + : public execution_context_service_base<win_iocp_io_context>, + public thread_context +{ +public: + // Constructor. Specifies a concurrency hint that is passed through to the + // underlying I/O completion port. + ASIO_DECL win_iocp_io_context(asio::execution_context& ctx, + int concurrency_hint = -1); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Initialise the task. Nothing to do here. + void init_task() + { + } + + // Register a handle with the IO completion port. + ASIO_DECL asio::error_code register_handle( + HANDLE handle, asio::error_code& ec); + + // Run the event loop until stopped or no more work. + ASIO_DECL size_t run(asio::error_code& ec); + + // Run until stopped or one operation is performed. + ASIO_DECL size_t run_one(asio::error_code& ec); + + // Run until timeout, interrupted, or one operation is performed. + ASIO_DECL size_t wait_one(long usec, asio::error_code& ec); + + // Poll for operations without blocking. + ASIO_DECL size_t poll(asio::error_code& ec); + + // Poll for one operation without blocking. + ASIO_DECL size_t poll_one(asio::error_code& ec); + + // Stop the event processing loop. + ASIO_DECL void stop(); + + // Determine whether the io_context is stopped. + bool stopped() const + { + return ::InterlockedExchangeAdd(&stopped_, 0) != 0; + } + + // Restart in preparation for a subsequent run invocation. + void restart() + { + ::InterlockedExchange(&stopped_, 0); + } + + // Notify that some work has started. + void work_started() + { + ::InterlockedIncrement(&outstanding_work_); + } + + // Notify that some work has finished. + void work_finished() + { + if (::InterlockedDecrement(&outstanding_work_) == 0) + stop(); + } + + // Return whether a handler can be dispatched immediately. + bool can_dispatch() + { + return thread_call_stack::contains(this) != 0; + } + + // 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(win_iocp_operation* op, bool) + { + 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. + ASIO_DECL void post_deferred_completion(win_iocp_operation* op); + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operations. + ASIO_DECL void post_deferred_completions( + op_queue<win_iocp_operation>& ops); + + // Request invocation of the given operation using the thread-private queue + // and return immediately. Assumes that work_started() has not yet been + // called for the operation. + void post_private_immediate_completion(win_iocp_operation* op) + { + post_immediate_completion(op, false); + } + + // Request invocation of the given operation using the thread-private queue + // and return immediately. Assumes that work_started() was previously called + // for the operation. + void post_private_deferred_completion(win_iocp_operation* op) + { + post_deferred_completion(op); + } + + // Enqueue the given operation following a failed attempt to dispatch the + // operation for immediate invocation. + void do_dispatch(operation* op) + { + post_immediate_completion(op, false); + } + + // Process unfinished operations as part of a shutdown operation. Assumes + // that work_started() was previously called for the operations. + ASIO_DECL void abandon_operations(op_queue<operation>& ops); + + // 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. + ASIO_DECL void on_pending(win_iocp_operation* 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. + ASIO_DECL void on_completion(win_iocp_operation* op, + DWORD last_error = 0, DWORD bytes_transferred = 0); + + // Called after starting an overlapped I/O operation that completed + // immediately. The caller must have already called work_started() prior to + // starting the operation. + ASIO_DECL void on_completion(win_iocp_operation* op, + const asio::error_code& ec, DWORD bytes_transferred = 0); + + // Add a new timer queue to the service. + template <typename Time_Traits> + void add_timer_queue(timer_queue<Time_Traits>& timer_queue); + + // Remove a timer queue from the service. + template <typename Time_Traits> + void remove_timer_queue(timer_queue<Time_Traits>& timer_queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template <typename Time_Traits> + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op); + + // Cancel the timer associated with the given token. Returns the number of + // handlers that have been posted or dispatched. + template <typename Time_Traits> + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from); + + // Get the concurrency hint that was used to initialise the io_context. + int concurrency_hint() const + { + return concurrency_hint_; + } + +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). + ASIO_DECL size_t do_one(DWORD msec, asio::error_code& ec); + + // Helper to calculate the GetQueuedCompletionStatus timeout. + ASIO_DECL static DWORD get_gqcs_timeout(); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + ASIO_DECL void update_timeout(); + + // Helper class to call work_finished() on block exit. + struct work_finished_on_block_exit; + + // Helper class for managing a HANDLE. + struct auto_handle + { + HANDLE handle; + auto_handle() : handle(0) {} + ~auto_handle() { if (handle) ::CloseHandle(handle); } + }; + + // The IO completion port used for queueing operations. + auto_handle iocp_; + + // The count of unfinished work. + long outstanding_work_; + + // Flag to indicate whether the event loop has been stopped. + mutable long stopped_; + + // Flag to indicate whether there is an in-flight stop event. Every event + // posted using PostQueuedCompletionStatus consumes non-paged pool, so to + // avoid exhausting this resouce we limit the number of outstanding events. + long stop_event_posted_; + + // Flag to indicate whether the service has been shut down. + long shutdown_; + + enum + { + // Timeout to use with GetQueuedCompletionStatus on older versions of + // Windows. Some versions of windows have a "bug" where a call to + // GetQueuedCompletionStatus can appear stuck even though there are events + // waiting on the queue. Using a timeout helps to work around the issue. + default_gqcs_timeout = 500, + + // Maximum waitable timer timeout, in milliseconds. + max_timeout_msec = 5 * 60 * 1000, + + // Maximum waitable timer timeout, in microseconds. + max_timeout_usec = max_timeout_msec * 1000, + + // Completion key value used to wake up a thread to dispatch timers or + // completed operations. + wake_for_dispatch = 1, + + // 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 = 2 + }; + + // Timeout to use with GetQueuedCompletionStatus. + const DWORD gqcs_timeout_; + + // Function object for processing timeouts in a background thread. + struct timer_thread_function; + friend struct timer_thread_function; + + // Background thread used for processing timeouts. + scoped_ptr<thread> timer_thread_; + + // A waitable timer object used for waiting for timeouts. + auto_handle waitable_timer_; + + // Non-zero if timers or completed operations need to be dispatched. + long dispatch_required_; + + // Mutex for protecting access to the timer queues and completed operations. + mutex dispatch_mutex_; + + // The timer queues. + timer_queue_set timer_queues_; + + // The operations that are ready to dispatch. + op_queue<win_iocp_operation> completed_ops_; + + // The concurrency hint used to initialise the io_context. + const int concurrency_hint_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/win_iocp_io_context.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_io_context.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP diff --git a/lib/asio/detail/win_iocp_null_buffers_op.hpp b/lib/asio/detail/win_iocp_null_buffers_op.hpp new file mode 100644 index 0000000..db70cb2 --- /dev/null +++ b/lib/asio/detail/win_iocp_null_buffers_op.hpp @@ -0,0 +1,121 @@ +// +// detail/win_iocp_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class win_iocp_null_buffers_op : public reactor_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op); + + win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token, + Handler& handler) + : reactor_op(&win_iocp_null_buffers_op::do_perform, + &win_iocp_null_buffers_op::do_complete), + cancel_token_(cancel_token), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // The reactor may have stored a result in the operation object. + if (o->ec_) + ec = o->ec_; + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + + // 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, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP diff --git a/lib/asio/detail/win_iocp_operation.hpp b/lib/asio/detail/win_iocp_operation.hpp new file mode 100644 index 0000000..81d43f0 --- /dev/null +++ b/lib/asio/detail/win_iocp_operation.hpp @@ -0,0 +1,96 @@ +// +// detail/win_iocp_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_OPERATION_HPP +#define ASIO_DETAIL_WIN_IOCP_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/handler_tracking.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_io_context; + +// 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 + ASIO_ALSO_INHERIT_TRACKED_HANDLER +{ +public: + typedef win_iocp_operation operation_type; + + void complete(void* owner, const asio::error_code& ec, + std::size_t bytes_transferred) + { + func_(owner, this, ec, bytes_transferred); + } + + void destroy() + { + func_(0, this, asio::error_code(), 0); + } + +protected: + typedef void (*func_type)( + void*, win_iocp_operation*, + const asio::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_context; + win_iocp_operation* next_; + func_type func_; + long ready_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_OPERATION_HPP diff --git a/lib/asio/detail/win_iocp_overlapped_op.hpp b/lib/asio/detail/win_iocp_overlapped_op.hpp new file mode 100644 index 0000000..2b2cc31 --- /dev/null +++ b/lib/asio/detail/win_iocp_overlapped_op.hpp @@ -0,0 +1,90 @@ +// +// detail/win_iocp_overlapped_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class win_iocp_overlapped_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op); + + win_iocp_overlapped_op(Handler& handler) + : operation(&win_iocp_overlapped_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_overlapped_op* o(static_cast<win_iocp_overlapped_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP diff --git a/lib/asio/detail/win_iocp_overlapped_ptr.hpp b/lib/asio/detail/win_iocp_overlapped_ptr.hpp new file mode 100644 index 0000000..7a19114 --- /dev/null +++ b/lib/asio/detail/win_iocp_overlapped_ptr.hpp @@ -0,0 +1,143 @@ +// +// detail/win_iocp_overlapped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP +#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/io_context.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/win_iocp_overlapped_op.hpp" +#include "asio/detail/win_iocp_io_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Wraps a handler to create an OVERLAPPED object for use with overlapped I/O. +class win_iocp_overlapped_ptr + : private noncopyable +{ +public: + // Construct an empty win_iocp_overlapped_ptr. + win_iocp_overlapped_ptr() + : ptr_(0), + iocp_service_(0) + { + } + + // Construct an win_iocp_overlapped_ptr to contain the specified handler. + template <typename Handler> + explicit win_iocp_overlapped_ptr( + asio::io_context& io_context, ASIO_MOVE_ARG(Handler) handler) + : ptr_(0), + iocp_service_(0) + { + this->reset(io_context, ASIO_MOVE_CAST(Handler)(handler)); + } + + // Destructor automatically frees the OVERLAPPED object unless released. + ~win_iocp_overlapped_ptr() + { + reset(); + } + + // Reset to empty. + void reset() + { + if (ptr_) + { + ptr_->destroy(); + ptr_ = 0; + iocp_service_->work_finished(); + iocp_service_ = 0; + } + } + + // Reset to contain the specified handler, freeing any current OVERLAPPED + // object. + template <typename Handler> + void reset(asio::io_context& io_context, Handler handler) + { + typedef win_iocp_overlapped_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((io_context, *p.p, + "io_context", &io_context.impl_, 0, "overlapped")); + + io_context.impl_.work_started(); + reset(); + ptr_ = p.p; + p.v = p.p = 0; + iocp_service_ = &io_context.impl_; + } + + // Get the contained OVERLAPPED object. + OVERLAPPED* get() + { + return ptr_; + } + + // Get the contained OVERLAPPED object. + const OVERLAPPED* get() const + { + return ptr_; + } + + // Release ownership of the OVERLAPPED object. + OVERLAPPED* release() + { + if (ptr_) + iocp_service_->on_pending(ptr_); + + OVERLAPPED* tmp = ptr_; + ptr_ = 0; + iocp_service_ = 0; + return tmp; + } + + // Post completion notification for overlapped operation. Releases ownership. + void complete(const asio::error_code& ec, + std::size_t bytes_transferred) + { + if (ptr_) + { + iocp_service_->on_completion(ptr_, ec, + static_cast<DWORD>(bytes_transferred)); + ptr_ = 0; + iocp_service_ = 0; + } + } + +private: + win_iocp_operation* ptr_; + win_iocp_io_context* iocp_service_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP diff --git a/lib/asio/detail/win_iocp_serial_port_service.hpp b/lib/asio/detail/win_iocp_serial_port_service.hpp new file mode 100644 index 0000000..ac06348 --- /dev/null +++ b/lib/asio/detail/win_iocp_serial_port_service.hpp @@ -0,0 +1,230 @@ +// +// detail/win_iocp_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP +#define ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + +#include <string> +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/detail/win_iocp_handle_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Extend win_iocp_handle_service to provide serial port support. +class win_iocp_serial_port_service : + public service_base<win_iocp_serial_port_service> +{ +public: + // The native type of a serial port. + typedef win_iocp_handle_service::native_handle_type native_handle_type; + + // The implementation type of the serial port. + typedef win_iocp_handle_service::implementation_type implementation_type; + + // Constructor. + ASIO_DECL win_iocp_serial_port_service( + asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new serial port implementation. + void construct(implementation_type& impl) + { + handle_service_.construct(impl); + } + + // Move-construct a new serial port implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + handle_service_.move_construct(impl, other_impl); + } + + // Move-assign from another serial port implementation. + void move_assign(implementation_type& impl, + win_iocp_serial_port_service& other_service, + implementation_type& other_impl) + { + handle_service_.move_assign(impl, + other_service.handle_service_, other_impl); + } + + // Destroy a serial port implementation. + void destroy(implementation_type& impl) + { + handle_service_.destroy(impl); + } + + // Open the serial port using the specified device name. + ASIO_DECL asio::error_code open(implementation_type& impl, + const std::string& device, asio::error_code& ec); + + // Assign a native handle to a serial port implementation. + asio::error_code assign(implementation_type& impl, + const native_handle_type& handle, asio::error_code& ec) + { + return handle_service_.assign(impl, handle, ec); + } + + // Determine whether the serial port is open. + bool is_open(const implementation_type& impl) const + { + return handle_service_.is_open(impl); + } + + // Destroy a serial port implementation. + asio::error_code close(implementation_type& impl, + asio::error_code& ec) + { + return handle_service_.close(impl, ec); + } + + // Get the native serial port representation. + native_handle_type native_handle(implementation_type& impl) + { + return handle_service_.native_handle(impl); + } + + // Cancel all operations associated with the handle. + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) + { + return handle_service_.cancel(impl, ec); + } + + // Set an option on the serial port. + template <typename SettableSerialPortOption> + asio::error_code set_option(implementation_type& impl, + const SettableSerialPortOption& option, asio::error_code& ec) + { + return do_set_option(impl, + &win_iocp_serial_port_service::store_option<SettableSerialPortOption>, + &option, ec); + } + + // Get an option from the serial port. + template <typename GettableSerialPortOption> + asio::error_code get_option(const implementation_type& impl, + GettableSerialPortOption& option, asio::error_code& ec) const + { + return do_get_option(impl, + &win_iocp_serial_port_service::load_option<GettableSerialPortOption>, + &option, ec); + } + + // Send a break sequence to the serial port. + asio::error_code send_break(implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Write the given data. Returns the number of bytes sent. + template <typename ConstBufferSequence> + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return handle_service_.write_some(impl, buffers, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, Handler& handler) + { + handle_service_.async_write_some(impl, buffers, handler); + } + + // Read some data. Returns the number of bytes received. + template <typename MutableBufferSequence> + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return handle_service_.read_some(impl, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being received must be + // valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, Handler& handler) + { + handle_service_.async_read_some(impl, buffers, handler); + } + +private: + // Function pointer type for storing a serial port option. + typedef asio::error_code (*store_function_type)( + const void*, ::DCB&, asio::error_code&); + + // Helper function template to store a serial port option. + template <typename SettableSerialPortOption> + static asio::error_code store_option(const void* option, + ::DCB& storage, asio::error_code& ec) + { + static_cast<const SettableSerialPortOption*>(option)->store(storage, ec); + return ec; + } + + // Helper function to set a serial port option. + ASIO_DECL asio::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, asio::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef asio::error_code (*load_function_type)( + void*, const ::DCB&, asio::error_code&); + + // Helper function template to load a serial port option. + template <typename GettableSerialPortOption> + static asio::error_code load_option(void* option, + const ::DCB& storage, asio::error_code& ec) + { + static_cast<GettableSerialPortOption*>(option)->load(storage, ec); + return ec; + } + + // Helper function to get a serial port option. + ASIO_DECL asio::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, asio::error_code& ec) const; + + // The implementation used for initiating asynchronous operations. + win_iocp_handle_service handle_service_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_serial_port_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP diff --git a/lib/asio/detail/win_iocp_socket_accept_op.hpp b/lib/asio/detail/win_iocp_socket_accept_op.hpp new file mode 100644 index 0000000..18e7335 --- /dev/null +++ b/lib/asio/detail/win_iocp_socket_accept_op.hpp @@ -0,0 +1,297 @@ +// +// detail/win_iocp_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/win_iocp_socket_service_base.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Socket, typename Protocol, typename Handler> +class win_iocp_socket_accept_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op); + + win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service, + socket_type socket, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, + bool enable_connection_aborted, Handler& handler) + : operation(&win_iocp_socket_accept_op::do_complete), + socket_service_(socket_service), + socket_(socket), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + socket_holder& new_socket() + { + return new_socket_; + } + + void* output_buffer() + { + return output_buffer_; + } + + DWORD address_length() + { + return sizeof(sockaddr_storage_type) + 16; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + if (owner) + { + typename Protocol::endpoint peer_endpoint; + std::size_t addr_len = peer_endpoint.capacity(); + socket_ops::complete_iocp_accept(o->socket_, + o->output_buffer(), o->address_length(), + peer_endpoint.data(), &addr_len, + o->new_socket_.get(), ec); + + // Restart the accept operation if we got the connection_aborted error + // and the enable_connection_aborted socket option is not set. + if (ec == asio::error::connection_aborted + && !o->enable_connection_aborted_) + { + o->reset(); + o->socket_service_.restart_accept_op(o->socket_, + o->new_socket_, o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), + o->output_buffer(), o->address_length(), o); + p.v = p.p = 0; + return; + } + + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) + { + o->peer_.assign(o->protocol_, + typename Socket::native_handle_type( + o->new_socket_.get(), peer_endpoint), ec); + if (!ec) + o->new_socket_.release(); + } + + // Pass endpoint back to caller. + if (o->peer_endpoint_) + *o->peer_endpoint_ = peer_endpoint; + } + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code> + handler(o->handler_, ec); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + win_iocp_socket_service_base& socket_service_; + socket_type socket_; + socket_holder new_socket_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; + bool enable_connection_aborted_; + Handler handler_; +}; + +#if defined(ASIO_HAS_MOVE) + +template <typename Protocol, typename Handler> +class win_iocp_socket_move_accept_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op); + + win_iocp_socket_move_accept_op( + win_iocp_socket_service_base& socket_service, socket_type socket, + const Protocol& protocol, asio::io_context& peer_io_context, + typename Protocol::endpoint* peer_endpoint, + bool enable_connection_aborted, Handler& handler) + : operation(&win_iocp_socket_move_accept_op::do_complete), + socket_service_(socket_service), + socket_(socket), + peer_(peer_io_context), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + socket_holder& new_socket() + { + return new_socket_; + } + + void* output_buffer() + { + return output_buffer_; + } + + DWORD address_length() + { + return sizeof(sockaddr_storage_type) + 16; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_move_accept_op* o( + static_cast<win_iocp_socket_move_accept_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + if (owner) + { + typename Protocol::endpoint peer_endpoint; + std::size_t addr_len = peer_endpoint.capacity(); + socket_ops::complete_iocp_accept(o->socket_, + o->output_buffer(), o->address_length(), + peer_endpoint.data(), &addr_len, + o->new_socket_.get(), ec); + + // Restart the accept operation if we got the connection_aborted error + // and the enable_connection_aborted socket option is not set. + if (ec == asio::error::connection_aborted + && !o->enable_connection_aborted_) + { + o->reset(); + o->socket_service_.restart_accept_op(o->socket_, + o->new_socket_, o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), + o->output_buffer(), o->address_length(), o); + p.v = p.p = 0; + return; + } + + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) + { + o->peer_.assign(o->protocol_, + typename Protocol::socket::native_handle_type( + o->new_socket_.get(), peer_endpoint), ec); + if (!ec) + o->new_socket_.release(); + } + + // Pass endpoint back to caller. + if (o->peer_endpoint_) + *o->peer_endpoint_ = peer_endpoint; + } + + ASIO_HANDLER_COMPLETION((*o)); + + // 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::move_binder2<Handler, + asio::error_code, typename Protocol::socket> + handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), ec, + ASIO_MOVE_CAST(typename Protocol::socket)(o->peer_)); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + win_iocp_socket_service_base& socket_service_; + socket_type socket_; + socket_holder new_socket_; + typename Protocol::socket peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; + bool enable_connection_aborted_; + Handler handler_; +}; + +#endif // defined(ASIO_HAS_MOVE) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP diff --git a/lib/asio/detail/win_iocp_socket_connect_op.hpp b/lib/asio/detail/win_iocp_socket_connect_op.hpp new file mode 100644 index 0000000..e0c52dc --- /dev/null +++ b/lib/asio/detail/win_iocp_socket_connect_op.hpp @@ -0,0 +1,127 @@ +// +// detail/win_iocp_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_socket_connect_op_base : public reactor_op +{ +public: + win_iocp_socket_connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&win_iocp_socket_connect_op_base::do_perform, complete_func), + socket_(socket), + connect_ex_(false) + { + } + + static status do_perform(reactor_op* base) + { + win_iocp_socket_connect_op_base* o( + static_cast<win_iocp_socket_connect_op_base*>(base)); + + return socket_ops::non_blocking_connect( + o->socket_, o->ec_) ? done : not_done; + } + + socket_type socket_; + bool connect_ex_; +}; + +template <typename Handler> +class win_iocp_socket_connect_op : public win_iocp_socket_connect_op_base +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_connect_op); + + win_iocp_socket_connect_op(socket_type socket, Handler& handler) + : win_iocp_socket_connect_op_base(socket, + &win_iocp_socket_connect_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_connect_op* o( + static_cast<win_iocp_socket_connect_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + if (owner) + { + if (o->connect_ex_) + socket_ops::complete_iocp_connect(o->socket_, ec); + else + ec = o->ec_; + } + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code> + handler(o->handler_, ec); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP diff --git a/lib/asio/detail/win_iocp_socket_recv_op.hpp b/lib/asio/detail/win_iocp_socket_recv_op.hpp new file mode 100644 index 0000000..4159540 --- /dev/null +++ b/lib/asio/detail/win_iocp_socket_recv_op.hpp @@ -0,0 +1,117 @@ +// +// detail/win_iocp_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Handler> +class win_iocp_socket_recv_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op); + + win_iocp_socket_recv_op(socket_ops::state_type state, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler& handler) + : operation(&win_iocp_socket_recv_op::do_complete), + state_(state), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recv(o->state_, o->cancel_token_, + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::all_empty(o->buffers_), + ec, bytes_transferred); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::state_type state_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP diff --git a/lib/asio/detail/win_iocp_socket_recvfrom_op.hpp b/lib/asio/detail/win_iocp_socket_recvfrom_op.hpp new file mode 100644 index 0000000..843ce5b --- /dev/null +++ b/lib/asio/detail/win_iocp_socket_recvfrom_op.hpp @@ -0,0 +1,125 @@ +// +// detail/win_iocp_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Endpoint, typename Handler> +class win_iocp_socket_recvfrom_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op); + + win_iocp_socket_recvfrom_op(Endpoint& endpoint, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler& handler) + : operation(&win_iocp_socket_recvfrom_op::do_complete), + endpoint_(endpoint), + endpoint_size_(static_cast<int>(endpoint.capacity())), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + int& endpoint_size() + { + return endpoint_size_; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_recvfrom_op* o( + static_cast<win_iocp_socket_recvfrom_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Endpoint& endpoint_; + int endpoint_size_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP diff --git a/lib/asio/detail/win_iocp_socket_recvmsg_op.hpp b/lib/asio/detail/win_iocp_socket_recvmsg_op.hpp new file mode 100644 index 0000000..78f36b7 --- /dev/null +++ b/lib/asio/detail/win_iocp_socket_recvmsg_op.hpp @@ -0,0 +1,118 @@ +// +// detail/win_iocp_socket_recvmsg_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" +#include "asio/socket_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Handler> +class win_iocp_socket_recvmsg_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvmsg_op); + + win_iocp_socket_recvmsg_op( + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, + socket_base::message_flags& out_flags, Handler& handler) + : operation(&win_iocp_socket_recvmsg_op::do_complete), + cancel_token_(cancel_token), + buffers_(buffers), + out_flags_(out_flags), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_recvmsg_op* o( + static_cast<win_iocp_socket_recvmsg_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recvmsg(o->cancel_token_, ec); + o->out_flags_ = 0; + + // 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, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + socket_base::message_flags& out_flags_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP diff --git a/lib/asio/detail/win_iocp_socket_send_op.hpp b/lib/asio/detail/win_iocp_socket_send_op.hpp new file mode 100644 index 0000000..e1c7ab9 --- /dev/null +++ b/lib/asio/detail/win_iocp_socket_send_op.hpp @@ -0,0 +1,111 @@ +// +// detail/win_iocp_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence, typename Handler> +class win_iocp_socket_send_op : public operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op); + + win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token, + const ConstBufferSequence& buffers, Handler& handler) + : operation(&win_iocp_socket_send_op::do_complete), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_send(o->cancel_token_, ec); + + // 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, asio::error_code, std::size_t> + handler(o->handler_, ec, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + ConstBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP diff --git a/lib/asio/detail/win_iocp_socket_service.hpp b/lib/asio/detail/win_iocp_socket_service.hpp new file mode 100644 index 0000000..3f01b4d --- /dev/null +++ b/lib/asio/detail/win_iocp_socket_service.hpp @@ -0,0 +1,599 @@ +// +// detail/win_iocp_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include <cstring> +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/select_reactor.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/win_iocp_io_context.hpp" +#include "asio/detail/win_iocp_null_buffers_op.hpp" +#include "asio/detail/win_iocp_socket_accept_op.hpp" +#include "asio/detail/win_iocp_socket_connect_op.hpp" +#include "asio/detail/win_iocp_socket_recvfrom_op.hpp" +#include "asio/detail/win_iocp_socket_send_op.hpp" +#include "asio/detail/win_iocp_socket_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol> +class win_iocp_socket_service : + public service_base<win_iocp_socket_service<Protocol> >, + public win_iocp_socket_service_base +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + class native_handle_type + { + public: + native_handle_type(socket_type s) + : socket_(s), + have_remote_endpoint_(false) + { + } + + native_handle_type(socket_type s, const endpoint_type& ep) + : socket_(s), + have_remote_endpoint_(true), + remote_endpoint_(ep) + { + } + + void operator=(socket_type s) + { + socket_ = s; + have_remote_endpoint_ = false; + remote_endpoint_ = endpoint_type(); + } + + operator socket_type() const + { + return socket_; + } + + bool have_remote_endpoint() const + { + return have_remote_endpoint_; + } + + endpoint_type remote_endpoint() const + { + return remote_endpoint_; + } + + private: + socket_type socket_; + bool have_remote_endpoint_; + endpoint_type remote_endpoint_; + }; + + // The implementation type of the socket. + struct implementation_type : + win_iocp_socket_service_base::base_implementation_type + { + // Default constructor. + implementation_type() + : protocol_(endpoint_type().protocol()), + have_remote_endpoint_(false), + remote_endpoint_() + { + } + + // The protocol associated with the socket. + protocol_type protocol_; + + // Whether we have a cached remote endpoint. + bool have_remote_endpoint_; + + // A cached remote endpoint. + endpoint_type remote_endpoint_; + }; + + // Constructor. + win_iocp_socket_service(asio::io_context& io_context) + : service_base<win_iocp_socket_service<Protocol> >(io_context), + win_iocp_socket_service_base(io_context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + + impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_; + other_impl.have_remote_endpoint_ = false; + + impl.remote_endpoint_ = other_impl.remote_endpoint_; + other_impl.remote_endpoint_ = endpoint_type(); + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type& impl, + win_iocp_socket_service_base& other_service, + implementation_type& other_impl) + { + this->base_move_assign(impl, other_service, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + + impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_; + other_impl.have_remote_endpoint_ = false; + + impl.remote_endpoint_ = other_impl.remote_endpoint_; + other_impl.remote_endpoint_ = endpoint_type(); + } + + // Move-construct a new socket implementation from another protocol type. + template <typename Protocol1> + void converting_move_construct(implementation_type& impl, + win_iocp_socket_service<Protocol1>&, + typename win_iocp_socket_service< + Protocol1>::implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = protocol_type(other_impl.protocol_); + other_impl.protocol_ = typename Protocol1::endpoint().protocol(); + + impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_; + other_impl.have_remote_endpoint_ = false; + + impl.remote_endpoint_ = other_impl.remote_endpoint_; + other_impl.remote_endpoint_ = typename Protocol1::endpoint(); + } + + // Open a new socket implementation. + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) + { + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) + { + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = false; + impl.remote_endpoint_ = endpoint_type(); + } + return ec; + } + + // Assign a native socket to a socket implementation. + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_handle_type& native_socket, + asio::error_code& ec) + { + if (!do_assign(impl, protocol.type(), native_socket, ec)) + { + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = native_socket.have_remote_endpoint(); + impl.remote_endpoint_ = native_socket.remote_endpoint(); + } + return ec; + } + + // Get the native socket representation. + native_handle_type native_handle(implementation_type& impl) + { + if (impl.have_remote_endpoint_) + return native_handle_type(impl.socket_, impl.remote_endpoint_); + return native_handle_type(impl.socket_); + } + + // Bind the socket to the specified local endpoint. + asio::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) + { + socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + return ec; + } + + // Set a socket option. + template <typename Option> + asio::error_code set_option(implementation_type& impl, + const Option& option, asio::error_code& ec) + { + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; + } + + // Set a socket option. + template <typename Option> + asio::error_code get_option(const implementation_type& impl, + Option& option, asio::error_code& ec) const + { + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint = impl.remote_endpoint_; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, endpoint.data(), + &addr_len, impl.have_remote_endpoint_, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Disable sends or receives on the socket. + asio::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template <typename ConstBufferSequence> + size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + asio::error_code& ec) + { + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(buffers); + + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); + } + + // Wait until data can be sent without blocking. + size_t send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + 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 win_iocp_socket_send_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_send_to")); + + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(buffers); + + start_send_to_op(impl, bufs.buffers(), bufs.count(), + destination.data(), static_cast<int>(destination.size()), + flags, p.p); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler> + void async_send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_send_to(null_buffers)")); + + start_reactor_op(impl, select_reactor::write_op, p.p); + p.v = p.p = 0; + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template <typename MutableBufferSequence> + size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + asio::error_code& ec) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); + + if (!ec) + sender_endpoint.resize(addr_len); + + return bytes_recvd; + } + + // Wait until data can be received without blocking. + size_t receive_from(implementation_type& impl, + const null_buffers&, endpoint_type& sender_endpoint, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + return 0; + } + + // 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 <typename MutableBufferSequence, typename Handler> + void async_receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endp, + socket_base::message_flags flags, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recvfrom_op< + MutableBufferSequence, endpoint_type, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_from")); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + start_receive_from_op(impl, bufs.buffers(), bufs.count(), + sender_endp.data(), flags, &p.p->endpoint_size(), p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive_from(implementation_type& impl, + const null_buffers&, endpoint_type& sender_endpoint, + socket_base::message_flags flags, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_from(null_buffers)")); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; + } + + // Accept a new connection. + template <typename Socket> + asio::error_code accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, asio::error_code& ec) + { + // We cannot accept a socket that is already open. + if (peer.is_open()) + { + ec = asio::error::already_open; + return ec; + } + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return ec; + } + +#if defined(ASIO_HAS_MOVE) + // Accept a new connection. + typename Protocol::socket accept(implementation_type& impl, + io_context* peer_io_context, endpoint_type* peer_endpoint, + asio::error_code& ec) + { + typename Protocol::socket peer( + peer_io_context ? *peer_io_context : io_context_); + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return peer; + } +#endif // defined(ASIO_HAS_MOVE) + + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template <typename Socket, typename Handler> + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + bool enable_connection_aborted = + (impl.state_ & socket_ops::enable_connection_aborted) != 0; + p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, + peer_endpoint, enable_connection_aborted, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, peer.is_open(), p.p->new_socket(), + impl.protocol_.family(), impl.protocol_.type(), + impl.protocol_.protocol(), p.p->output_buffer(), + p.p->address_length(), p.p); + p.v = p.p = 0; + } + +#if defined(ASIO_HAS_MOVE) + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template <typename Handler> + void async_accept(implementation_type& impl, + asio::io_context* peer_io_context, + endpoint_type* peer_endpoint, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_move_accept_op<protocol_type, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + bool enable_connection_aborted = + (impl.state_ & socket_ops::enable_connection_aborted) != 0; + p.p = new (p.v) op(*this, impl.socket_, impl.protocol_, + peer_io_context ? *peer_io_context : io_context_, + peer_endpoint, enable_connection_aborted, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, false, p.p->new_socket(), + impl.protocol_.family(), impl.protocol_.type(), + impl.protocol_.protocol(), p.p->output_buffer(), + p.p->address_length(), p.p); + p.v = p.p = 0; + } +#endif // defined(ASIO_HAS_MOVE) + + // Connect the socket to the specified endpoint. + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) + { + socket_ops::sync_connect(impl.socket_, + peer_endpoint.data(), peer_endpoint.size(), ec); + return ec; + } + + // Start an asynchronous connect. + template <typename Handler> + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_connect_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_connect")); + + start_connect_op(impl, impl.protocol_.family(), impl.protocol_.type(), + peer_endpoint.data(), static_cast<int>(peer_endpoint.size()), p.p); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP diff --git a/lib/asio/detail/win_iocp_socket_service_base.hpp b/lib/asio/detail/win_iocp_socket_service_base.hpp new file mode 100644 index 0000000..ef1d718 --- /dev/null +++ b/lib/asio/detail/win_iocp_socket_service_base.hpp @@ -0,0 +1,591 @@ +// +// detail/win_iocp_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP +#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/operation.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/select_reactor.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/win_iocp_io_context.hpp" +#include "asio/detail/win_iocp_null_buffers_op.hpp" +#include "asio/detail/win_iocp_socket_connect_op.hpp" +#include "asio/detail/win_iocp_socket_send_op.hpp" +#include "asio/detail/win_iocp_socket_recv_op.hpp" +#include "asio/detail/win_iocp_socket_recvmsg_op.hpp" +#include "asio/detail/win_iocp_wait_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_iocp_socket_service_base +{ +public: + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // We use a shared pointer as a cancellation token here to work around the + // broken Windows support for cancellation. MSDN says that when you call + // closesocket any outstanding WSARecv or WSASend operations will complete + // with the error ERROR_OPERATION_ABORTED. In practice they complete with + // ERROR_NETNAME_DELETED, which means you can't tell the difference between + // a local cancellation and the socket being hard-closed by the peer. + socket_ops::shared_cancel_token_type cancel_token_; + + // Per-descriptor data used by the reactor. + select_reactor::per_descriptor_data reactor_data_; + +#if defined(ASIO_ENABLE_CANCELIO) + // The ID of the thread from which it is safe to cancel asynchronous + // operations. 0 means no asynchronous operations have been started yet. + // ~0 means asynchronous operations have been started from more than one + // thread, and cancellation is not supported for the socket. + DWORD safe_cancellation_thread_id_; +#endif // defined(ASIO_ENABLE_CANCELIO) + + // Pointers to adjacent socket implementations in linked list. + base_implementation_type* next_; + base_implementation_type* prev_; + }; + + // Constructor. + ASIO_DECL win_iocp_socket_service_base( + asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void base_shutdown(); + + // Construct a new socket implementation. + ASIO_DECL void construct(base_implementation_type& impl); + + // Move-construct a new socket implementation. + ASIO_DECL void base_move_construct(base_implementation_type& impl, + base_implementation_type& other_impl); + + // Move-assign from another socket implementation. + ASIO_DECL void base_move_assign(base_implementation_type& impl, + win_iocp_socket_service_base& other_service, + base_implementation_type& other_impl); + + // Destroy a socket implementation. + ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + ASIO_DECL asio::error_code close( + base_implementation_type& impl, asio::error_code& ec); + + // Release ownership of the socket. + ASIO_DECL socket_type release( + base_implementation_type& impl, asio::error_code& ec); + + // Cancel all operations associated with the socket. + ASIO_DECL asio::error_code cancel( + base_implementation_type& impl, asio::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + asio::error_code listen(base_implementation_type& impl, + int backlog, asio::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template <typename IO_Control_Command> + asio::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast<ioctl_arg_type*>(command.data()), ec); + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the socket. + asio::error_code non_blocking(base_implementation_type& impl, + bool mode, asio::error_code& ec) + { + socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native socket implementation. + asio::error_code native_non_blocking(base_implementation_type& impl, + bool mode, asio::error_code& ec) + { + socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Wait for the socket to become ready to read, ready to write, or to have + // pending error conditions. + asio::error_code wait(base_implementation_type& impl, + socket_base::wait_type w, asio::error_code& ec) + { + switch (w) + { + case socket_base::wait_read: + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_write: + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_error: + socket_ops::poll_error(impl.socket_, impl.state_, -1, ec); + break; + default: + ec = asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the socket to become ready to read, ready to + // write, or to have pending error conditions. + template <typename Handler> + void async_wait(base_implementation_type& impl, + socket_base::wait_type w, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_wait_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_wait")); + + switch (w) + { + case socket_base::wait_read: + start_null_buffers_receive_op(impl, 0, p.p); + break; + case socket_base::wait_write: + start_reactor_op(impl, select_reactor::write_op, p.p); + break; + case socket_base::wait_error: + start_reactor_op(impl, select_reactor::except_op, p.p); + break; + default: + p.p->ec_ = asio::error::invalid_argument; + iocp_service_.post_immediate_completion(p.p, is_continuation); + break; + } + + p.v = p.p = 0; + } + + // Send the given data to the peer. Returns the number of bytes sent. + template <typename ConstBufferSequence> + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_send")); + + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs(buffers); + + start_send_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler> + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_send(null_buffers)")); + + start_reactor_op(impl, select_reactor::write_op, p.p); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template <typename MutableBufferSequence> + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recv_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive")); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + start_receive_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags flags, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive(null_buffers)")); + + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; + } + + // Receive some data with associated flags. Returns the number of bytes + // received. + template <typename MutableBufferSequence> + size_t receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + return socket_ops::sync_recvmsg(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), in_flags, out_flags, ec); + } + + // Wait until data can be received without blocking. + size_t receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recvmsg_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, out_flags, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags")); + + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + start_receive_op(impl, bufs.buffers(), bufs.count(), in_flags, false, p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); + + // Reset out_flags since it can be given no sensible value at this time. + out_flags = 0; + + start_null_buffers_receive_op(impl, in_flags, p.p); + p.v = p.p = 0; + } + + // Helper function to restart an asynchronous accept operation. + ASIO_DECL void restart_accept_op(socket_type s, + socket_holder& new_socket, int family, int type, int protocol, + void* output_buffer, DWORD address_length, operation* op); + +protected: + // Open a new socket implementation. + ASIO_DECL asio::error_code do_open( + base_implementation_type& impl, int family, int type, + int protocol, asio::error_code& ec); + + // Assign a native socket to a socket implementation. + ASIO_DECL asio::error_code do_assign( + base_implementation_type& impl, int type, + socket_type native_socket, asio::error_code& ec); + + // Helper function to start an asynchronous send operation. + ASIO_DECL void start_send_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous send_to operation. + ASIO_DECL void start_send_to_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op); + + // Helper function to start an asynchronous receive operation. + ASIO_DECL void start_receive_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous null_buffers receive operation. + ASIO_DECL void start_null_buffers_receive_op( + base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op); + + // Helper function to start an asynchronous receive_from operation. + ASIO_DECL void start_receive_from_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op); + + // Helper function to start an asynchronous accept operation. + ASIO_DECL void start_accept_op(base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op); + + // Start an asynchronous read or write operation using the reactor. + ASIO_DECL void start_reactor_op(base_implementation_type& impl, + int op_type, reactor_op* op); + + // Start the asynchronous connect operation using the reactor. + ASIO_DECL void start_connect_op(base_implementation_type& impl, + int family, int type, const socket_addr_type* remote_addr, + std::size_t remote_addrlen, win_iocp_socket_connect_op_base* op); + + // Helper function to close a socket when the associated object is being + // destroyed. + ASIO_DECL void close_for_destruction(base_implementation_type& impl); + + // Update the ID of the thread from which cancellation is safe. + ASIO_DECL void update_cancellation_thread_id( + base_implementation_type& impl); + + // Helper function to get the reactor. If no reactor has been created yet, a + // new one is obtained from the io_context and a pointer to it is cached in + // this service. + ASIO_DECL select_reactor& get_reactor(); + + // The type of a ConnectEx function pointer, as old SDKs may not provide it. + typedef BOOL (PASCAL *connect_ex_fn)(SOCKET, + const socket_addr_type*, int, void*, DWORD, DWORD*, OVERLAPPED*); + + // Helper function to get the ConnectEx pointer. If no ConnectEx pointer has + // been obtained yet, one is obtained using WSAIoctl and the pointer is + // cached. Returns a null pointer if ConnectEx is not available. + ASIO_DECL connect_ex_fn get_connect_ex( + base_implementation_type& impl, int type); + + // The type of a NtSetInformationFile function pointer. + typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG); + + // Helper function to get the NtSetInformationFile function pointer. If no + // NtSetInformationFile pointer has been obtained yet, one is obtained using + // GetProcAddress and the pointer is cached. Returns a null pointer if + // NtSetInformationFile is not available. + ASIO_DECL nt_set_info_fn get_nt_set_info(); + + // Helper function to emulate InterlockedCompareExchangePointer functionality + // for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + ASIO_DECL void* interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp); + + // Helper function to emulate InterlockedExchangePointer functionality for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val); + + // The io_context used to obtain the reactor, if required. + asio::io_context& io_context_; + + // The IOCP service used for running asynchronous operations and dispatching + // handlers. + win_iocp_io_context& iocp_service_; + + // The reactor used for performing connect operations. This object is created + // only if needed. + select_reactor* reactor_; + + // Pointer to ConnectEx implementation. + void* connect_ex_; + + // Pointer to NtSetInformationFile implementation. + void* nt_set_info_; + + // Mutex to protect access to the linked list of implementations. + asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + base_implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_socket_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP diff --git a/lib/asio/detail/win_iocp_thread_info.hpp b/lib/asio/detail/win_iocp_thread_info.hpp new file mode 100644 index 0000000..13181e2 --- /dev/null +++ b/lib/asio/detail/win_iocp_thread_info.hpp @@ -0,0 +1,34 @@ +// +// detail/win_iocp_thread_info.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP +#define ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/thread_info_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct win_iocp_thread_info : public thread_info_base +{ +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP diff --git a/lib/asio/detail/win_iocp_wait_op.hpp b/lib/asio/detail/win_iocp_wait_op.hpp new file mode 100644 index 0000000..472eea3 --- /dev/null +++ b/lib/asio/detail/win_iocp_wait_op.hpp @@ -0,0 +1,121 @@ +// +// detail/win_iocp_wait_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP +#define ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class win_iocp_wait_op : public reactor_op +{ +public: + ASIO_DEFINE_HANDLER_PTR(win_iocp_wait_op); + + win_iocp_wait_op(socket_ops::weak_cancel_token_type cancel_token, + Handler& handler) + : reactor_op(&win_iocp_wait_op::do_perform, + &win_iocp_wait_op::do_complete), + cancel_token_(cancel_token), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + asio::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_wait_op* o(static_cast<win_iocp_wait_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // The reactor may have stored a result in the operation object. + if (o->ec_) + ec = o->ec_; + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = asio::error::operation_aborted; + else + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + + // 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, asio::error_code> + handler(o->handler_, ec); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IOCP) + +#endif // ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP diff --git a/lib/asio/detail/win_mutex.hpp b/lib/asio/detail/win_mutex.hpp new file mode 100644 index 0000000..ce52a2f --- /dev/null +++ b/lib/asio/detail/win_mutex.hpp @@ -0,0 +1,78 @@ +// +// detail/win_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_MUTEX_HPP +#define ASIO_DETAIL_WIN_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_lock.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_mutex + : private noncopyable +{ +public: + typedef asio::detail::scoped_lock<win_mutex> scoped_lock; + + // Constructor. + ASIO_DECL win_mutex(); + + // Destructor. + ~win_mutex() + { + ::DeleteCriticalSection(&crit_section_); + } + + // Lock the mutex. + void lock() + { + ::EnterCriticalSection(&crit_section_); + } + + // Unlock the mutex. + void unlock() + { + ::LeaveCriticalSection(&crit_section_); + } + +private: + // Initialisation must be performed in a separate function to the constructor + // since the compiler does not support the use of structured exceptions and + // C++ exceptions in the same function. + ASIO_DECL int do_init(); + + ::CRITICAL_SECTION crit_section_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_mutex.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_WIN_MUTEX_HPP diff --git a/lib/asio/detail/win_object_handle_service.hpp b/lib/asio/detail/win_object_handle_service.hpp new file mode 100644 index 0000000..1d8abc9 --- /dev/null +++ b/lib/asio/detail/win_object_handle_service.hpp @@ -0,0 +1,184 @@ +// +// detail/win_object_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2011 Boris Schaeling (boris@highscore.de) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP +#define ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/wait_handler.hpp" +#include "asio/error.hpp" +#include "asio/io_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class win_object_handle_service : + public service_base<win_object_handle_service> +{ +public: + // The native type of an object handle. + typedef HANDLE native_handle_type; + + // The implementation type of the object handle. + class implementation_type + { + public: + // Default constructor. + implementation_type() + : handle_(INVALID_HANDLE_VALUE), + wait_handle_(INVALID_HANDLE_VALUE), + owner_(0), + next_(0), + prev_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class win_object_handle_service; + + // The native object handle representation. May be accessed or modified + // without locking the mutex. + native_handle_type handle_; + + // The handle used to unregister the wait operation. The mutex must be + // locked when accessing or modifying this member. + HANDLE wait_handle_; + + // The operations waiting on the object handle. If there is a registered + // wait then the mutex must be locked when accessing or modifying this + // member + op_queue<wait_op> op_queue_; + + // The service instance that owns the object handle implementation. + win_object_handle_service* owner_; + + // Pointers to adjacent handle implementations in linked list. The mutex + // must be locked when accessing or modifying these members. + implementation_type* next_; + implementation_type* prev_; + }; + + // Constructor. + ASIO_DECL win_object_handle_service( + asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new handle implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Move-construct a new handle implementation. + ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another handle implementation. + ASIO_DECL void move_assign(implementation_type& impl, + win_object_handle_service& other_service, + implementation_type& other_impl); + + // Destroy a handle implementation. + ASIO_DECL void destroy(implementation_type& impl); + + // Assign a native handle to a handle implementation. + ASIO_DECL asio::error_code assign(implementation_type& impl, + const native_handle_type& handle, asio::error_code& ec); + + // Determine whether the handle is open. + bool is_open(const implementation_type& impl) const + { + return impl.handle_ != INVALID_HANDLE_VALUE && impl.handle_ != 0; + } + + // Destroy a handle implementation. + ASIO_DECL asio::error_code close(implementation_type& impl, + asio::error_code& ec); + + // Get the native handle representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return impl.handle_; + } + + // Cancel all operations associated with the handle. + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); + + // Perform a synchronous wait for the object to enter a signalled state. + ASIO_DECL void wait(implementation_type& impl, + asio::error_code& ec); + + /// Start an asynchronous wait. + template <typename Handler> + void async_wait(implementation_type& impl, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef wait_handler<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((io_context_.context(), *p.p, "object_handle", + &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "async_wait")); + + start_wait_op(impl, p.p); + p.v = p.p = 0; + } + +private: + // Helper function to start an asynchronous wait operation. + ASIO_DECL void start_wait_op(implementation_type& impl, wait_op* op); + + // Helper function to register a wait operation. + ASIO_DECL void register_wait_callback( + implementation_type& impl, mutex::scoped_lock& lock); + + // Callback function invoked when the registered wait completes. + static ASIO_DECL VOID CALLBACK wait_callback( + PVOID param, BOOLEAN timeout); + + // The io_context implementation used to post completions. + io_context_impl& io_context_; + + // Mutex to protect access to internal state. + mutex mutex_; + + // The head of a linked list of all implementations. + implementation_type* impl_list_; + + // Flag to indicate that the dispatcher has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_object_handle_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#endif // ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP diff --git a/lib/asio/detail/win_static_mutex.hpp b/lib/asio/detail/win_static_mutex.hpp new file mode 100644 index 0000000..b169688 --- /dev/null +++ b/lib/asio/detail/win_static_mutex.hpp @@ -0,0 +1,74 @@ +// +// detail/win_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_STATIC_MUTEX_HPP +#define ASIO_DETAIL_WIN_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/scoped_lock.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct win_static_mutex +{ + typedef asio::detail::scoped_lock<win_static_mutex> scoped_lock; + + // Initialise the mutex. + ASIO_DECL void init(); + + // Initialisation must be performed in a separate function to the "public" + // init() function since the compiler does not support the use of structured + // exceptions and C++ exceptions in the same function. + ASIO_DECL int do_init(); + + // Lock the mutex. + void lock() + { + ::EnterCriticalSection(&crit_section_); + } + + // Unlock the mutex. + void unlock() + { + ::LeaveCriticalSection(&crit_section_); + } + + bool initialised_; + ::CRITICAL_SECTION crit_section_; +}; + +#if defined(UNDER_CE) +# define ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0 } } +#else // defined(UNDER_CE) +# define ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0, 0 } } +#endif // defined(UNDER_CE) + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_static_mutex.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_WIN_STATIC_MUTEX_HPP diff --git a/lib/asio/detail/win_thread.hpp b/lib/asio/detail/win_thread.hpp new file mode 100644 index 0000000..8b28a90 --- /dev/null +++ b/lib/asio/detail/win_thread.hpp @@ -0,0 +1,147 @@ +// +// detail/win_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_THREAD_HPP +#define ASIO_DETAIL_WIN_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_APP) \ + && !defined(UNDER_CE) + +#include <cstddef> +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); + +#if defined(WINVER) && (WINVER < 0x0500) +ASIO_DECL void __stdcall apc_function(ULONG data); +#else +ASIO_DECL void __stdcall apc_function(ULONG_PTR data); +#endif + +template <typename T> +class win_thread_base +{ +public: + static bool terminate_threads() + { + return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0; + } + + static void set_terminate_threads(bool b) + { + ::InterlockedExchange(&terminate_threads_, b ? 1 : 0); + } + +private: + static long terminate_threads_; +}; + +template <typename T> +long win_thread_base<T>::terminate_threads_ = 0; + +class win_thread + : private noncopyable, + public win_thread_base<win_thread> +{ +public: + // Constructor. + template <typename Function> + win_thread(Function f, unsigned int stack_size = 0) + : thread_(0), + exit_event_(0) + { + start_thread(new func<Function>(f), stack_size); + } + + // Destructor. + ASIO_DECL ~win_thread(); + + // Wait for the thread to exit. + ASIO_DECL void join(); + + // Get number of CPUs. + ASIO_DECL static std::size_t hardware_concurrency(); + +private: + friend ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); + +#if defined(WINVER) && (WINVER < 0x0500) + friend ASIO_DECL void __stdcall apc_function(ULONG); +#else + friend ASIO_DECL void __stdcall apc_function(ULONG_PTR); +#endif + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + ::HANDLE entry_event_; + ::HANDLE exit_event_; + }; + + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + + template <typename Function> + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size); + + ::HANDLE thread_; + ::HANDLE exit_event_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_thread.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_APP) + // && !defined(UNDER_CE) + +#endif // ASIO_DETAIL_WIN_THREAD_HPP diff --git a/lib/asio/detail/win_tss_ptr.hpp b/lib/asio/detail/win_tss_ptr.hpp new file mode 100644 index 0000000..4207108 --- /dev/null +++ b/lib/asio/detail/win_tss_ptr.hpp @@ -0,0 +1,79 @@ +// +// detail/win_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WIN_TSS_PTR_HPP +#define ASIO_DETAIL_WIN_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper function to create thread-specific storage. +ASIO_DECL DWORD win_tss_ptr_create(); + +template <typename T> +class win_tss_ptr + : private noncopyable +{ +public: + // Constructor. + win_tss_ptr() + : tss_key_(win_tss_ptr_create()) + { + } + + // Destructor. + ~win_tss_ptr() + { + ::TlsFree(tss_key_); + } + + // Get the value. + operator T*() const + { + return static_cast<T*>(::TlsGetValue(tss_key_)); + } + + // Set the value. + void operator=(T* value) + { + ::TlsSetValue(tss_key_, value); + } + +private: + // Thread-specific storage to allow unlocked access to determine whether a + // thread is a member of the pool. + DWORD tss_key_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_tss_ptr.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) + +#endif // ASIO_DETAIL_WIN_TSS_PTR_HPP diff --git a/lib/asio/detail/winapp_thread.hpp b/lib/asio/detail/winapp_thread.hpp new file mode 100644 index 0000000..69dcf08 --- /dev/null +++ b/lib/asio/detail/winapp_thread.hpp @@ -0,0 +1,124 @@ +// +// detail/winapp_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINAPP_THREAD_HPP +#define ASIO_DETAIL_WINAPP_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) && defined(ASIO_WINDOWS_APP) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +DWORD WINAPI winapp_thread_function(LPVOID arg); + +class winapp_thread + : private noncopyable +{ +public: + // Constructor. + template <typename Function> + winapp_thread(Function f, unsigned int = 0) + { + scoped_ptr<func_base> arg(new func<Function>(f)); + DWORD thread_id = 0; + thread_ = ::CreateThread(0, 0, winapp_thread_function, + arg.get(), 0, &thread_id); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); + } + arg.release(); + } + + // Destructor. + ~winapp_thread() + { + ::CloseHandle(thread_); + } + + // Wait for the thread to exit. + void join() + { + ::WaitForSingleObjectEx(thread_, INFINITE, false); + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + SYSTEM_INFO system_info; + ::GetNativeSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; + } + +private: + friend DWORD WINAPI winapp_thread_function(LPVOID arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template <typename Function> + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::HANDLE thread_; +}; + +inline DWORD WINAPI winapp_thread_function(LPVOID arg) +{ + scoped_ptr<winapp_thread::func_base> func( + static_cast<winapp_thread::func_base*>(arg)); + func->run(); + return 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) && defined(ASIO_WINDOWS_APP) + +#endif // ASIO_DETAIL_WINAPP_THREAD_HPP diff --git a/lib/asio/detail/wince_thread.hpp b/lib/asio/detail/wince_thread.hpp new file mode 100644 index 0000000..a2863f6 --- /dev/null +++ b/lib/asio/detail/wince_thread.hpp @@ -0,0 +1,124 @@ +// +// detail/wince_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINCE_THREAD_HPP +#define ASIO_DETAIL_WINCE_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) && defined(UNDER_CE) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +DWORD WINAPI wince_thread_function(LPVOID arg); + +class wince_thread + : private noncopyable +{ +public: + // Constructor. + template <typename Function> + wince_thread(Function f, unsigned int = 0) + { + scoped_ptr<func_base> arg(new func<Function>(f)); + DWORD thread_id = 0; + thread_ = ::CreateThread(0, 0, wince_thread_function, + arg.get(), 0, &thread_id); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + asio::error_code ec(last_error, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "thread"); + } + arg.release(); + } + + // Destructor. + ~wince_thread() + { + ::CloseHandle(thread_); + } + + // Wait for the thread to exit. + void join() + { + ::WaitForSingleObject(thread_, INFINITE); + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + SYSTEM_INFO system_info; + ::GetSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; + } + +private: + friend DWORD WINAPI wince_thread_function(LPVOID arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template <typename Function> + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::HANDLE thread_; +}; + +inline DWORD WINAPI wince_thread_function(LPVOID arg) +{ + scoped_ptr<wince_thread::func_base> func( + static_cast<wince_thread::func_base*>(arg)); + func->run(); + return 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS) && defined(UNDER_CE) + +#endif // ASIO_DETAIL_WINCE_THREAD_HPP diff --git a/lib/asio/detail/winrt_async_manager.hpp b/lib/asio/detail/winrt_async_manager.hpp new file mode 100644 index 0000000..e22ad52 --- /dev/null +++ b/lib/asio/detail/winrt_async_manager.hpp @@ -0,0 +1,294 @@ +// +// detail/winrt_async_manager.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP +#define ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include <future> +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/error.hpp" +#include "asio/io_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class winrt_async_manager + : public asio::detail::service_base<winrt_async_manager> +{ +public: + // Constructor. + winrt_async_manager(asio::io_context& io_context) + : asio::detail::service_base<winrt_async_manager>(io_context), + io_context_(use_service<io_context_impl>(io_context)), + outstanding_ops_(1) + { + } + + // Destructor. + ~winrt_async_manager() + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + if (--outstanding_ops_ > 0) + { + // Block until last operation is complete. + std::future<void> f = promise_.get_future(); + f.wait(); + } + } + + void sync(Windows::Foundation::IAsyncAction^ action, + asio::error_code& ec) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto promise = std::make_shared<std::promise<asio::error_code>>(); + auto future = promise->get_future(); + + action->Completed = ref new AsyncActionCompletedHandler( + [promise](IAsyncAction^ action, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + promise->set_value(asio::error::operation_aborted); + break; + case AsyncStatus::Error: + case AsyncStatus::Completed: + default: + asio::error_code ec( + action->ErrorCode.Value, + asio::system_category()); + promise->set_value(ec); + break; + } + }); + + ec = future.get(); + } + + template <typename TResult> + TResult sync(Windows::Foundation::IAsyncOperation<TResult>^ operation, + asio::error_code& ec) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto promise = std::make_shared<std::promise<asio::error_code>>(); + auto future = promise->get_future(); + + operation->Completed = ref new AsyncOperationCompletedHandler<TResult>( + [promise](IAsyncOperation<TResult>^ operation, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + promise->set_value(asio::error::operation_aborted); + break; + case AsyncStatus::Error: + case AsyncStatus::Completed: + default: + asio::error_code ec( + operation->ErrorCode.Value, + asio::system_category()); + promise->set_value(ec); + break; + } + }); + + ec = future.get(); + return operation->GetResults(); + } + + template <typename TResult, typename TProgress> + TResult sync( + Windows::Foundation::IAsyncOperationWithProgress< + TResult, TProgress>^ operation, + asio::error_code& ec) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto promise = std::make_shared<std::promise<asio::error_code>>(); + auto future = promise->get_future(); + + operation->Completed + = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>( + [promise](IAsyncOperationWithProgress<TResult, TProgress>^ operation, + AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + promise->set_value(asio::error::operation_aborted); + break; + case AsyncStatus::Started: + break; + case AsyncStatus::Error: + case AsyncStatus::Completed: + default: + asio::error_code ec( + operation->ErrorCode.Value, + asio::system_category()); + promise->set_value(ec); + break; + } + }); + + ec = future.get(); + return operation->GetResults(); + } + + void async(Windows::Foundation::IAsyncAction^ action, + winrt_async_op<void>* handler) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto on_completed = ref new AsyncActionCompletedHandler( + [this, handler](IAsyncAction^ action, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + handler->ec_ = asio::error::operation_aborted; + break; + case AsyncStatus::Started: + return; + case AsyncStatus::Completed: + case AsyncStatus::Error: + default: + handler->ec_ = asio::error_code( + action->ErrorCode.Value, + asio::system_category()); + break; + } + io_context_.post_deferred_completion(handler); + if (--outstanding_ops_ == 0) + promise_.set_value(); + }); + + io_context_.work_started(); + ++outstanding_ops_; + action->Completed = on_completed; + } + + template <typename TResult> + void async(Windows::Foundation::IAsyncOperation<TResult>^ operation, + winrt_async_op<TResult>* handler) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto on_completed = ref new AsyncOperationCompletedHandler<TResult>( + [this, handler](IAsyncOperation<TResult>^ operation, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + handler->ec_ = asio::error::operation_aborted; + break; + case AsyncStatus::Started: + return; + case AsyncStatus::Completed: + handler->result_ = operation->GetResults(); + // Fall through. + case AsyncStatus::Error: + default: + handler->ec_ = asio::error_code( + operation->ErrorCode.Value, + asio::system_category()); + break; + } + io_context_.post_deferred_completion(handler); + if (--outstanding_ops_ == 0) + promise_.set_value(); + }); + + io_context_.work_started(); + ++outstanding_ops_; + operation->Completed = on_completed; + } + + template <typename TResult, typename TProgress> + void async( + Windows::Foundation::IAsyncOperationWithProgress< + TResult, TProgress>^ operation, + winrt_async_op<TResult>* handler) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto on_completed + = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>( + [this, handler](IAsyncOperationWithProgress< + TResult, TProgress>^ operation, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + handler->ec_ = asio::error::operation_aborted; + break; + case AsyncStatus::Started: + return; + case AsyncStatus::Completed: + handler->result_ = operation->GetResults(); + // Fall through. + case AsyncStatus::Error: + default: + handler->ec_ = asio::error_code( + operation->ErrorCode.Value, + asio::system_category()); + break; + } + io_context_.post_deferred_completion(handler); + if (--outstanding_ops_ == 0) + promise_.set_value(); + }); + + io_context_.work_started(); + ++outstanding_ops_; + operation->Completed = on_completed; + } + +private: + // The io_context implementation used to post completed handlers. + io_context_impl& io_context_; + + // Count of outstanding operations. + atomic_count outstanding_ops_; + + // Used to keep wait for outstanding operations to complete. + std::promise<void> promise_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP diff --git a/lib/asio/detail/winrt_async_op.hpp b/lib/asio/detail/winrt_async_op.hpp new file mode 100644 index 0000000..75891a4 --- /dev/null +++ b/lib/asio/detail/winrt_async_op.hpp @@ -0,0 +1,65 @@ +// +// detail/winrt_async_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_ASYNC_OP_HPP +#define ASIO_DETAIL_WINRT_ASYNC_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename TResult> +class winrt_async_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + + // The result of the operation, to be passed to the completion handler. + TResult result_; + +protected: + winrt_async_op(func_type complete_func) + : operation(complete_func), + result_() + { + } +}; + +template <> +class winrt_async_op<void> + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + +protected: + winrt_async_op(func_type complete_func) + : operation(complete_func) + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WINRT_ASYNC_OP_HPP diff --git a/lib/asio/detail/winrt_resolve_op.hpp b/lib/asio/detail/winrt_resolve_op.hpp new file mode 100644 index 0000000..07efd29 --- /dev/null +++ b/lib/asio/detail/winrt_resolve_op.hpp @@ -0,0 +1,118 @@ +// +// detail/winrt_resolve_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_RESOLVE_OP_HPP +#define ASIO_DETAIL_WINRT_RESOLVE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/ip/basic_resolver_results.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol, typename Handler> +class winrt_resolve_op : + public winrt_async_op< + Windows::Foundation::Collections::IVectorView< + Windows::Networking::EndpointPair^>^> +{ +public: + ASIO_DEFINE_HANDLER_PTR(winrt_resolve_op); + + typedef typename Protocol::endpoint endpoint_type; + typedef asio::ip::basic_resolver_query<Protocol> query_type; + typedef asio::ip::basic_resolver_results<Protocol> results_type; + + winrt_resolve_op(const query_type& query, Handler& handler) + : winrt_async_op< + Windows::Foundation::Collections::IVectorView< + Windows::Networking::EndpointPair^>^>( + &winrt_resolve_op::do_complete), + query_(query), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code&, std::size_t) + { + // Take ownership of the operation object. + winrt_resolve_op* o(static_cast<winrt_resolve_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + results_type results = results_type(); + if (!o->ec_) + { + try + { + results = results_type::create(o->result_, o->query_.hints(), + o->query_.host_name(), o->query_.service_name()); + } + catch (Platform::Exception^ e) + { + o->ec_ = asio::error_code(e->HResult, + asio::system_category()); + } + } + + // 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, asio::error_code, results_type> + handler(o->handler_, o->ec_, results); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + query_type query_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_RESOLVE_OP_HPP diff --git a/lib/asio/detail/winrt_resolver_service.hpp b/lib/asio/detail/winrt_resolver_service.hpp new file mode 100644 index 0000000..aeb4448 --- /dev/null +++ b/lib/asio/detail/winrt_resolver_service.hpp @@ -0,0 +1,198 @@ +// +// detail/winrt_resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP +#define ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/ip/basic_resolver_results.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/winrt_async_manager.hpp" +#include "asio/detail/winrt_resolve_op.hpp" +#include "asio/detail/winrt_utils.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol> +class winrt_resolver_service : + public service_base<winrt_resolver_service<Protocol> > +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the asynchronous operation that the operation has been + // cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The query type. + typedef asio::ip::basic_resolver_query<Protocol> query_type; + + // The results type. + typedef asio::ip::basic_resolver_results<Protocol> results_type; + + // Constructor. + winrt_resolver_service(asio::io_context& io_context) + : service_base<winrt_resolver_service<Protocol> >(io_context), + io_context_(use_service<io_context_impl>(io_context)), + async_manager_(use_service<winrt_async_manager>(io_context)) + { + } + + // Destructor. + ~winrt_resolver_service() + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // Perform any fork-related housekeeping. + void notify_fork(asio::io_context::fork_event) + { + } + + // Construct a new resolver implementation. + void construct(implementation_type&) + { + } + + // Move-construct a new resolver implementation. + void move_construct(implementation_type&, + implementation_type&) + { + } + + // Move-assign from another resolver implementation. + void move_assign(implementation_type&, + winrt_resolver_service&, implementation_type&) + { + } + + // Destroy a resolver implementation. + void destroy(implementation_type&) + { + } + + // Cancel pending asynchronous operations. + void cancel(implementation_type&) + { + } + + // Resolve a query to a list of entries. + results_type resolve(implementation_type&, + const query_type& query, asio::error_code& ec) + { + try + { + using namespace Windows::Networking::Sockets; + auto endpoint_pairs = async_manager_.sync( + DatagramSocket::GetEndpointPairsAsync( + winrt_utils::host_name(query.host_name()), + winrt_utils::string(query.service_name())), ec); + + if (ec) + return results_type(); + + return results_type::create( + endpoint_pairs, query.hints(), + query.host_name(), query.service_name()); + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + return results_type(); + } + } + + // Asynchronously resolve a query to a list of entries. + template <typename Handler> + void async_resolve(implementation_type& impl, + const query_type& query, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef winrt_resolve_op<Protocol, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(query, handler); + + ASIO_HANDLER_CREATION((io_context_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); + (void)impl; + + try + { + using namespace Windows::Networking::Sockets; + async_manager_.async(DatagramSocket::GetEndpointPairsAsync( + winrt_utils::host_name(query.host_name()), + winrt_utils::string(query.service_name())), p.p); + p.v = p.p = 0; + } + catch (Platform::Exception^ e) + { + p.p->ec_ = asio::error_code( + e->HResult, asio::system_category()); + io_context_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + } + } + + // Resolve an endpoint to a list of entries. + results_type resolve(implementation_type&, + const endpoint_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return results_type(); + } + + // Asynchronously resolve an endpoint to a list of entries. + template <typename Handler> + void async_resolve(implementation_type&, + const endpoint_type&, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const results_type results; + io_context_.get_io_context().post( + detail::bind_handler(handler, ec, results)); + } + +private: + io_context_impl& io_context_; + winrt_async_manager& async_manager_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP diff --git a/lib/asio/detail/winrt_socket_connect_op.hpp b/lib/asio/detail/winrt_socket_connect_op.hpp new file mode 100644 index 0000000..f18b445 --- /dev/null +++ b/lib/asio/detail/winrt_socket_connect_op.hpp @@ -0,0 +1,92 @@ +// +// detail/winrt_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP +#define ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class winrt_socket_connect_op : + public winrt_async_op<void> +{ +public: + ASIO_DEFINE_HANDLER_PTR(winrt_socket_connect_op); + + winrt_socket_connect_op(Handler& handler) + : winrt_async_op<void>(&winrt_socket_connect_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code&, std::size_t) + { + // Take ownership of the operation object. + winrt_socket_connect_op* o(static_cast<winrt_socket_connect_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + + // 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, asio::error_code> + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP diff --git a/lib/asio/detail/winrt_socket_recv_op.hpp b/lib/asio/detail/winrt_socket_recv_op.hpp new file mode 100644 index 0000000..8f1fcf5 --- /dev/null +++ b/lib/asio/detail/winrt_socket_recv_op.hpp @@ -0,0 +1,112 @@ +// +// detail/winrt_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP +#define ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Handler> +class winrt_socket_recv_op : + public winrt_async_op<Windows::Storage::Streams::IBuffer^> +{ +public: + ASIO_DEFINE_HANDLER_PTR(winrt_socket_recv_op); + + winrt_socket_recv_op(const MutableBufferSequence& buffers, Handler& handler) + : winrt_async_op<Windows::Storage::Streams::IBuffer^>( + &winrt_socket_recv_op::do_complete), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code&, std::size_t) + { + // Take ownership of the operation object. + winrt_socket_recv_op* o(static_cast<winrt_socket_recv_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + std::size_t bytes_transferred = o->result_ ? o->result_->Length : 0; + if (bytes_transferred == 0 && !o->ec_ && + !buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::all_empty(o->buffers_)) + { + o->ec_ = asio::error::eof; + } + + // 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, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, bytes_transferred); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP diff --git a/lib/asio/detail/winrt_socket_send_op.hpp b/lib/asio/detail/winrt_socket_send_op.hpp new file mode 100644 index 0000000..1148c24 --- /dev/null +++ b/lib/asio/detail/winrt_socket_send_op.hpp @@ -0,0 +1,103 @@ +// +// detail/winrt_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP +#define ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/winrt_async_op.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence, typename Handler> +class winrt_socket_send_op : + public winrt_async_op<unsigned int> +{ +public: + ASIO_DEFINE_HANDLER_PTR(winrt_socket_send_op); + + winrt_socket_send_op(const ConstBufferSequence& buffers, Handler& handler) + : winrt_async_op<unsigned int>(&winrt_socket_send_op::do_complete), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code&, std::size_t) + { + // Take ownership of the operation object. + winrt_socket_send_op* o(static_cast<winrt_socket_send_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((*o)); + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::validate(o->buffers_); + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // 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, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->result_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + ConstBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP diff --git a/lib/asio/detail/winrt_ssocket_service.hpp b/lib/asio/detail/winrt_ssocket_service.hpp new file mode 100644 index 0000000..603724a --- /dev/null +++ b/lib/asio/detail/winrt_ssocket_service.hpp @@ -0,0 +1,241 @@ +// +// detail/winrt_ssocket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP +#define ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/winrt_socket_connect_op.hpp" +#include "asio/detail/winrt_ssocket_service_base.hpp" +#include "asio/detail/winrt_utils.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol> +class winrt_ssocket_service : + public service_base<winrt_ssocket_service<Protocol> >, + public winrt_ssocket_service_base +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type; + + // The implementation type of the socket. + struct implementation_type : base_implementation_type + { + // Default constructor. + implementation_type() + : base_implementation_type(), + protocol_(endpoint_type().protocol()) + { + } + + // The protocol associated with the socket. + protocol_type protocol_; + }; + + // Constructor. + winrt_ssocket_service(asio::io_context& io_context) + : service_base<winrt_ssocket_service<Protocol> >(io_context), + winrt_ssocket_service_base(io_context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type& impl, + winrt_ssocket_service& other_service, + implementation_type& other_impl) + { + this->base_move_assign(impl, other_service, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-construct a new socket implementation from another protocol type. + template <typename Protocol1> + void converting_move_construct(implementation_type& impl, + winrt_ssocket_service<Protocol1>&, + typename winrt_ssocket_service< + Protocol1>::implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = protocol_type(other_impl.protocol_); + other_impl.protocol_ = typename Protocol1::endpoint().protocol(); + } + + // Open a new socket implementation. + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) + { + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + try + { + impl.socket_ = ref new Windows::Networking::Sockets::StreamSocket; + impl.protocol_ = protocol; + ec = asio::error_code(); + } + catch (Platform::Exception^ e) + { + ec = asio::error_code(e->HResult, + asio::system_category()); + } + + return ec; + } + + // Assign a native socket to a socket implementation. + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_handle_type& native_socket, + asio::error_code& ec) + { + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + impl.socket_ = native_socket; + impl.protocol_ = protocol; + ec = asio::error_code(); + + return ec; + } + + // Bind the socket to the specified local endpoint. + asio::error_code bind(implementation_type&, + const endpoint_type&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + endpoint.resize(do_get_endpoint(impl, true, + endpoint.data(), endpoint.size(), ec)); + return endpoint; + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + endpoint.resize(do_get_endpoint(impl, false, + endpoint.data(), endpoint.size(), ec)); + return endpoint; + } + + // Set a socket option. + template <typename Option> + asio::error_code set_option(implementation_type& impl, + const Option& option, asio::error_code& ec) + { + return do_set_option(impl, option.level(impl.protocol_), + option.name(impl.protocol_), option.data(impl.protocol_), + option.size(impl.protocol_), ec); + } + + // Get a socket option. + template <typename Option> + asio::error_code get_option(const implementation_type& impl, + Option& option, asio::error_code& ec) const + { + std::size_t size = option.size(impl.protocol_); + do_get_option(impl, option.level(impl.protocol_), + option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; + } + + // Connect the socket to the specified endpoint. + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) + { + return do_connect(impl, peer_endpoint.data(), ec); + } + + // Start an asynchronous connect. + template <typename Handler> + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef winrt_socket_connect_op<Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + ASIO_HANDLER_CREATION((io_context_.context(), + *p.p, "socket", &impl, 0, "async_connect")); + + start_connect_op(impl, peer_endpoint.data(), p.p, is_continuation); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP diff --git a/lib/asio/detail/winrt_ssocket_service_base.hpp b/lib/asio/detail/winrt_ssocket_service_base.hpp new file mode 100644 index 0000000..61328d0 --- /dev/null +++ b/lib/asio/detail/winrt_ssocket_service_base.hpp @@ -0,0 +1,359 @@ +// +// detail/winrt_ssocket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP +#define ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/io_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/winrt_async_manager.hpp" +#include "asio/detail/winrt_socket_recv_op.hpp" +#include "asio/detail/winrt_socket_send_op.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class winrt_ssocket_service_base +{ +public: + // The native type of a socket. + typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type; + + // The implementation type of the socket. + struct base_implementation_type + { + // Default constructor. + base_implementation_type() + : socket_(nullptr), + next_(0), + prev_(0) + { + } + + // The underlying native socket. + native_handle_type socket_; + + // Pointers to adjacent socket implementations in linked list. + base_implementation_type* next_; + base_implementation_type* prev_; + }; + + // Constructor. + ASIO_DECL winrt_ssocket_service_base( + asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void base_shutdown(); + + // Construct a new socket implementation. + ASIO_DECL void construct(base_implementation_type&); + + // Move-construct a new socket implementation. + ASIO_DECL void base_move_construct(base_implementation_type& impl, + base_implementation_type& other_impl); + + // Move-assign from another socket implementation. + ASIO_DECL void base_move_assign(base_implementation_type& impl, + winrt_ssocket_service_base& other_service, + base_implementation_type& other_impl); + + // Destroy a socket implementation. + ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != nullptr; + } + + // Destroy a socket implementation. + ASIO_DECL asio::error_code close( + base_implementation_type& impl, asio::error_code& ec); + + // Release ownership of the socket. + ASIO_DECL native_handle_type release( + base_implementation_type& impl, asio::error_code& ec); + + // Get the native socket representation. + native_handle_type native_handle(base_implementation_type& impl) + { + return impl.socket_; + } + + // Cancel all operations associated with the socket. + asio::error_code cancel(base_implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return false; + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type&, + asio::error_code& ec) const + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Perform an IO control command on the socket. + template <typename IO_Control_Command> + asio::error_code io_control(base_implementation_type&, + IO_Control_Command&, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const base_implementation_type&) const + { + return false; + } + + // Sets the non-blocking mode of the socket. + asio::error_code non_blocking(base_implementation_type&, + bool, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const base_implementation_type&) const + { + return false; + } + + // Sets the non-blocking mode of the native socket implementation. + asio::error_code native_non_blocking(base_implementation_type&, + bool, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Disable sends or receives on the socket. + asio::error_code shutdown(base_implementation_type&, + socket_base::shutdown_type, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + + // Send the given data to the peer. + template <typename ConstBufferSequence> + std::size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return do_send(impl, + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::first(buffers), flags, ec); + } + + // Wait until data can be sent without blocking. + std::size_t send(base_implementation_type&, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler> + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef winrt_socket_send_op<ConstBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler); + + ASIO_HANDLER_CREATION((io_context_.context(), + *p.p, "socket", &impl, 0, "async_send")); + + start_send_op(impl, + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::first(buffers), + flags, p.p, is_continuation); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler> + void async_send(base_implementation_type&, const null_buffers&, + socket_base::message_flags, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.get_io_context().post( + detail::bind_handler(handler, ec, bytes_transferred)); + } + + // Receive some data from the peer. Returns the number of bytes received. + template <typename MutableBufferSequence> + std::size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return do_receive(impl, + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::first(buffers), flags, ec); + } + + // Wait until data can be received without blocking. + std::size_t receive(base_implementation_type&, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, typename Handler> + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef winrt_socket_recv_op<MutableBufferSequence, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler); + + ASIO_HANDLER_CREATION((io_context_.context(), + *p.p, "socket", &impl, 0, "async_receive")); + + start_receive_op(impl, + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::first(buffers), + flags, p.p, is_continuation); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler> + void async_receive(base_implementation_type&, const null_buffers&, + socket_base::message_flags, Handler& handler) + { + asio::error_code ec = asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + io_context_.get_io_context().post( + detail::bind_handler(handler, ec, bytes_transferred)); + } + +protected: + // Helper function to obtain endpoints associated with the connection. + ASIO_DECL std::size_t do_get_endpoint( + const base_implementation_type& impl, bool local, + void* addr, std::size_t addr_len, asio::error_code& ec) const; + + // Helper function to set a socket option. + ASIO_DECL asio::error_code do_set_option( + base_implementation_type& impl, + int level, int optname, const void* optval, + std::size_t optlen, asio::error_code& ec); + + // Helper function to get a socket option. + ASIO_DECL void do_get_option( + const base_implementation_type& impl, + int level, int optname, void* optval, + std::size_t* optlen, asio::error_code& ec) const; + + // Helper function to perform a synchronous connect. + ASIO_DECL asio::error_code do_connect( + base_implementation_type& impl, + const void* addr, asio::error_code& ec); + + // Helper function to start an asynchronous connect. + ASIO_DECL void start_connect_op( + base_implementation_type& impl, const void* addr, + winrt_async_op<void>* op, bool is_continuation); + + // Helper function to perform a synchronous send. + ASIO_DECL std::size_t do_send( + base_implementation_type& impl, const asio::const_buffer& data, + socket_base::message_flags flags, asio::error_code& ec); + + // Helper function to start an asynchronous send. + ASIO_DECL void start_send_op(base_implementation_type& impl, + const asio::const_buffer& data, socket_base::message_flags flags, + winrt_async_op<unsigned int>* op, bool is_continuation); + + // Helper function to perform a synchronous receive. + ASIO_DECL std::size_t do_receive( + base_implementation_type& impl, const asio::mutable_buffer& data, + socket_base::message_flags flags, asio::error_code& ec); + + // Helper function to start an asynchronous receive. + ASIO_DECL void start_receive_op(base_implementation_type& impl, + const asio::mutable_buffer& data, socket_base::message_flags flags, + winrt_async_op<Windows::Storage::Streams::IBuffer^>* op, + bool is_continuation); + + // The io_context implementation used for delivering completions. + io_context_impl& io_context_; + + // The manager that keeps track of outstanding operations. + winrt_async_manager& async_manager_; + + // Mutex to protect access to the linked list of implementations. + asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + base_implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/winrt_ssocket_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP diff --git a/lib/asio/detail/winrt_timer_scheduler.hpp b/lib/asio/detail/winrt_timer_scheduler.hpp new file mode 100644 index 0000000..5dec7c0 --- /dev/null +++ b/lib/asio/detail/winrt_timer_scheduler.hpp @@ -0,0 +1,137 @@ +// +// detail/winrt_timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP +#define ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include <cstddef> +#include "asio/detail/event.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/thread.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/io_context.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/thread.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class winrt_timer_scheduler + : public asio::detail::service_base<winrt_timer_scheduler> +{ +public: + // Constructor. + ASIO_DECL winrt_timer_scheduler(asio::io_context& io_context); + + // Destructor. + ASIO_DECL ~winrt_timer_scheduler(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + ASIO_DECL void notify_fork( + asio::io_context::fork_event fork_ev); + + // Initialise the task. No effect as this class uses its own thread. + ASIO_DECL void init_task(); + + // Add a new timer queue to the reactor. + template <typename Time_Traits> + void add_timer_queue(timer_queue<Time_Traits>& queue); + + // Remove a timer queue from the reactor. + template <typename Time_Traits> + void remove_timer_queue(timer_queue<Time_Traits>& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template <typename Time_Traits> + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template <typename Time_Traits> + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from); + +private: + // Run the select loop in the thread. + ASIO_DECL void run_thread(); + + // Entry point for the select loop thread. + ASIO_DECL static void call_run_thread(winrt_timer_scheduler* reactor); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // The io_context implementation used to post completions. + io_context_impl& io_context_; + + // Mutex used to protect internal variables. + asio::detail::mutex mutex_; + + // Event used to wake up background thread. + asio::detail::event event_; + + // The timer queues. + timer_queue_set timer_queues_; + + // The background thread that is waiting for timers to expire. + asio::detail::thread* thread_; + + // Does the background thread need to stop. + bool stop_thread_; + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/winrt_timer_scheduler.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/winrt_timer_scheduler.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP diff --git a/lib/asio/detail/winrt_utils.hpp b/lib/asio/detail/winrt_utils.hpp new file mode 100644 index 0000000..22a2489 --- /dev/null +++ b/lib/asio/detail/winrt_utils.hpp @@ -0,0 +1,106 @@ +// +// detail/winrt_utils.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINRT_UTILS_HPP +#define ASIO_DETAIL_WINRT_UTILS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS_RUNTIME) + +#include <codecvt> +#include <cstdlib> +#include <future> +#include <locale> +#include <robuffer.h> +#include <windows.storage.streams.h> +#include <wrl/implements.h> +#include "asio/buffer.hpp" +#include "asio/error_code.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { +namespace winrt_utils { + +inline Platform::String^ string(const char* from) +{ + std::wstring tmp(from, from + std::strlen(from)); + return ref new Platform::String(tmp.c_str()); +} + +inline Platform::String^ string(const std::string& from) +{ + std::wstring tmp(from.begin(), from.end()); + return ref new Platform::String(tmp.c_str()); +} + +inline std::string string(Platform::String^ from) +{ + std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; + return converter.to_bytes(from->Data()); +} + +inline Platform::String^ string(unsigned short from) +{ + return string(std::to_string(from)); +} + +template <typename T> +inline Platform::String^ string(const T& from) +{ + return string(from.to_string()); +} + +inline int integer(Platform::String^ from) +{ + return _wtoi(from->Data()); +} + +template <typename T> +inline Windows::Networking::HostName^ host_name(const T& from) +{ + return ref new Windows::Networking::HostName((string)(from)); +} + +template <typename ConstBufferSequence> +inline Windows::Storage::Streams::IBuffer^ buffer_dup( + const ConstBufferSequence& buffers) +{ + using Microsoft::WRL::ComPtr; + using asio::buffer_size; + std::size_t size = buffer_size(buffers); + auto b = ref new Windows::Storage::Streams::Buffer(size); + ComPtr<IInspectable> insp = reinterpret_cast<IInspectable*>(b); + ComPtr<Windows::Storage::Streams::IBufferByteAccess> bacc; + insp.As(&bacc); + byte* bytes = nullptr; + bacc->Buffer(&bytes); + asio::buffer_copy(asio::buffer(bytes, size), buffers); + b->Length = size; + return b; +} + +} // namespace winrt_utils +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_WINDOWS_RUNTIME) + +#endif // ASIO_DETAIL_WINRT_UTILS_HPP diff --git a/lib/asio/detail/winsock_init.hpp b/lib/asio/detail/winsock_init.hpp new file mode 100644 index 0000000..9094363 --- /dev/null +++ b/lib/asio/detail/winsock_init.hpp @@ -0,0 +1,128 @@ +// +// detail/winsock_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINSOCK_INIT_HPP +#define ASIO_DETAIL_WINSOCK_INIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class winsock_init_base +{ +protected: + // Structure to track result of initialisation and number of uses. POD is used + // to ensure that the values are zero-initialised prior to any code being run. + struct data + { + long init_count_; + long result_; + }; + + ASIO_DECL static void startup(data& d, + unsigned char major, unsigned char minor); + + ASIO_DECL static void manual_startup(data& d); + + ASIO_DECL static void cleanup(data& d); + + ASIO_DECL static void manual_cleanup(data& d); + + ASIO_DECL static void throw_on_error(data& d); +}; + +template <int Major = 2, int Minor = 0> +class winsock_init : private winsock_init_base +{ +public: + winsock_init(bool allow_throw = true) + { + startup(data_, Major, Minor); + if (allow_throw) + throw_on_error(data_); + } + + winsock_init(const winsock_init&) + { + startup(data_, Major, Minor); + throw_on_error(data_); + } + + ~winsock_init() + { + cleanup(data_); + } + + // This class may be used to indicate that user code will manage Winsock + // initialisation and cleanup. This may be required in the case of a DLL, for + // example, where it is not safe to initialise Winsock from global object + // constructors. + // + // To prevent asio from initialising Winsock, the object must be constructed + // before any Asio's own global objects. With MSVC, this may be accomplished + // by adding the following code to the DLL: + // + // #pragma warning(push) + // #pragma warning(disable:4073) + // #pragma init_seg(lib) + // asio::detail::winsock_init<>::manual manual_winsock_init; + // #pragma warning(pop) + class manual + { + public: + manual() + { + manual_startup(data_); + } + + manual(const manual&) + { + manual_startup(data_); + } + + ~manual() + { + manual_cleanup(data_); + } + }; + +private: + friend class manual; + static data data_; +}; + +template <int Major, int Minor> +winsock_init_base::data winsock_init<Major, Minor>::data_; + +// Static variable to ensure that winsock is initialised before main, and +// therefore before any other threads can get started. +static const winsock_init<>& winsock_init_instance = winsock_init<>(false); + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/winsock_init.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // ASIO_DETAIL_WINSOCK_INIT_HPP diff --git a/lib/asio/detail/work_dispatcher.hpp b/lib/asio/detail/work_dispatcher.hpp new file mode 100644 index 0000000..7abce49 --- /dev/null +++ b/lib/asio/detail/work_dispatcher.hpp @@ -0,0 +1,72 @@ +// +// detail/work_dispatcher.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WORK_DISPATCHER_HPP +#define ASIO_DETAIL_WORK_DISPATCHER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_executor.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/executor_work_guard.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler> +class work_dispatcher +{ +public: + work_dispatcher(Handler& handler) + : work_((get_associated_executor)(handler)), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + work_dispatcher(const work_dispatcher& other) + : work_(other.work_), + handler_(other.handler_) + { + } + + work_dispatcher(work_dispatcher&& other) + : work_(ASIO_MOVE_CAST(executor_work_guard< + typename associated_executor<Handler>::type>)(other.work_)), + handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + typename associated_allocator<Handler>::type alloc( + (get_associated_allocator)(handler_)); + work_.get_executor().dispatch( + ASIO_MOVE_CAST(Handler)(handler_), alloc); + work_.reset(); + } + +private: + executor_work_guard<typename associated_executor<Handler>::type> work_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WORK_DISPATCHER_HPP diff --git a/lib/asio/detail/wrapped_handler.hpp b/lib/asio/detail/wrapped_handler.hpp new file mode 100644 index 0000000..751f0ea --- /dev/null +++ b/lib/asio/detail/wrapped_handler.hpp @@ -0,0 +1,291 @@ +// +// detail/wrapped_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WRAPPED_HANDLER_HPP +#define ASIO_DETAIL_WRAPPED_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct is_continuation_delegated +{ + template <typename Dispatcher, typename Handler> + bool operator()(Dispatcher&, Handler& handler) const + { + return asio_handler_cont_helpers::is_continuation(handler); + } +}; + +struct is_continuation_if_running +{ + template <typename Dispatcher, typename Handler> + bool operator()(Dispatcher& dispatcher, Handler&) const + { + return dispatcher.running_in_this_thread(); + } +}; + +template <typename Dispatcher, typename Handler, + typename IsContinuation = is_continuation_delegated> +class wrapped_handler +{ +public: + typedef void result_type; + + wrapped_handler(Dispatcher dispatcher, Handler& handler) + : dispatcher_(dispatcher), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + wrapped_handler(const wrapped_handler& other) + : dispatcher_(other.dispatcher_), + handler_(other.handler_) + { + } + + wrapped_handler(wrapped_handler&& other) + : dispatcher_(other.dispatcher_), + handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + dispatcher_.dispatch(ASIO_MOVE_CAST(Handler)(handler_)); + } + + void operator()() const + { + dispatcher_.dispatch(handler_); + } + + template <typename Arg1> + void operator()(const Arg1& arg1) + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1)); + } + + template <typename Arg1> + void operator()(const Arg1& arg1) const + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1)); + } + + template <typename Arg1, typename Arg2> + void operator()(const Arg1& arg1, const Arg2& arg2) + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2)); + } + + template <typename Arg1, typename Arg2> + void operator()(const Arg1& arg1, const Arg2& arg2) const + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2)); + } + + template <typename Arg1, typename Arg2, typename Arg3> + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3)); + } + + template <typename Arg1, typename Arg2, typename Arg3> + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) const + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3)); + } + + template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4) + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4)); + } + + template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4) const + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4)); + } + + template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, + typename Arg5> + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5) + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5)); + } + + template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, + typename Arg5> + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5) const + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5)); + } + +//private: + Dispatcher dispatcher_; + Handler handler_; +}; + +template <typename Handler, typename Context> +class rewrapped_handler +{ +public: + explicit rewrapped_handler(Handler& handler, const Context& context) + : context_(context), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + } + + explicit rewrapped_handler(const Handler& handler, const Context& context) + : context_(context), + handler_(handler) + { + } + +#if defined(ASIO_HAS_MOVE) + rewrapped_handler(const rewrapped_handler& other) + : context_(other.context_), + handler_(other.handler_) + { + } + + rewrapped_handler(rewrapped_handler&& other) + : context_(ASIO_MOVE_CAST(Context)(other.context_)), + handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()() + { + handler_(); + } + + void operator()() const + { + handler_(); + } + +//private: + Context context_; + Handler handler_; +}; + +template <typename Dispatcher, typename Handler, typename IsContinuation> +inline void* asio_handler_allocate(std::size_t size, + wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Dispatcher, typename Handler, typename IsContinuation> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Dispatcher, typename Handler, typename IsContinuation> +inline bool asio_handler_is_continuation( + wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) +{ + return IsContinuation()(this_handler->dispatcher_, this_handler->handler_); +} + +template <typename Function, typename Dispatcher, + typename Handler, typename IsContinuation> +inline void asio_handler_invoke(Function& function, + wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) +{ + this_handler->dispatcher_.dispatch( + rewrapped_handler<Function, Handler>( + function, this_handler->handler_)); +} + +template <typename Function, typename Dispatcher, + typename Handler, typename IsContinuation> +inline void asio_handler_invoke(const Function& function, + wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) +{ + this_handler->dispatcher_.dispatch( + rewrapped_handler<Function, Handler>( + function, this_handler->handler_)); +} + +template <typename Handler, typename Context> +inline void* asio_handler_allocate(std::size_t size, + rewrapped_handler<Handler, Context>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->context_); +} + +template <typename Handler, typename Context> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + rewrapped_handler<Handler, Context>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->context_); +} + +template <typename Dispatcher, typename Context> +inline bool asio_handler_is_continuation( + rewrapped_handler<Dispatcher, Context>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->context_); +} + +template <typename Function, typename Handler, typename Context> +inline void asio_handler_invoke(Function& function, + rewrapped_handler<Handler, Context>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->context_); +} + +template <typename Function, typename Handler, typename Context> +inline void asio_handler_invoke(const Function& function, + rewrapped_handler<Handler, Context>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + function, this_handler->context_); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WRAPPED_HANDLER_HPP |