summaryrefslogtreecommitdiff
path: root/boost/asio/detail
diff options
context:
space:
mode:
Diffstat (limited to 'boost/asio/detail')
-rw-r--r--boost/asio/detail/addressof.hpp40
-rw-r--r--boost/asio/detail/bind_handler.hpp479
-rw-r--r--boost/asio/detail/buffer_sequence_adapter.hpp261
-rw-r--r--boost/asio/detail/call_stack.hpp2
-rw-r--r--boost/asio/detail/chrono.hpp68
-rw-r--r--boost/asio/detail/completion_handler.hpp12
-rw-r--r--boost/asio/detail/concurrency_hint.hpp94
-rw-r--r--boost/asio/detail/conditionally_enabled_event.hpp114
-rw-r--r--boost/asio/detail/conditionally_enabled_mutex.hpp151
-rw-r--r--boost/asio/detail/config.hpp323
-rw-r--r--boost/asio/detail/consuming_buffers.hpp450
-rw-r--r--boost/asio/detail/cstddef.hpp33
-rw-r--r--boost/asio/detail/cstdint.hpp14
-rw-r--r--boost/asio/detail/deadline_timer_service.hpp77
-rw-r--r--boost/asio/detail/descriptor_ops.hpp4
-rw-r--r--boost/asio/detail/descriptor_read_op.hpp23
-rw-r--r--boost/asio/detail/descriptor_write_op.hpp23
-rw-r--r--boost/asio/detail/dev_poll_reactor.hpp28
-rw-r--r--boost/asio/detail/epoll_reactor.hpp39
-rw-r--r--boost/asio/detail/executor_op.hpp86
-rw-r--r--boost/asio/detail/functional.hpp (renamed from boost/asio/detail/function.hpp)18
-rw-r--r--boost/asio/detail/gcc_arm_fenced_block.hpp2
-rw-r--r--boost/asio/detail/gcc_hppa_fenced_block.hpp2
-rw-r--r--boost/asio/detail/gcc_sync_fenced_block.hpp2
-rw-r--r--boost/asio/detail/gcc_x86_fenced_block.hpp2
-rw-r--r--boost/asio/detail/global.hpp54
-rw-r--r--boost/asio/detail/handler_alloc_helpers.hpp159
-rw-r--r--boost/asio/detail/handler_cont_helpers.hpp2
-rw-r--r--boost/asio/detail/handler_invoke_helpers.hpp2
-rw-r--r--boost/asio/detail/handler_tracking.hpp97
-rw-r--r--boost/asio/detail/handler_type_requirements.hpp150
-rw-r--r--boost/asio/detail/handler_work.hpp97
-rw-r--r--boost/asio/detail/impl/buffer_sequence_adapter.ipp10
-rw-r--r--boost/asio/detail/impl/descriptor_ops.ipp23
-rw-r--r--boost/asio/detail/impl/dev_poll_reactor.hpp19
-rw-r--r--boost/asio/detail/impl/dev_poll_reactor.ipp45
-rw-r--r--boost/asio/detail/impl/epoll_reactor.hpp19
-rw-r--r--boost/asio/detail/impl/epoll_reactor.ipp164
-rw-r--r--boost/asio/detail/impl/handler_tracking.ipp105
-rw-r--r--boost/asio/detail/impl/kqueue_reactor.hpp23
-rw-r--r--boost/asio/detail/impl/kqueue_reactor.ipp88
-rw-r--r--boost/asio/detail/impl/null_event.ipp76
-rw-r--r--boost/asio/detail/impl/posix_event.ipp12
-rw-r--r--boost/asio/detail/impl/posix_thread.ipp10
-rw-r--r--boost/asio/detail/impl/reactive_descriptor_service.ipp19
-rw-r--r--boost/asio/detail/impl/reactive_serial_port_service.ipp11
-rw-r--r--boost/asio/detail/impl/reactive_socket_service_base.ipp37
-rw-r--r--boost/asio/detail/impl/resolver_service_base.ipp82
-rw-r--r--boost/asio/detail/impl/scheduler.ipp (renamed from boost/asio/detail/impl/task_io_service.ipp)235
-rw-r--r--boost/asio/detail/impl/select_reactor.hpp19
-rw-r--r--boost/asio/detail/impl/select_reactor.ipp65
-rw-r--r--boost/asio/detail/impl/service_registry.hpp64
-rw-r--r--boost/asio/detail/impl/service_registry.ipp67
-rw-r--r--boost/asio/detail/impl/signal_set_service.ipp56
-rw-r--r--boost/asio/detail/impl/socket_ops.ipp153
-rw-r--r--boost/asio/detail/impl/strand_executor_service.hpp181
-rw-r--r--boost/asio/detail/impl/strand_executor_service.ipp126
-rw-r--r--boost/asio/detail/impl/strand_service.hpp24
-rw-r--r--boost/asio/detail/impl/strand_service.ipp27
-rw-r--r--boost/asio/detail/impl/task_io_service.hpp80
-rw-r--r--boost/asio/detail/impl/timer_queue_ptime.ipp15
-rw-r--r--boost/asio/detail/impl/win_event.ipp5
-rw-r--r--boost/asio/detail/impl/win_iocp_handle_service.ipp44
-rw-r--r--boost/asio/detail/impl/win_iocp_io_context.hpp (renamed from boost/asio/detail/impl/win_iocp_io_service.hpp)71
-rw-r--r--boost/asio/detail/impl/win_iocp_io_context.ipp (renamed from boost/asio/detail/impl/win_iocp_io_service.ipp)112
-rw-r--r--boost/asio/detail/impl/win_iocp_serial_port_service.ipp7
-rw-r--r--boost/asio/detail/impl/win_iocp_socket_service_base.ipp90
-rw-r--r--boost/asio/detail/impl/win_object_handle_service.ipp36
-rw-r--r--boost/asio/detail/impl/win_thread.ipp7
-rw-r--r--boost/asio/detail/impl/win_tss_ptr.ipp4
-rw-r--r--boost/asio/detail/impl/winrt_ssocket_service_base.ipp55
-rw-r--r--boost/asio/detail/impl/winrt_timer_scheduler.hpp19
-rw-r--r--boost/asio/detail/impl/winrt_timer_scheduler.ipp16
-rw-r--r--boost/asio/detail/io_control.hpp50
-rw-r--r--boost/asio/detail/is_buffer_sequence.hpp241
-rw-r--r--boost/asio/detail/is_executor.hpp128
-rw-r--r--boost/asio/detail/kqueue_reactor.hpp36
-rw-r--r--boost/asio/detail/macos_fenced_block.hpp1
-rw-r--r--boost/asio/detail/memory.hpp41
-rw-r--r--boost/asio/detail/null_event.hpp20
-rw-r--r--boost/asio/detail/null_fenced_block.hpp2
-rw-r--r--boost/asio/detail/null_global.hpp61
-rw-r--r--boost/asio/detail/null_reactor.hpp17
-rw-r--r--boost/asio/detail/null_socket_service.hpp46
-rw-r--r--boost/asio/detail/null_thread.hpp6
-rw-r--r--boost/asio/detail/object_pool.hpp25
-rw-r--r--boost/asio/detail/operation.hpp4
-rw-r--r--boost/asio/detail/pop_options.hpp4
-rw-r--r--boost/asio/detail/posix_event.hpp33
-rw-r--r--boost/asio/detail/posix_global.hpp82
-rw-r--r--boost/asio/detail/posix_thread.hpp4
-rw-r--r--boost/asio/detail/push_options.hpp9
-rw-r--r--boost/asio/detail/reactive_descriptor_service.hpp104
-rw-r--r--boost/asio/detail/reactive_null_buffers_op.hpp14
-rw-r--r--boost/asio/detail/reactive_serial_port_service.hpp16
-rw-r--r--boost/asio/detail/reactive_socket_accept_op.hpp119
-rw-r--r--boost/asio/detail/reactive_socket_connect_op.hpp19
-rw-r--r--boost/asio/detail/reactive_socket_recv_op.hpp26
-rw-r--r--boost/asio/detail/reactive_socket_recvfrom_op.hpp19
-rw-r--r--boost/asio/detail/reactive_socket_recvmsg_op.hpp21
-rw-r--r--boost/asio/detail/reactive_socket_send_op.hpp34
-rw-r--r--boost/asio/detail/reactive_socket_sendto_op.hpp21
-rw-r--r--boost/asio/detail/reactive_socket_service.hpp128
-rw-r--r--boost/asio/detail/reactive_socket_service_base.hpp129
-rw-r--r--boost/asio/detail/reactive_wait_op.hpp92
-rw-r--r--boost/asio/detail/reactor.hpp2
-rw-r--r--boost/asio/detail/reactor_fwd.hpp2
-rw-r--r--boost/asio/detail/reactor_op.hpp8
-rw-r--r--boost/asio/detail/recycling_allocator.hpp106
-rw-r--r--boost/asio/detail/resolve_endpoint_op.hpp47
-rw-r--r--boost/asio/detail/resolve_op.hpp96
-rw-r--r--boost/asio/detail/resolve_query_op.hpp136
-rw-r--r--boost/asio/detail/resolver_service.hpp58
-rw-r--r--boost/asio/detail/resolver_service_base.hpp47
-rw-r--r--boost/asio/detail/scheduler.hpp (renamed from boost/asio/detail/task_io_service.hpp)100
-rw-r--r--boost/asio/detail/scheduler_operation.hpp (renamed from boost/asio/detail/task_io_service_operation.hpp)34
-rw-r--r--boost/asio/detail/scheduler_thread_info.hpp (renamed from boost/asio/detail/task_io_service_thread_info.hpp)18
-rw-r--r--boost/asio/detail/scoped_ptr.hpp8
-rw-r--r--boost/asio/detail/select_reactor.hpp40
-rw-r--r--boost/asio/detail/service_registry.hpp86
-rw-r--r--boost/asio/detail/shared_ptr.hpp40
-rw-r--r--boost/asio/detail/signal_handler.hpp12
-rw-r--r--boost/asio/detail/signal_set_service.hpp25
-rw-r--r--boost/asio/detail/socket_ops.hpp13
-rw-r--r--boost/asio/detail/socket_types.hpp6
-rw-r--r--boost/asio/detail/solaris_fenced_block.hpp1
-rw-r--r--boost/asio/detail/std_global.hpp72
-rw-r--r--boost/asio/detail/std_thread.hpp6
-rw-r--r--boost/asio/detail/strand_executor_service.hpp140
-rw-r--r--boost/asio/detail/strand_service.hpp18
-rw-r--r--boost/asio/detail/string_view.hpp47
-rw-r--r--boost/asio/detail/thread.hpp12
-rw-r--r--boost/asio/detail/thread_context.hpp44
-rw-r--r--boost/asio/detail/thread_group.hpp91
-rw-r--r--boost/asio/detail/thread_info_base.hpp11
-rw-r--r--boost/asio/detail/timer_queue.hpp29
-rw-r--r--boost/asio/detail/timer_queue_ptime.hpp14
-rw-r--r--boost/asio/detail/timer_scheduler.hpp2
-rw-r--r--boost/asio/detail/timer_scheduler_fwd.hpp2
-rw-r--r--boost/asio/detail/type_traits.hpp22
-rw-r--r--boost/asio/detail/variadic_templates.hpp98
-rw-r--r--boost/asio/detail/wait_handler.hpp12
-rw-r--r--boost/asio/detail/weak_ptr.hpp40
-rw-r--r--boost/asio/detail/win_event.hpp21
-rw-r--r--boost/asio/detail/win_fenced_block.hpp1
-rw-r--r--boost/asio/detail/win_global.hpp75
-rw-r--r--boost/asio/detail/win_iocp_handle_read_op.hpp10
-rw-r--r--boost/asio/detail/win_iocp_handle_service.hpp39
-rw-r--r--boost/asio/detail/win_iocp_handle_write_op.hpp10
-rw-r--r--boost/asio/detail/win_iocp_io_context.hpp (renamed from boost/asio/detail/win_iocp_io_service.hpp)75
-rw-r--r--boost/asio/detail/win_iocp_null_buffers_op.hpp14
-rw-r--r--boost/asio/detail/win_iocp_operation.hpp13
-rw-r--r--boost/asio/detail/win_iocp_overlapped_op.hpp10
-rw-r--r--boost/asio/detail/win_iocp_overlapped_ptr.hpp25
-rw-r--r--boost/asio/detail/win_iocp_serial_port_service.hpp16
-rw-r--r--boost/asio/detail/win_iocp_socket_accept_op.hpp140
-rw-r--r--boost/asio/detail/win_iocp_socket_connect_op.hpp15
-rw-r--r--boost/asio/detail/win_iocp_socket_recv_op.hpp10
-rw-r--r--boost/asio/detail/win_iocp_socket_recvfrom_op.hpp10
-rw-r--r--boost/asio/detail/win_iocp_socket_recvmsg_op.hpp10
-rw-r--r--boost/asio/detail/win_iocp_socket_send_op.hpp10
-rw-r--r--boost/asio/detail/win_iocp_socket_service.hpp135
-rw-r--r--boost/asio/detail/win_iocp_socket_service_base.hpp153
-rw-r--r--boost/asio/detail/win_iocp_wait_op.hpp123
-rw-r--r--boost/asio/detail/win_object_handle_service.hpp21
-rw-r--r--boost/asio/detail/win_thread.hpp4
-rw-r--r--boost/asio/detail/winapp_thread.hpp (renamed from boost/asio/detail/winapi_thread.hpp)44
-rw-r--r--boost/asio/detail/wince_thread.hpp126
-rw-r--r--boost/asio/detail/winrt_async_manager.hpp26
-rw-r--r--boost/asio/detail/winrt_resolve_op.hpp25
-rw-r--r--boost/asio/detail/winrt_resolver_service.hpp65
-rw-r--r--boost/asio/detail/winrt_socket_connect_op.hpp12
-rw-r--r--boost/asio/detail/winrt_socket_recv_op.hpp10
-rw-r--r--boost/asio/detail/winrt_socket_send_op.hpp10
-rw-r--r--boost/asio/detail/winrt_ssocket_service.hpp22
-rw-r--r--boost/asio/detail/winrt_ssocket_service_base.hpp32
-rw-r--r--boost/asio/detail/winrt_timer_scheduler.hpp20
-rw-r--r--boost/asio/detail/winrt_utils.hpp6
-rw-r--r--boost/asio/detail/work_dispatcher.hpp74
179 files changed, 7620 insertions, 2118 deletions
diff --git a/boost/asio/detail/addressof.hpp b/boost/asio/detail/addressof.hpp
deleted file mode 100644
index cc1099764d..0000000000
--- a/boost/asio/detail/addressof.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// detail/addressof.hpp
-// ~~~~~~~~~~~~~~~~~~~~
-//
-// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef BOOST_ASIO_DETAIL_ADDRESSOF_HPP
-#define BOOST_ASIO_DETAIL_ADDRESSOF_HPP
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1200)
-# pragma once
-#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-
-#include <boost/asio/detail/config.hpp>
-
-#if defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
-# include <memory>
-#else // defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
-# include <boost/utility/addressof.hpp>
-#endif // defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
-
-namespace boost {
-namespace asio {
-namespace detail {
-
-#if defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
-using std::addressof;
-#else // defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
-using boost::addressof;
-#endif // defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
-
-} // namespace detail
-} // namespace asio
-} // namespace boost
-
-#endif // BOOST_ASIO_DETAIL_ADDRESSOF_HPP
diff --git a/boost/asio/detail/bind_handler.hpp b/boost/asio/detail/bind_handler.hpp
index 0f3672edab..b55c2acd5e 100644
--- a/boost/asio/detail/bind_handler.hpp
+++ b/boost/asio/detail/bind_handler.hpp
@@ -16,9 +16,12 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
+#include <boost/asio/associated_allocator.hpp>
+#include <boost/asio/associated_executor.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -30,8 +33,9 @@ template <typename Handler, typename Arg1>
class binder1
{
public:
- binder1(const Handler& handler, const Arg1& arg1)
- : handler_(handler),
+ template <typename T>
+ binder1(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1)
+ : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)),
arg1_(arg1)
{
}
@@ -42,6 +46,20 @@ public:
{
}
+#if defined(BOOST_ASIO_HAS_MOVE)
+ binder1(const binder1& other)
+ : handler_(other.handler_),
+ arg1_(other.arg1_)
+ {
+ }
+
+ binder1(binder1&& other)
+ : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_))
+ {
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
void operator()()
{
handler_(static_cast<const Arg1&>(arg1_));
@@ -98,18 +116,21 @@ inline void asio_handler_invoke(const Function& function,
}
template <typename Handler, typename Arg1>
-inline binder1<Handler, Arg1> bind_handler(Handler handler,
- const Arg1& arg1)
+inline binder1<typename decay<Handler>::type, Arg1> bind_handler(
+ BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1)
{
- return binder1<Handler, Arg1>(handler, arg1);
+ return binder1<typename decay<Handler>::type, Arg1>(0,
+ BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1);
}
template <typename Handler, typename Arg1, typename Arg2>
class binder2
{
public:
- binder2(const Handler& handler, const Arg1& arg1, const Arg2& arg2)
- : handler_(handler),
+ template <typename T>
+ binder2(int, BOOST_ASIO_MOVE_ARG(T) handler,
+ const Arg1& arg1, const Arg2& arg2)
+ : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)),
arg1_(arg1),
arg2_(arg2)
{
@@ -122,6 +143,22 @@ public:
{
}
+#if defined(BOOST_ASIO_HAS_MOVE)
+ binder2(const binder2& other)
+ : handler_(other.handler_),
+ arg1_(other.arg1_),
+ arg2_(other.arg2_)
+ {
+ }
+
+ binder2(binder2&& other)
+ : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+ arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_))
+ {
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
void operator()()
{
handler_(static_cast<const Arg1&>(arg1_),
@@ -180,27 +217,29 @@ inline void asio_handler_invoke(const Function& function,
}
template <typename Handler, typename Arg1, typename Arg2>
-inline binder2<Handler, Arg1, Arg2> bind_handler(Handler handler,
- const Arg1& arg1, const Arg2& arg2)
+inline binder2<typename decay<Handler>::type, Arg1, Arg2> bind_handler(
+ BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2)
{
- return binder2<Handler, Arg1, Arg2>(handler, arg1, arg2);
+ return binder2<typename decay<Handler>::type, Arg1, Arg2>(0,
+ BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
class binder3
{
public:
- binder3(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
- const Arg3& arg3)
- : handler_(handler),
+ template <typename T>
+ binder3(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3)
+ : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3)
{
}
- binder3(Handler& handler, const Arg1& arg1, const Arg2& arg2,
- const Arg3& arg3)
+ binder3(Handler& handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3)
: handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
arg1_(arg1),
arg2_(arg2),
@@ -208,11 +247,28 @@ public:
{
}
+#if defined(BOOST_ASIO_HAS_MOVE)
+ binder3(const binder3& other)
+ : handler_(other.handler_),
+ arg1_(other.arg1_),
+ arg2_(other.arg2_),
+ arg3_(other.arg3_)
+ {
+ }
+
+ binder3(binder3&& other)
+ : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+ arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)),
+ arg3_(BOOST_ASIO_MOVE_CAST(Arg3)(other.arg3_))
+ {
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
void operator()()
{
handler_(static_cast<const Arg1&>(arg1_),
- static_cast<const Arg2&>(arg2_),
- static_cast<const Arg3&>(arg3_));
+ static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_));
}
void operator()() const
@@ -251,8 +307,8 @@ inline bool asio_handler_is_continuation(
this_handler->handler_);
}
-template <typename Function, typename Handler, typename Arg1, typename Arg2,
- typename Arg3>
+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)
{
@@ -260,8 +316,8 @@ inline void asio_handler_invoke(Function& function,
function, this_handler->handler_);
}
-template <typename Function, typename Handler, typename Arg1, typename Arg2,
- typename Arg3>
+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)
{
@@ -270,20 +326,23 @@ inline void asio_handler_invoke(const Function& function,
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
-inline binder3<Handler, Arg1, Arg2, Arg3> bind_handler(Handler handler,
- const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
+inline binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3> bind_handler(
+ BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3)
{
- return binder3<Handler, Arg1, Arg2, Arg3>(handler, arg1, arg2, arg3);
+ return binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3>(0,
+ BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3);
}
-template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
- typename Arg4>
+template <typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4>
class binder4
{
public:
- binder4(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
- const Arg3& arg3, const Arg4& arg4)
- : handler_(handler),
+ template <typename T>
+ binder4(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
+ : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
@@ -291,8 +350,8 @@ public:
{
}
- binder4(Handler& handler, const Arg1& arg1, const Arg2& arg2,
- const Arg3& arg3, const Arg4& arg4)
+ binder4(Handler& handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
: handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
arg1_(arg1),
arg2_(arg2),
@@ -301,11 +360,30 @@ public:
{
}
+#if defined(BOOST_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_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+ arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)),
+ arg3_(BOOST_ASIO_MOVE_CAST(Arg3)(other.arg3_)),
+ arg4_(BOOST_ASIO_MOVE_CAST(Arg4)(other.arg4_))
+ {
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
void operator()()
{
handler_(static_cast<const Arg1&>(arg1_),
- static_cast<const Arg2&>(arg2_),
- static_cast<const Arg3&>(arg3_),
+ static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_));
}
@@ -322,8 +400,8 @@ public:
Arg4 arg4_;
};
-template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
- typename 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)
{
@@ -331,8 +409,8 @@ inline void* asio_handler_allocate(std::size_t size,
size, this_handler->handler_);
}
-template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
- typename Arg4>
+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)
{
@@ -340,8 +418,8 @@ inline void asio_handler_deallocate(void* pointer, std::size_t size,
pointer, size, this_handler->handler_);
}
-template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
- typename Arg4>
+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)
{
@@ -349,8 +427,8 @@ inline bool asio_handler_is_continuation(
this_handler->handler_);
}
-template <typename Function, typename Handler, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4>
+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)
{
@@ -358,8 +436,8 @@ inline void asio_handler_invoke(Function& function,
function, this_handler->handler_);
}
-template <typename Function, typename Handler, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4>
+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)
{
@@ -367,24 +445,25 @@ inline void asio_handler_invoke(const Function& function,
function, this_handler->handler_);
}
-template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
- typename Arg4>
-inline binder4<Handler, Arg1, Arg2, Arg3, Arg4> bind_handler(
- Handler handler, const Arg1& arg1, const Arg2& arg2,
- const Arg3& arg3, const Arg4& arg4)
+template <typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4>
+inline binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>
+bind_handler(BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
{
- return binder4<Handler, Arg1, Arg2, Arg3, Arg4>(handler, arg1, arg2, arg3,
- arg4);
+ return binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>(0,
+ BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4);
}
-template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
- typename Arg4, typename Arg5>
+template <typename Handler, typename Arg1, typename Arg2,
+ typename Arg3, typename Arg4, typename Arg5>
class binder5
{
public:
- binder5(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
- const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
- : handler_(handler),
+ template <typename T>
+ binder5(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+ : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
@@ -404,13 +483,33 @@ public:
{
}
+#if defined(BOOST_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_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+ arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)),
+ arg3_(BOOST_ASIO_MOVE_CAST(Arg3)(other.arg3_)),
+ arg4_(BOOST_ASIO_MOVE_CAST(Arg4)(other.arg4_)),
+ arg5_(BOOST_ASIO_MOVE_CAST(Arg5)(other.arg5_))
+ {
+ }
+#endif // defined(BOOST_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_));
+ static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),
+ static_cast<const Arg4&>(arg4_), static_cast<const Arg5&>(arg5_));
}
void operator()() const
@@ -427,8 +526,8 @@ public:
Arg5 arg5_;
};
-template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
- typename Arg4, typename 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)
{
@@ -436,8 +535,8 @@ inline void* asio_handler_allocate(std::size_t size,
size, this_handler->handler_);
}
-template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
- typename Arg4, typename Arg5>
+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)
{
@@ -445,8 +544,8 @@ inline void asio_handler_deallocate(void* pointer, std::size_t size,
pointer, size, this_handler->handler_);
}
-template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
- typename Arg4, typename Arg5>
+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)
{
@@ -454,8 +553,8 @@ inline bool asio_handler_is_continuation(
this_handler->handler_);
}
-template <typename Function, typename Handler, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4, typename Arg5>
+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)
{
@@ -463,8 +562,8 @@ inline void asio_handler_invoke(Function& function,
function, this_handler->handler_);
}
-template <typename Function, typename Handler, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4, typename Arg5>
+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)
{
@@ -472,17 +571,245 @@ inline void asio_handler_invoke(const Function& function,
function, this_handler->handler_);
}
-template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
- typename Arg4, typename Arg5>
-inline binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> bind_handler(
- Handler handler, const Arg1& arg1, const Arg2& arg2,
- const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+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(BOOST_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,
+ BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4, arg5);
+}
+
+#if defined(BOOST_ASIO_HAS_MOVE)
+
+template <typename Handler, typename Arg1>
+class move_binder1
+{
+public:
+ move_binder1(int, BOOST_ASIO_MOVE_ARG(Handler) handler,
+ BOOST_ASIO_MOVE_ARG(Arg1) arg1)
+ : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
+ arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(arg1))
+ {
+ }
+
+ move_binder1(move_binder1&& other)
+ : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_))
+ {
+ }
+
+ void operator()()
+ {
+ handler_(BOOST_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 boost_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)
+{
+ boost_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 boost_asio_handler_cont_helpers::is_continuation(
+ this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1>
+inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function,
+ move_binder1<Handler, Arg1>* this_handler)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+class move_binder2
+{
+public:
+ move_binder2(int, BOOST_ASIO_MOVE_ARG(Handler) handler,
+ const Arg1& arg1, BOOST_ASIO_MOVE_ARG(Arg2) arg2)
+ : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
+ arg1_(arg1),
+ arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(arg2))
+ {
+ }
+
+ move_binder2(move_binder2&& other)
+ : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+ arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_))
+ {
+ }
+
+ void operator()()
+ {
+ handler_(static_cast<const Arg1&>(arg1_),
+ BOOST_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 boost_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)
+{
+ boost_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 binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>(handler, arg1, arg2,
- arg3, arg4, arg5);
+ return boost_asio_handler_cont_helpers::is_continuation(
+ this_handler->handler_);
}
+template <typename Function, typename Handler, typename Arg1, typename Arg2>
+inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function,
+ move_binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_);
+}
+
+#endif // defined(BOOST_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()) BOOST_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()) BOOST_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()) BOOST_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()) BOOST_ASIO_NOEXCEPT
+ {
+ return associated_executor<Handler, Executor>::get(h.handler_, ex);
+ }
+};
+
+#if defined(BOOST_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()) BOOST_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()) BOOST_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()) BOOST_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()) BOOST_ASIO_NOEXCEPT
+ {
+ return associated_executor<Handler, Executor>::get(h.handler_, ex);
+ }
+};
+
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
} // namespace asio
} // namespace boost
diff --git a/boost/asio/detail/buffer_sequence_adapter.hpp b/boost/asio/detail/buffer_sequence_adapter.hpp
index 20c529e0a2..e04b292266 100644
--- a/boost/asio/detail/buffer_sequence_adapter.hpp
+++ b/boost/asio/detail/buffer_sequence_adapter.hpp
@@ -28,11 +28,12 @@ namespace detail {
class buffer_sequence_adapter_base
{
-protected:
#if defined(BOOST_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;
BOOST_ASIO_DECL static void init_native_buffer(
@@ -43,28 +44,32 @@ protected:
native_buffer_type& buf,
const boost::asio::const_buffer& buffer);
#elif defined(BOOST_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 boost::asio::mutable_buffer& buffer)
{
- buf.buf = boost::asio::buffer_cast<char*>(buffer);
- buf.len = static_cast<ULONG>(boost::asio::buffer_size(buffer));
+ buf.buf = static_cast<char*>(buffer.data());
+ buf.len = static_cast<ULONG>(buffer.size());
}
static void init_native_buffer(WSABUF& buf,
const boost::asio::const_buffer& buffer)
{
- buf.buf = const_cast<char*>(boost::asio::buffer_cast<const char*>(buffer));
- buf.len = static_cast<ULONG>(boost::asio::buffer_size(buffer));
+ buf.buf = const_cast<char*>(static_cast<const char*>(buffer.data()));
+ buf.len = static_cast<ULONG>(buffer.size());
}
#else // defined(BOOST_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)
@@ -81,16 +86,15 @@ protected:
static void init_native_buffer(iovec& iov,
const boost::asio::mutable_buffer& buffer)
{
- init_iov_base(iov.iov_base, boost::asio::buffer_cast<void*>(buffer));
- iov.iov_len = boost::asio::buffer_size(buffer);
+ init_iov_base(iov.iov_base, buffer.data());
+ iov.iov_len = buffer.size();
}
static void init_native_buffer(iovec& iov,
const boost::asio::const_buffer& buffer)
{
- init_iov_base(iov.iov_base, const_cast<void*>(
- boost::asio::buffer_cast<const void*>(buffer)));
- iov.iov_len = boost::asio::buffer_size(buffer);
+ init_iov_base(iov.iov_base, const_cast<void*>(buffer.data()));
+ iov.iov_len = buffer.size();
}
#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
};
@@ -104,14 +108,9 @@ public:
explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
: count_(0), total_buffer_size_(0)
{
- typename Buffers::const_iterator iter = buffer_sequence.begin();
- typename Buffers::const_iterator end = buffer_sequence.end();
- for (; iter != end && count_ < max_buffers; ++iter, ++count_)
- {
- Buffer buffer(*iter);
- init_native_buffer(buffers_[count_], buffer);
- total_buffer_size_ += boost::asio::buffer_size(buffer);
- }
+ buffer_sequence_adapter::init(
+ boost::asio::buffer_sequence_begin(buffer_sequence),
+ boost::asio::buffer_sequence_end(buffer_sequence));
}
native_buffer_type* buffers()
@@ -124,6 +123,11 @@ public:
return count_;
}
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -131,46 +135,185 @@ public:
static bool all_empty(const Buffers& buffer_sequence)
{
- typename Buffers::const_iterator iter = buffer_sequence.begin();
- typename Buffers::const_iterator end = buffer_sequence.end();
+ return buffer_sequence_adapter::all_empty(
+ boost::asio::buffer_sequence_begin(buffer_sequence),
+ boost::asio::buffer_sequence_end(buffer_sequence));
+ }
+
+ static void validate(const Buffers& buffer_sequence)
+ {
+ buffer_sequence_adapter::validate(
+ boost::asio::buffer_sequence_begin(buffer_sequence),
+ boost::asio::buffer_sequence_end(buffer_sequence));
+ }
+
+ static Buffer first(const Buffers& buffer_sequence)
+ {
+ return buffer_sequence_adapter::first(
+ boost::asio::buffer_sequence_begin(buffer_sequence),
+ boost::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 (boost::asio::buffer_size(Buffer(*iter)) > 0)
+ if (Buffer(*iter).size() > 0)
return false;
return true;
}
- static void validate(const Buffers& buffer_sequence)
+ template <typename Iterator>
+ static void validate(Iterator begin, Iterator end)
{
- typename Buffers::const_iterator iter = buffer_sequence.begin();
- typename Buffers::const_iterator end = buffer_sequence.end();
+ Iterator iter = begin;
for (; iter != end; ++iter)
{
Buffer buffer(*iter);
- boost::asio::buffer_cast<const void*>(buffer);
+ buffer.data();
}
}
- static Buffer first(const Buffers& buffer_sequence)
+ template <typename Iterator>
+ static Buffer first(Iterator begin, Iterator end)
{
- typename Buffers::const_iterator iter = buffer_sequence.begin();
- typename Buffers::const_iterator end = buffer_sequence.end();
+ Iterator iter = begin;
for (; iter != end; ++iter)
{
Buffer buffer(*iter);
- if (boost::asio::buffer_size(buffer) != 0)
+ if (buffer.size() != 0)
return buffer;
}
return Buffer();
}
-private:
native_buffer_type buffers_[max_buffers];
std::size_t count_;
std::size_t total_buffer_size_;
};
template <typename Buffer>
+class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffer>
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(
+ const boost::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 boost::asio::mutable_buffer& buffer_sequence)
+ {
+ return buffer_sequence.size() == 0;
+ }
+
+ static void validate(const boost::asio::mutable_buffer& buffer_sequence)
+ {
+ buffer_sequence.data();
+ }
+
+ static Buffer first(const boost::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, boost::asio::const_buffer>
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(
+ const boost::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 boost::asio::const_buffer& buffer_sequence)
+ {
+ return buffer_sequence.size() == 0;
+ }
+
+ static void validate(const boost::asio::const_buffer& buffer_sequence)
+ {
+ buffer_sequence.data();
+ }
+
+ static Buffer first(const boost::asio::const_buffer& buffer_sequence)
+ {
+ return Buffer(buffer_sequence);
+ }
+
+private:
+ native_buffer_type buffer_;
+ std::size_t total_buffer_size_;
+};
+
+#if !defined(BOOST_ASIO_NO_DEPRECATED)
+
+template <typename Buffer>
class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffers_1>
: buffer_sequence_adapter_base
{
@@ -179,7 +322,7 @@ public:
const boost::asio::mutable_buffers_1& buffer_sequence)
{
init_native_buffer(buffer_, Buffer(buffer_sequence));
- total_buffer_size_ = boost::asio::buffer_size(buffer_sequence);
+ total_buffer_size_ = buffer_sequence.size();
}
native_buffer_type* buffers()
@@ -192,6 +335,11 @@ public:
return 1;
}
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -199,12 +347,12 @@ public:
static bool all_empty(const boost::asio::mutable_buffers_1& buffer_sequence)
{
- return boost::asio::buffer_size(buffer_sequence) == 0;
+ return buffer_sequence.size() == 0;
}
static void validate(const boost::asio::mutable_buffers_1& buffer_sequence)
{
- boost::asio::buffer_cast<const void*>(buffer_sequence);
+ buffer_sequence.data();
}
static Buffer first(const boost::asio::mutable_buffers_1& buffer_sequence)
@@ -226,7 +374,7 @@ public:
const boost::asio::const_buffers_1& buffer_sequence)
{
init_native_buffer(buffer_, Buffer(buffer_sequence));
- total_buffer_size_ = boost::asio::buffer_size(buffer_sequence);
+ total_buffer_size_ = buffer_sequence.size();
}
native_buffer_type* buffers()
@@ -239,6 +387,11 @@ public:
return 1;
}
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -246,12 +399,12 @@ public:
static bool all_empty(const boost::asio::const_buffers_1& buffer_sequence)
{
- return boost::asio::buffer_size(buffer_sequence) == 0;
+ return buffer_sequence.size() == 0;
}
static void validate(const boost::asio::const_buffers_1& buffer_sequence)
{
- boost::asio::buffer_cast<const void*>(buffer_sequence);
+ buffer_sequence.data();
}
static Buffer first(const boost::asio::const_buffers_1& buffer_sequence)
@@ -264,6 +417,8 @@ private:
std::size_t total_buffer_size_;
};
+#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
+
template <typename Buffer, typename Elem>
class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >
: buffer_sequence_adapter_base
@@ -274,8 +429,7 @@ public:
{
init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
- total_buffer_size_ = boost::asio::buffer_size(buffer_sequence[0])
- + boost::asio::buffer_size(buffer_sequence[1]);
+ total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();
}
native_buffer_type* buffers()
@@ -288,6 +442,11 @@ public:
return 2;
}
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -295,19 +454,18 @@ public:
static bool all_empty(const boost::array<Elem, 2>& buffer_sequence)
{
- return boost::asio::buffer_size(buffer_sequence[0]) == 0
- && boost::asio::buffer_size(buffer_sequence[1]) == 0;
+ return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;
}
static void validate(const boost::array<Elem, 2>& buffer_sequence)
{
- boost::asio::buffer_cast<const void*>(buffer_sequence[0]);
- boost::asio::buffer_cast<const void*>(buffer_sequence[1]);
+ buffer_sequence[0].data();
+ buffer_sequence[1].data();
}
static Buffer first(const boost::array<Elem, 2>& buffer_sequence)
{
- return Buffer(boost::asio::buffer_size(buffer_sequence[0]) != 0
+ return Buffer(buffer_sequence[0].size() != 0
? buffer_sequence[0] : buffer_sequence[1]);
}
@@ -328,8 +486,7 @@ public:
{
init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
- total_buffer_size_ = boost::asio::buffer_size(buffer_sequence[0])
- + boost::asio::buffer_size(buffer_sequence[1]);
+ total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();
}
native_buffer_type* buffers()
@@ -342,6 +499,11 @@ public:
return 2;
}
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -349,19 +511,18 @@ public:
static bool all_empty(const std::array<Elem, 2>& buffer_sequence)
{
- return boost::asio::buffer_size(buffer_sequence[0]) == 0
- && boost::asio::buffer_size(buffer_sequence[1]) == 0;
+ return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;
}
static void validate(const std::array<Elem, 2>& buffer_sequence)
{
- boost::asio::buffer_cast<const void*>(buffer_sequence[0]);
- boost::asio::buffer_cast<const void*>(buffer_sequence[1]);
+ buffer_sequence[0].data();
+ buffer_sequence[1].data();
}
static Buffer first(const std::array<Elem, 2>& buffer_sequence)
{
- return Buffer(boost::asio::buffer_size(buffer_sequence[0]) != 0
+ return Buffer(buffer_sequence[0].size() != 0
? buffer_sequence[0] : buffer_sequence[1]);
}
diff --git a/boost/asio/detail/call_stack.hpp b/boost/asio/detail/call_stack.hpp
index 5253e3b153..52de6ef00d 100644
--- a/boost/asio/detail/call_stack.hpp
+++ b/boost/asio/detail/call_stack.hpp
@@ -26,7 +26,7 @@ namespace asio {
namespace detail {
// Helper class to determine whether or not the current thread is inside an
-// invocation of io_service::run() for a specified io_service object.
+// invocation of io_context::run() for a specified io_context object.
template <typename Key, typename Value = unsigned char>
class call_stack
{
diff --git a/boost/asio/detail/chrono.hpp b/boost/asio/detail/chrono.hpp
new file mode 100644
index 0000000000..923e7697b2
--- /dev/null
+++ b/boost/asio/detail/chrono.hpp
@@ -0,0 +1,68 @@
+//
+// detail/chrono.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_CHRONO_HPP
+#define BOOST_ASIO_DETAIL_CHRONO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if defined(BOOST_ASIO_HAS_STD_CHRONO)
+# include <chrono>
+#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO)
+# include <boost/chrono/system_clocks.hpp>
+#endif // defined(BOOST_ASIO_HAS_BOOST_CHRONO)
+
+namespace boost {
+namespace asio {
+namespace chrono {
+
+#if defined(BOOST_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(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
+typedef std::chrono::monotonic_clock steady_clock;
+#else // defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
+using std::chrono::steady_clock;
+#endif // defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
+using std::chrono::system_clock;
+using std::chrono::high_resolution_clock;
+#elif defined(BOOST_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(BOOST_ASIO_HAS_BOOST_CHRONO)
+
+} // namespace chrono
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_CHRONO_HPP
diff --git a/boost/asio/detail/completion_handler.hpp b/boost/asio/detail/completion_handler.hpp
index 6333dce569..d18d372eeb 100644
--- a/boost/asio/detail/completion_handler.hpp
+++ b/boost/asio/detail/completion_handler.hpp
@@ -15,11 +15,11 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
-#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/handler_work.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -38,17 +38,19 @@ public:
: operation(&completion_handler::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(h))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
// Take ownership of the handler object.
completion_handler* h(static_cast<completion_handler*>(base));
ptr p = { boost::asio::detail::addressof(h->handler_), h, h };
+ handler_work<Handler> w(h->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((h));
+ BOOST_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
@@ -65,7 +67,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN(());
- boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ w.complete(handler, handler);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/concurrency_hint.hpp b/boost/asio/detail/concurrency_hint.hpp
new file mode 100644
index 0000000000..0a13205499
--- /dev/null
+++ b/boost/asio/detail/concurrency_hint.hpp
@@ -0,0 +1,94 @@
+//
+// detail/concurrency_hint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_CONCURRENCY_HINT_HPP
+#define BOOST_ASIO_DETAIL_CONCURRENCY_HINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/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 BOOST_ASIO_CONCURRENCY_HINT_ID 0xA5100000u
+#define BOOST_ASIO_CONCURRENCY_HINT_ID_MASK 0xFFFF0000u
+
+// If set, this bit indicates that the scheduler should perform locking.
+#define BOOST_ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER 0x1u
+
+// If set, this bit indicates that the reactor should perform locking when
+// managing descriptor registrations.
+#define BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION 0x2u
+
+// If set, this bit indicates that the reactor should perform locking for I/O.
+#define BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO 0x4u
+
+// Helper macro to determine if we have a special concurrency hint.
+#define BOOST_ASIO_CONCURRENCY_HINT_IS_SPECIAL(hint) \
+ ((static_cast<unsigned>(hint) \
+ & BOOST_ASIO_CONCURRENCY_HINT_ID_MASK) \
+ == BOOST_ASIO_CONCURRENCY_HINT_ID)
+
+// Helper macro to determine if locking is enabled for a given facility.
+#define BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(facility, hint) \
+ (((static_cast<unsigned>(hint) \
+ & (BOOST_ASIO_CONCURRENCY_HINT_ID_MASK \
+ | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_ ## facility)) \
+ ^ BOOST_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 BOOST_ASIO_CONCURRENCY_HINT_UNSAFE \
+ static_cast<int>(BOOST_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 BOOST_ASIO_CONCURRENCY_HINT_UNSAFE_IO \
+ static_cast<int>(BOOST_ASIO_CONCURRENCY_HINT_ID \
+ | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \
+ | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION)
+
+// The special concurrency hint provides full thread safety.
+#define BOOST_ASIO_CONCURRENCY_HINT_SAFE \
+ static_cast<int>(BOOST_ASIO_CONCURRENCY_HINT_ID \
+ | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \
+ | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION \
+ | BOOST_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(BOOST_ASIO_CONCURRENCY_HINT_DEFAULT)
+# define BOOST_ASIO_CONCURRENCY_HINT_DEFAULT -1
+#endif // !defined(BOOST_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(BOOST_ASIO_CONCURRENCY_HINT_1)
+# define BOOST_ASIO_CONCURRENCY_HINT_1 1
+#endif // !defined(BOOST_ASIO_CONCURRENCY_HINT_DEFAULT)
+
+#endif // BOOST_ASIO_DETAIL_CONCURRENCY_HINT_HPP
diff --git a/boost/asio/detail/conditionally_enabled_event.hpp b/boost/asio/detail/conditionally_enabled_event.hpp
new file mode 100644
index 0000000000..c2be28587c
--- /dev/null
+++ b/boost/asio/detail/conditionally_enabled_event.hpp
@@ -0,0 +1,114 @@
+//
+// detail/conditionally_enabled_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
+#define BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/conditionally_enabled_mutex.hpp>
+#include <boost/asio/detail/event.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/null_event.hpp>
+#include <boost/asio/detail/scoped_lock.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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:
+ boost::asio::detail::event event_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
diff --git a/boost/asio/detail/conditionally_enabled_mutex.hpp b/boost/asio/detail/conditionally_enabled_mutex.hpp
new file mode 100644
index 0000000000..c7762b6889
--- /dev/null
+++ b/boost/asio/detail/conditionally_enabled_mutex.hpp
@@ -0,0 +1,151 @@
+//
+// detail/conditionally_enabled_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
+#define BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/scoped_lock.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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.
+ boost::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;
+ boost::asio::detail::mutex mutex_;
+ const bool enabled_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
diff --git a/boost/asio/detail/config.hpp b/boost/asio/detail/config.hpp
index afe400e5b7..b3272a666f 100644
--- a/boost/asio/detail/config.hpp
+++ b/boost/asio/detail/config.hpp
@@ -83,6 +83,11 @@
# 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(BOOST_ASIO_HAS_MOVE)
# if !defined(BOOST_ASIO_DISABLE_MOVE)
@@ -111,6 +116,7 @@
// references and perfect forwarding.
#if defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST)
# define BOOST_ASIO_MOVE_ARG(type) type&&
+# define BOOST_ASIO_MOVE_ARG2(type1, type2) type1, type2&&
# define BOOST_ASIO_MOVE_CAST(type) static_cast<type&&>
# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast<type1, type2&&>
#endif // defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST)
@@ -163,6 +169,30 @@
# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES)
#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+// Support deleted functions on compilers known to allow it.
+#if !defined(BOOST_ASIO_DELETED)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define BOOST_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 BOOST_ASIO_DELETED = delete
+# endif // __has_feature(__cxx_deleted_functions__)
+# endif // defined(__clang__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1900)
+# define BOOST_ASIO_DELETED = delete
+# endif // (_MSC_VER >= 1900)
+# endif // defined(BOOST_ASIO_MSVC)
+# if !defined(BOOST_ASIO_DELETED)
+# define BOOST_ASIO_DELETED
+# endif // !defined(BOOST_ASIO_DELETED)
+#endif // !defined(BOOST_ASIO_DELETED)
+
// Support constexpr on compilers known to allow it.
#if !defined(BOOST_ASIO_HAS_CONSTEXPR)
# if !defined(BOOST_ASIO_DISABLE_CONSTEXPR)
@@ -193,6 +223,85 @@
# endif // defined(BOOST_ASIO_HAS_CONSTEXPR)
#endif // !defined(BOOST_ASIO_CONSTEXPR)
+// Support noexcept on compilers known to allow it.
+#if !defined(BOOST_ASIO_NOEXCEPT)
+# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT)
+# if (BOOST_VERSION >= 105300)
+# define BOOST_ASIO_NOEXCEPT BOOST_NOEXCEPT
+# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW
+# elif defined(__clang__)
+# if __has_feature(__cxx_noexcept__)
+# define BOOST_ASIO_NOEXCEPT noexcept(true)
+# define BOOST_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 BOOST_ASIO_NOEXCEPT noexcept(true)
+# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# elif defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1900)
+# define BOOST_ASIO_NOEXCEPT noexcept(true)
+# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
+# endif // (_MSC_VER >= 1900)
+# endif // defined(BOOST_ASIO_MSVC)
+# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT)
+# if !defined(BOOST_ASIO_NOEXCEPT)
+# define BOOST_ASIO_NOEXCEPT
+# endif // !defined(BOOST_ASIO_NOEXCEPT)
+# if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW)
+# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw()
+# endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW)
+#endif // !defined(BOOST_ASIO_NOEXCEPT)
+
+// Support automatic type deduction on compilers known to support it.
+#if !defined(BOOST_ASIO_HAS_DECLTYPE)
+# if !defined(BOOST_ASIO_DISABLE_DECLTYPE)
+# if defined(__clang__)
+# if __has_feature(__cxx_decltype__)
+# define BOOST_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 BOOST_ASIO_HAS_DECLTYPE 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define BOOST_ASIO_HAS_DECLTYPE 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(BOOST_ASIO_MSVC)
+# endif // !defined(BOOST_ASIO_DISABLE_DECLTYPE)
+#endif // !defined(BOOST_ASIO_HAS_DECLTYPE)
+
+// Support alias templates on compilers known to allow it.
+#if !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES)
+# if !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES)
+# if defined(__clang__)
+# if __has_feature(__cxx_alias_templates__)
+# define BOOST_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 BOOST_ASIO_HAS_ALIAS_TEMPLATES 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1900)
+# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1
+# endif // (_MSC_VER >= 1900)
+# endif // defined(BOOST_ASIO_MSVC)
+# endif // !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES)
+#endif // !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES)
+
// Standard library support for system errors.
# if !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR)
# if defined(__clang__)
@@ -294,6 +403,31 @@
# endif // !defined(BOOST_ASIO_DISABLE_STD_SHARED_PTR)
#endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
+// Standard library support for allocator_arg_t.
+#if !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG)
+# if !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG)
+# if defined(__clang__)
+# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX)
+# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1
+# elif (__cplusplus >= 201103)
+# define BOOST_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 BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1600)
+# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1
+# endif // (_MSC_VER >= 1600)
+# endif // defined(BOOST_ASIO_MSVC)
+# endif // !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG)
+#endif // !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG)
+
// Standard library support for atomic operations.
#if !defined(BOOST_ASIO_HAS_STD_ATOMIC)
# if !defined(BOOST_ASIO_DISABLE_STD_ATOMIC)
@@ -362,6 +496,15 @@
# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO)
#endif // !defined(BOOST_ASIO_HAS_BOOST_CHRONO)
+// Some form of chrono library is available.
+#if !defined(BOOST_ASIO_HAS_CHRONO)
+# if defined(BOOST_ASIO_HAS_STD_CHRONO) \
+ || defined(BOOST_ASIO_HAS_BOOST_CHRONO)
+# define BOOST_ASIO_HAS_CHRONO 1
+# endif // defined(BOOST_ASIO_HAS_STD_CHRONO)
+ // || defined(BOOST_ASIO_HAS_BOOST_CHRONO)
+#endif // !defined(BOOST_ASIO_HAS_CHRONO)
+
// Boost support for the DateTime library.
#if !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
# if !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME)
@@ -446,6 +589,28 @@
# endif // !defined(BOOST_ASIO_DISABLE_STD_TYPE_TRAITS)
#endif // !defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS)
+// Standard library support for the nullptr_t type.
+#if !defined(BOOST_ASIO_HAS_NULLPTR)
+# if !defined(BOOST_ASIO_DISABLE_NULLPTR)
+# if defined(__clang__)
+# if __has_feature(__cxx_nullptr__)
+# define BOOST_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 BOOST_ASIO_HAS_NULLPTR 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define BOOST_ASIO_HAS_NULLPTR 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(BOOST_ASIO_MSVC)
+# endif // !defined(BOOST_ASIO_DISABLE_NULLPTR)
+#endif // !defined(BOOST_ASIO_HAS_NULLPTR)
+
// Standard library support for the C++11 allocator additions.
#if !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS)
# if !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS)
@@ -456,16 +621,16 @@
# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1
# endif // (__cplusplus >= 201103)
# elif defined(__GNUC__)
-# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
# if defined(__GXX_EXPERIMENTAL_CXX0X__)
# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1
# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
-# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
# endif // defined(__GNUC__)
# if defined(BOOST_ASIO_MSVC)
-# if (_MSC_VER >= 1700)
+# if (_MSC_VER >= 1800)
# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1
-# endif // (_MSC_VER >= 1700)
+# endif // (_MSC_VER >= 1800)
# endif // defined(BOOST_ASIO_MSVC)
# endif // !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS)
#endif // !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS)
@@ -549,6 +714,105 @@
# endif // !defined(BOOST_ASIO_DISABLE_STD_MUTEX_AND_CONDVAR)
#endif // !defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+// Standard library support for the call_once function.
+#if !defined(BOOST_ASIO_HAS_STD_CALL_ONCE)
+# if !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE)
+# if defined(__clang__)
+# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX)
+# define BOOST_ASIO_HAS_STD_CALL_ONCE 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<mutex>)
+# define BOOST_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 BOOST_ASIO_HAS_STD_CALL_ONCE 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define BOOST_ASIO_HAS_STD_CALL_ONCE 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(BOOST_ASIO_MSVC)
+# endif // !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE)
+#endif // !defined(BOOST_ASIO_HAS_STD_CALL_ONCE)
+
+// Standard library support for futures.
+#if !defined(BOOST_ASIO_HAS_STD_FUTURE)
+# if !defined(BOOST_ASIO_DISABLE_STD_FUTURE)
+# if defined(__clang__)
+# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX)
+# define BOOST_ASIO_HAS_STD_FUTURE 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<future>)
+# define BOOST_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__)
+# define BOOST_ASIO_HAS_STD_FUTURE 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define BOOST_ASIO_HAS_STD_FUTURE 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(BOOST_ASIO_MSVC)
+# endif // !defined(BOOST_ASIO_DISABLE_STD_FUTURE)
+#endif // !defined(BOOST_ASIO_HAS_STD_FUTURE)
+
+// Standard library support for experimental::string_view.
+#if !defined(BOOST_ASIO_HAS_STD_STRING_VIEW)
+# if !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW)
+# if defined(__clang__)
+# if (__cplusplus >= 201402)
+# if __has_include(<experimental/string_view>)
+# define BOOST_ASIO_HAS_STD_STRING_VIEW 1
+# define BOOST_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 BOOST_ASIO_HAS_STD_STRING_VIEW 1
+# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1
+# endif // (__cplusplus >= 201402)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1910 && _HAS_CXX17)
+# define BOOST_ASIO_HAS_STD_STRING_VIEW
+# endif // (_MSC_VER >= 1910)
+# endif // defined(BOOST_ASIO_MSVC)
+# endif // !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW)
+#endif // !defined(BOOST_ASIO_HAS_STD_STRING_VIEW)
+
+// Standard library support for iostream move construction and assignment.
+#if !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE)
+# if !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE)
+# if defined(__GNUC__)
+# if (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(BOOST_ASIO_MSVC)
+# endif // !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE)
+#endif // !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE)
+
// Windows App target. Windows but with a limited API.
#if !defined(BOOST_ASIO_WINDOWS_APP)
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603)
@@ -884,11 +1148,18 @@
# if !defined(BOOST_ASIO_DISABLE_THREADS)
# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS)
# define BOOST_ASIO_HAS_THREADS 1
-# elif defined(_MSC_VER) && defined(_MT)
+# elif defined(__GNUC__) && !defined(__MINGW32__) \
+ && !defined(linux) && !defined(__linux) && !defined(__linux__)
# define BOOST_ASIO_HAS_THREADS 1
-# elif defined(__BORLANDC__) && defined(__MT__)
+# elif defined(_MT) || defined(__MT__)
# define BOOST_ASIO_HAS_THREADS 1
-# elif defined(_POSIX_THREADS)
+# elif defined(_REENTRANT)
+# define BOOST_ASIO_HAS_THREADS 1
+# elif defined(__APPLE__)
+# define BOOST_ASIO_HAS_THREADS 1
+# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0)
+# define BOOST_ASIO_HAS_THREADS 1
+# elif defined(_PTHREADS)
# define BOOST_ASIO_HAS_THREADS 1
# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS)
# endif // !defined(BOOST_ASIO_DISABLE_THREADS)
@@ -899,7 +1170,7 @@
# if defined(BOOST_ASIO_HAS_THREADS)
# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS)
# define BOOST_ASIO_HAS_PTHREADS 1
-# elif defined(_POSIX_THREADS)
+# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0)
# define BOOST_ASIO_HAS_PTHREADS 1
# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS)
# endif // defined(BOOST_ASIO_HAS_THREADS)
@@ -1030,6 +1301,42 @@
// || (defined(__MACH__) && defined(__APPLE__))
#endif // !defined(BOOST_ASIO_DISABLE_SSIZE_T)
+// Helper macros to manage the transition away from the old services-based API.
+#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
+# define BOOST_ASIO_SVC_TPARAM , typename Service
+# define BOOST_ASIO_SVC_TPARAM_DEF1(d1) , typename Service d1
+# define BOOST_ASIO_SVC_TPARAM_DEF2(d1, d2) , typename Service d1, d2
+# define BOOST_ASIO_SVC_TARG , Service
+# define BOOST_ASIO_SVC_T Service
+# define BOOST_ASIO_SVC_TPARAM1 , typename Service1
+# define BOOST_ASIO_SVC_TPARAM1_DEF1(d1) , typename Service1 d1
+# define BOOST_ASIO_SVC_TPARAM1_DEF2(d1, d2) , typename Service1 d1, d2
+# define BOOST_ASIO_SVC_TARG1 , Service1
+# define BOOST_ASIO_SVC_T1 Service1
+# define BOOST_ASIO_SVC_ACCESS public
+#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
+# define BOOST_ASIO_SVC_TPARAM
+# define BOOST_ASIO_SVC_TPARAM_DEF1(d1)
+# define BOOST_ASIO_SVC_TPARAM_DEF2(d1, d2)
+# define BOOST_ASIO_SVC_TARG
+// BOOST_ASIO_SVC_T is defined at each point of use.
+# define BOOST_ASIO_SVC_TPARAM1
+# define BOOST_ASIO_SVC_TPARAM1_DEF1(d1)
+# define BOOST_ASIO_SVC_TPARAM1_DEF2(d1, d2)
+# define BOOST_ASIO_SVC_TARG1
+// BOOST_ASIO_SVC_T1 is defined at each point of use.
+# define BOOST_ASIO_SVC_ACCESS protected
+#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
+
+// Helper macros to manage transition away from error_code return values.
+#if defined(BOOST_ASIO_NO_DEPRECATED)
+# define BOOST_ASIO_SYNC_OP_VOID void
+# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return
+#else // defined(BOOST_ASIO_NO_DEPRECATED)
+# define BOOST_ASIO_SYNC_OP_VOID boost::system::error_code
+# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return e
+#endif // defined(BOOST_ASIO_NO_DEPRECATED)
+
// Newer gcc, clang need special treatment to suppress unused typedef warnings.
#if defined(__clang__)
# if defined(__apple_build_version__)
diff --git a/boost/asio/detail/consuming_buffers.hpp b/boost/asio/detail/consuming_buffers.hpp
index f0978b54d3..a429f974d6 100644
--- a/boost/asio/detail/consuming_buffers.hpp
+++ b/boost/asio/detail/consuming_buffers.hpp
@@ -17,8 +17,8 @@
#include <boost/asio/detail/config.hpp>
#include <cstddef>
-#include <iterator>
#include <boost/asio/buffer.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/limits.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -27,262 +27,384 @@ namespace boost {
namespace asio {
namespace detail {
-// A proxy iterator for a sub-range in a list of buffers.
-template <typename Buffer, typename Buffer_Iterator>
-class consuming_buffers_iterator
+// Helper template to determine the maximum number of prepared buffers.
+template <typename Buffers>
+struct prepared_buffers_max
{
-public:
- /// The type used for the distance between two iterators.
- typedef std::ptrdiff_t difference_type;
+ 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(BOOST_ASIO_HAS_STD_ARRAY)
+
+template <typename Elem, std::size_t N>
+struct prepared_buffers_max<std::array<Elem, N> >
+{
+ enum { value = N };
+};
- /// The type of the value pointed to by the iterator.
+#endif // defined(BOOST_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;
- /// The type of the result of applying operator->() to the iterator.
- typedef const Buffer* pointer;
+ enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 };
- /// The type of the result of applying operator*() to the iterator.
- typedef const Buffer& reference;
+ 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;
+};
- /// The iterator category.
- typedef std::forward_iterator_tag iterator_category;
+// 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;
- // Default constructor creates an end iterator.
- consuming_buffers_iterator()
- : at_end_(true)
+ // 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 boost::asio::buffer_size;
+ total_size_ = buffer_size(buffers);
}
- // Construct with a buffer for the first entry and an iterator
- // range for the remaining entries.
- consuming_buffers_iterator(bool at_end, const Buffer& first,
- Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder,
- std::size_t max_size)
- : at_end_(max_size > 0 ? at_end : true),
- first_(buffer(first, max_size)),
- begin_remainder_(begin_remainder),
- end_remainder_(end_remainder),
- offset_(0),
- max_size_(max_size)
+ // Determine if we are at the end of the buffers.
+ bool empty() const
{
+ return total_consumed_ >= total_size_;
}
- // Dereference an iterator.
- const Buffer& operator*() const
+ // Get the buffer for a single transfer, with a size.
+ prepared_buffers_type prepare(std::size_t max_size)
{
- return dereference();
+ prepared_buffers_type result;
+
+ Buffer_Iterator next = boost::asio::buffer_sequence_begin(buffers_);
+ Buffer_Iterator end = boost::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] = boost::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;
}
- // Dereference an iterator.
- const Buffer* operator->() const
+ // Consume the specified number of bytes from the buffers.
+ void consume(std::size_t size)
+ {
+ total_consumed_ += size;
+
+ Buffer_Iterator next = boost::asio::buffer_sequence_begin(buffers_);
+ Buffer_Iterator end = boost::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)
{
- return &dereference();
}
- // Increment operator (prefix).
- consuming_buffers_iterator& operator++()
+ // Determine if we are at the end of the buffers.
+ bool empty() const
{
- increment();
- return *this;
+ return total_consumed_ >= buffer_.size();
}
- // Increment operator (postfix).
- consuming_buffers_iterator operator++(int)
+ // Get the buffer for a single transfer, with a size.
+ Buffer prepare(std::size_t max_size)
{
- consuming_buffers_iterator tmp(*this);
- ++*this;
- return tmp;
+ return boost::asio::buffer(buffer_ + total_consumed_, max_size);
}
- // Test two iterators for equality.
- friend bool operator==(const consuming_buffers_iterator& a,
- const consuming_buffers_iterator& b)
+ // Consume the specified number of bytes from the buffers.
+ void consume(std::size_t size)
{
- return a.equal(b);
+ total_consumed_ += size;
}
- // Test two iterators for inequality.
- friend bool operator!=(const consuming_buffers_iterator& a,
- const consuming_buffers_iterator& b)
+ // Get the total number of bytes consumed from the buffers.
+ std::size_t total_consumed() const
{
- return !a.equal(b);
+ return total_consumed_;
}
private:
- void increment()
+ Buffer buffer_;
+ std::size_t total_consumed_;
+};
+
+template <>
+class consuming_buffers<mutable_buffer, mutable_buffer, const mutable_buffer*>
+ : public consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>
+{
+public:
+ explicit consuming_buffers(const mutable_buffer& buffer)
+ : consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>(buffer)
{
- if (!at_end_)
- {
- if (begin_remainder_ == end_remainder_
- || offset_ + buffer_size(first_) >= max_size_)
- {
- at_end_ = true;
- }
- else
- {
- offset_ += buffer_size(first_);
- first_ = buffer(*begin_remainder_++, max_size_ - offset_);
- }
- }
}
+};
- bool equal(const consuming_buffers_iterator& other) const
+template <>
+class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*>
+ : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>
+{
+public:
+ explicit consuming_buffers(const mutable_buffer& buffer)
+ : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer)
{
- if (at_end_ && other.at_end_)
- return true;
- return !at_end_ && !other.at_end_
- && buffer_cast<const void*>(first_)
- == buffer_cast<const void*>(other.first_)
- && buffer_size(first_) == buffer_size(other.first_)
- && begin_remainder_ == other.begin_remainder_
- && end_remainder_ == other.end_remainder_;
}
+};
- const Buffer& dereference() const
+template <>
+class consuming_buffers<const_buffer, const_buffer, const const_buffer*>
+ : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>
+{
+public:
+ explicit consuming_buffers(const const_buffer& buffer)
+ : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer)
{
- return first_;
}
+};
+
+#if !defined(BOOST_ASIO_NO_DEPRECATED)
- bool at_end_;
- Buffer first_;
- Buffer_Iterator begin_remainder_;
- Buffer_Iterator end_remainder_;
- std::size_t offset_;
- std::size_t max_size_;
+template <>
+class consuming_buffers<mutable_buffer,
+ mutable_buffers_1, const mutable_buffer*>
+ : public consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>
+{
+public:
+ explicit consuming_buffers(const mutable_buffers_1& buffer)
+ : consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>(buffer)
+ {
+ }
};
-// A proxy for a sub-range in a list of buffers.
-template <typename Buffer, typename Buffers>
-class consuming_buffers
+template <>
+class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*>
+ : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>
{
public:
- // The type for each element in the list of buffers.
- typedef Buffer value_type;
+ explicit consuming_buffers(const mutable_buffers_1& buffer)
+ : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer)
+ {
+ }
+};
- // A forward-only iterator type that may be used to read elements.
- typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator>
- const_iterator;
+template <>
+class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*>
+ : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>
+{
+public:
+ explicit consuming_buffers(const const_buffers_1& buffer)
+ : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer)
+ {
+ }
+};
+
+#endif // !defined(BOOST_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.
- consuming_buffers(const Buffers& buffers)
+ explicit consuming_buffers(const boost::array<Elem, 2>& buffers)
: buffers_(buffers),
- at_end_(buffers_.begin() == buffers_.end()),
- begin_remainder_(buffers_.begin()),
- max_size_((std::numeric_limits<std::size_t>::max)())
+ total_consumed_(0)
{
- if (!at_end_)
- {
- first_ = *buffers_.begin();
- ++begin_remainder_;
- }
}
- // Copy constructor.
- consuming_buffers(const consuming_buffers& other)
- : buffers_(other.buffers_),
- at_end_(other.at_end_),
- first_(other.first_),
- begin_remainder_(buffers_.begin()),
- max_size_(other.max_size_)
+ // 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] = boost::asio::buffer(result[0] + total_consumed_, max_size);
+ result[1] = boost::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)
{
- typename Buffers::const_iterator first = other.buffers_.begin();
- typename Buffers::const_iterator second = other.begin_remainder_;
- std::advance(begin_remainder_, std::distance(first, second));
+ total_consumed_ += size;
}
- // Assignment operator.
- consuming_buffers& operator=(const consuming_buffers& other)
+ // Get the total number of bytes consumed from the buffers.
+ std::size_t total_consumed() const
{
- buffers_ = other.buffers_;
- at_end_ = other.at_end_;
- first_ = other.first_;
- begin_remainder_ = buffers_.begin();
- typename Buffers::const_iterator first = other.buffers_.begin();
- typename Buffers::const_iterator second = other.begin_remainder_;
- std::advance(begin_remainder_, std::distance(first, second));
- max_size_ = other.max_size_;
- return *this;
+ return total_consumed_;
}
- // Get a forward-only iterator to the first element.
- const_iterator begin() const
+private:
+ boost::array<Elem, 2> buffers_;
+ std::size_t total_consumed_;
+};
+
+#if defined(BOOST_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)
{
- return const_iterator(at_end_, first_,
- begin_remainder_, buffers_.end(), max_size_);
}
- // Get a forward-only iterator for one past the last element.
- const_iterator end() const
+ // Determine if we are at the end of the buffers.
+ bool empty() const
{
- return const_iterator();
+ return total_consumed_ >=
+ Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
}
- // Set the maximum size for a single transfer.
- void prepare(std::size_t max_size)
+ // Get the buffer for a single transfer, with a size.
+ std::array<Buffer, 2> prepare(std::size_t max_size)
{
- max_size_ = max_size;
+ std::array<Buffer, 2> result = {{
+ Buffer(buffers_[0]), Buffer(buffers_[1]) }};
+ std::size_t buffer0_size = result[0].size();
+ result[0] = boost::asio::buffer(result[0] + total_consumed_, max_size);
+ result[1] = boost::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)
{
- // Remove buffers from the start until the specified size is reached.
- while (size > 0 && !at_end_)
- {
- if (buffer_size(first_) <= size)
- {
- size -= buffer_size(first_);
- if (begin_remainder_ == buffers_.end())
- at_end_ = true;
- else
- first_ = *begin_remainder_++;
- }
- else
- {
- first_ = first_ + size;
- size = 0;
- }
- }
+ total_consumed_ += size;
+ }
- // Remove any more empty buffers at the start.
- while (!at_end_ && buffer_size(first_) == 0)
- {
- if (begin_remainder_ == buffers_.end())
- at_end_ = true;
- else
- first_ = *begin_remainder_++;
- }
+ // Get the total number of bytes consumed from the buffers.
+ std::size_t total_consumed() const
+ {
+ return total_consumed_;
}
private:
- Buffers buffers_;
- bool at_end_;
- Buffer first_;
- typename Buffers::const_iterator begin_remainder_;
- std::size_t max_size_;
+ std::array<Elem, 2> buffers_;
+ std::size_t total_consumed_;
};
+#endif // defined(BOOST_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, boost::asio::null_buffers>
+class consuming_buffers<Buffer, null_buffers, const mutable_buffer*>
: public boost::asio::null_buffers
{
public:
- consuming_buffers(const boost::asio::null_buffers&)
+ consuming_buffers(const null_buffers&)
{
// No-op.
}
- void prepare(std::size_t)
+ bool empty()
{
- // No-op.
+ return false;
+ }
+
+ null_buffers prepare(std::size_t)
+ {
+ return null_buffers();
}
void consume(std::size_t)
{
// No-op.
}
+
+ std::size_t total_consume() const
+ {
+ return 0;
+ }
};
} // namespace detail
diff --git a/boost/asio/detail/cstddef.hpp b/boost/asio/detail/cstddef.hpp
new file mode 100644
index 0000000000..a6dacc1de4
--- /dev/null
+++ b/boost/asio/detail/cstddef.hpp
@@ -0,0 +1,33 @@
+//
+// detail/cstddef.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_CSTDDEF_HPP
+#define BOOST_ASIO_DETAIL_CSTDDEF_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <cstddef>
+
+namespace boost {
+namespace asio {
+
+#if defined(BOOST_ASIO_HAS_NULLPTR)
+using std::nullptr_t;
+#else // defined(BOOST_ASIO_HAS_NULLPTR)
+struct nullptr_t {};
+#endif // defined(BOOST_ASIO_HAS_NULLPTR)
+
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_CSTDDEF_HPP
diff --git a/boost/asio/detail/cstdint.hpp b/boost/asio/detail/cstdint.hpp
index a1be0dced0..61627c7ed3 100644
--- a/boost/asio/detail/cstdint.hpp
+++ b/boost/asio/detail/cstdint.hpp
@@ -28,18 +28,32 @@ namespace asio {
#if defined(BOOST_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(BOOST_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(BOOST_ASIO_HAS_CSTDINT)
} // namespace asio
diff --git a/boost/asio/detail/deadline_timer_service.hpp b/boost/asio/detail/deadline_timer_service.hpp
index bbd5358425..bc17eb288c 100644
--- a/boost/asio/detail/deadline_timer_service.hpp
+++ b/boost/asio/detail/deadline_timer_service.hpp
@@ -18,14 +18,15 @@
#include <boost/asio/detail/config.hpp>
#include <cstddef>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
#include <boost/asio/detail/timer_queue.hpp>
+#include <boost/asio/detail/timer_queue_ptime.hpp>
#include <boost/asio/detail/timer_scheduler.hpp>
#include <boost/asio/detail/wait_handler.hpp>
#include <boost/asio/detail/wait_op.hpp>
@@ -43,6 +44,7 @@ namespace detail {
template <typename Time_Traits>
class deadline_timer_service
+ : public service_base<deadline_timer_service<Time_Traits> >
{
public:
// The time type.
@@ -62,8 +64,9 @@ public:
};
// Constructor.
- deadline_timer_service(boost::asio::io_service& io_service)
- : scheduler_(boost::asio::use_service<timer_scheduler>(io_service))
+ deadline_timer_service(boost::asio::io_context& io_context)
+ : service_base<deadline_timer_service<Time_Traits> >(io_context),
+ scheduler_(boost::asio::use_service<timer_scheduler>(io_context))
{
scheduler_.init_task();
scheduler_.add_timer_queue(timer_queue_);
@@ -76,7 +79,7 @@ public:
}
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
+ void shutdown()
{
}
@@ -94,6 +97,38 @@ public:
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, boost::system::error_code& ec)
{
@@ -103,7 +138,8 @@ public:
return 0;
}
- BOOST_ASIO_HANDLER_OPERATION(("deadline_timer", &impl, "cancel"));
+ BOOST_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;
@@ -121,7 +157,8 @@ public:
return 0;
}
- BOOST_ASIO_HANDLER_OPERATION(("deadline_timer", &impl, "cancel_one"));
+ BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(),
+ "deadline_timer", &impl, 0, "cancel_one"));
std::size_t count = scheduler_.cancel_timer(
timer_queue_, impl.timer_data, 1);
@@ -132,11 +169,23 @@ public:
}
// 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, boost::system::error_code& ec)
@@ -147,10 +196,12 @@ public:
return count;
}
- // Get the expiry time for the timer relative to now.
- duration_type expires_from_now(const implementation_type& impl) const
+ // Set the expiry time for the timer relative to now.
+ std::size_t expires_after(implementation_type& impl,
+ const duration_type& expiry_time, boost::system::error_code& ec)
{
- return Time_Traits::subtract(expires_at(impl), Time_Traits::now());
+ return expires_at(impl,
+ Time_Traits::add(Time_Traits::now(), expiry_time), ec);
}
// Set the expiry time for the timer relative to now.
@@ -181,13 +232,13 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef wait_handler<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
impl.might_have_pending_waits = true;
- BOOST_ASIO_HANDLER_CREATION((p.p, "deadline_timer", &impl, "async_wait"));
+ BOOST_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;
diff --git a/boost/asio/detail/descriptor_ops.hpp b/boost/asio/detail/descriptor_ops.hpp
index 62100392da..5c1ce20d9c 100644
--- a/boost/asio/detail/descriptor_ops.hpp
+++ b/boost/asio/detail/descriptor_ops.hpp
@@ -22,6 +22,7 @@
&& !defined(__CYGWIN__)
#include <cstddef>
+#include <boost/asio/error.hpp>
#include <boost/system/error_code.hpp>
#include <boost/asio/detail/socket_types.hpp>
@@ -101,6 +102,9 @@ BOOST_ASIO_DECL int poll_read(int d,
BOOST_ASIO_DECL int poll_write(int d,
state_type state, boost::system::error_code& ec);
+BOOST_ASIO_DECL int poll_error(int d,
+ state_type state, boost::system::error_code& ec);
+
} // namespace descriptor_ops
} // namespace detail
} // namespace asio
diff --git a/boost/asio/detail/descriptor_read_op.hpp b/boost/asio/detail/descriptor_read_op.hpp
index ddbdf7d3e5..1ca2d236fe 100644
--- a/boost/asio/detail/descriptor_read_op.hpp
+++ b/boost/asio/detail/descriptor_read_op.hpp
@@ -19,11 +19,12 @@
#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/descriptor_ops.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_work.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -44,15 +45,21 @@ public:
{
}
- static bool do_perform(reactor_op* base)
+ static status do_perform(reactor_op* base)
{
descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base));
buffer_sequence_adapter<boost::asio::mutable_buffer,
MutableBufferSequence> bufs(o->buffers_);
- return descriptor_ops::non_blocking_read(o->descriptor_,
- bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_);
+ status result = descriptor_ops::non_blocking_read(o->descriptor_,
+ bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
+ ? done : not_done;
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
}
private:
@@ -73,17 +80,19 @@ public:
descriptor, buffers, &descriptor_read_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -101,7 +110,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/descriptor_write_op.hpp b/boost/asio/detail/descriptor_write_op.hpp
index f635feb122..0063491742 100644
--- a/boost/asio/detail/descriptor_write_op.hpp
+++ b/boost/asio/detail/descriptor_write_op.hpp
@@ -19,11 +19,12 @@
#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/descriptor_ops.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_work.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -44,15 +45,21 @@ public:
{
}
- static bool do_perform(reactor_op* base)
+ static status do_perform(reactor_op* base)
{
descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base));
buffer_sequence_adapter<boost::asio::const_buffer,
ConstBufferSequence> bufs(o->buffers_);
- return descriptor_ops::non_blocking_write(o->descriptor_,
- bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_);
+ status result = descriptor_ops::non_blocking_write(o->descriptor_,
+ bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
+ ? done : not_done;
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
}
private:
@@ -73,17 +80,19 @@ public:
descriptor, buffers, &descriptor_write_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -101,7 +110,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/dev_poll_reactor.hpp b/boost/asio/detail/dev_poll_reactor.hpp
index 17f57d5221..805f44b6ee 100644
--- a/boost/asio/detail/dev_poll_reactor.hpp
+++ b/boost/asio/detail/dev_poll_reactor.hpp
@@ -33,7 +33,7 @@
#include <boost/asio/detail/timer_queue_base.hpp>
#include <boost/asio/detail/timer_queue_set.hpp>
#include <boost/asio/detail/wait_op.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/execution_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -42,7 +42,7 @@ namespace asio {
namespace detail {
class dev_poll_reactor
- : public boost::asio::detail::service_base<dev_poll_reactor>
+ : public execution_context_service_base<dev_poll_reactor>
{
public:
enum op_types { read_op = 0, write_op = 1,
@@ -54,17 +54,17 @@ public:
};
// Constructor.
- BOOST_ASIO_DECL dev_poll_reactor(boost::asio::io_service& io_service);
+ BOOST_ASIO_DECL dev_poll_reactor(boost::asio::execution_context& ctx);
// Destructor.
BOOST_ASIO_DECL ~dev_poll_reactor();
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Recreate internal descriptors following a fork.
- BOOST_ASIO_DECL void fork_service(
- boost::asio::io_service::fork_event fork_ev);
+ BOOST_ASIO_DECL void notify_fork(
+ boost::asio::execution_context::fork_event fork_ev);
// Initialise the task.
BOOST_ASIO_DECL void init_task();
@@ -87,7 +87,7 @@ public:
// Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op, bool is_continuation)
{
- io_service_.post_immediate_completion(op, is_continuation);
+ scheduler_.post_immediate_completion(op, is_continuation);
}
// Start a new operation. The reactor operation will be performed when the
@@ -139,8 +139,14 @@ public:
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.
- BOOST_ASIO_DECL void run(bool block, op_queue<operation>& ops);
+ BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops);
// Interrupt the select loop.
BOOST_ASIO_DECL void interrupt();
@@ -159,7 +165,7 @@ private:
// 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.
- BOOST_ASIO_DECL int get_timeout();
+ BOOST_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
@@ -170,8 +176,8 @@ private:
// Add a pending event entry for the given descriptor.
BOOST_ASIO_DECL ::pollfd& add_pending_event_change(int descriptor);
- // The io_service implementation used to post completions.
- io_service_impl& io_service_;
+ // The scheduler implementation used to post completions.
+ scheduler& scheduler_;
// Mutex to protect access to internal data.
boost::asio::detail::mutex mutex_;
diff --git a/boost/asio/detail/epoll_reactor.hpp b/boost/asio/detail/epoll_reactor.hpp
index 34ed0370f5..e1acb48da7 100644
--- a/boost/asio/detail/epoll_reactor.hpp
+++ b/boost/asio/detail/epoll_reactor.hpp
@@ -19,10 +19,9 @@
#if defined(BOOST_ASIO_HAS_EPOLL)
-#include <boost/asio/io_service.hpp>
#include <boost/asio/detail/atomic_count.hpp>
+#include <boost/asio/detail/conditionally_enabled_mutex.hpp>
#include <boost/asio/detail/limits.hpp>
-#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/object_pool.hpp>
#include <boost/asio/detail/op_queue.hpp>
#include <boost/asio/detail/reactor_op.hpp>
@@ -31,6 +30,7 @@
#include <boost/asio/detail/timer_queue_base.hpp>
#include <boost/asio/detail/timer_queue_set.hpp>
#include <boost/asio/detail/wait_op.hpp>
+#include <boost/asio/execution_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -39,8 +39,12 @@ namespace asio {
namespace detail {
class epoll_reactor
- : public boost::asio::detail::service_base<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 };
@@ -59,14 +63,15 @@ public:
int descriptor_;
uint32_t registered_events_;
op_queue<reactor_op> op_queue_[max_ops];
+ bool try_speculative_[max_ops];
bool shutdown_;
- BOOST_ASIO_DECL descriptor_state();
+ BOOST_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; }
BOOST_ASIO_DECL operation* perform_io(uint32_t events);
BOOST_ASIO_DECL static void do_complete(
- io_service_impl* owner, operation* base,
+ void* owner, operation* base,
const boost::system::error_code& ec, std::size_t bytes_transferred);
};
@@ -74,17 +79,17 @@ public:
typedef descriptor_state* per_descriptor_data;
// Constructor.
- BOOST_ASIO_DECL epoll_reactor(boost::asio::io_service& io_service);
+ BOOST_ASIO_DECL epoll_reactor(boost::asio::execution_context& ctx);
// Destructor.
BOOST_ASIO_DECL ~epoll_reactor();
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Recreate internal descriptors following a fork.
- BOOST_ASIO_DECL void fork_service(
- boost::asio::io_service::fork_event fork_ev);
+ BOOST_ASIO_DECL void notify_fork(
+ boost::asio::execution_context::fork_event fork_ev);
// Initialise the task.
BOOST_ASIO_DECL void init_task();
@@ -108,7 +113,7 @@ public:
// Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op, bool is_continuation)
{
- io_service_.post_immediate_completion(op, is_continuation);
+ scheduler_.post_immediate_completion(op, is_continuation);
}
// Start a new operation. The reactor operation will be performed when the
@@ -162,8 +167,14 @@ public:
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.
- BOOST_ASIO_DECL void run(bool block, op_queue<operation>& ops);
+ BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops);
// Interrupt the select loop.
BOOST_ASIO_DECL void interrupt();
@@ -197,7 +208,7 @@ private:
// 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.
- BOOST_ASIO_DECL int get_timeout();
+ BOOST_ASIO_DECL int get_timeout(int msec);
#if defined(BOOST_ASIO_HAS_TIMERFD)
// Get the timeout value for the timer descriptor. The return value is the
@@ -205,8 +216,8 @@ private:
BOOST_ASIO_DECL int get_timeout(itimerspec& ts);
#endif // defined(BOOST_ASIO_HAS_TIMERFD)
- // The io_service implementation used to post completions.
- io_service_impl& io_service_;
+ // The scheduler implementation used to post completions.
+ scheduler& scheduler_;
// Mutex to protect access to internal data.
mutex mutex_;
diff --git a/boost/asio/detail/executor_op.hpp b/boost/asio/detail/executor_op.hpp
new file mode 100644
index 0000000000..f3364f5155
--- /dev/null
+++ b/boost/asio/detail/executor_op.hpp
@@ -0,0 +1,86 @@
+//
+// detail/executor_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_EXECUTOR_OP_HPP
+#define BOOST_ASIO_DETAIL_EXECUTOR_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/scheduler_operation.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename Alloc,
+ typename Operation = scheduler_operation>
+class executor_op : public Operation
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op);
+
+ template <typename H>
+ executor_op(BOOST_ASIO_MOVE_ARG(H) h, const Alloc& allocator)
+ : Operation(&executor_op::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(H)(h)),
+ allocator_(allocator)
+ {
+ }
+
+ static void do_complete(void* owner, Operation* base,
+ const boost::system::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 };
+
+ BOOST_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(BOOST_ASIO_MOVE_CAST(Handler)(o->handler_));
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN(());
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+ Alloc allocator_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_EXECUTOR_OP_HPP
diff --git a/boost/asio/detail/function.hpp b/boost/asio/detail/functional.hpp
index db26144c5f..a7d6064e4a 100644
--- a/boost/asio/detail/function.hpp
+++ b/boost/asio/detail/functional.hpp
@@ -1,6 +1,6 @@
//
-// detail/function.hpp
-// ~~~~~~~~~~~~~~~~~~~
+// detail/functional.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
@@ -8,8 +8,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef BOOST_ASIO_DETAIL_FUNCTION_HPP
-#define BOOST_ASIO_DETAIL_FUNCTION_HPP
+#ifndef BOOST_ASIO_DETAIL_FUNCTIONAL_HPP
+#define BOOST_ASIO_DETAIL_FUNCTIONAL_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -17,11 +17,11 @@
#include <boost/asio/detail/config.hpp>
-#if defined(BOOST_ASIO_HAS_STD_FUNCTION)
-# include <functional>
-#else // defined(BOOST_ASIO_HAS_STD_FUNCTION)
+#include <functional>
+
+#if !defined(BOOST_ASIO_HAS_STD_FUNCTION)
# include <boost/function.hpp>
-#endif // defined(BOOST_ASIO_HAS_STD_FUNCTION)
+#endif // !defined(BOOST_ASIO_HAS_STD_FUNCTION)
namespace boost {
namespace asio {
@@ -37,4 +37,4 @@ using boost::function;
} // namespace asio
} // namespace boost
-#endif // BOOST_ASIO_DETAIL_FUNCTION_HPP
+#endif // BOOST_ASIO_DETAIL_FUNCTIONAL_HPP
diff --git a/boost/asio/detail/gcc_arm_fenced_block.hpp b/boost/asio/detail/gcc_arm_fenced_block.hpp
index b4805c35cd..51a8ca7c55 100644
--- a/boost/asio/detail/gcc_arm_fenced_block.hpp
+++ b/boost/asio/detail/gcc_arm_fenced_block.hpp
@@ -19,6 +19,8 @@
#if defined(__GNUC__) && defined(__arm__)
+#include <boost/asio/detail/noncopyable.hpp>
+
#include <boost/asio/detail/push_options.hpp>
namespace boost {
diff --git a/boost/asio/detail/gcc_hppa_fenced_block.hpp b/boost/asio/detail/gcc_hppa_fenced_block.hpp
index b9aa9e2ca4..95f47ac8eb 100644
--- a/boost/asio/detail/gcc_hppa_fenced_block.hpp
+++ b/boost/asio/detail/gcc_hppa_fenced_block.hpp
@@ -19,6 +19,8 @@
#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+#include <boost/asio/detail/noncopyable.hpp>
+
#include <boost/asio/detail/push_options.hpp>
namespace boost {
diff --git a/boost/asio/detail/gcc_sync_fenced_block.hpp b/boost/asio/detail/gcc_sync_fenced_block.hpp
index e8e6c54643..b9026b1206 100644
--- a/boost/asio/detail/gcc_sync_fenced_block.hpp
+++ b/boost/asio/detail/gcc_sync_fenced_block.hpp
@@ -22,6 +22,8 @@
&& !defined(__INTEL_COMPILER) && !defined(__ICL) \
&& !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+#include <boost/asio/detail/noncopyable.hpp>
+
#include <boost/asio/detail/push_options.hpp>
namespace boost {
diff --git a/boost/asio/detail/gcc_x86_fenced_block.hpp b/boost/asio/detail/gcc_x86_fenced_block.hpp
index fe0ce8a316..be355a115a 100644
--- a/boost/asio/detail/gcc_x86_fenced_block.hpp
+++ b/boost/asio/detail/gcc_x86_fenced_block.hpp
@@ -19,6 +19,8 @@
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#include <boost/asio/detail/noncopyable.hpp>
+
#include <boost/asio/detail/push_options.hpp>
namespace boost {
diff --git a/boost/asio/detail/global.hpp b/boost/asio/detail/global.hpp
new file mode 100644
index 0000000000..581478909f
--- /dev/null
+++ b/boost/asio/detail/global.hpp
@@ -0,0 +1,54 @@
+//
+// detail/global.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_GLOBAL_HPP
+#define BOOST_ASIO_DETAIL_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_THREADS)
+# include <boost/asio/detail/null_global.hpp>
+#elif defined(BOOST_ASIO_WINDOWS)
+# include <boost/asio/detail/win_global.hpp>
+#elif defined(BOOST_ASIO_HAS_PTHREADS)
+# include <boost/asio/detail/posix_global.hpp>
+#elif defined(BOOST_ASIO_HAS_STD_CALL_ONCE)
+# include <boost/asio/detail/std_global.hpp>
+#else
+# error Only Windows, POSIX and std::call_once are supported!
+#endif
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename T>
+inline T& global()
+{
+#if !defined(BOOST_ASIO_HAS_THREADS)
+ return null_global<T>();
+#elif defined(BOOST_ASIO_WINDOWS)
+ return win_global<T>();
+#elif defined(BOOST_ASIO_HAS_PTHREADS)
+ return posix_global<T>();
+#elif defined(BOOST_ASIO_HAS_STD_CALL_ONCE)
+ return std_global<T>();
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_GLOBAL_HPP
diff --git a/boost/asio/detail/handler_alloc_helpers.hpp b/boost/asio/detail/handler_alloc_helpers.hpp
index a03cb41976..ee2e80c81d 100644
--- a/boost/asio/detail/handler_alloc_helpers.hpp
+++ b/boost/asio/detail/handler_alloc_helpers.hpp
@@ -16,8 +16,10 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/recycling_allocator.hpp>
+#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/handler_alloc_hook.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -51,16 +53,165 @@ inline void deallocate(void* p, std::size_t s, Handler& h)
} // namespace boost_asio_handler_alloc_helpers
+namespace boost {
+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*>(
+ boost_asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_));
+ }
+
+ void deallocate(T* p, std::size_t n)
+ {
+ boost_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
+} // namespace boost
+
#define BOOST_ASIO_DEFINE_HANDLER_PTR(op) \
struct ptr \
{ \
Handler* h; \
+ op* v; \
+ op* p; \
+ ~ptr() \
+ { \
+ reset(); \
+ } \
+ static op* allocate(Handler& handler) \
+ { \
+ typedef typename ::boost::asio::associated_allocator< \
+ Handler>::type associated_allocator_type; \
+ typedef typename ::boost::asio::detail::get_hook_allocator< \
+ Handler, associated_allocator_type>::type hook_allocator_type; \
+ BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \
+ ::boost::asio::detail::get_hook_allocator< \
+ Handler, associated_allocator_type>::get( \
+ handler, ::boost::asio::get_associated_allocator(handler))); \
+ return a.allocate(1); \
+ } \
+ void reset() \
+ { \
+ if (p) \
+ { \
+ p->~op(); \
+ p = 0; \
+ } \
+ if (v) \
+ { \
+ typedef typename ::boost::asio::associated_allocator< \
+ Handler>::type associated_allocator_type; \
+ typedef typename ::boost::asio::detail::get_hook_allocator< \
+ Handler, associated_allocator_type>::type hook_allocator_type; \
+ BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \
+ ::boost::asio::detail::get_hook_allocator< \
+ Handler, associated_allocator_type>::get( \
+ *h, ::boost::asio::get_associated_allocator(*h))); \
+ a.deallocate(static_cast<op*>(v), 1); \
+ v = 0; \
+ } \
+ } \
+ } \
+ /**/
+
+#define BOOST_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 ::boost::asio::detail::get_recycling_allocator< \
+ Alloc>::type recycling_allocator_type; \
+ BOOST_ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \
+ ::boost::asio::detail::get_recycling_allocator<Alloc>::get(a)); \
+ return a1.allocate(1); \
+ } \
void reset() \
{ \
if (p) \
@@ -70,7 +221,11 @@ inline void deallocate(void* p, std::size_t s, Handler& h)
} \
if (v) \
{ \
- boost_asio_handler_alloc_helpers::deallocate(v, sizeof(op), *h); \
+ typedef typename ::boost::asio::detail::get_recycling_allocator< \
+ Alloc>::type recycling_allocator_type; \
+ BOOST_ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \
+ ::boost::asio::detail::get_recycling_allocator<Alloc>::get(*a)); \
+ a1.deallocate(static_cast<op*>(v), 1); \
v = 0; \
} \
} \
diff --git a/boost/asio/detail/handler_cont_helpers.hpp b/boost/asio/detail/handler_cont_helpers.hpp
index 9a361a9ca4..a47ecf2d4a 100644
--- a/boost/asio/detail/handler_cont_helpers.hpp
+++ b/boost/asio/detail/handler_cont_helpers.hpp
@@ -16,7 +16,7 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/detail/push_options.hpp>
diff --git a/boost/asio/detail/handler_invoke_helpers.hpp b/boost/asio/detail/handler_invoke_helpers.hpp
index 43f74f3272..290ecb194f 100644
--- a/boost/asio/detail/handler_invoke_helpers.hpp
+++ b/boost/asio/detail/handler_invoke_helpers.hpp
@@ -16,7 +16,7 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/detail/push_options.hpp>
diff --git a/boost/asio/detail/handler_tracking.hpp b/boost/asio/detail/handler_tracking.hpp
index fd69bdd5b6..92e8a469f1 100644
--- a/boost/asio/detail/handler_tracking.hpp
+++ b/boost/asio/detail/handler_tracking.hpp
@@ -17,7 +17,17 @@
#include <boost/asio/detail/config.hpp>
-#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
+namespace boost {
+namespace asio {
+
+class execution_context;
+
+} // namespace asio
+} // namespace boost
+
+#if defined(BOOST_ASIO_CUSTOM_HANDLER_TRACKING)
+# include BOOST_ASIO_CUSTOM_HANDLER_TRACKING
+#elif defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
# include <boost/system/error_code.hpp>
# include <boost/asio/detail/cstdint.hpp>
# include <boost/asio/detail/static_mutex.hpp>
@@ -30,7 +40,30 @@ namespace boost {
namespace asio {
namespace detail {
-#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
+#if defined(BOOST_ASIO_CUSTOM_HANDLER_TRACKING)
+
+// The user-specified header must define the following macros:
+// - BOOST_ASIO_INHERIT_TRACKED_HANDLER
+// - BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER
+// - BOOST_ASIO_HANDLER_TRACKING_INIT
+// - BOOST_ASIO_HANDLER_CREATION(args)
+// - BOOST_ASIO_HANDLER_COMPLETION(args)
+// - BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args)
+// - BOOST_ASIO_HANDLER_INVOCATION_END
+// - BOOST_ASIO_HANDLER_OPERATION(args)
+// - BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args)
+// - BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args)
+// - BOOST_ASIO_HANDLER_REACTOR_READ_EVENT
+// - BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT
+// - BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT
+// - BOOST_ASIO_HANDLER_REACTOR_EVENTS(args)
+// - BOOST_ASIO_HANDLER_REACTOR_OPERATION(args)
+
+# if !defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
+# define BOOST_ASIO_ENABLE_HANDLER_TRACKING 1
+# endif /// !defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
+
+#elif defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
class handler_tracking
{
@@ -58,14 +91,16 @@ public:
BOOST_ASIO_DECL static void init();
// Record the creation of a tracked handler.
- BOOST_ASIO_DECL static void creation(tracked_handler* h,
- const char* object_type, void* object, const char* op_name);
+ BOOST_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.
- BOOST_ASIO_DECL explicit completion(tracked_handler* h);
+ BOOST_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.
@@ -99,9 +134,32 @@ public:
completion* next_;
};
- // Record an operation that affects pending handlers.
- BOOST_ASIO_DECL static void operation(const char* object_type,
- void* object, const char* op_name);
+ // Record an operation that is not directly associated with a handler.
+ BOOST_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.
+ BOOST_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.
+ BOOST_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.
+ BOOST_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.
+ BOOST_ASIO_DECL static void reactor_operation(
+ const tracked_handler& h, const char* op_name,
+ const boost::system::error_code& ec);
+
+ // Record a reactor-based operation that is associated with a handler.
+ BOOST_ASIO_DECL static void reactor_operation(
+ const tracked_handler& h, const char* op_name,
+ const boost::system::error_code& ec, std::size_t bytes_transferred);
// Write a line of output.
BOOST_ASIO_DECL static void write_line(const char* format, ...);
@@ -135,6 +193,22 @@ private:
# define BOOST_ASIO_HANDLER_OPERATION(args) \
boost::asio::detail::handler_tracking::operation args
+# define BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) \
+ boost::asio::detail::handler_tracking::reactor_registration args
+
+# define BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \
+ boost::asio::detail::handler_tracking::reactor_deregistration args
+
+# define BOOST_ASIO_HANDLER_REACTOR_READ_EVENT 1
+# define BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT 2
+# define BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT 4
+
+# define BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) \
+ boost::asio::detail::handler_tracking::reactor_events args
+
+# define BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) \
+ boost::asio::detail::handler_tracking::reactor_operation args
+
#else // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
# define BOOST_ASIO_INHERIT_TRACKED_HANDLER
@@ -145,6 +219,13 @@ private:
# define BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0
# define BOOST_ASIO_HANDLER_INVOCATION_END (void)0
# define BOOST_ASIO_HANDLER_OPERATION(args) (void)0
+# define BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) (void)0
+# define BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) (void)0
+# define BOOST_ASIO_HANDLER_REACTOR_READ_EVENT 0
+# define BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT 0
+# define BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT 0
+# define BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) (void)0
+# define BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) (void)0
#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
diff --git a/boost/asio/detail/handler_type_requirements.hpp b/boost/asio/detail/handler_type_requirements.hpp
index bc2fbce0ce..65b5e62dac 100644
--- a/boost/asio/detail/handler_type_requirements.hpp
+++ b/boost/asio/detail/handler_type_requirements.hpp
@@ -50,7 +50,7 @@
#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
-# include <boost/asio/handler_type.hpp>
+# include <boost/asio/async_result.hpp>
#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
namespace boost {
@@ -62,19 +62,19 @@ namespace detail {
# if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
template <typename Handler>
-auto zero_arg_handler_test(Handler h, void*)
+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_handler_test(Handler, ...))[2];
+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(static_cast<const Handler&>(h))),
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
((h)(*a1)),
char(0));
@@ -84,13 +84,23 @@ 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(static_cast<const Handler&>(h))),
+ sizeof(Handler(BOOST_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(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1, BOOST_ASIO_MOVE_CAST(Arg2)(*a2))),
+ char(0));
+
+template <typename Handler>
+char (&two_arg_move_handler_test(Handler, ...))[2];
+
# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \
static_assert(expr, msg);
@@ -104,6 +114,13 @@ 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(BOOST_ASIO_HAS_MOVE)
+template <typename T> T rvref();
+template <typename T> T rvref(T);
+#else // defined(BOOST_ASIO_HAS_MOVE)
+template <typename T> const T& rvref();
+template <typename T> const T& rvref(T);
+#endif // defined(BOOST_ASIO_HAS_MOVE)
template <typename T> char argbyv(T);
template <int>
@@ -118,7 +135,7 @@ struct handler_type_requirements
void()) asio_true_handler_type; \
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
- sizeof(boost::asio::detail::zero_arg_handler_test( \
+ sizeof(boost::asio::detail::zero_arg_copyable_handler_test( \
boost::asio::detail::clvref< \
asio_true_handler_type>(), 0)) == 1, \
"CompletionHandler type requirements not met") \
@@ -142,7 +159,7 @@ struct handler_type_requirements
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::two_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0), \
static_cast<const std::size_t*>(0))) == 1, \
@@ -151,7 +168,7 @@ struct handler_type_requirements
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
@@ -160,7 +177,6 @@ struct handler_type_requirements
boost::asio::detail::lvref<const std::size_t>()), \
char(0))> BOOST_ASIO_UNUSED_TYPEDEF
-
#define BOOST_ASIO_WRITE_HANDLER_CHECK( \
handler_type, handler) \
\
@@ -170,7 +186,7 @@ struct handler_type_requirements
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::two_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0), \
static_cast<const std::size_t*>(0))) == 1, \
@@ -179,7 +195,7 @@ struct handler_type_requirements
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
@@ -197,7 +213,7 @@ struct handler_type_requirements
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::one_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0))) == 1, \
"AcceptHandler type requirements not met") \
@@ -205,7 +221,7 @@ struct handler_type_requirements
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
@@ -213,6 +229,33 @@ struct handler_type_requirements
boost::asio::detail::lvref<const boost::system::error_code>()), \
char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+#define BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler, socket_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, socket_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_move_handler_test( \
+ boost::asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<socket_type*>(0))) == 1, \
+ "MoveAcceptHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::rvref<socket_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \
handler_type, handler) \
\
@@ -222,7 +265,7 @@ struct handler_type_requirements
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::one_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0))) == 1, \
"ConnectHandler type requirements not met") \
@@ -230,7 +273,7 @@ struct handler_type_requirements
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
@@ -238,7 +281,34 @@ struct handler_type_requirements
boost::asio::detail::lvref<const boost::system::error_code>()), \
char(0))> BOOST_ASIO_UNUSED_TYPEDEF
-#define BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( \
+#define BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, endpoint_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, endpoint_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_handler_test( \
+ boost::asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const endpoint_type*>(0))) == 1, \
+ "RangeConnectHandler type requirements not met") \
+ \
+ typedef boost::asio::detail::handler_type_requirements< \
+ sizeof( \
+ boost::asio::detail::argbyv( \
+ boost::asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ boost::asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const endpoint_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \
handler_type, handler, iter_type) \
\
typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
@@ -247,16 +317,16 @@ struct handler_type_requirements
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::two_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0), \
static_cast<const iter_type*>(0))) == 1, \
- "ComposedConnectHandler type requirements not met") \
+ "IteratorConnectHandler type requirements not met") \
\
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
@@ -266,30 +336,30 @@ struct handler_type_requirements
char(0))> BOOST_ASIO_UNUSED_TYPEDEF
#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \
- handler_type, handler, iter_type) \
+ handler_type, handler, range_type) \
\
typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
- void(boost::system::error_code, iter_type)) \
+ void(boost::system::error_code, range_type)) \
asio_true_handler_type; \
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::two_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0), \
- static_cast<const iter_type*>(0))) == 1, \
+ static_cast<const range_type*>(0))) == 1, \
"ResolveHandler type requirements not met") \
\
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>(), \
- boost::asio::detail::lvref<const iter_type>()), \
+ boost::asio::detail::lvref<const range_type>()), \
char(0))> BOOST_ASIO_UNUSED_TYPEDEF
#define BOOST_ASIO_WAIT_HANDLER_CHECK( \
@@ -301,7 +371,7 @@ struct handler_type_requirements
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::one_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0))) == 1, \
"WaitHandler type requirements not met") \
@@ -309,7 +379,7 @@ struct handler_type_requirements
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
@@ -326,7 +396,7 @@ struct handler_type_requirements
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::two_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0), \
static_cast<const int*>(0))) == 1, \
@@ -335,7 +405,7 @@ struct handler_type_requirements
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
@@ -353,7 +423,7 @@ struct handler_type_requirements
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::one_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0))) == 1, \
"HandshakeHandler type requirements not met") \
@@ -361,7 +431,7 @@ struct handler_type_requirements
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
@@ -378,7 +448,7 @@ struct handler_type_requirements
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::two_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0), \
static_cast<const std::size_t*>(0))) == 1, \
@@ -387,7 +457,7 @@ struct handler_type_requirements
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
@@ -405,7 +475,7 @@ struct handler_type_requirements
\
BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
sizeof(boost::asio::detail::one_arg_handler_test( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>(), \
static_cast<const boost::system::error_code*>(0))) == 1, \
"ShutdownHandler type requirements not met") \
@@ -413,7 +483,7 @@ struct handler_type_requirements
typedef boost::asio::detail::handler_type_requirements< \
sizeof( \
boost::asio::detail::argbyv( \
- boost::asio::detail::clvref< \
+ boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
@@ -439,11 +509,19 @@ struct handler_type_requirements
handler_type, handler) \
typedef int BOOST_ASIO_UNUSED_TYPEDEF
+#define BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler, socket_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \
handler_type, handler) \
typedef int BOOST_ASIO_UNUSED_TYPEDEF
-#define BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( \
+#define BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \
handler_type, handler, iter_type) \
typedef int BOOST_ASIO_UNUSED_TYPEDEF
diff --git a/boost/asio/detail/handler_work.hpp b/boost/asio/detail/handler_work.hpp
new file mode 100644
index 0000000000..62fbe68e46
--- /dev/null
+++ b/boost/asio/detail/handler_work.hpp
@@ -0,0 +1,97 @@
+//
+// detail/handler_work.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_HANDLER_WORK_HPP
+#define BOOST_ASIO_DETAIL_HANDLER_WORK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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) BOOST_ASIO_NOEXCEPT
+ : executor_(associated_executor<Handler>::get(handler))
+ {
+ }
+
+ static void start(Handler& handler) BOOST_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(BOOST_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&) BOOST_ASIO_NOEXCEPT {}
+ static void start(Handler&) BOOST_ASIO_NOEXCEPT {}
+ ~handler_work() {}
+
+ template <typename Function>
+ void complete(Function& function, Handler& handler)
+ {
+ boost_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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_HANDLER_WORK_HPP
diff --git a/boost/asio/detail/impl/buffer_sequence_adapter.ipp b/boost/asio/detail/impl/buffer_sequence_adapter.ipp
index f471863e1a..c2114ba1cf 100644
--- a/boost/asio/detail/impl/buffer_sequence_adapter.ipp
+++ b/boost/asio/detail/impl/buffer_sequence_adapter.ipp
@@ -40,16 +40,16 @@ class winrt_buffer_impl :
public:
explicit winrt_buffer_impl(const boost::asio::const_buffer& b)
{
- bytes_ = const_cast<byte*>(boost::asio::buffer_cast<const byte*>(b));
- length_ = boost::asio::buffer_size(b);
- capacity_ = boost::asio::buffer_size(b);
+ bytes_ = const_cast<byte*>(static_cast<const byte*>(b.data()));
+ length_ = b.size();
+ capacity_ = b.size();
}
explicit winrt_buffer_impl(const boost::asio::mutable_buffer& b)
{
- bytes_ = const_cast<byte*>(boost::asio::buffer_cast<const byte*>(b));
+ bytes_ = static_cast<byte*>(b.data());
length_ = 0;
- capacity_ = boost::asio::buffer_size(b);
+ capacity_ = b.size();
}
~winrt_buffer_impl()
diff --git a/boost/asio/detail/impl/descriptor_ops.ipp b/boost/asio/detail/impl/descriptor_ops.ipp
index 00f6b4796e..cdf5022306 100644
--- a/boost/asio/detail/impl/descriptor_ops.ipp
+++ b/boost/asio/detail/impl/descriptor_ops.ipp
@@ -439,6 +439,29 @@ int poll_write(int d, state_type state, boost::system::error_code& ec)
return result;
}
+int poll_error(int d, state_type state, boost::system::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = boost::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)
+ ? boost::asio::error::would_block : boost::system::error_code();
+ else if (result > 0)
+ ec = boost::system::error_code();
+ return result;
+}
+
} // namespace descriptor_ops
} // namespace detail
} // namespace asio
diff --git a/boost/asio/detail/impl/dev_poll_reactor.hpp b/boost/asio/detail/impl/dev_poll_reactor.hpp
index 623346edd5..c01450ffea 100644
--- a/boost/asio/detail/impl/dev_poll_reactor.hpp
+++ b/boost/asio/detail/impl/dev_poll_reactor.hpp
@@ -46,12 +46,12 @@ void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
if (shutdown_)
{
- io_service_.post_immediate_completion(op, false);
+ scheduler_.post_immediate_completion(op, false);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
- io_service_.work_started();
+ scheduler_.work_started();
if (earliest)
interrupter_.interrupt();
}
@@ -65,10 +65,23 @@ std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
lock.unlock();
- io_service_.post_deferred_completions(ops);
+ 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)
+{
+ boost::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
} // namespace boost
diff --git a/boost/asio/detail/impl/dev_poll_reactor.ipp b/boost/asio/detail/impl/dev_poll_reactor.ipp
index 7efb05ed02..5186d30473 100644
--- a/boost/asio/detail/impl/dev_poll_reactor.ipp
+++ b/boost/asio/detail/impl/dev_poll_reactor.ipp
@@ -30,9 +30,9 @@ namespace boost {
namespace asio {
namespace detail {
-dev_poll_reactor::dev_poll_reactor(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<dev_poll_reactor>(io_service),
- io_service_(use_service<io_service_impl>(io_service)),
+dev_poll_reactor::dev_poll_reactor(boost::asio::execution_context& ctx)
+ : boost::asio::detail::execution_context_service_base<dev_poll_reactor>(ctx),
+ scheduler_(use_service<scheduler>(ctx)),
mutex_(),
dev_poll_fd_(do_dev_poll_create()),
interrupter_(),
@@ -48,11 +48,11 @@ dev_poll_reactor::dev_poll_reactor(boost::asio::io_service& io_service)
dev_poll_reactor::~dev_poll_reactor()
{
- shutdown_service();
+ shutdown();
::close(dev_poll_fd_);
}
-void dev_poll_reactor::shutdown_service()
+void dev_poll_reactor::shutdown()
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
@@ -65,12 +65,13 @@ void dev_poll_reactor::shutdown_service()
timer_queues_.get_all_timers(ops);
- io_service_.abandon_operations(ops);
+ scheduler_.abandon_operations(ops);
}
-void dev_poll_reactor::fork_service(boost::asio::io_service::fork_event fork_ev)
+void dev_poll_reactor::notify_fork(
+ boost::asio::execution_context::fork_event fork_ev)
{
- if (fork_ev == boost::asio::io_service::fork_child)
+ if (fork_ev == boost::asio::execution_context::fork_child)
{
detail::mutex::scoped_lock lock(mutex_);
@@ -113,7 +114,7 @@ void dev_poll_reactor::fork_service(boost::asio::io_service::fork_event fork_ev)
void dev_poll_reactor::init_task()
{
- io_service_.init_task();
+ scheduler_.init_task();
}
int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&)
@@ -168,7 +169,7 @@ void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
if (op->perform())
{
lock.unlock();
- io_service_.post_immediate_completion(op, is_continuation);
+ scheduler_.post_immediate_completion(op, is_continuation);
return;
}
}
@@ -176,7 +177,7 @@ void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
}
bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
- io_service_.work_started();
+ scheduler_.work_started();
if (first)
{
::pollfd& ev = add_pending_event_change(descriptor);
@@ -240,13 +241,13 @@ void dev_poll_reactor::cleanup_descriptor_data(
{
}
-void dev_poll_reactor::run(bool block, op_queue<operation>& ops)
+void dev_poll_reactor::run(long usec, op_queue<operation>& ops)
{
boost::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 (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty()
+ if (usec == 0 && op_queue_[read_op].empty() && op_queue_[write_op].empty()
&& op_queue_[except_op].empty() && timer_queues_.all_empty())
return;
@@ -272,7 +273,15 @@ void dev_poll_reactor::run(bool block, op_queue<operation>& ops)
pending_event_change_index_.clear();
}
- int timeout = block ? get_timeout() : 0;
+ // 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.
@@ -386,11 +395,13 @@ void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue)
timer_queues_.erase(&queue);
}
-int dev_poll_reactor::get_timeout()
+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.
- return timer_queues_.wait_duration_msec(5 * 60 * 1000);
+ 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,
@@ -401,7 +412,7 @@ void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor,
for (int i = 0; i < max_ops; ++i)
need_interrupt = op_queue_[i].cancel_operations(
descriptor, ops, ec) || need_interrupt;
- io_service_.post_deferred_completions(ops);
+ scheduler_.post_deferred_completions(ops);
if (need_interrupt)
interrupter_.interrupt();
}
diff --git a/boost/asio/detail/impl/epoll_reactor.hpp b/boost/asio/detail/impl/epoll_reactor.hpp
index ea5c6bfc69..537b0fc7da 100644
--- a/boost/asio/detail/impl/epoll_reactor.hpp
+++ b/boost/asio/detail/impl/epoll_reactor.hpp
@@ -44,12 +44,12 @@ void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
if (shutdown_)
{
- io_service_.post_immediate_completion(op, false);
+ scheduler_.post_immediate_completion(op, false);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
- io_service_.work_started();
+ scheduler_.work_started();
if (earliest)
update_timeout();
}
@@ -63,10 +63,23 @@ std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
lock.unlock();
- io_service_.post_deferred_completions(ops);
+ 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
} // namespace boost
diff --git a/boost/asio/detail/impl/epoll_reactor.ipp b/boost/asio/detail/impl/epoll_reactor.ipp
index 3d3d244e0a..a9c2602fbe 100644
--- a/boost/asio/detail/impl/epoll_reactor.ipp
+++ b/boost/asio/detail/impl/epoll_reactor.ipp
@@ -35,14 +35,16 @@ namespace boost {
namespace asio {
namespace detail {
-epoll_reactor::epoll_reactor(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<epoll_reactor>(io_service),
- io_service_(use_service<io_service_impl>(io_service)),
- mutex_(),
+epoll_reactor::epoll_reactor(boost::asio::execution_context& ctx)
+ : execution_context_service_base<epoll_reactor>(ctx),
+ scheduler_(use_service<scheduler>(ctx)),
+ mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
interrupter_(),
epoll_fd_(do_epoll_create()),
timer_fd_(do_timerfd_create()),
- shutdown_(false)
+ shutdown_(false),
+ registered_descriptors_mutex_(mutex_.enabled())
{
// Add the interrupter's descriptor to epoll.
epoll_event ev = { 0, { 0 } };
@@ -68,7 +70,7 @@ epoll_reactor::~epoll_reactor()
close(timer_fd_);
}
-void epoll_reactor::shutdown_service()
+void epoll_reactor::shutdown()
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
@@ -86,12 +88,13 @@ void epoll_reactor::shutdown_service()
timer_queues_.get_all_timers(ops);
- io_service_.abandon_operations(ops);
+ scheduler_.abandon_operations(ops);
}
-void epoll_reactor::fork_service(boost::asio::io_service::fork_event fork_ev)
+void epoll_reactor::notify_fork(
+ boost::asio::execution_context::fork_event fork_ev)
{
- if (fork_ev == boost::asio::io_service::fork_child)
+ if (fork_ev == boost::asio::execution_context::fork_child)
{
if (epoll_fd_ != -1)
::close(epoll_fd_);
@@ -142,7 +145,7 @@ void epoll_reactor::fork_service(boost::asio::io_service::fork_event fork_ev)
void epoll_reactor::init_task()
{
- io_service_.init_task();
+ scheduler_.init_task();
}
int epoll_reactor::register_descriptor(socket_type descriptor,
@@ -150,12 +153,18 @@ int epoll_reactor::register_descriptor(socket_type descriptor,
{
descriptor_data = allocate_descriptor_state();
+ BOOST_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 } };
@@ -186,6 +195,10 @@ int epoll_reactor::register_internal_descriptor(
{
descriptor_data = allocate_descriptor_state();
+ BOOST_ASIO_HANDLER_REACTOR_REGISTRATION((
+ context(), static_cast<uintmax_t>(descriptor),
+ reinterpret_cast<uintmax_t>(descriptor_data)));
+
{
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
@@ -193,6 +206,8 @@ int epoll_reactor::register_internal_descriptor(
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 } };
@@ -239,17 +254,23 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
&& (op_type != read_op
|| descriptor_data->op_queue_[except_op].empty()))
{
- if (op->perform())
+ if (descriptor_data->try_speculative_[op_type])
{
- descriptor_lock.unlock();
- io_service_.post_immediate_completion(op, is_continuation);
- return;
+ 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_ = boost::asio::error::operation_not_supported;
- io_service_.post_immediate_completion(op, is_continuation);
+ scheduler_.post_immediate_completion(op, is_continuation);
return;
}
@@ -268,7 +289,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
{
op->ec_ = boost::system::error_code(errno,
boost::asio::error::get_system_category());
- io_service_.post_immediate_completion(op, is_continuation);
+ scheduler_.post_immediate_completion(op, is_continuation);
return;
}
}
@@ -277,7 +298,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
else if (descriptor_data->registered_events_ == 0)
{
op->ec_ = boost::asio::error::operation_not_supported;
- io_service_.post_immediate_completion(op, is_continuation);
+ scheduler_.post_immediate_completion(op, is_continuation);
return;
}
else
@@ -295,7 +316,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
}
descriptor_data->op_queue_[op_type].push(op);
- io_service_.work_started();
+ scheduler_.work_started();
}
void epoll_reactor::cancel_ops(socket_type,
@@ -319,7 +340,7 @@ void epoll_reactor::cancel_ops(socket_type,
descriptor_lock.unlock();
- io_service_.post_deferred_completions(ops);
+ scheduler_.post_deferred_completions(ops);
}
void epoll_reactor::deregister_descriptor(socket_type descriptor,
@@ -359,7 +380,11 @@ void epoll_reactor::deregister_descriptor(socket_type descriptor,
descriptor_lock.unlock();
- io_service_.post_deferred_completions(ops);
+ BOOST_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.
@@ -394,6 +419,10 @@ void epoll_reactor::deregister_internal_descriptor(socket_type descriptor,
descriptor_lock.unlock();
+ BOOST_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.
}
@@ -415,28 +444,62 @@ void epoll_reactor::cleanup_descriptor_data(
}
}
-void epoll_reactor::run(bool block, op_queue<operation>& ops)
+void epoll_reactor::run(long usec, op_queue<operation>& ops)
{
- // This code relies on the fact that the task_io_service 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 task_io_service to queue again.
+ // 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 a timeout only if timerfd is not used.
+ // Calculate timeout. Check the timer queues only if timerfd is not in use.
int timeout;
- if (timer_fd_ != -1)
- timeout = block ? -1 : 0;
+ if (usec == 0)
+ timeout = 0;
else
{
- mutex::scoped_lock lock(mutex_);
- timeout = block ? get_timeout() : 0;
+ 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(BOOST_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(BOOST_ASIO_HAS_TIMERFD)
+ else if (ptr == &timer_fd_)
+ {
+ // Ignore.
+ }
+# endif // defined(BOOST_ASIO_HAS_TIMERFD)
+ else
+ {
+ unsigned event_mask = 0;
+ if ((events[i].events & EPOLLIN) != 0)
+ event_mask |= BOOST_ASIO_HANDLER_REACTOR_READ_EVENT;
+ if ((events[i].events & EPOLLOUT))
+ event_mask |= BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT;
+ if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0)
+ event_mask |= BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT;
+ BOOST_ASIO_HANDLER_REACTOR_EVENTS((context(),
+ reinterpret_cast<uintmax_t>(ptr), event_mask));
+ }
+ }
+#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
+
#if defined(BOOST_ASIO_HAS_TIMERFD)
bool check_timers = (timer_fd_ == -1);
#else // defined(BOOST_ASIO_HAS_TIMERFD)
@@ -470,7 +533,7 @@ void epoll_reactor::run(bool block, op_queue<operation>& ops)
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 io_service to
+ // 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))
@@ -562,7 +625,8 @@ int epoll_reactor::do_timerfd_create()
epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state()
{
mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
- return registered_descriptors_.alloc();
+ return registered_descriptors_.alloc(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ REACTOR_IO, scheduler_.concurrency_hint()));
}
void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s)
@@ -598,11 +662,13 @@ void epoll_reactor::update_timeout()
interrupt();
}
-int epoll_reactor::get_timeout()
+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.
- return timer_queues_.wait_duration_msec(5 * 60 * 1000);
+ const int max_msec = 5 * 60 * 1000;
+ return timer_queues_.wait_duration_msec(
+ (msec < 0 || max_msec < msec) ? max_msec : msec);
}
#if defined(BOOST_ASIO_HAS_TIMERFD)
@@ -632,19 +698,18 @@ struct epoll_reactor::perform_io_cleanup_on_block_exit
{
// Post the remaining completed operations for invocation.
if (!ops_.empty())
- reactor_->io_service_.post_deferred_completions(ops_);
+ 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 task_io_service will call work_finished() once we
- // return.
+ // 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 task_io_service will make once
- // this operation returns.
- reactor_->io_service_.work_started();
+ // for the work_finished() call that the scheduler will make once this
+ // operation returns.
+ reactor_->scheduler_.compensating_work_started();
}
}
@@ -653,8 +718,9 @@ struct epoll_reactor::perform_io_cleanup_on_block_exit
operation* first_op_;
};
-epoll_reactor::descriptor_state::descriptor_state()
- : operation(&epoll_reactor::descriptor_state::do_complete)
+epoll_reactor::descriptor_state::descriptor_state(bool locking)
+ : operation(&epoll_reactor::descriptor_state::do_complete),
+ mutex_(locking)
{
}
@@ -671,12 +737,18 @@ operation* epoll_reactor::descriptor_state::perform_io(uint32_t events)
{
if (events & (flag[j] | EPOLLERR | EPOLLHUP))
{
+ try_speculative_[j] = true;
while (reactor_op* op = op_queue_[j].front())
{
- if (op->perform())
+ 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;
@@ -692,7 +764,7 @@ operation* epoll_reactor::descriptor_state::perform_io(uint32_t events)
}
void epoll_reactor::descriptor_state::do_complete(
- io_service_impl* owner, operation* base,
+ void* owner, operation* base,
const boost::system::error_code& ec, std::size_t bytes_transferred)
{
if (owner)
@@ -701,7 +773,7 @@ void epoll_reactor::descriptor_state::do_complete(
uint32_t events = static_cast<uint32_t>(bytes_transferred);
if (operation* op = descriptor_data->perform_io(events))
{
- op->complete(*owner, ec, 0);
+ op->complete(owner, ec, 0);
}
}
}
diff --git a/boost/asio/detail/impl/handler_tracking.ipp b/boost/asio/detail/impl/handler_tracking.ipp
index 259b5ab62b..aa6b9b2917 100644
--- a/boost/asio/detail/impl/handler_tracking.ipp
+++ b/boost/asio/detail/impl/handler_tracking.ipp
@@ -17,7 +17,11 @@
#include <boost/asio/detail/config.hpp>
-#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
+#if defined(BOOST_ASIO_CUSTOM_HANDLER_TRACKING)
+
+// The handler tracking implementation is provided by the user-specified header.
+
+#elif defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
#include <cstdarg>
#include <cstdio>
@@ -25,17 +29,15 @@
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
# include <boost/asio/time_traits.hpp>
-#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
-# if defined(BOOST_ASIO_HAS_STD_CHRONO)
-# include <chrono>
-# elif defined(BOOST_ASIO_HAS_BOOST_CHRONO)
-# include <boost/chrono/system_clocks.hpp>
-# endif
+#elif defined(BOOST_ASIO_HAS_CHRONO)
+# include <boost/asio/detail/chrono.hpp>
# include <boost/asio/detail/chrono_time_traits.hpp>
# include <boost/asio/wait_traits.hpp>
#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
-#if !defined(BOOST_ASIO_WINDOWS)
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+# include <boost/asio/detail/socket_types.hpp>
+#elif !defined(BOOST_ASIO_WINDOWS)
# include <unistd.h>
#endif // !defined(BOOST_ASIO_WINDOWS)
@@ -56,16 +58,11 @@ struct handler_tracking_timestamp
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(BOOST_ASIO_HAS_STD_CHRONO)
- typedef chrono_time_traits<std::chrono::system_clock,
- boost::asio::wait_traits<std::chrono::system_clock> > traits_helper;
- traits_helper::posix_time_duration now(
- std::chrono::system_clock::now().time_since_epoch());
-#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO)
- typedef chrono_time_traits<boost::chrono::system_clock,
- boost::asio::wait_traits<boost::chrono::system_clock> > traits_helper;
+#elif defined(BOOST_ASIO_HAS_CHRONO)
+ typedef chrono_time_traits<chrono::system_clock,
+ boost::asio::wait_traits<chrono::system_clock> > traits_helper;
traits_helper::posix_time_duration now(
- boost::chrono::system_clock::now().time_since_epoch());
+ 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);
@@ -96,13 +93,15 @@ void handler_tracking::init()
state->current_completion_ = new tss_ptr<completion>;
}
-void handler_tracking::creation(handler_tracking::tracked_handler* h,
- const char* object_type, void* object, const char* op_name)
+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_++;
+ h.id_ = state->next_id_++;
lock.unlock();
handler_tracking_timestamp timestamp;
@@ -118,11 +117,12 @@ void handler_tracking::creation(handler_tracking::tracked_handler* h,
"@asio|%llu.%06llu|%llu*%llu|%.20s@%p.%.50s\n",
#endif // defined(BOOST_ASIO_WINDOWS)
timestamp.seconds, timestamp.microseconds,
- current_id, h->id_, object_type, object, op_name);
+ current_id, h.id_, object_type, object, op_name);
}
-handler_tracking::completion::completion(handler_tracking::tracked_handler* h)
- : id_(h->id_),
+handler_tracking::completion::completion(
+ const handler_tracking::tracked_handler& h)
+ : id_(h.id_),
invoked_(false),
next_(*get_state()->current_completion_)
{
@@ -250,8 +250,9 @@ void handler_tracking::completion::invocation_end()
}
}
-void handler_tracking::operation(const char* object_type,
- void* object, const char* op_name)
+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();
@@ -271,6 +272,54 @@ void handler_tracking::operation(const char* object_type,
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 boost::system::error_code& ec)
+{
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(BOOST_ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d\n",
+#else // defined(BOOST_ASIO_WINDOWS)
+ "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d\n",
+#endif // defined(BOOST_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 boost::system::error_code& ec, std::size_t bytes_transferred)
+{
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(BOOST_ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d,bytes_transferred=%I64u\n",
+#else // defined(BOOST_ASIO_WINDOWS)
+ "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d,bytes_transferred=%llu\n",
+#endif // defined(BOOST_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).
@@ -287,7 +336,11 @@ void handler_tracking::write_line(const char* format, ...)
va_end(args);
-#if defined(BOOST_ASIO_WINDOWS)
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ wchar_t wline[256] = L"";
+ mbstowcs_s(0, wline, sizeof(wline) / sizeof(wchar_t), line, length);
+ ::OutputDebugStringW(wline);
+#elif defined(BOOST_ASIO_WINDOWS)
HANDLE stderr_handle = ::GetStdHandle(STD_ERROR_HANDLE);
DWORD bytes_written = 0;
::WriteFile(stderr_handle, line, length, &bytes_written, 0);
diff --git a/boost/asio/detail/impl/kqueue_reactor.hpp b/boost/asio/detail/impl/kqueue_reactor.hpp
index 93cbca26a2..83bfa95765 100644
--- a/boost/asio/detail/impl/kqueue_reactor.hpp
+++ b/boost/asio/detail/impl/kqueue_reactor.hpp
@@ -44,16 +44,16 @@ 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)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
- io_service_.post_immediate_completion(op, false);
+ scheduler_.post_immediate_completion(op, false);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
- io_service_.work_started();
+ scheduler_.work_started();
if (earliest)
interrupt();
}
@@ -63,14 +63,27 @@ 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)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
lock.unlock();
- io_service_.post_deferred_completions(ops);
+ 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
} // namespace boost
diff --git a/boost/asio/detail/impl/kqueue_reactor.ipp b/boost/asio/detail/impl/kqueue_reactor.ipp
index 8057606ce6..c492646a0b 100644
--- a/boost/asio/detail/impl/kqueue_reactor.ipp
+++ b/boost/asio/detail/impl/kqueue_reactor.ipp
@@ -21,6 +21,7 @@
#if defined(BOOST_ASIO_HAS_KQUEUE)
#include <boost/asio/detail/kqueue_reactor.hpp>
+#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
@@ -39,13 +40,15 @@ namespace boost {
namespace asio {
namespace detail {
-kqueue_reactor::kqueue_reactor(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<kqueue_reactor>(io_service),
- io_service_(use_service<io_service_impl>(io_service)),
- mutex_(),
+kqueue_reactor::kqueue_reactor(boost::asio::execution_context& ctx)
+ : execution_context_service_base<kqueue_reactor>(ctx),
+ scheduler_(use_service<scheduler>(ctx)),
+ mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
kqueue_fd_(do_kqueue_create()),
interrupter_(),
- shutdown_(false)
+ shutdown_(false),
+ registered_descriptors_mutex_(mutex_.enabled())
{
struct kevent events[1];
BOOST_ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(),
@@ -63,7 +66,7 @@ kqueue_reactor::~kqueue_reactor()
close(kqueue_fd_);
}
-void kqueue_reactor::shutdown_service()
+void kqueue_reactor::shutdown()
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
@@ -81,12 +84,13 @@ void kqueue_reactor::shutdown_service()
timer_queues_.get_all_timers(ops);
- io_service_.abandon_operations(ops);
+ scheduler_.abandon_operations(ops);
}
-void kqueue_reactor::fork_service(boost::asio::io_service::fork_event fork_ev)
+void kqueue_reactor::notify_fork(
+ boost::asio::execution_context::fork_event fork_ev)
{
- if (fork_ev == boost::asio::io_service::fork_child)
+ if (fork_ev == boost::asio::execution_context::fork_child)
{
// The kqueue descriptor is automatically closed in the child.
kqueue_fd_ = -1;
@@ -128,7 +132,7 @@ void kqueue_reactor::fork_service(boost::asio::io_service::fork_event fork_ev)
void kqueue_reactor::init_task()
{
- io_service_.init_task();
+ scheduler_.init_task();
}
int kqueue_reactor::register_descriptor(socket_type descriptor,
@@ -136,6 +140,10 @@ int kqueue_reactor::register_descriptor(socket_type descriptor,
{
descriptor_data = allocate_descriptor_state();
+ BOOST_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;
@@ -151,6 +159,10 @@ int kqueue_reactor::register_internal_descriptor(
{
descriptor_data = allocate_descriptor_state();
+ BOOST_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;
@@ -205,7 +217,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor,
if (op->perform())
{
descriptor_lock.unlock();
- io_service_.post_immediate_completion(op, is_continuation);
+ scheduler_.post_immediate_completion(op, is_continuation);
return;
}
@@ -224,7 +236,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor,
{
op->ec_ = boost::system::error_code(errno,
boost::asio::error::get_system_category());
- io_service_.post_immediate_completion(op, is_continuation);
+ scheduler_.post_immediate_completion(op, is_continuation);
return;
}
}
@@ -244,7 +256,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor,
}
descriptor_data->op_queue_[op_type].push(op);
- io_service_.work_started();
+ scheduler_.work_started();
}
void kqueue_reactor::cancel_ops(socket_type,
@@ -268,7 +280,7 @@ void kqueue_reactor::cancel_ops(socket_type,
descriptor_lock.unlock();
- io_service_.post_deferred_completions(ops);
+ scheduler_.post_deferred_completions(ops);
}
void kqueue_reactor::deregister_descriptor(socket_type descriptor,
@@ -312,7 +324,11 @@ void kqueue_reactor::deregister_descriptor(socket_type descriptor,
descriptor_lock.unlock();
- io_service_.post_deferred_completions(ops);
+ BOOST_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.
@@ -351,6 +367,10 @@ void kqueue_reactor::deregister_internal_descriptor(socket_type descriptor,
descriptor_lock.unlock();
+ BOOST_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.
}
@@ -372,13 +392,13 @@ void kqueue_reactor::cleanup_descriptor_data(
}
}
-void kqueue_reactor::run(bool block, op_queue<operation>& ops)
+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 = block ? get_timeout(timeout_buf) : &timeout_buf;
+ timespec* timeout = usec ? get_timeout(usec, timeout_buf) : &timeout_buf;
lock.unlock();
@@ -386,6 +406,31 @@ void kqueue_reactor::run(bool block, op_queue<operation>& ops)
struct kevent events[128];
int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);
+#if defined(BOOST_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 |= BOOST_ASIO_HANDLER_REACTOR_READ_EVENT;
+ break;
+ case EVFILT_WRITE:
+ event_mask |= BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT;
+ break;
+ }
+ if ((events[i].flags & (EV_ERROR | EV_OOBAND)) != 0)
+ event_mask |= BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT;
+ BOOST_ASIO_HANDLER_REACTOR_EVENTS((context(),
+ reinterpret_cast<uintmax_t>(ptr), event_mask));
+ }
+ }
+#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
+
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
@@ -476,7 +521,8 @@ int kqueue_reactor::do_kqueue_create()
kqueue_reactor::descriptor_state* kqueue_reactor::allocate_descriptor_state()
{
mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
- return registered_descriptors_.alloc();
+ return registered_descriptors_.alloc(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ REACTOR_IO, scheduler_.concurrency_hint()));
}
void kqueue_reactor::free_descriptor_state(kqueue_reactor::descriptor_state* s)
@@ -497,11 +543,13 @@ void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue)
timer_queues_.erase(&queue);
}
-timespec* kqueue_reactor::get_timeout(timespec& ts)
+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.
- long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+ 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;
diff --git a/boost/asio/detail/impl/null_event.ipp b/boost/asio/detail/impl/null_event.ipp
new file mode 100644
index 0000000000..fb9f2e2ed2
--- /dev/null
+++ b/boost/asio/detail/impl/null_event.ipp
@@ -0,0 +1,76 @@
+//
+// detail/impl/null_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_IMPL_NULL_EVENT_IPP
+#define BOOST_ASIO_DETAIL_IMPL_NULL_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+# include <thread>
+#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+# include <boost/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 <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+void null_event::do_wait()
+{
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ std::this_thread::sleep_until((std::chrono::steady_clock::time_point::max)());
+#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ ::Sleep(INFINITE);
+#else
+ ::pause();
+#endif
+}
+
+void null_event::do_wait_for_usec(long usec)
+{
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ std::this_thread::sleep_for(std::chrono::microseconds(usec));
+#elif defined(BOOST_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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_IMPL_NULL_EVENT_IPP
diff --git a/boost/asio/detail/impl/posix_event.ipp b/boost/asio/detail/impl/posix_event.ipp
index 3b465ca3cd..4ff246f301 100644
--- a/boost/asio/detail/impl/posix_event.ipp
+++ b/boost/asio/detail/impl/posix_event.ipp
@@ -32,7 +32,19 @@ 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))
+
boost::system::error_code ec(error,
boost::asio::error::get_system_category());
boost::asio::detail::throw_error(ec, "event");
diff --git a/boost/asio/detail/impl/posix_thread.ipp b/boost/asio/detail/impl/posix_thread.ipp
index 66cb18da33..66a6792a4a 100644
--- a/boost/asio/detail/impl/posix_thread.ipp
+++ b/boost/asio/detail/impl/posix_thread.ipp
@@ -44,6 +44,16 @@ void posix_thread::join()
}
}
+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,
diff --git a/boost/asio/detail/impl/reactive_descriptor_service.ipp b/boost/asio/detail/impl/reactive_descriptor_service.ipp
index a0300c47d0..ffb623839f 100644
--- a/boost/asio/detail/impl/reactive_descriptor_service.ipp
+++ b/boost/asio/detail/impl/reactive_descriptor_service.ipp
@@ -31,13 +31,14 @@ namespace asio {
namespace detail {
reactive_descriptor_service::reactive_descriptor_service(
- boost::asio::io_service& io_service)
- : reactor_(boost::asio::use_service<reactor>(io_service))
+ boost::asio::io_context& io_context)
+ : service_base<reactive_descriptor_service>(io_context),
+ reactor_(boost::asio::use_service<reactor>(io_context))
{
reactor_.init_task();
}
-void reactive_descriptor_service::shutdown_service()
+void reactive_descriptor_service::shutdown()
{
}
@@ -84,7 +85,8 @@ void reactive_descriptor_service::destroy(
{
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("descriptor", &impl, "close"));
+ BOOST_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);
@@ -126,7 +128,8 @@ boost::system::error_code reactive_descriptor_service::close(
{
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("descriptor", &impl, "close"));
+ BOOST_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);
@@ -159,7 +162,8 @@ reactive_descriptor_service::release(
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("descriptor", &impl, "release"));
+ BOOST_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_);
@@ -179,7 +183,8 @@ boost::system::error_code reactive_descriptor_service::cancel(
return ec;
}
- BOOST_ASIO_HANDLER_OPERATION(("descriptor", &impl, "cancel"));
+ BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
+ "descriptor", &impl, impl.descriptor_, "cancel"));
reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
ec = boost::system::error_code();
diff --git a/boost/asio/detail/impl/reactive_serial_port_service.ipp b/boost/asio/detail/impl/reactive_serial_port_service.ipp
index ffa8857ab6..ffd2a2b558 100644
--- a/boost/asio/detail/impl/reactive_serial_port_service.ipp
+++ b/boost/asio/detail/impl/reactive_serial_port_service.ipp
@@ -31,14 +31,15 @@ namespace asio {
namespace detail {
reactive_serial_port_service::reactive_serial_port_service(
- boost::asio::io_service& io_service)
- : descriptor_service_(io_service)
+ boost::asio::io_context& io_context)
+ : service_base<reactive_serial_port_service>(io_context),
+ descriptor_service_(io_context)
{
}
-void reactive_serial_port_service::shutdown_service()
+void reactive_serial_port_service::shutdown()
{
- descriptor_service_.shutdown_service();
+ descriptor_service_.shutdown();
}
boost::system::error_code reactive_serial_port_service::open(
@@ -73,7 +74,7 @@ boost::system::error_code reactive_serial_port_service::open(
s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
if (s >= 0)
{
-#if defined(_BSD_SOURCE)
+#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
::cfmakeraw(&ios);
#else
ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
diff --git a/boost/asio/detail/impl/reactive_socket_service_base.ipp b/boost/asio/detail/impl/reactive_socket_service_base.ipp
index 3594ae0528..23dbbb583c 100644
--- a/boost/asio/detail/impl/reactive_socket_service_base.ipp
+++ b/boost/asio/detail/impl/reactive_socket_service_base.ipp
@@ -29,13 +29,14 @@ namespace asio {
namespace detail {
reactive_socket_service_base::reactive_socket_service_base(
- boost::asio::io_service& io_service)
- : reactor_(use_service<reactor>(io_service))
+ boost::asio::io_context& io_context)
+ : io_context_(io_context),
+ reactor_(use_service<reactor>(io_context))
{
reactor_.init_task();
}
-void reactive_socket_service_base::shutdown_service()
+void reactive_socket_service_base::base_shutdown()
{
}
@@ -82,7 +83,8 @@ void reactive_socket_service_base::destroy(
{
if (impl.socket_ != invalid_socket)
{
- BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close"));
+ BOOST_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);
@@ -100,7 +102,8 @@ boost::system::error_code reactive_socket_service_base::close(
{
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close"));
+ BOOST_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);
@@ -127,6 +130,27 @@ boost::system::error_code reactive_socket_service_base::close(
return ec;
}
+socket_type reactive_socket_service_base::release(
+ reactive_socket_service_base::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return invalid_socket;
+ }
+
+ BOOST_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 = boost::system::error_code();
+ return sock;
+}
+
boost::system::error_code reactive_socket_service_base::cancel(
reactive_socket_service_base::base_implementation_type& impl,
boost::system::error_code& ec)
@@ -137,7 +161,8 @@ boost::system::error_code reactive_socket_service_base::cancel(
return ec;
}
- BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "cancel"));
+ BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
+ "socket", &impl, impl.socket_, "cancel"));
reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
ec = boost::system::error_code();
diff --git a/boost/asio/detail/impl/resolver_service_base.ipp b/boost/asio/detail/impl/resolver_service_base.ipp
index 4ef66cde15..1dbbd20c3f 100644
--- a/boost/asio/detail/impl/resolver_service_base.ipp
+++ b/boost/asio/detail/impl/resolver_service_base.ipp
@@ -24,62 +24,62 @@ namespace boost {
namespace asio {
namespace detail {
-class resolver_service_base::work_io_service_runner
+class resolver_service_base::work_io_context_runner
{
public:
- work_io_service_runner(boost::asio::io_service& io_service)
- : io_service_(io_service) {}
- void operator()() { io_service_.run(); }
+ work_io_context_runner(boost::asio::io_context& io_context)
+ : io_context_(io_context) {}
+ void operator()() { io_context_.run(); }
private:
- boost::asio::io_service& io_service_;
+ boost::asio::io_context& io_context_;
};
resolver_service_base::resolver_service_base(
- boost::asio::io_service& io_service)
- : io_service_impl_(boost::asio::use_service<io_service_impl>(io_service)),
- work_io_service_(new boost::asio::io_service),
- work_io_service_impl_(boost::asio::use_service<
- io_service_impl>(*work_io_service_)),
- work_(new boost::asio::io_service::work(*work_io_service_)),
+ boost::asio::io_context& io_context)
+ : io_context_impl_(boost::asio::use_service<io_context_impl>(io_context)),
+ work_io_context_(new boost::asio::io_context(-1)),
+ work_io_context_impl_(boost::asio::use_service<
+ io_context_impl>(*work_io_context_)),
+ work_(boost::asio::make_work_guard(*work_io_context_)),
work_thread_(0)
{
}
resolver_service_base::~resolver_service_base()
{
- shutdown_service();
+ base_shutdown();
}
-void resolver_service_base::shutdown_service()
+void resolver_service_base::base_shutdown()
{
work_.reset();
- if (work_io_service_.get())
+ if (work_io_context_.get())
{
- work_io_service_->stop();
+ work_io_context_->stop();
if (work_thread_.get())
{
work_thread_->join();
work_thread_.reset();
}
- work_io_service_.reset();
+ work_io_context_.reset();
}
}
-void resolver_service_base::fork_service(
- boost::asio::io_service::fork_event fork_ev)
+void resolver_service_base::base_notify_fork(
+ boost::asio::io_context::fork_event fork_ev)
{
if (work_thread_.get())
{
- if (fork_ev == boost::asio::io_service::fork_prepare)
+ if (fork_ev == boost::asio::io_context::fork_prepare)
{
- work_io_service_->stop();
+ work_io_context_->stop();
work_thread_->join();
}
else
{
- work_io_service_->reset();
+ work_io_context_->restart();
work_thread_.reset(new boost::asio::detail::thread(
- work_io_service_runner(*work_io_service_)));
+ work_io_context_runner(*work_io_context_)));
}
}
}
@@ -93,24 +93,48 @@ void resolver_service_base::construct(
void resolver_service_base::destroy(
resolver_service_base::implementation_type& impl)
{
- BOOST_ASIO_HANDLER_OPERATION(("resolver", &impl, "cancel"));
+ BOOST_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 = BOOST_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 = BOOST_ASIO_MOVE_CAST(implementation_type)(other_impl);
+}
+
void resolver_service_base::cancel(
resolver_service_base::implementation_type& impl)
{
- BOOST_ASIO_HANDLER_OPERATION(("resolver", &impl, "cancel"));
+ BOOST_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(operation* op)
+void resolver_service_base::start_resolve_op(resolve_op* op)
{
- start_work_thread();
- io_service_impl_.work_started();
- work_io_service_impl_.post_immediate_completion(op, false);
+ if (BOOST_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_ = boost::asio::error::operation_not_supported;
+ io_context_impl_.post_immediate_completion(op, false);
+ }
}
void resolver_service_base::start_work_thread()
@@ -119,7 +143,7 @@ void resolver_service_base::start_work_thread()
if (!work_thread_.get())
{
work_thread_.reset(new boost::asio::detail::thread(
- work_io_service_runner(*work_io_service_)));
+ work_io_context_runner(*work_io_context_)));
}
}
diff --git a/boost/asio/detail/impl/task_io_service.ipp b/boost/asio/detail/impl/scheduler.ipp
index bc83fd4757..7af3907016 100644
--- a/boost/asio/detail/impl/task_io_service.ipp
+++ b/boost/asio/detail/impl/scheduler.ipp
@@ -1,6 +1,6 @@
//
-// detail/impl/task_io_service.ipp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/impl/scheduler.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
@@ -8,8 +8,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
-#define BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
+#ifndef BOOST_ASIO_DETAIL_IMPL_SCHEDULER_IPP
+#define BOOST_ASIO_DETAIL_IMPL_SCHEDULER_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -17,13 +17,12 @@
#include <boost/asio/detail/config.hpp>
-#if !defined(BOOST_ASIO_HAS_IOCP)
-
+#include <boost/asio/detail/concurrency_hint.hpp>
#include <boost/asio/detail/event.hpp>
#include <boost/asio/detail/limits.hpp>
#include <boost/asio/detail/reactor.hpp>
-#include <boost/asio/detail/task_io_service.hpp>
-#include <boost/asio/detail/task_io_service_thread_info.hpp>
+#include <boost/asio/detail/scheduler.hpp>
+#include <boost/asio/detail/scheduler_thread_info.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -31,14 +30,14 @@ namespace boost {
namespace asio {
namespace detail {
-struct task_io_service::task_cleanup
+struct scheduler::task_cleanup
{
~task_cleanup()
{
if (this_thread_->private_outstanding_work > 0)
{
boost::asio::detail::increment(
- task_io_service_->outstanding_work_,
+ scheduler_->outstanding_work_,
this_thread_->private_outstanding_work);
}
this_thread_->private_outstanding_work = 0;
@@ -46,29 +45,29 @@ struct task_io_service::task_cleanup
// Enqueue the completed operations and reinsert the task at the end of
// the operation queue.
lock_->lock();
- task_io_service_->task_interrupted_ = true;
- task_io_service_->op_queue_.push(this_thread_->private_op_queue);
- task_io_service_->op_queue_.push(&task_io_service_->task_operation_);
+ scheduler_->task_interrupted_ = true;
+ scheduler_->op_queue_.push(this_thread_->private_op_queue);
+ scheduler_->op_queue_.push(&scheduler_->task_operation_);
}
- task_io_service* task_io_service_;
+ scheduler* scheduler_;
mutex::scoped_lock* lock_;
thread_info* this_thread_;
};
-struct task_io_service::work_cleanup
+struct scheduler::work_cleanup
{
~work_cleanup()
{
if (this_thread_->private_outstanding_work > 1)
{
boost::asio::detail::increment(
- task_io_service_->outstanding_work_,
+ scheduler_->outstanding_work_,
this_thread_->private_outstanding_work - 1);
}
else if (this_thread_->private_outstanding_work < 1)
{
- task_io_service_->work_finished();
+ scheduler_->work_finished();
}
this_thread_->private_outstanding_work = 0;
@@ -76,31 +75,37 @@ struct task_io_service::work_cleanup
if (!this_thread_->private_op_queue.empty())
{
lock_->lock();
- task_io_service_->op_queue_.push(this_thread_->private_op_queue);
+ scheduler_->op_queue_.push(this_thread_->private_op_queue);
}
#endif // defined(BOOST_ASIO_HAS_THREADS)
}
- task_io_service* task_io_service_;
+ scheduler* scheduler_;
mutex::scoped_lock* lock_;
thread_info* this_thread_;
};
-task_io_service::task_io_service(
- boost::asio::io_service& io_service, std::size_t concurrency_hint)
- : boost::asio::detail::service_base<task_io_service>(io_service),
- one_thread_(concurrency_hint == 1),
- mutex_(),
+scheduler::scheduler(
+ boost::asio::execution_context& ctx, int concurrency_hint)
+ : boost::asio::detail::execution_context_service_base<scheduler>(ctx),
+ one_thread_(concurrency_hint == 1
+ || !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ SCHEDULER, concurrency_hint)
+ || !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ REACTOR_IO, concurrency_hint)),
+ mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ SCHEDULER, concurrency_hint)),
task_(0),
task_interrupted_(true),
outstanding_work_(0),
stopped_(false),
- shutdown_(false)
+ shutdown_(false),
+ concurrency_hint_(concurrency_hint)
{
BOOST_ASIO_HANDLER_TRACKING_INIT;
}
-void task_io_service::shutdown_service()
+void scheduler::shutdown()
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
@@ -119,18 +124,18 @@ void task_io_service::shutdown_service()
task_ = 0;
}
-void task_io_service::init_task()
+void scheduler::init_task()
{
mutex::scoped_lock lock(mutex_);
if (!shutdown_ && !task_)
{
- task_ = &use_service<reactor>(this->get_io_service());
+ task_ = &use_service<reactor>(this->context());
op_queue_.push(&task_operation_);
wake_one_thread_and_unlock(lock);
}
}
-std::size_t task_io_service::run(boost::system::error_code& ec)
+std::size_t scheduler::run(boost::system::error_code& ec)
{
ec = boost::system::error_code();
if (outstanding_work_ == 0)
@@ -152,7 +157,7 @@ std::size_t task_io_service::run(boost::system::error_code& ec)
return n;
}
-std::size_t task_io_service::run_one(boost::system::error_code& ec)
+std::size_t scheduler::run_one(boost::system::error_code& ec)
{
ec = boost::system::error_code();
if (outstanding_work_ == 0)
@@ -170,7 +175,25 @@ std::size_t task_io_service::run_one(boost::system::error_code& ec)
return do_run_one(lock, this_thread, ec);
}
-std::size_t task_io_service::poll(boost::system::error_code& ec)
+std::size_t scheduler::wait_one(long usec, boost::system::error_code& ec)
+{
+ ec = boost::system::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(boost::system::error_code& ec)
{
ec = boost::system::error_code();
if (outstanding_work_ == 0)
@@ -190,8 +213,8 @@ std::size_t task_io_service::poll(boost::system::error_code& ec)
// 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_thread_info = ctx.next_by_key())
- op_queue_.push(outer_thread_info->private_op_queue);
+ if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key()))
+ op_queue_.push(outer_info->private_op_queue);
#endif // defined(BOOST_ASIO_HAS_THREADS)
std::size_t n = 0;
@@ -201,7 +224,7 @@ std::size_t task_io_service::poll(boost::system::error_code& ec)
return n;
}
-std::size_t task_io_service::poll_one(boost::system::error_code& ec)
+std::size_t scheduler::poll_one(boost::system::error_code& ec)
{
ec = boost::system::error_code();
if (outstanding_work_ == 0)
@@ -221,41 +244,47 @@ std::size_t task_io_service::poll_one(boost::system::error_code& ec)
// 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_thread_info = ctx.next_by_key())
- op_queue_.push(outer_thread_info->private_op_queue);
+ if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key()))
+ op_queue_.push(outer_info->private_op_queue);
#endif // defined(BOOST_ASIO_HAS_THREADS)
return do_poll_one(lock, this_thread, ec);
}
-void task_io_service::stop()
+void scheduler::stop()
{
mutex::scoped_lock lock(mutex_);
stop_all_threads(lock);
}
-bool task_io_service::stopped() const
+bool scheduler::stopped() const
{
mutex::scoped_lock lock(mutex_);
return stopped_;
}
-void task_io_service::reset()
+void scheduler::restart()
{
mutex::scoped_lock lock(mutex_);
stopped_ = false;
}
-void task_io_service::post_immediate_completion(
- task_io_service::operation* op, bool is_continuation)
+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(BOOST_ASIO_HAS_THREADS)
if (one_thread_ || is_continuation)
{
- if (thread_info* this_thread = thread_call_stack::contains(this))
+ if (thread_info_base* this_thread = thread_call_stack::contains(this))
{
- ++this_thread->private_outstanding_work;
- this_thread->private_op_queue.push(op);
+ ++static_cast<thread_info*>(this_thread)->private_outstanding_work;
+ static_cast<thread_info*>(this_thread)->private_op_queue.push(op);
return;
}
}
@@ -269,14 +298,14 @@ void task_io_service::post_immediate_completion(
wake_one_thread_and_unlock(lock);
}
-void task_io_service::post_deferred_completion(task_io_service::operation* op)
+void scheduler::post_deferred_completion(scheduler::operation* op)
{
#if defined(BOOST_ASIO_HAS_THREADS)
if (one_thread_)
{
- if (thread_info* this_thread = thread_call_stack::contains(this))
+ if (thread_info_base* this_thread = thread_call_stack::contains(this))
{
- this_thread->private_op_queue.push(op);
+ static_cast<thread_info*>(this_thread)->private_op_queue.push(op);
return;
}
}
@@ -287,17 +316,17 @@ void task_io_service::post_deferred_completion(task_io_service::operation* op)
wake_one_thread_and_unlock(lock);
}
-void task_io_service::post_deferred_completions(
- op_queue<task_io_service::operation>& ops)
+void scheduler::post_deferred_completions(
+ op_queue<scheduler::operation>& ops)
{
if (!ops.empty())
{
#if defined(BOOST_ASIO_HAS_THREADS)
if (one_thread_)
{
- if (thread_info* this_thread = thread_call_stack::contains(this))
+ if (thread_info_base* this_thread = thread_call_stack::contains(this))
{
- this_thread->private_op_queue.push(ops);
+ static_cast<thread_info*>(this_thread)->private_op_queue.push(ops);
return;
}
}
@@ -309,8 +338,8 @@ void task_io_service::post_deferred_completions(
}
}
-void task_io_service::do_dispatch(
- task_io_service::operation* op)
+void scheduler::do_dispatch(
+ scheduler::operation* op)
{
work_started();
mutex::scoped_lock lock(mutex_);
@@ -318,15 +347,15 @@ void task_io_service::do_dispatch(
wake_one_thread_and_unlock(lock);
}
-void task_io_service::abandon_operations(
- op_queue<task_io_service::operation>& ops)
+void scheduler::abandon_operations(
+ op_queue<scheduler::operation>& ops)
{
- op_queue<task_io_service::operation> ops2;
+ op_queue<scheduler::operation> ops2;
ops2.push(ops);
}
-std::size_t task_io_service::do_run_one(mutex::scoped_lock& lock,
- task_io_service::thread_info& this_thread,
+std::size_t scheduler::do_run_one(mutex::scoped_lock& lock,
+ scheduler::thread_info& this_thread,
const boost::system::error_code& ec)
{
while (!stopped_)
@@ -353,7 +382,7 @@ std::size_t task_io_service::do_run_one(mutex::scoped_lock& lock,
// 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, this_thread.private_op_queue);
+ task_->run(more_handlers ? 0 : -1, this_thread.private_op_queue);
}
else
{
@@ -369,7 +398,7 @@ std::size_t task_io_service::do_run_one(mutex::scoped_lock& lock,
(void)on_exit;
// Complete the operation. May throw an exception. Deletes the object.
- o->complete(*this, ec, task_result);
+ o->complete(this, ec, task_result);
return 1;
}
@@ -384,8 +413,78 @@ std::size_t task_io_service::do_run_one(mutex::scoped_lock& lock,
return 0;
}
-std::size_t task_io_service::do_poll_one(mutex::scoped_lock& lock,
- task_io_service::thread_info& this_thread,
+std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock,
+ scheduler::thread_info& this_thread, long usec,
+ const boost::system::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 boost::system::error_code& ec)
{
if (stopped_)
@@ -404,7 +503,7 @@ std::size_t task_io_service::do_poll_one(mutex::scoped_lock& lock,
// 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(false, this_thread.private_op_queue);
+ task_->run(0, this_thread.private_op_queue);
}
o = op_queue_.front();
@@ -433,12 +532,12 @@ std::size_t task_io_service::do_poll_one(mutex::scoped_lock& lock,
(void)on_exit;
// Complete the operation. May throw an exception. Deletes the object.
- o->complete(*this, ec, task_result);
+ o->complete(this, ec, task_result);
return 1;
}
-void task_io_service::stop_all_threads(
+void scheduler::stop_all_threads(
mutex::scoped_lock& lock)
{
stopped_ = true;
@@ -451,7 +550,7 @@ void task_io_service::stop_all_threads(
}
}
-void task_io_service::wake_one_thread_and_unlock(
+void scheduler::wake_one_thread_and_unlock(
mutex::scoped_lock& lock)
{
if (!wakeup_event_.maybe_unlock_and_signal_one(lock))
@@ -471,6 +570,4 @@ void task_io_service::wake_one_thread_and_unlock(
#include <boost/asio/detail/pop_options.hpp>
-#endif // !defined(BOOST_ASIO_HAS_IOCP)
-
-#endif // BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP
+#endif // BOOST_ASIO_DETAIL_IMPL_SCHEDULER_IPP
diff --git a/boost/asio/detail/impl/select_reactor.hpp b/boost/asio/detail/impl/select_reactor.hpp
index d3f28f5e61..207a045f6c 100644
--- a/boost/asio/detail/impl/select_reactor.hpp
+++ b/boost/asio/detail/impl/select_reactor.hpp
@@ -51,12 +51,12 @@ void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
if (shutdown_)
{
- io_service_.post_immediate_completion(op, false);
+ scheduler_.post_immediate_completion(op, false);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
- io_service_.work_started();
+ scheduler_.work_started();
if (earliest)
interrupter_.interrupt();
}
@@ -70,10 +70,23 @@ std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
lock.unlock();
- io_service_.post_deferred_completions(ops);
+ 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)
+{
+ boost::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
} // namespace boost
diff --git a/boost/asio/detail/impl/select_reactor.ipp b/boost/asio/detail/impl/select_reactor.ipp
index 869f73492b..44fab64269 100644
--- a/boost/asio/detail/impl/select_reactor.ipp
+++ b/boost/asio/detail/impl/select_reactor.ipp
@@ -23,7 +23,6 @@
&& !defined(BOOST_ASIO_HAS_KQUEUE) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME))
-#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/fd_set_adapter.hpp>
#include <boost/asio/detail/select_reactor.hpp>
#include <boost/asio/detail/signal_blocker.hpp>
@@ -35,9 +34,28 @@ namespace boost {
namespace asio {
namespace detail {
-select_reactor::select_reactor(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<select_reactor>(io_service),
- io_service_(use_service<io_service_impl>(io_service)),
+#if defined(BOOST_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(BOOST_ASIO_HAS_IOCP)
+
+select_reactor::select_reactor(boost::asio::execution_context& ctx)
+ : execution_context_service_base<select_reactor>(ctx),
+ scheduler_(use_service<scheduler_type>(ctx)),
mutex_(),
interrupter_(),
#if defined(BOOST_ASIO_HAS_IOCP)
@@ -48,17 +66,16 @@ select_reactor::select_reactor(boost::asio::io_service& io_service)
{
#if defined(BOOST_ASIO_HAS_IOCP)
boost::asio::detail::signal_blocker sb;
- thread_ = new boost::asio::detail::thread(
- bind_handler(&select_reactor::call_run_thread, this));
+ thread_ = new boost::asio::detail::thread(thread_function(this));
#endif // defined(BOOST_ASIO_HAS_IOCP)
}
select_reactor::~select_reactor()
{
- shutdown_service();
+ shutdown();
}
-void select_reactor::shutdown_service()
+void select_reactor::shutdown()
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
@@ -84,18 +101,19 @@ void select_reactor::shutdown_service()
timer_queues_.get_all_timers(ops);
- io_service_.abandon_operations(ops);
+ scheduler_.abandon_operations(ops);
}
-void select_reactor::fork_service(boost::asio::io_service::fork_event fork_ev)
+void select_reactor::notify_fork(
+ boost::asio::execution_context::fork_event fork_ev)
{
- if (fork_ev == boost::asio::io_service::fork_child)
+ if (fork_ev == boost::asio::execution_context::fork_child)
interrupter_.recreate();
}
void select_reactor::init_task()
{
- io_service_.init_task();
+ scheduler_.init_task();
}
int select_reactor::register_descriptor(socket_type,
@@ -135,7 +153,7 @@ void select_reactor::start_op(int op_type, socket_type descriptor,
}
bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
- io_service_.work_started();
+ scheduler_.work_started();
if (first)
interrupter_.interrupt();
}
@@ -168,7 +186,7 @@ void select_reactor::cleanup_descriptor_data(
{
}
-void select_reactor::run(bool block, op_queue<operation>& ops)
+void select_reactor::run(long usec, op_queue<operation>& ops)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
@@ -205,12 +223,12 @@ void select_reactor::run(bool block, op_queue<operation>& ops)
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
- if (!block && !have_work_to_do)
+ if (!usec && !have_work_to_do)
return;
// Determine how long to block while waiting for events.
timeval tv_buf = { 0, 0 };
- timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
+ timeval* tv = usec ? get_timeout(usec, tv_buf) : &tv_buf;
lock.unlock();
@@ -259,15 +277,10 @@ void select_reactor::run_thread()
lock.unlock();
op_queue<operation> ops;
run(true, ops);
- io_service_.post_deferred_completions(ops);
+ scheduler_.post_deferred_completions(ops);
lock.lock();
}
}
-
-void select_reactor::call_run_thread(select_reactor* reactor)
-{
- reactor->run_thread();
-}
#endif // defined(BOOST_ASIO_HAS_IOCP)
void select_reactor::do_add_timer_queue(timer_queue_base& queue)
@@ -282,11 +295,13 @@ void select_reactor::do_remove_timer_queue(timer_queue_base& queue)
timer_queues_.erase(&queue);
}
-timeval* select_reactor::get_timeout(timeval& tv)
+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.
- long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+ 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;
@@ -300,7 +315,7 @@ void select_reactor::cancel_ops_unlocked(socket_type descriptor,
for (int i = 0; i < max_ops; ++i)
need_interrupt = op_queue_[i].cancel_operations(
descriptor, ops, ec) || need_interrupt;
- io_service_.post_deferred_completions(ops);
+ scheduler_.post_deferred_completions(ops);
if (need_interrupt)
interrupter_.interrupt();
}
diff --git a/boost/asio/detail/impl/service_registry.hpp b/boost/asio/detail/impl/service_registry.hpp
index 7ffdd029f7..11ad4cf5cc 100644
--- a/boost/asio/detail/impl/service_registry.hpp
+++ b/boost/asio/detail/impl/service_registry.hpp
@@ -21,64 +21,70 @@ namespace boost {
namespace asio {
namespace detail {
-template <typename Service, typename Arg>
-service_registry::service_registry(
- boost::asio::io_service& o, Service*, Arg arg)
- : owner_(o),
- first_service_(new Service(o, arg))
-{
- boost::asio::io_service::service::key key;
- init_key(key, Service::id);
- first_service_->key_ = key;
- first_service_->next_ = 0;
-}
-
template <typename Service>
-Service& service_registry::first_service()
+Service& service_registry::use_service()
{
- return *static_cast<Service*>(first_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()
+Service& service_registry::use_service(io_context& owner)
{
- boost::asio::io_service::service::key key;
- init_key(key, Service::id);
- factory_type factory = &service_registry::create<Service>;
- return *static_cast<Service*>(do_use_service(key, factory));
+ 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)
{
- boost::asio::io_service::service::key key;
- init_key(key, Service::id);
+ 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
{
- boost::asio::io_service::service::key key;
- init_key(key, Service::id);
+ 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(BOOST_ASIO_NO_TYPEID)
template <typename Service>
-void service_registry::init_key(boost::asio::io_service::service::key& key,
- const boost::asio::detail::service_id<Service>& /*id*/)
+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;
}
-#endif // !defined(BOOST_ASIO_NO_TYPEID)
template <typename Service>
-boost::asio::io_service::service* service_registry::create(
- boost::asio::io_service& owner)
+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(BOOST_ASIO_NO_TYPEID)
+
+template <typename Service, typename Owner>
+execution_context::service* service_registry::create(void* owner)
{
- return new Service(owner);
+ return new Service(*static_cast<Owner*>(owner));
}
} // namespace detail
diff --git a/boost/asio/detail/impl/service_registry.ipp b/boost/asio/detail/impl/service_registry.ipp
index 25ac8eccc6..75c3f45625 100644
--- a/boost/asio/detail/impl/service_registry.ipp
+++ b/boost/asio/detail/impl/service_registry.ipp
@@ -26,36 +26,45 @@ namespace boost {
namespace asio {
namespace detail {
+service_registry::service_registry(execution_context& owner)
+ : owner_(owner),
+ first_service_(0)
+{
+}
+
service_registry::~service_registry()
{
- // Shutdown all services. This must be done in a separate loop before the
- // services are destroyed since the destructors of user-defined handler
- // objects may try to access other service objects.
- boost::asio::io_service::service* service = first_service_;
+}
+
+void service_registry::shutdown_services()
+{
+ execution_context::service* service = first_service_;
while (service)
{
- service->shutdown_service();
+ service->shutdown();
service = service->next_;
}
+}
- // Destroy all services.
+void service_registry::destroy_services()
+{
while (first_service_)
{
- boost::asio::io_service::service* next_service = first_service_->next_;
+ execution_context::service* next_service = first_service_->next_;
destroy(first_service_);
first_service_ = next_service;
}
}
-void service_registry::notify_fork(boost::asio::io_service::fork_event fork_ev)
+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<boost::asio::io_service::service*> services;
+ std::vector<execution_context::service*> services;
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- boost::asio::io_service::service* service = first_service_;
+ execution_context::service* service = first_service_;
while (service)
{
services.push_back(service);
@@ -68,24 +77,24 @@ void service_registry::notify_fork(boost::asio::io_service::fork_event fork_ev)
// 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 == boost::asio::io_service::fork_prepare)
+ if (fork_ev == execution_context::fork_prepare)
for (std::size_t i = 0; i < num_services; ++i)
- services[i]->fork_service(fork_ev);
+ services[i]->notify_fork(fork_ev);
else
for (std::size_t i = num_services; i > 0; --i)
- services[i - 1]->fork_service(fork_ev);
+ services[i - 1]->notify_fork(fork_ev);
}
-void service_registry::init_key(boost::asio::io_service::service::key& key,
- const boost::asio::io_service::id& id)
+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 boost::asio::io_service::service::key& key1,
- const boost::asio::io_service::service::key& key2)
+ const execution_context::service::key& key1,
+ const execution_context::service::key& key2)
{
if (key1.id_ && key2.id_)
if (key1.id_ == key2.id_)
@@ -96,19 +105,19 @@ bool service_registry::keys_match(
return false;
}
-void service_registry::destroy(boost::asio::io_service::service* service)
+void service_registry::destroy(execution_context::service* service)
{
delete service;
}
-boost::asio::io_service::service* service_registry::do_use_service(
- const boost::asio::io_service::service::key& key,
- factory_type factory)
+execution_context::service* service_registry::do_use_service(
+ const execution_context::service::key& key,
+ factory_type factory, void* owner)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
// First see if there is an existing service object with the given key.
- boost::asio::io_service::service* service = first_service_;
+ execution_context::service* service = first_service_;
while (service)
{
if (keys_match(service->key_, key))
@@ -120,7 +129,7 @@ boost::asio::io_service::service* service_registry::do_use_service(
// 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_) };
+ auto_service_ptr new_service = { factory(owner) };
new_service.ptr_->key_ = key;
lock.lock();
@@ -142,16 +151,16 @@ boost::asio::io_service::service* service_registry::do_use_service(
}
void service_registry::do_add_service(
- const boost::asio::io_service::service::key& key,
- boost::asio::io_service::service* new_service)
+ const execution_context::service::key& key,
+ execution_context::service* new_service)
{
- if (&owner_ != &new_service->get_io_service())
+ if (&owner_ != &new_service->context())
boost::asio::detail::throw_exception(invalid_service_owner());
boost::asio::detail::mutex::scoped_lock lock(mutex_);
// Check if there is an existing service object with the given key.
- boost::asio::io_service::service* service = first_service_;
+ execution_context::service* service = first_service_;
while (service)
{
if (keys_match(service->key_, key))
@@ -166,11 +175,11 @@ void service_registry::do_add_service(
}
bool service_registry::do_has_service(
- const boost::asio::io_service::service::key& key) const
+ const execution_context::service::key& key) const
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- boost::asio::io_service::service* service = first_service_;
+ execution_context::service* service = first_service_;
while (service)
{
if (keys_match(service->key_, key))
diff --git a/boost/asio/detail/impl/signal_set_service.ipp b/boost/asio/detail/impl/signal_set_service.ipp
index 95ea8bee21..376d311471 100644
--- a/boost/asio/detail/impl/signal_set_service.ipp
+++ b/boost/asio/detail/impl/signal_set_service.ipp
@@ -18,10 +18,12 @@
#include <boost/asio/detail/config.hpp>
#include <cstring>
+#include <stdexcept>
#include <boost/asio/detail/reactor.hpp>
#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/signal_set_service.hpp>
#include <boost/asio/detail/static_mutex.hpp>
+#include <boost/asio/detail/throw_exception.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -92,7 +94,7 @@ public:
{
}
- static bool do_perform(reactor_op*)
+ static status do_perform(reactor_op*)
{
signal_state* state = get_signal_state();
@@ -102,10 +104,10 @@ public:
if (signal_number >= 0 && signal_number < max_signal_number)
signal_set_service::deliver_signal(signal_number);
- return false;
+ return not_done;
}
- static void do_complete(io_service_impl* /*owner*/, operation* base,
+ static void do_complete(void* /*owner*/, operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
@@ -118,12 +120,13 @@ public:
// && !defined(__CYGWIN__)
signal_set_service::signal_set_service(
- boost::asio::io_service& io_service)
- : io_service_(boost::asio::use_service<io_service_impl>(io_service)),
+ boost::asio::io_context& io_context)
+ : service_base<signal_set_service>(io_context),
+ io_context_(boost::asio::use_service<io_context_impl>(io_context)),
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(__CYGWIN__)
- reactor_(boost::asio::use_service<reactor>(io_service)),
+ reactor_(boost::asio::use_service<reactor>(io_context)),
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
@@ -151,7 +154,7 @@ signal_set_service::~signal_set_service()
remove_service(this);
}
-void signal_set_service::shutdown_service()
+void signal_set_service::shutdown()
{
remove_service(this);
@@ -167,11 +170,11 @@ void signal_set_service::shutdown_service()
}
}
- io_service_.abandon_operations(ops);
+ io_context_.abandon_operations(ops);
}
-void signal_set_service::fork_service(
- boost::asio::io_service::fork_event fork_ev)
+void signal_set_service::notify_fork(
+ boost::asio::io_context::fork_event fork_ev)
{
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
@@ -181,7 +184,7 @@ void signal_set_service::fork_service(
switch (fork_ev)
{
- case boost::asio::io_service::fork_prepare:
+ case boost::asio::io_context::fork_prepare:
{
int read_descriptor = state->read_descriptor_;
state->fork_prepared_ = true;
@@ -190,7 +193,7 @@ void signal_set_service::fork_service(
reactor_.cleanup_descriptor_data(reactor_data_);
}
break;
- case boost::asio::io_service::fork_parent:
+ case boost::asio::io_context::fork_parent:
if (state->fork_prepared_)
{
int read_descriptor = state->read_descriptor_;
@@ -200,7 +203,7 @@ void signal_set_service::fork_service(
read_descriptor, reactor_data_, new pipe_read_op);
}
break;
- case boost::asio::io_service::fork_child:
+ case boost::asio::io_context::fork_child:
if (state->fork_prepared_)
{
boost::asio::detail::signal_blocker blocker;
@@ -439,7 +442,8 @@ boost::system::error_code signal_set_service::cancel(
signal_set_service::implementation_type& impl,
boost::system::error_code& ec)
{
- BOOST_ASIO_HANDLER_OPERATION(("signal_set", &impl, "cancel"));
+ BOOST_ASIO_HANDLER_OPERATION((io_context_.context(),
+ "signal_set", &impl, 0, "cancel"));
op_queue<operation> ops;
{
@@ -454,7 +458,7 @@ boost::system::error_code signal_set_service::cancel(
}
}
- io_service_.post_deferred_completions(ops);
+ io_context_.post_deferred_completions(ops);
ec = boost::system::error_code();
return ec;
@@ -490,7 +494,7 @@ void signal_set_service::deliver_signal(int signal_number)
reg = reg->next_in_table_;
}
- service->io_service_.post_deferred_completions(ops);
+ service->io_context_.post_deferred_completions(ops);
service = service->next_;
}
@@ -507,6 +511,22 @@ void signal_set_service::add_service(signal_set_service* service)
open_descriptors();
#endif // !defined(BOOST_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 (!BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
+ service->io_context_.concurrency_hint())
+ || !BOOST_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.");
+ boost::asio::detail::throw_exception(ex);
+ }
+ }
+
// Insert service into linked list of all services.
service->next_ = state->service_list_;
service->prev_ = 0;
@@ -620,7 +640,7 @@ void signal_set_service::close_descriptors()
void signal_set_service::start_wait_op(
signal_set_service::implementation_type& impl, signal_op* op)
{
- io_service_.work_started();
+ io_context_.work_started();
signal_state* state = get_signal_state();
static_mutex::scoped_lock lock(state->mutex_);
@@ -632,7 +652,7 @@ void signal_set_service::start_wait_op(
{
--reg->undelivered_;
op->signal_number_ = reg->signal_number_;
- io_service_.post_deferred_completion(op);
+ io_context_.post_deferred_completion(op);
return;
}
diff --git a/boost/asio/detail/impl/socket_ops.ipp b/boost/asio/detail/impl/socket_ops.ipp
index c9683f4a09..94be0f280c 100644
--- a/boost/asio/detail/impl/socket_ops.ipp
+++ b/boost/asio/detail/impl/socket_ops.ipp
@@ -169,7 +169,7 @@ socket_type sync_accept(socket_type s, state_type state,
return invalid_socket;
// Wait for socket to become ready.
- if (socket_ops::poll_read(s, 0, ec) < 0)
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
return invalid_socket;
}
}
@@ -242,8 +242,6 @@ bool non_blocking_accept(socket_type s,
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
{
- if (state & user_set_non_blocking)
- return true;
// Fall through to retry operation.
}
else if (ec == boost::asio::error::connection_aborted)
@@ -506,7 +504,7 @@ void sync_connect(socket_type s, const socket_addr_type* addr,
}
// Wait for socket to become ready.
- if (socket_ops::poll_connect(s, ec) < 0)
+ if (socket_ops::poll_connect(s, -1, ec) < 0)
return;
// Get the error code from the connect operation.
@@ -773,6 +771,8 @@ signed_size_type recv(socket_type s, buf* bufs, size_t count,
ec = boost::asio::error::connection_reset;
else if (ec.value() == ERROR_PORT_UNREACHABLE)
ec = boost::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 = boost::system::error_code();
@@ -828,7 +828,7 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs,
return 0;
// Wait for socket to become ready.
- if (socket_ops::poll_read(s, 0, ec) < 0)
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
return 0;
}
}
@@ -851,6 +851,10 @@ void complete_iocp_recv(state_type state,
{
ec = boost::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
@@ -921,6 +925,8 @@ signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,
ec = boost::asio::error::connection_reset;
else if (ec.value() == ERROR_PORT_UNREACHABLE)
ec = boost::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 = boost::system::error_code();
@@ -967,7 +973,7 @@ size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
return 0;
// Wait for socket to become ready.
- if (socket_ops::poll_read(s, 0, ec) < 0)
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
return 0;
}
}
@@ -990,6 +996,10 @@ void complete_iocp_recvfrom(
{
ec = boost::asio::error::connection_refused;
}
+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+ {
+ ec.assign(0, ec.category());
+ }
}
#else // defined(BOOST_ASIO_HAS_IOCP)
@@ -1080,7 +1090,7 @@ size_t sync_recvmsg(socket_type s, state_type state,
return 0;
// Wait for socket to become ready.
- if (socket_ops::poll_read(s, 0, ec) < 0)
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
return 0;
}
}
@@ -1103,6 +1113,10 @@ void complete_iocp_recvmsg(
{
ec = boost::asio::error::connection_refused;
}
+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+ {
+ ec.assign(0, ec.category());
+ }
}
#else // defined(BOOST_ASIO_HAS_IOCP)
@@ -1207,7 +1221,7 @@ size_t sync_send(socket_type s, state_type state, const buf* bufs,
return 0;
// Wait for socket to become ready.
- if (socket_ops::poll_write(s, 0, ec) < 0)
+ if (socket_ops::poll_write(s, 0, -1, ec) < 0)
return 0;
}
}
@@ -1331,7 +1345,7 @@ size_t sync_sendto(socket_type s, state_type state, const buf* bufs,
return 0;
// Wait for socket to become ready.
- if (socket_ops::poll_write(s, 0, ec) < 0)
+ if (socket_ops::poll_write(s, 0, -1, ec) < 0)
return 0;
}
}
@@ -1785,7 +1799,8 @@ int select(int nfds, fd_set* readfds, fd_set* writefds,
#endif
}
-int poll_read(socket_type s, state_type state, boost::system::error_code& ec)
+int poll_read(socket_type s, state_type state,
+ int msec, boost::system::error_code& ec)
{
if (s == invalid_socket)
{
@@ -1799,10 +1814,22 @@ int poll_read(socket_type s, state_type state, boost::system::error_code& ec)
fd_set fds;
FD_ZERO(&fds);
FD_SET(s, &fds);
- timeval zero_timeout;
- zero_timeout.tv_sec = 0;
- zero_timeout.tv_usec = 0;
- timeval* timeout = (state & user_set_non_blocking) ? &zero_timeout : 0;
+ 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(BOOST_ASIO_WINDOWS)
@@ -1812,7 +1839,7 @@ int poll_read(socket_type s, state_type state, boost::system::error_code& ec)
fds.fd = s;
fds.events = POLLIN;
fds.revents = 0;
- int timeout = (state & user_set_non_blocking) ? 0 : -1;
+ int timeout = (state & user_set_non_blocking) ? 0 : msec;
clear_last_error();
int result = error_wrapper(::poll(&fds, 1, timeout), ec);
#endif // defined(BOOST_ASIO_WINDOWS)
@@ -1826,7 +1853,8 @@ int poll_read(socket_type s, state_type state, boost::system::error_code& ec)
return result;
}
-int poll_write(socket_type s, state_type state, boost::system::error_code& ec)
+int poll_write(socket_type s, state_type state,
+ int msec, boost::system::error_code& ec)
{
if (s == invalid_socket)
{
@@ -1840,10 +1868,22 @@ int poll_write(socket_type s, state_type state, boost::system::error_code& ec)
fd_set fds;
FD_ZERO(&fds);
FD_SET(s, &fds);
- timeval zero_timeout;
- zero_timeout.tv_sec = 0;
- zero_timeout.tv_usec = 0;
- timeval* timeout = (state & user_set_non_blocking) ? &zero_timeout : 0;
+ 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(BOOST_ASIO_WINDOWS)
@@ -1853,7 +1893,7 @@ int poll_write(socket_type s, state_type state, boost::system::error_code& ec)
fds.fd = s;
fds.events = POLLOUT;
fds.revents = 0;
- int timeout = (state & user_set_non_blocking) ? 0 : -1;
+ int timeout = (state & user_set_non_blocking) ? 0 : msec;
clear_last_error();
int result = error_wrapper(::poll(&fds, 1, timeout), ec);
#endif // defined(BOOST_ASIO_WINDOWS)
@@ -1867,7 +1907,61 @@ int poll_write(socket_type s, state_type state, boost::system::error_code& ec)
return result;
}
-int poll_connect(socket_type s, boost::system::error_code& ec)
+int poll_error(socket_type s, state_type state,
+ int msec, boost::system::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+#if defined(BOOST_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(BOOST_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(BOOST_ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ if (result == 0)
+ ec = (state & user_set_non_blocking)
+ ? boost::asio::error::would_block : boost::system::error_code();
+ else if (result > 0)
+ ec = boost::system::error_code();
+ return result;
+}
+
+int poll_connect(socket_type s, int msec, boost::system::error_code& ec)
{
if (s == invalid_socket)
{
@@ -1884,9 +1978,19 @@ int poll_connect(socket_type s, boost::system::error_code& ec)
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, 0), ec);
+ s + 1, 0, &write_fds, &except_fds, timeout), ec);
if (result >= 0)
ec = boost::system::error_code();
return result;
@@ -1898,7 +2002,7 @@ int poll_connect(socket_type s, boost::system::error_code& ec)
fds.events = POLLOUT;
fds.revents = 0;
clear_last_error();
- int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ int result = error_wrapper(::poll(&fds, 1, msec), ec);
if (result >= 0)
ec = boost::system::error_code();
return result;
@@ -3346,7 +3450,6 @@ boost::system::error_code getnameinfo(const socket_addr_type* addr,
using namespace std; // For memcpy.
sockaddr_storage_type tmp_addr;
memcpy(&tmp_addr, addr, addrlen);
- tmp_addr.ss_len = addrlen;
addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
clear_last_error();
return getnameinfo_emulation(addr, addrlen,
diff --git a/boost/asio/detail/impl/strand_executor_service.hpp b/boost/asio/detail/impl/strand_executor_service.hpp
new file mode 100644
index 0000000000..6821c2ec64
--- /dev/null
+++ b/boost/asio/detail/impl/strand_executor_service.hpp
@@ -0,0 +1,181 @@
+//
+// detail/impl/strand_executor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/call_stack.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/recycling_allocator.hpp>
+#include <boost/asio/executor_work_guard.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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(BOOST_ASIO_HAS_MOVE)
+ invoker(invoker&& other)
+ : impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)),
+ work_(BOOST_ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_))
+ {
+ }
+#endif // defined(BOOST_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(BOOST_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.
+ boost::system::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, BOOST_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(BOOST_ASIO_MOVE_CAST(Function)(function));
+
+ fenced_block b(fenced_block::full);
+ boost_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(BOOST_ASIO_MOVE_CAST(Function)(function), a);
+
+ BOOST_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, BOOST_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(BOOST_ASIO_MOVE_CAST(Function)(function), a);
+
+ BOOST_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, BOOST_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(BOOST_ASIO_MOVE_CAST(Function)(function), a);
+
+ BOOST_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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
diff --git a/boost/asio/detail/impl/strand_executor_service.ipp b/boost/asio/detail/impl/strand_executor_service.ipp
new file mode 100644
index 0000000000..353304ae27
--- /dev/null
+++ b/boost/asio/detail/impl/strand_executor_service.ipp
@@ -0,0 +1,126 @@
+//
+// detail/impl/strand_executor_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP
+#define BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/strand_executor_service.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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;
+
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ strand_impl* impl = impl_list_;
+ while (impl)
+ {
+ ops.push(impl->waiting_queue_);
+ ops.push(impl->ready_queue_);
+ impl = impl->next_;
+ }
+}
+
+strand_executor_service::implementation_type
+strand_executor_service::create_implementation()
+{
+ implementation_type new_impl(new strand_impl);
+ new_impl->locked_ = false;
+
+ boost::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()
+{
+ boost::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->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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP
diff --git a/boost/asio/detail/impl/strand_service.hpp b/boost/asio/detail/impl/strand_service.hpp
index 4167f686d1..df21099971 100644
--- a/boost/asio/detail/impl/strand_service.hpp
+++ b/boost/asio/detail/impl/strand_service.hpp
@@ -15,12 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/call_stack.hpp>
#include <boost/asio/detail/completion_handler.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -36,7 +36,7 @@ inline strand_service::strand_impl::strand_impl()
struct strand_service::on_dispatch_exit
{
- io_service_impl* io_service_;
+ io_context_impl* io_context_;
strand_impl* impl_;
~on_dispatch_exit()
@@ -47,7 +47,7 @@ struct strand_service::on_dispatch_exit
impl_->mutex_.unlock();
if (more_handlers)
- io_service_->post_immediate_completion(impl_, false);
+ io_context_->post_immediate_completion(impl_, false);
}
};
@@ -66,11 +66,11 @@ void strand_service::dispatch(strand_service::implementation_type& impl,
// Allocate and construct an operation to wrap the handler.
typedef completion_handler<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "strand", impl, "dispatch"));
+ BOOST_ASIO_HANDLER_CREATION((this->context(),
+ *p.p, "strand", impl, 0, "dispatch"));
bool dispatch_immediately = do_dispatch(impl, p.p);
operation* o = p.p;
@@ -82,15 +82,15 @@ void strand_service::dispatch(strand_service::implementation_type& impl,
call_stack<strand_impl>::context ctx(impl);
// Ensure the next handler, if any, is scheduled on block exit.
- on_dispatch_exit on_exit = { &io_service_, impl };
+ on_dispatch_exit on_exit = { &io_context_, impl };
(void)on_exit;
completion_handler<Handler>::do_complete(
- &io_service_, o, boost::system::error_code(), 0);
+ &io_context_, o, boost::system::error_code(), 0);
}
}
-// Request the io_service to invoke the given handler and return immediately.
+// 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)
@@ -101,11 +101,11 @@ void strand_service::post(strand_service::implementation_type& impl,
// Allocate and construct an operation to wrap the handler.
typedef completion_handler<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "strand", impl, "post"));
+ BOOST_ASIO_HANDLER_CREATION((this->context(),
+ *p.p, "strand", impl, 0, "post"));
do_post(impl, p.p, is_continuation);
p.v = p.p = 0;
diff --git a/boost/asio/detail/impl/strand_service.ipp b/boost/asio/detail/impl/strand_service.ipp
index 54ecde2cc7..e92355d837 100644
--- a/boost/asio/detail/impl/strand_service.ipp
+++ b/boost/asio/detail/impl/strand_service.ipp
@@ -27,7 +27,7 @@ namespace detail {
struct strand_service::on_do_complete_exit
{
- io_service_impl* owner_;
+ io_context_impl* owner_;
strand_impl* impl_;
~on_do_complete_exit()
@@ -42,15 +42,15 @@ struct strand_service::on_do_complete_exit
}
};
-strand_service::strand_service(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<strand_service>(io_service),
- io_service_(boost::asio::use_service<io_service_impl>(io_service)),
+strand_service::strand_service(boost::asio::io_context& io_context)
+ : boost::asio::detail::service_base<strand_service>(io_context),
+ io_context_(boost::asio::use_service<io_context_impl>(io_context)),
mutex_(),
salt_(0)
{
}
-void strand_service::shutdown_service()
+void strand_service::shutdown()
{
op_queue<operation> ops;
@@ -93,9 +93,9 @@ bool strand_service::running_in_this_thread(
bool strand_service::do_dispatch(implementation_type& impl, operation* op)
{
- // If we are running inside the io_service, and no other handler already
+ // 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_service_.can_dispatch();
+ bool can_dispatch = io_context_.can_dispatch();
impl->mutex_.lock();
if (can_dispatch && !impl->locked_)
{
@@ -118,7 +118,7 @@ bool strand_service::do_dispatch(implementation_type& impl, operation* op)
impl->locked_ = true;
impl->mutex_.unlock();
impl->ready_queue_.push(op);
- io_service_.post_immediate_completion(impl, false);
+ io_context_.post_immediate_completion(impl, false);
}
return false;
@@ -141,11 +141,11 @@ void strand_service::do_post(implementation_type& impl,
impl->locked_ = true;
impl->mutex_.unlock();
impl->ready_queue_.push(op);
- io_service_.post_immediate_completion(impl, is_continuation);
+ io_context_.post_immediate_completion(impl, is_continuation);
}
}
-void strand_service::do_complete(io_service_impl* owner, operation* base,
+void strand_service::do_complete(void* owner, operation* base,
const boost::system::error_code& ec, std::size_t /*bytes_transferred*/)
{
if (owner)
@@ -156,15 +156,16 @@ void strand_service::do_complete(io_service_impl* owner, operation* base,
call_stack<strand_impl>::context ctx(impl);
// Ensure the next handler, if any, is scheduled on block exit.
- on_do_complete_exit on_exit = { owner, impl };
- (void)on_exit;
+ 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);
+ o->complete(owner, ec, 0);
}
}
}
diff --git a/boost/asio/detail/impl/task_io_service.hpp b/boost/asio/detail/impl/task_io_service.hpp
deleted file mode 100644
index 09b4ba6985..0000000000
--- a/boost/asio/detail/impl/task_io_service.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// detail/impl/task_io_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//
-// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
-#define BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1200)
-# pragma once
-#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-
-#include <boost/asio/detail/addressof.hpp>
-#include <boost/asio/detail/completion_handler.hpp>
-#include <boost/asio/detail/fenced_block.hpp>
-#include <boost/asio/detail/handler_alloc_helpers.hpp>
-#include <boost/asio/detail/handler_cont_helpers.hpp>
-#include <boost/asio/detail/handler_invoke_helpers.hpp>
-
-#include <boost/asio/detail/push_options.hpp>
-
-namespace boost {
-namespace asio {
-namespace detail {
-
-template <typename Handler>
-void task_io_service::dispatch(Handler& handler)
-{
- if (thread_call_stack::contains(this))
- {
- fenced_block b(fenced_block::full);
- boost_asio_handler_invoke_helpers::invoke(handler, handler);
- }
- else
- {
- // Allocate and construct an operation to wrap the handler.
- typedef completion_handler<Handler> op;
- typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
- p.p = new (p.v) op(handler);
-
- BOOST_ASIO_HANDLER_CREATION((p.p, "io_service", this, "dispatch"));
-
- do_dispatch(p.p);
- p.v = p.p = 0;
- }
-}
-
-template <typename Handler>
-void task_io_service::post(Handler& handler)
-{
- bool is_continuation =
- boost_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 = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
- p.p = new (p.v) op(handler);
-
- BOOST_ASIO_HANDLER_CREATION((p.p, "io_service", this, "post"));
-
- post_immediate_completion(p.p, is_continuation);
- p.v = p.p = 0;
-}
-
-} // namespace detail
-} // namespace asio
-} // namespace boost
-
-#include <boost/asio/detail/pop_options.hpp>
-
-#endif // BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP
diff --git a/boost/asio/detail/impl/timer_queue_ptime.ipp b/boost/asio/detail/impl/timer_queue_ptime.ipp
index 0216d20ba5..885ee7d06e 100644
--- a/boost/asio/detail/impl/timer_queue_ptime.ipp
+++ b/boost/asio/detail/impl/timer_queue_ptime.ipp
@@ -16,12 +16,13 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
+
+#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
+
#include <boost/asio/detail/timer_queue_ptime.hpp>
#include <boost/asio/detail/push_options.hpp>
-#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
-
namespace boost {
namespace asio {
namespace detail {
@@ -75,12 +76,18 @@ std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer(
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
} // namespace boost
-#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
-
#include <boost/asio/detail/pop_options.hpp>
+#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
+
#endif // BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP
diff --git a/boost/asio/detail/impl/win_event.ipp b/boost/asio/detail/impl/win_event.ipp
index 2519d3165d..4e084de2ba 100644
--- a/boost/asio/detail/impl/win_event.ipp
+++ b/boost/asio/detail/impl/win_event.ipp
@@ -33,7 +33,8 @@ win_event::win_event()
: state_(0)
{
#if defined(BOOST_ASIO_WINDOWS_APP)
- events_[0] = ::CreateEventExW(0, 0, CREATE_EVENT_MANUAL_RESET, 0);
+ events_[0] = ::CreateEventExW(0, 0,
+ CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
#else // defined(BOOST_ASIO_WINDOWS_APP)
events_[0] = ::CreateEventW(0, true, false, 0);
#endif // defined(BOOST_ASIO_WINDOWS_APP)
@@ -46,7 +47,7 @@ win_event::win_event()
}
#if defined(BOOST_ASIO_WINDOWS_APP)
- events_[1] = ::CreateEventExW(0, 0, 0, 0);
+ events_[1] = ::CreateEventExW(0, 0, 0, EVENT_ALL_ACCESS);
#else // defined(BOOST_ASIO_WINDOWS_APP)
events_[1] = ::CreateEventW(0, false, false, 0);
#endif // defined(BOOST_ASIO_WINDOWS_APP)
diff --git a/boost/asio/detail/impl/win_iocp_handle_service.ipp b/boost/asio/detail/impl/win_iocp_handle_service.ipp
index ea513bc1dd..4f35a1c0a8 100644
--- a/boost/asio/detail/impl/win_iocp_handle_service.ipp
+++ b/boost/asio/detail/impl/win_iocp_handle_service.ipp
@@ -67,14 +67,15 @@ public:
};
win_iocp_handle_service::win_iocp_handle_service(
- boost::asio::io_service& io_service)
- : iocp_service_(boost::asio::use_service<win_iocp_io_service>(io_service)),
+ boost::asio::io_context& io_context)
+ : service_base<win_iocp_handle_service>(io_context),
+ iocp_service_(boost::asio::use_service<win_iocp_io_context>(io_context)),
mutex_(),
impl_list_(0)
{
}
-void win_iocp_handle_service::shutdown_service()
+void win_iocp_handle_service::shutdown()
{
// Close all implementations, causing all operations to complete.
boost::asio::detail::mutex::scoped_lock lock(mutex_);
@@ -200,7 +201,8 @@ boost::system::error_code win_iocp_handle_service::close(
{
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("handle", &impl, "close"));
+ BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close"));
if (!::CloseHandle(impl.handle_))
{
@@ -234,7 +236,8 @@ boost::system::error_code win_iocp_handle_service::cancel(
return ec;
}
- BOOST_ASIO_HANDLER_OPERATION(("handle", &impl, "cancel"));
+ BOOST_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"))
@@ -304,7 +307,7 @@ size_t win_iocp_handle_service::do_write(
}
// A request to write 0 bytes on a handle is a no-op.
- if (boost::asio::buffer_size(buffer) == 0)
+ if (buffer.size() == 0)
{
ec = boost::system::error_code();
return 0;
@@ -319,9 +322,8 @@ size_t win_iocp_handle_service::do_write(
// Write the data.
overlapped.Offset = offset & 0xFFFFFFFF;
overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
- BOOL ok = ::WriteFile(impl.handle_,
- boost::asio::buffer_cast<LPCVOID>(buffer),
- static_cast<DWORD>(boost::asio::buffer_size(buffer)), 0, &overlapped);
+ BOOL ok = ::WriteFile(impl.handle_, buffer.data(),
+ static_cast<DWORD>(buffer.size()), 0, &overlapped);
if (!ok)
{
DWORD last_error = ::GetLastError();
@@ -360,7 +362,7 @@ void win_iocp_handle_service::start_write_op(
{
iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
}
- else if (boost::asio::buffer_size(buffer) == 0)
+ else if (buffer.size() == 0)
{
// A request to write 0 bytes on a handle is a no-op.
iocp_service_.on_completion(op);
@@ -370,9 +372,8 @@ void win_iocp_handle_service::start_write_op(
DWORD bytes_transferred = 0;
op->Offset = offset & 0xFFFFFFFF;
op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
- BOOL ok = ::WriteFile(impl.handle_,
- boost::asio::buffer_cast<LPCVOID>(buffer),
- static_cast<DWORD>(boost::asio::buffer_size(buffer)),
+ 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
@@ -398,7 +399,7 @@ size_t win_iocp_handle_service::do_read(
}
// A request to read 0 bytes on a stream handle is a no-op.
- if (boost::asio::buffer_size(buffer) == 0)
+ if (buffer.size() == 0)
{
ec = boost::system::error_code();
return 0;
@@ -413,9 +414,8 @@ size_t win_iocp_handle_service::do_read(
// Read some data.
overlapped.Offset = offset & 0xFFFFFFFF;
overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
- BOOL ok = ::ReadFile(impl.handle_,
- boost::asio::buffer_cast<LPVOID>(buffer),
- static_cast<DWORD>(boost::asio::buffer_size(buffer)), 0, &overlapped);
+ BOOL ok = ::ReadFile(impl.handle_, buffer.data(),
+ static_cast<DWORD>(buffer.size()), 0, &overlapped);
if (!ok)
{
DWORD last_error = ::GetLastError();
@@ -468,7 +468,7 @@ void win_iocp_handle_service::start_read_op(
{
iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
}
- else if (boost::asio::buffer_size(buffer) == 0)
+ else if (buffer.size() == 0)
{
// A request to read 0 bytes on a handle is a no-op.
iocp_service_.on_completion(op);
@@ -478,9 +478,8 @@ void win_iocp_handle_service::start_read_op(
DWORD bytes_transferred = 0;
op->Offset = offset & 0xFFFFFFFF;
op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
- BOOL ok = ::ReadFile(impl.handle_,
- boost::asio::buffer_cast<LPVOID>(buffer),
- static_cast<DWORD>(boost::asio::buffer_size(buffer)),
+ 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
@@ -508,7 +507,8 @@ void win_iocp_handle_service::close_for_destruction(implementation_type& impl)
{
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("handle", &impl, "close"));
+ BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close"));
::CloseHandle(impl.handle_);
impl.handle_ = INVALID_HANDLE_VALUE;
diff --git a/boost/asio/detail/impl/win_iocp_io_service.hpp b/boost/asio/detail/impl/win_iocp_io_context.hpp
index e3505cb852..948b0c93d4 100644
--- a/boost/asio/detail/impl/win_iocp_io_service.hpp
+++ b/boost/asio/detail/impl/win_iocp_io_context.hpp
@@ -1,5 +1,5 @@
//
-// detail/impl/win_iocp_io_service.hpp
+// detail/impl/win_iocp_io_context.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
@@ -8,8 +8,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
-#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
+#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP
+#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -19,11 +19,11 @@
#if defined(BOOST_ASIO_HAS_IOCP)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/completion_handler.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -31,62 +31,22 @@ namespace boost {
namespace asio {
namespace detail {
-template <typename Handler>
-void win_iocp_io_service::dispatch(Handler& handler)
-{
- if (thread_call_stack::contains(this))
- {
- fenced_block b(fenced_block::full);
- boost_asio_handler_invoke_helpers::invoke(handler, handler);
- }
- else
- {
- // Allocate and construct an operation to wrap the handler.
- typedef completion_handler<Handler> op;
- typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
- p.p = new (p.v) op(handler);
-
- BOOST_ASIO_HANDLER_CREATION((p.p, "io_service", this, "dispatch"));
-
- post_immediate_completion(p.p, false);
- p.v = p.p = 0;
- }
-}
-
-template <typename Handler>
-void win_iocp_io_service::post(Handler& handler)
-{
- // Allocate and construct an operation to wrap the handler.
- typedef completion_handler<Handler> op;
- typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
- p.p = new (p.v) op(handler);
-
- BOOST_ASIO_HANDLER_CREATION((p.p, "io_service", this, "post"));
-
- post_immediate_completion(p.p, false);
- p.v = p.p = 0;
-}
-
template <typename Time_Traits>
-void win_iocp_io_service::add_timer_queue(
+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_service::remove_timer_queue(
+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_service::schedule_timer(timer_queue<Time_Traits>& queue,
+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)
{
@@ -106,7 +66,7 @@ void win_iocp_io_service::schedule_timer(timer_queue<Time_Traits>& queue,
}
template <typename Time_Traits>
-std::size_t win_iocp_io_service::cancel_timer(timer_queue<Time_Traits>& queue,
+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)
{
@@ -121,6 +81,19 @@ std::size_t win_iocp_io_service::cancel_timer(timer_queue<Time_Traits>& queue,
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)
+{
+ boost::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
} // namespace boost
@@ -129,4 +102,4 @@ std::size_t win_iocp_io_service::cancel_timer(timer_queue<Time_Traits>& queue,
#endif // defined(BOOST_ASIO_HAS_IOCP)
-#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP
+#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP
diff --git a/boost/asio/detail/impl/win_iocp_io_service.ipp b/boost/asio/detail/impl/win_iocp_io_context.ipp
index a5bfcbbdea..9071836aa9 100644
--- a/boost/asio/detail/impl/win_iocp_io_service.ipp
+++ b/boost/asio/detail/impl/win_iocp_io_context.ipp
@@ -1,5 +1,5 @@
//
-// detail/impl/win_iocp_io_service.ipp
+// detail/impl/win_iocp_io_context.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
@@ -8,8 +8,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
-#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
+#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP
+#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -20,13 +20,12 @@
#if defined(BOOST_ASIO_HAS_IOCP)
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
#include <boost/asio/detail/cstdint.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/limits.hpp>
#include <boost/asio/detail/throw_error.hpp>
-#include <boost/asio/detail/win_iocp_io_service.hpp>
+#include <boost/asio/detail/win_iocp_io_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -34,51 +33,51 @@ namespace boost {
namespace asio {
namespace detail {
-struct win_iocp_io_service::work_finished_on_block_exit
+struct win_iocp_io_context::work_finished_on_block_exit
{
~work_finished_on_block_exit()
{
- io_service_->work_finished();
+ io_context_->work_finished();
}
- win_iocp_io_service* io_service_;
+ win_iocp_io_context* io_context_;
};
-struct win_iocp_io_service::timer_thread_function
+struct win_iocp_io_context::timer_thread_function
{
void operator()()
{
- while (::InterlockedExchangeAdd(&io_service_->shutdown_, 0) == 0)
+ while (::InterlockedExchangeAdd(&io_context_->shutdown_, 0) == 0)
{
- if (::WaitForSingleObject(io_service_->waitable_timer_.handle,
+ if (::WaitForSingleObject(io_context_->waitable_timer_.handle,
INFINITE) == WAIT_OBJECT_0)
{
- ::InterlockedExchange(&io_service_->dispatch_required_, 1);
- ::PostQueuedCompletionStatus(io_service_->iocp_.handle,
+ ::InterlockedExchange(&io_context_->dispatch_required_, 1);
+ ::PostQueuedCompletionStatus(io_context_->iocp_.handle,
0, wake_for_dispatch, 0);
}
}
}
- win_iocp_io_service* io_service_;
+ win_iocp_io_context* io_context_;
};
-win_iocp_io_service::win_iocp_io_service(
- boost::asio::io_service& io_service, size_t concurrency_hint)
- : boost::asio::detail::service_base<win_iocp_io_service>(io_service),
+win_iocp_io_context::win_iocp_io_context(
+ boost::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)
+ dispatch_required_(0),
+ concurrency_hint_(concurrency_hint)
{
BOOST_ASIO_HANDLER_TRACKING_INIT;
iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
- static_cast<DWORD>(concurrency_hint < DWORD(~0)
- ? concurrency_hint : DWORD(~0)));
+ static_cast<DWORD>(concurrency_hint >= 0 ? concurrency_hint : DWORD(~0)));
if (!iocp_.handle)
{
DWORD last_error = ::GetLastError();
@@ -88,7 +87,7 @@ win_iocp_io_service::win_iocp_io_service(
}
}
-void win_iocp_io_service::shutdown_service()
+void win_iocp_io_context::shutdown()
{
::InterlockedExchange(&shutdown_, 1);
@@ -132,7 +131,7 @@ void win_iocp_io_service::shutdown_service()
timer_thread_->join();
}
-boost::system::error_code win_iocp_io_service::register_handle(
+boost::system::error_code win_iocp_io_context::register_handle(
HANDLE handle, boost::system::error_code& ec)
{
if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
@@ -148,7 +147,7 @@ boost::system::error_code win_iocp_io_service::register_handle(
return ec;
}
-size_t win_iocp_io_service::run(boost::system::error_code& ec)
+size_t win_iocp_io_context::run(boost::system::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
@@ -161,13 +160,13 @@ size_t win_iocp_io_service::run(boost::system::error_code& ec)
thread_call_stack::context ctx(this, this_thread);
size_t n = 0;
- while (do_one(true, ec))
+ while (do_one(INFINITE, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
-size_t win_iocp_io_service::run_one(boost::system::error_code& ec)
+size_t win_iocp_io_context::run_one(boost::system::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
@@ -179,10 +178,25 @@ size_t win_iocp_io_service::run_one(boost::system::error_code& ec)
win_iocp_thread_info this_thread;
thread_call_stack::context ctx(this, this_thread);
- return do_one(true, ec);
+ return do_one(INFINITE, ec);
}
-size_t win_iocp_io_service::poll(boost::system::error_code& ec)
+size_t win_iocp_io_context::wait_one(long usec, boost::system::error_code& ec)
+{
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ stop();
+ ec = boost::system::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(boost::system::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
@@ -195,13 +209,13 @@ size_t win_iocp_io_service::poll(boost::system::error_code& ec)
thread_call_stack::context ctx(this, this_thread);
size_t n = 0;
- while (do_one(false, ec))
+ while (do_one(0, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
-size_t win_iocp_io_service::poll_one(boost::system::error_code& ec)
+size_t win_iocp_io_context::poll_one(boost::system::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
@@ -213,10 +227,10 @@ size_t win_iocp_io_service::poll_one(boost::system::error_code& ec)
win_iocp_thread_info this_thread;
thread_call_stack::context ctx(this, this_thread);
- return do_one(false, ec);
+ return do_one(0, ec);
}
-void win_iocp_io_service::stop()
+void win_iocp_io_context::stop()
{
if (::InterlockedExchange(&stopped_, 1) == 0)
{
@@ -233,7 +247,7 @@ void win_iocp_io_service::stop()
}
}
-void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op)
+void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op)
{
// Flag the operation as ready.
op->ready_ = 1;
@@ -248,7 +262,7 @@ void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op)
}
}
-void win_iocp_io_service::post_deferred_completions(
+void win_iocp_io_context::post_deferred_completions(
op_queue<win_iocp_operation>& ops)
{
while (win_iocp_operation* op = ops.front())
@@ -270,7 +284,7 @@ void win_iocp_io_service::post_deferred_completions(
}
}
-void win_iocp_io_service::abandon_operations(
+void win_iocp_io_context::abandon_operations(
op_queue<win_iocp_operation>& ops)
{
while (win_iocp_operation* op = ops.front())
@@ -281,7 +295,7 @@ void win_iocp_io_service::abandon_operations(
}
}
-void win_iocp_io_service::on_pending(win_iocp_operation* op)
+void win_iocp_io_context::on_pending(win_iocp_operation* op)
{
if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
{
@@ -297,7 +311,7 @@ void win_iocp_io_service::on_pending(win_iocp_operation* op)
}
}
-void win_iocp_io_service::on_completion(win_iocp_operation* op,
+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.
@@ -320,7 +334,7 @@ void win_iocp_io_service::on_completion(win_iocp_operation* op,
}
}
-void win_iocp_io_service::on_completion(win_iocp_operation* op,
+void win_iocp_io_context::on_completion(win_iocp_operation* op,
const boost::system::error_code& ec, DWORD bytes_transferred)
{
// Flag that the operation is ready for invocation.
@@ -342,7 +356,7 @@ void win_iocp_io_service::on_completion(win_iocp_operation* op,
}
}
-size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec)
+size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec)
{
for (;;)
{
@@ -364,8 +378,9 @@ size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec)
dword_ptr_t completion_key = 0;
LPOVERLAPPED overlapped = 0;
::SetLastError(0);
- BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
- &completion_key, &overlapped, block ? gqcs_timeout_ : 0);
+ BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle,
+ &bytes_transferred, &completion_key, &overlapped,
+ msec < gqcs_timeout_ ? msec : gqcs_timeout_);
DWORD last_error = ::GetLastError();
if (overlapped)
@@ -402,7 +417,7 @@ size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec)
work_finished_on_block_exit on_exit = { this };
(void)on_exit;
- op->complete(*this, result_ec, bytes_transferred);
+ op->complete(this, result_ec, bytes_transferred);
ec = boost::system::error_code();
return 1;
}
@@ -416,8 +431,9 @@ size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec)
return 0;
}
- // If we're not polling we need to keep going until we get a real handler.
- if (block)
+ // If we're waiting indefinitely we need to keep going until we get a
+ // real handler.
+ if (msec == INFINITE)
continue;
ec = boost::system::error_code();
@@ -456,7 +472,7 @@ size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec)
}
}
-DWORD win_iocp_io_service::get_gqcs_timeout()
+DWORD win_iocp_io_context::get_gqcs_timeout()
{
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(osvi));
@@ -472,7 +488,7 @@ DWORD win_iocp_io_service::get_gqcs_timeout()
return default_gqcs_timeout;
}
-void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue)
+void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(dispatch_mutex_);
@@ -503,14 +519,14 @@ void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue)
}
}
-void win_iocp_io_service::do_remove_timer_queue(timer_queue_base& queue)
+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_service::update_timeout()
+void win_iocp_io_context::update_timeout()
{
if (timer_thread_.get())
{
@@ -537,4 +553,4 @@ void win_iocp_io_service::update_timeout()
#endif // defined(BOOST_ASIO_HAS_IOCP)
-#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP
+#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP
diff --git a/boost/asio/detail/impl/win_iocp_serial_port_service.ipp b/boost/asio/detail/impl/win_iocp_serial_port_service.ipp
index 32ba34684b..c0d2dbbd59 100644
--- a/boost/asio/detail/impl/win_iocp_serial_port_service.ipp
+++ b/boost/asio/detail/impl/win_iocp_serial_port_service.ipp
@@ -30,12 +30,13 @@ namespace asio {
namespace detail {
win_iocp_serial_port_service::win_iocp_serial_port_service(
- boost::asio::io_service& io_service)
- : handle_service_(io_service)
+ boost::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_service()
+void win_iocp_serial_port_service::shutdown()
{
}
diff --git a/boost/asio/detail/impl/win_iocp_socket_service_base.ipp b/boost/asio/detail/impl/win_iocp_socket_service_base.ipp
index 93f5ed0713..e9a5049345 100644
--- a/boost/asio/detail/impl/win_iocp_socket_service_base.ipp
+++ b/boost/asio/detail/impl/win_iocp_socket_service_base.ipp
@@ -28,24 +28,24 @@ namespace asio {
namespace detail {
win_iocp_socket_service_base::win_iocp_socket_service_base(
- boost::asio::io_service& io_service)
- : io_service_(io_service),
- iocp_service_(use_service<win_iocp_io_service>(io_service)),
+ boost::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::shutdown_service()
+void win_iocp_socket_service_base::base_shutdown()
{
// Close all implementations, causing all operations to complete.
boost::asio::detail::mutex::scoped_lock lock(mutex_);
base_implementation_type* impl = impl_list_;
while (impl)
{
- boost::system::error_code ignored_ec;
close_for_destruction(*impl);
impl = impl->next_;
}
@@ -167,12 +167,13 @@ boost::system::error_code win_iocp_socket_service_base::close(
{
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close"));
+ BOOST_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.
- reactor* r = static_cast<reactor*>(
+ select_reactor* r = static_cast<select_reactor*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (r)
@@ -198,6 +199,39 @@ boost::system::error_code win_iocp_socket_service_base::close(
return ec;
}
+socket_type win_iocp_socket_service_base::release(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ boost::system::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 = boost::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 = boost::asio::error::operation_not_supported;
+ return invalid_socket;
+ }
+
+ socket_type tmp = impl.socket_;
+ impl.socket_ = invalid_socket;
+ return tmp;
+}
+
boost::system::error_code win_iocp_socket_service_base::cancel(
win_iocp_socket_service_base::base_implementation_type& impl,
boost::system::error_code& ec)
@@ -208,7 +242,8 @@ boost::system::error_code win_iocp_socket_service_base::cancel(
return ec;
}
- BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "cancel"));
+ BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(),
+ "socket", &impl, impl.socket_, "cancel"));
if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
@@ -279,7 +314,7 @@ boost::system::error_code win_iocp_socket_service_base::cancel(
// Cancel any operations started via the reactor.
if (!ec)
{
- reactor* r = static_cast<reactor*>(
+ select_reactor* r = static_cast<select_reactor*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (r)
@@ -445,7 +480,7 @@ void win_iocp_socket_service_base::start_null_buffers_receive_op(
{
start_reactor_op(impl,
(flags & socket_base::message_out_of_band)
- ? reactor::except_op : reactor::read_op,
+ ? select_reactor::except_op : select_reactor::read_op,
op);
}
}
@@ -537,7 +572,7 @@ void win_iocp_socket_service_base::start_reactor_op(
win_iocp_socket_service_base::base_implementation_type& impl,
int op_type, reactor_op* op)
{
- reactor& r = get_reactor();
+ select_reactor& r = get_reactor();
update_cancellation_thread_id(impl);
if (is_open(impl))
@@ -598,7 +633,7 @@ void win_iocp_socket_service_base::start_connect_op(
}
// Otherwise, fall back to a reactor-based implementation.
- reactor& r = get_reactor();
+ select_reactor& r = get_reactor();
update_cancellation_thread_id(impl);
if ((impl.state_ & socket_ops::non_blocking) != 0
@@ -611,7 +646,7 @@ void win_iocp_socket_service_base::start_connect_op(
|| op->ec_ == boost::asio::error::would_block)
{
op->ec_ = boost::system::error_code();
- r.start_op(reactor::connect_op, impl.socket_,
+ r.start_op(select_reactor::connect_op, impl.socket_,
impl.reactor_data_, op, false, false);
return;
}
@@ -626,12 +661,13 @@ void win_iocp_socket_service_base::close_for_destruction(
{
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close"));
+ BOOST_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.
- reactor* r = static_cast<reactor*>(
+ select_reactor* r = static_cast<select_reactor*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (r)
@@ -665,14 +701,14 @@ void win_iocp_socket_service_base::update_cancellation_thread_id(
#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
}
-reactor& win_iocp_socket_service_base::get_reactor()
+select_reactor& win_iocp_socket_service_base::get_reactor()
{
- reactor* r = static_cast<reactor*>(
+ select_reactor* r = static_cast<select_reactor*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
if (!r)
{
- r = &(use_service<reactor>(io_service_));
+ r = &(use_service<select_reactor>(io_context_));
interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
}
return *r;
@@ -713,6 +749,24 @@ win_iocp_socket_service_base::get_connect_ex(
#endif // defined(BOOST_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)
{
diff --git a/boost/asio/detail/impl/win_object_handle_service.ipp b/boost/asio/detail/impl/win_object_handle_service.ipp
index a940161cba..31718a012b 100644
--- a/boost/asio/detail/impl/win_object_handle_service.ipp
+++ b/boost/asio/detail/impl/win_object_handle_service.ipp
@@ -29,15 +29,16 @@ namespace asio {
namespace detail {
win_object_handle_service::win_object_handle_service(
- boost::asio::io_service& io_service)
- : io_service_(boost::asio::use_service<io_service_impl>(io_service)),
+ boost::asio::io_context& io_context)
+ : service_base<win_object_handle_service>(io_context),
+ io_context_(boost::asio::use_service<io_context_impl>(io_context)),
mutex_(),
impl_list_(0),
shutdown_(false)
{
}
-void win_object_handle_service::shutdown_service()
+void win_object_handle_service::shutdown()
{
mutex::scoped_lock lock(mutex_);
@@ -52,7 +53,7 @@ void win_object_handle_service::shutdown_service()
lock.unlock();
- io_service_.abandon_operations(ops);
+ io_context_.abandon_operations(ops);
}
void win_object_handle_service::construct(
@@ -178,7 +179,8 @@ void win_object_handle_service::destroy(
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "close"));
+ BOOST_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;
@@ -202,7 +204,7 @@ void win_object_handle_service::destroy(
::CloseHandle(impl.handle_);
impl.handle_ = INVALID_HANDLE_VALUE;
- io_service_.post_deferred_completions(ops);
+ io_context_.post_deferred_completions(ops);
}
}
@@ -227,7 +229,8 @@ boost::system::error_code win_object_handle_service::close(
{
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "close"));
+ BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
mutex::scoped_lock lock(mutex_);
@@ -262,7 +265,7 @@ boost::system::error_code win_object_handle_service::close(
boost::asio::error::get_system_category());
}
- io_service_.post_deferred_completions(completed_ops);
+ io_context_.post_deferred_completions(completed_ops);
}
else
{
@@ -278,7 +281,8 @@ boost::system::error_code win_object_handle_service::cancel(
{
if (is_open(impl))
{
- BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "cancel"));
+ BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel"));
mutex::scoped_lock lock(mutex_);
@@ -303,7 +307,7 @@ boost::system::error_code win_object_handle_service::cancel(
ec = boost::system::error_code();
- io_service_.post_deferred_completions(completed_ops);
+ io_context_.post_deferred_completions(completed_ops);
}
else
{
@@ -337,7 +341,7 @@ void win_object_handle_service::wait(
void win_object_handle_service::start_wait_op(
win_object_handle_service::implementation_type& impl, wait_op* op)
{
- io_service_.work_started();
+ io_context_.work_started();
if (is_open(impl))
{
@@ -355,13 +359,13 @@ void win_object_handle_service::start_wait_op(
else
{
lock.unlock();
- io_service_.post_deferred_completion(op);
+ io_context_.post_deferred_completion(op);
}
}
else
{
op->ec_ = boost::asio::error::bad_descriptor;
- io_service_.post_deferred_completion(op);
+ io_context_.post_deferred_completion(op);
}
}
@@ -388,7 +392,7 @@ void win_object_handle_service::register_wait_callback(
}
lock.unlock();
- io_service_.post_deferred_completions(completed_ops);
+ io_context_.post_deferred_completions(completed_ops);
}
}
@@ -430,9 +434,9 @@ void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)
}
}
- io_service_impl& ios = impl->owner_->io_service_;
+ io_context_impl& ioc = impl->owner_->io_context_;
lock.unlock();
- ios.post_deferred_completions(completed_ops);
+ ioc.post_deferred_completions(completed_ops);
}
}
diff --git a/boost/asio/detail/impl/win_thread.ipp b/boost/asio/detail/impl/win_thread.ipp
index e2d9384007..c90c3f3986 100644
--- a/boost/asio/detail/impl/win_thread.ipp
+++ b/boost/asio/detail/impl/win_thread.ipp
@@ -56,6 +56,13 @@ void win_thread::join()
}
}
+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;
diff --git a/boost/asio/detail/impl/win_tss_ptr.ipp b/boost/asio/detail/impl/win_tss_ptr.ipp
index 3390066695..105cf3022c 100644
--- a/boost/asio/detail/impl/win_tss_ptr.ipp
+++ b/boost/asio/detail/impl/win_tss_ptr.ipp
@@ -32,9 +32,9 @@ namespace detail {
DWORD win_tss_ptr_create()
{
#if defined(UNDER_CE)
- enum { out_of_indexes = 0xFFFFFFFF };
+ const DWORD out_of_indexes = 0xFFFFFFFF;
#else
- enum { out_of_indexes = TLS_OUT_OF_INDEXES };
+ const DWORD out_of_indexes = TLS_OUT_OF_INDEXES;
#endif
DWORD tss_key = ::TlsAlloc();
diff --git a/boost/asio/detail/impl/winrt_ssocket_service_base.ipp b/boost/asio/detail/impl/winrt_ssocket_service_base.ipp
index f5990a97ad..a7a340b70b 100644
--- a/boost/asio/detail/impl/winrt_ssocket_service_base.ipp
+++ b/boost/asio/detail/impl/winrt_ssocket_service_base.ipp
@@ -31,15 +31,15 @@ namespace asio {
namespace detail {
winrt_ssocket_service_base::winrt_ssocket_service_base(
- boost::asio::io_service& io_service)
- : io_service_(use_service<io_service_impl>(io_service)),
- async_manager_(use_service<winrt_async_manager>(io_service)),
+ boost::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::shutdown_service()
+void winrt_ssocket_service_base::base_shutdown()
{
// Close all implementations, causing all operations to complete.
boost::asio::detail::mutex::scoped_lock lock(mutex_);
@@ -149,6 +149,23 @@ boost::system::error_code winrt_ssocket_service_base::close(
return ec;
}
+winrt_ssocket_service_base::native_handle_type
+winrt_ssocket_service_base::release(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ boost::system::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, boost::system::error_code& ec) const
@@ -382,7 +399,7 @@ void winrt_ssocket_service_base::start_connect_op(
if (!is_open(impl))
{
op->ec_ = boost::asio::error::bad_descriptor;
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
return;
}
@@ -411,7 +428,7 @@ void winrt_ssocket_service_base::start_connect_op(
if (op->ec_)
{
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
return;
}
@@ -426,7 +443,7 @@ void winrt_ssocket_service_base::start_connect_op(
{
op->ec_ = boost::system::error_code(
e->HResult, boost::system::system_category());
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
}
}
@@ -450,7 +467,7 @@ std::size_t winrt_ssocket_service_base::do_send(
try
{
buffer_sequence_adapter<boost::asio::const_buffer,
- boost::asio::const_buffers_1> bufs(boost::asio::buffer(data));
+ boost::asio::const_buffer> bufs(boost::asio::buffer(data));
if (bufs.all_empty())
{
@@ -477,25 +494,25 @@ void winrt_ssocket_service_base::start_send_op(
if (flags)
{
op->ec_ = boost::asio::error::operation_not_supported;
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
return;
}
if (!is_open(impl))
{
op->ec_ = boost::asio::error::bad_descriptor;
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
return;
}
try
{
buffer_sequence_adapter<boost::asio::const_buffer,
- boost::asio::const_buffers_1> bufs(boost::asio::buffer(data));
+ boost::asio::const_buffer> bufs(boost::asio::buffer(data));
if (bufs.all_empty())
{
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
return;
}
@@ -506,7 +523,7 @@ void winrt_ssocket_service_base::start_send_op(
{
op->ec_ = boost::system::error_code(e->HResult,
boost::system::system_category());
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
}
}
@@ -530,7 +547,7 @@ std::size_t winrt_ssocket_service_base::do_receive(
try
{
buffer_sequence_adapter<boost::asio::mutable_buffer,
- boost::asio::mutable_buffers_1> bufs(boost::asio::buffer(data));
+ boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
if (bufs.all_empty())
{
@@ -568,25 +585,25 @@ void winrt_ssocket_service_base::start_receive_op(
if (flags)
{
op->ec_ = boost::asio::error::operation_not_supported;
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
return;
}
if (!is_open(impl))
{
op->ec_ = boost::asio::error::bad_descriptor;
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
return;
}
try
{
buffer_sequence_adapter<boost::asio::mutable_buffer,
- boost::asio::mutable_buffers_1> bufs(boost::asio::buffer(data));
+ boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
if (bufs.all_empty())
{
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
return;
}
@@ -599,7 +616,7 @@ void winrt_ssocket_service_base::start_receive_op(
{
op->ec_ = boost::system::error_code(e->HResult,
boost::system::system_category());
- io_service_.post_immediate_completion(op, is_continuation);
+ io_context_.post_immediate_completion(op, is_continuation);
}
}
diff --git a/boost/asio/detail/impl/winrt_timer_scheduler.hpp b/boost/asio/detail/impl/winrt_timer_scheduler.hpp
index 8d93e57962..b1522b4673 100644
--- a/boost/asio/detail/impl/winrt_timer_scheduler.hpp
+++ b/boost/asio/detail/impl/winrt_timer_scheduler.hpp
@@ -47,12 +47,12 @@ void winrt_timer_scheduler::schedule_timer(timer_queue<Time_Traits>& queue,
if (shutdown_)
{
- io_service_.post_immediate_completion(op, false);
+ io_context_.post_immediate_completion(op, false);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
- io_service_.work_started();
+ io_context_.work_started();
if (earliest)
event_.signal(lock);
}
@@ -66,10 +66,23 @@ std::size_t winrt_timer_scheduler::cancel_timer(timer_queue<Time_Traits>& queue,
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
lock.unlock();
- io_service_.post_deferred_completions(ops);
+ 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)
+{
+ boost::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
} // namespace boost
diff --git a/boost/asio/detail/impl/winrt_timer_scheduler.ipp b/boost/asio/detail/impl/winrt_timer_scheduler.ipp
index 914849d822..2e8145b6b8 100644
--- a/boost/asio/detail/impl/winrt_timer_scheduler.ipp
+++ b/boost/asio/detail/impl/winrt_timer_scheduler.ipp
@@ -29,9 +29,9 @@ namespace asio {
namespace detail {
winrt_timer_scheduler::winrt_timer_scheduler(
- boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<winrt_timer_scheduler>(io_service),
- io_service_(use_service<io_service_impl>(io_service)),
+ boost::asio::io_context& io_context)
+ : boost::asio::detail::service_base<winrt_timer_scheduler>(io_context),
+ io_context_(use_service<io_context_impl>(io_context)),
mutex_(),
event_(),
timer_queues_(),
@@ -45,10 +45,10 @@ winrt_timer_scheduler::winrt_timer_scheduler(
winrt_timer_scheduler::~winrt_timer_scheduler()
{
- shutdown_service();
+ shutdown();
}
-void winrt_timer_scheduler::shutdown_service()
+void winrt_timer_scheduler::shutdown()
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
@@ -65,10 +65,10 @@ void winrt_timer_scheduler::shutdown_service()
op_queue<operation> ops;
timer_queues_.get_all_timers(ops);
- io_service_.abandon_operations(ops);
+ io_context_.abandon_operations(ops);
}
-void winrt_timer_scheduler::fork_service(boost::asio::io_service::fork_event)
+void winrt_timer_scheduler::notify_fork(boost::asio::io_context::fork_event)
{
}
@@ -90,7 +90,7 @@ void winrt_timer_scheduler::run_thread()
if (!ops.empty())
{
lock.unlock();
- io_service_.post_deferred_completions(ops);
+ io_context_.post_deferred_completions(ops);
lock.lock();
}
}
diff --git a/boost/asio/detail/io_control.hpp b/boost/asio/detail/io_control.hpp
index 6c7527d1cf..d235fa1fda 100644
--- a/boost/asio/detail/io_control.hpp
+++ b/boost/asio/detail/io_control.hpp
@@ -26,56 +26,6 @@ namespace asio {
namespace detail {
namespace io_control {
-// IO control command for non-blocking I/O.
-class non_blocking_io
-{
-public:
- // Default constructor.
- non_blocking_io()
- : value_(0)
- {
- }
-
- // Construct with a specific command value.
- non_blocking_io(bool value)
- : value_(value ? 1 : 0)
- {
- }
-
- // Get the name of the IO control command.
- int name() const
- {
- return static_cast<int>(BOOST_ASIO_OS_DEF(FIONBIO));
- }
-
- // Set the value of the I/O control command.
- void set(bool value)
- {
- value_ = value ? 1 : 0;
- }
-
- // Get the current value of the I/O control command.
- bool get() const
- {
- return value_ != 0;
- }
-
- // 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_;
-};
-
// I/O control command for getting number of bytes available.
class bytes_readable
{
diff --git a/boost/asio/detail/is_buffer_sequence.hpp b/boost/asio/detail/is_buffer_sequence.hpp
new file mode 100644
index 0000000000..c788c55d28
--- /dev/null
+++ b/boost/asio/detail/is_buffer_sequence.hpp
@@ -0,0 +1,241 @@
+//
+// detail/is_buffer_sequence.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP
+#define BOOST_ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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>::data>*);
+
+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(BOOST_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(BOOST_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(BOOST_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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP
diff --git a/boost/asio/detail/is_executor.hpp b/boost/asio/detail/is_executor.hpp
new file mode 100644
index 0000000000..43db5d0120
--- /dev/null
+++ b/boost/asio/detail/is_executor.hpp
@@ -0,0 +1,128 @@
+//
+// detail/is_executor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_IS_EXECUTOR_HPP
+#define BOOST_ASIO_DETAIL_IS_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_IS_EXECUTOR_HPP
diff --git a/boost/asio/detail/kqueue_reactor.hpp b/boost/asio/detail/kqueue_reactor.hpp
index c6182b4d55..492b7ff016 100644
--- a/boost/asio/detail/kqueue_reactor.hpp
+++ b/boost/asio/detail/kqueue_reactor.hpp
@@ -35,7 +35,7 @@
#include <boost/asio/detail/timer_queue_set.hpp>
#include <boost/asio/detail/wait_op.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/execution_context.hpp>
// Older versions of Mac OS X may not define EV_OOBAND.
#if !defined(EV_OOBAND)
@@ -48,9 +48,15 @@ namespace boost {
namespace asio {
namespace detail {
+class scheduler;
+
class kqueue_reactor
- : public boost::asio::detail::service_base<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 };
@@ -58,6 +64,8 @@ public:
// Per-descriptor queues.
struct descriptor_state
{
+ descriptor_state(bool locking) : mutex_(locking) {}
+
friend class kqueue_reactor;
friend class object_pool_access;
@@ -75,17 +83,17 @@ public:
typedef descriptor_state* per_descriptor_data;
// Constructor.
- BOOST_ASIO_DECL kqueue_reactor(boost::asio::io_service& io_service);
+ BOOST_ASIO_DECL kqueue_reactor(boost::asio::execution_context& ctx);
// Destructor.
BOOST_ASIO_DECL ~kqueue_reactor();
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Recreate internal descriptors following a fork.
- BOOST_ASIO_DECL void fork_service(
- boost::asio::io_service::fork_event fork_ev);
+ BOOST_ASIO_DECL void notify_fork(
+ boost::asio::execution_context::fork_event fork_ev);
// Initialise the task.
BOOST_ASIO_DECL void init_task();
@@ -109,7 +117,7 @@ public:
// Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op, bool is_continuation)
{
- io_service_.post_immediate_completion(op, is_continuation);
+ scheduler_.post_immediate_completion(op, is_continuation);
}
// Start a new operation. The reactor operation will be performed when the
@@ -163,8 +171,14 @@ public:
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.
- BOOST_ASIO_DECL void run(bool block, op_queue<operation>& ops);
+ BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops);
// Interrupt the kqueue loop.
BOOST_ASIO_DECL void interrupt();
@@ -187,10 +201,10 @@ private:
BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
// Get the timeout value for the kevent call.
- BOOST_ASIO_DECL timespec* get_timeout(timespec& ts);
+ BOOST_ASIO_DECL timespec* get_timeout(long usec, timespec& ts);
- // The io_service implementation used to post completions.
- io_service_impl& io_service_;
+ // The scheduler used to post completions.
+ scheduler& scheduler_;
// Mutex to protect access to internal data.
mutex mutex_;
diff --git a/boost/asio/detail/macos_fenced_block.hpp b/boost/asio/detail/macos_fenced_block.hpp
index 5ab7f91c5e..20a995ebec 100644
--- a/boost/asio/detail/macos_fenced_block.hpp
+++ b/boost/asio/detail/macos_fenced_block.hpp
@@ -20,6 +20,7 @@
#if defined(__MACH__) && defined(__APPLE__)
#include <libkern/OSAtomic.h>
+#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/push_options.hpp>
diff --git a/boost/asio/detail/memory.hpp b/boost/asio/detail/memory.hpp
index 479b57a3d1..c0a205e169 100644
--- a/boost/asio/detail/memory.hpp
+++ b/boost/asio/detail/memory.hpp
@@ -18,14 +18,55 @@
#include <boost/asio/detail/config.hpp>
#include <memory>
+#if !defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
+# include <boost/shared_ptr.hpp>
+# include <boost/weak_ptr.hpp>
+#endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
+
+#if !defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
+# include <boost/utility/addressof.hpp>
+#endif // !defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
+using std::shared_ptr;
+using std::weak_ptr;
+#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
+using boost::shared_ptr;
+using boost::weak_ptr;
+#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
+
+#if defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
+using std::addressof;
+#else // defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
+using boost::addressof;
+#endif // defined(BOOST_ASIO_HAS_STD_ADDRESSOF)
+
+} // namespace detail
+
#if defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS)
+using std::allocator_arg_t;
+# define BOOST_ASIO_USES_ALLOCATOR(t) \
+ namespace std { \
+ template <typename Allocator> \
+ struct uses_allocator<t, Allocator> : true_type {}; \
+ } \
+ /**/
# define BOOST_ASIO_REBIND_ALLOC(alloc, t) \
typename std::allocator_traits<alloc>::template rebind_alloc<t>
/**/
#else // defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS)
+struct allocator_arg_t {};
+# define BOOST_ASIO_USES_ALLOCATOR(t)
# define BOOST_ASIO_REBIND_ALLOC(alloc, t) \
typename alloc::template rebind<t>::other
/**/
#endif // defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS)
+} // namespace asio
+} // namespace boost
+
#endif // BOOST_ASIO_DETAIL_MEMORY_HPP
diff --git a/boost/asio/detail/null_event.hpp b/boost/asio/detail/null_event.hpp
index 28ba5ede55..3bc74afb68 100644
--- a/boost/asio/detail/null_event.hpp
+++ b/boost/asio/detail/null_event.hpp
@@ -16,9 +16,6 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-
-#if !defined(BOOST_ASIO_HAS_THREADS)
-
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -76,7 +73,20 @@ public:
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:
+ BOOST_ASIO_DECL static void do_wait();
+ BOOST_ASIO_DECL static void do_wait_for_usec(long usec);
};
} // namespace detail
@@ -85,6 +95,8 @@ public:
#include <boost/asio/detail/pop_options.hpp>
-#endif // !defined(BOOST_ASIO_HAS_THREADS)
+#if defined(BOOST_ASIO_HEADER_ONLY)
+# include <boost/asio/detail/impl/null_event.ipp>
+#endif // defined(BOOST_ASIO_HEADER_ONLY)
#endif // BOOST_ASIO_DETAIL_NULL_EVENT_HPP
diff --git a/boost/asio/detail/null_fenced_block.hpp b/boost/asio/detail/null_fenced_block.hpp
index 27029b9e31..6d2b22f8cf 100644
--- a/boost/asio/detail/null_fenced_block.hpp
+++ b/boost/asio/detail/null_fenced_block.hpp
@@ -15,6 +15,8 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+#include <boost/asio/detail/noncopyable.hpp>
+
#include <boost/asio/detail/push_options.hpp>
namespace boost {
diff --git a/boost/asio/detail/null_global.hpp b/boost/asio/detail/null_global.hpp
new file mode 100644
index 0000000000..fa24b5cbaf
--- /dev/null
+++ b/boost/asio/detail/null_global.hpp
@@ -0,0 +1,61 @@
+//
+// detail/null_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_NULL_GLOBAL_HPP
+#define BOOST_ASIO_DETAIL_NULL_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_NULL_GLOBAL_HPP
diff --git a/boost/asio/detail/null_reactor.hpp b/boost/asio/detail/null_reactor.hpp
index 2cfce63a4c..30a07390a7 100644
--- a/boost/asio/detail/null_reactor.hpp
+++ b/boost/asio/detail/null_reactor.hpp
@@ -17,9 +17,10 @@
#include <boost/asio/detail/config.hpp>
-#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+#if defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME)
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/scheduler_operation.hpp>
+#include <boost/asio/execution_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -28,12 +29,12 @@ namespace asio {
namespace detail {
class null_reactor
- : public boost::asio::detail::service_base<null_reactor>
+ : public execution_context_service_base<null_reactor>
{
public:
// Constructor.
- null_reactor(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<null_reactor>(io_service)
+ null_reactor(boost::asio::execution_context& ctx)
+ : execution_context_service_base<null_reactor>(ctx)
{
}
@@ -43,12 +44,12 @@ public:
}
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
+ void shutdown()
{
}
// No-op because should never be called.
- void run(bool /*block*/, op_queue<operation>& /*ops*/)
+ void run(long /*usec*/, op_queue<scheduler_operation>& /*ops*/)
{
}
@@ -64,6 +65,6 @@ public:
#include <boost/asio/detail/pop_options.hpp>
-#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
+#endif // defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME)
#endif // BOOST_ASIO_DETAIL_NULL_REACTOR_HPP
diff --git a/boost/asio/detail/null_socket_service.hpp b/boost/asio/detail/null_socket_service.hpp
index bf06ebb545..73a11cf9e8 100644
--- a/boost/asio/detail/null_socket_service.hpp
+++ b/boost/asio/detail/null_socket_service.hpp
@@ -21,7 +21,7 @@
#include <boost/asio/buffer.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/socket_base.hpp>
#include <boost/asio/detail/bind_handler.hpp>
@@ -32,7 +32,8 @@ namespace asio {
namespace detail {
template <typename Protocol>
-class null_socket_service
+class null_socket_service :
+ public service_base<null_socket_service<Protocol> >
{
public:
// The protocol type.
@@ -50,13 +51,14 @@ public:
};
// Constructor.
- null_socket_service(boost::asio::io_service& io_service)
- : io_service_(io_service)
+ null_socket_service(boost::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_service()
+ void shutdown()
{
}
@@ -119,6 +121,14 @@ public:
return ec;
}
+ // Release ownership of the socket.
+ native_handle_type release(implementation_type&,
+ boost::system::error_code& ec)
+ {
+ ec = boost::asio::error::operation_not_supported;
+ return 0;
+ }
+
// Get the native socket representation.
native_handle_type native_handle(implementation_type&)
{
@@ -269,7 +279,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
}
// Start an asynchronous wait until data can be sent without blocking.
@@ -279,7 +289,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
}
// Receive some data from the peer. Returns the number of bytes received.
@@ -307,7 +317,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
}
// Wait until data can be received without blocking.
@@ -317,7 +327,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
}
// Receive some data with associated flags. Returns the number of bytes
@@ -349,7 +359,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
}
// Wait until data can be received without blocking.
@@ -360,7 +370,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
}
// Send a datagram to the specified endpoint. Returns the number of bytes
@@ -392,7 +402,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
}
// Start an asynchronous wait until data can be sent without blocking.
@@ -402,7 +412,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
}
// Receive a datagram with the endpoint of the sender. Returns the number of
@@ -435,7 +445,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
}
// Wait until data can be received without blocking.
@@ -446,7 +456,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
}
// Accept a new connection.
@@ -465,7 +475,7 @@ public:
endpoint_type*, Handler& handler)
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
- io_service_.post(detail::bind_handler(handler, ec));
+ io_context_.post(detail::bind_handler(handler, ec));
}
// Connect the socket to the specified endpoint.
@@ -482,11 +492,11 @@ public:
const endpoint_type&, Handler& handler)
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
- io_service_.post(detail::bind_handler(handler, ec));
+ io_context_.post(detail::bind_handler(handler, ec));
}
private:
- boost::asio::io_service& io_service_;
+ boost::asio::io_context& io_context_;
};
} // namespace detail
diff --git a/boost/asio/detail/null_thread.hpp b/boost/asio/detail/null_thread.hpp
index 5e9b458638..bdb9912be3 100644
--- a/boost/asio/detail/null_thread.hpp
+++ b/boost/asio/detail/null_thread.hpp
@@ -50,6 +50,12 @@ public:
void join()
{
}
+
+ // Get number of CPUs.
+ static std::size_t hardware_concurrency()
+ {
+ return 1;
+ }
};
} // namespace detail
diff --git a/boost/asio/detail/object_pool.hpp b/boost/asio/detail/object_pool.hpp
index 692efed09d..3affeb8dab 100644
--- a/boost/asio/detail/object_pool.hpp
+++ b/boost/asio/detail/object_pool.hpp
@@ -35,6 +35,12 @@ public:
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)
{
@@ -97,6 +103,25 @@ public:
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)
{
diff --git a/boost/asio/detail/operation.hpp b/boost/asio/detail/operation.hpp
index a186a1f4d8..be62d12514 100644
--- a/boost/asio/detail/operation.hpp
+++ b/boost/asio/detail/operation.hpp
@@ -20,7 +20,7 @@
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/win_iocp_operation.hpp>
#else
-# include <boost/asio/detail/task_io_service_operation.hpp>
+# include <boost/asio/detail/scheduler_operation.hpp>
#endif
namespace boost {
@@ -30,7 +30,7 @@ namespace detail {
#if defined(BOOST_ASIO_HAS_IOCP)
typedef win_iocp_operation operation;
#else
-typedef task_io_service_operation operation;
+typedef scheduler_operation operation;
#endif
} // namespace detail
diff --git a/boost/asio/detail/pop_options.hpp b/boost/asio/detail/pop_options.hpp
index 29213ede7b..7126d75040 100644
--- a/boost/asio/detail/pop_options.hpp
+++ b/boost/asio/detail/pop_options.hpp
@@ -67,6 +67,10 @@
# 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++
diff --git a/boost/asio/detail/posix_event.hpp b/boost/asio/detail/posix_event.hpp
index 4eae96e2a8..970f298638 100644
--- a/boost/asio/detail/posix_event.hpp
+++ b/boost/asio/detail/posix_event.hpp
@@ -108,6 +108,39 @@ public:
}
}
+ // Timed wait for the event to become signalled.
+ template <typename Lock>
+ bool wait_for_usec(Lock& lock, long usec)
+ {
+ BOOST_ASIO_ASSERT(lock.locked());
+ if ((state_ & 1) == 0)
+ {
+ state_ += 2;
+ timespec ts;
+#if (defined(__MACH__) && defined(__APPLE__)) \
+ || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
+ 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))
+ 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))
+ state_ -= 2;
+ }
+ return (state_ & 1) != 0;
+ }
+
private:
::pthread_cond_t cond_;
std::size_t state_;
diff --git a/boost/asio/detail/posix_global.hpp b/boost/asio/detail/posix_global.hpp
new file mode 100644
index 0000000000..463809fc29
--- /dev/null
+++ b/boost/asio/detail/posix_global.hpp
@@ -0,0 +1,82 @@
+//
+// detail/posix_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_POSIX_GLOBAL_HPP
+#define BOOST_ASIO_DETAIL_POSIX_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if defined(BOOST_ASIO_HAS_PTHREADS)
+
+#include <exception>
+#include <pthread.h>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // defined(BOOST_ASIO_HAS_PTHREADS)
+
+#endif // BOOST_ASIO_DETAIL_POSIX_GLOBAL_HPP
diff --git a/boost/asio/detail/posix_thread.hpp b/boost/asio/detail/posix_thread.hpp
index ddf5ba46f3..985e14028f 100644
--- a/boost/asio/detail/posix_thread.hpp
+++ b/boost/asio/detail/posix_thread.hpp
@@ -19,6 +19,7 @@
#if defined(BOOST_ASIO_HAS_PTHREADS)
+#include <cstddef>
#include <pthread.h>
#include <boost/asio/detail/noncopyable.hpp>
@@ -51,6 +52,9 @@ public:
// Wait for the thread to exit.
BOOST_ASIO_DECL void join();
+ // Get number of CPUs.
+ BOOST_ASIO_DECL static std::size_t hardware_concurrency();
+
private:
friend void* boost_asio_detail_posix_thread_function(void* arg);
diff --git a/boost/asio/detail/push_options.hpp b/boost/asio/detail/push_options.hpp
index ae189c0519..08e541d0d1 100644
--- a/boost/asio/detail/push_options.hpp
+++ b/boost/asio/detail/push_options.hpp
@@ -71,6 +71,11 @@
# 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++
@@ -135,6 +140,10 @@
# 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!
diff --git a/boost/asio/detail/reactive_descriptor_service.hpp b/boost/asio/detail/reactive_descriptor_service.hpp
index 3d6d1e98c8..f413edbc7b 100644
--- a/boost/asio/detail/reactive_descriptor_service.hpp
+++ b/boost/asio/detail/reactive_descriptor_service.hpp
@@ -22,17 +22,19 @@
&& !defined(__CYGWIN__)
#include <boost/asio/buffer.hpp>
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/descriptor_ops.hpp>
#include <boost/asio/detail/descriptor_read_op.hpp>
#include <boost/asio/detail/descriptor_write_op.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/reactive_null_buffers_op.hpp>
+#include <boost/asio/detail/reactive_wait_op.hpp>
#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/posix/descriptor_base.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -40,7 +42,8 @@ namespace boost {
namespace asio {
namespace detail {
-class reactive_descriptor_service
+class reactive_descriptor_service :
+ public service_base<reactive_descriptor_service>
{
public:
// The native type of a descriptor.
@@ -74,10 +77,10 @@ public:
// Constructor.
BOOST_ASIO_DECL reactive_descriptor_service(
- boost::asio::io_service& io_service);
+ boost::asio::io_context& io_context);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Construct a new descriptor implementation.
BOOST_ASIO_DECL void construct(implementation_type& impl);
@@ -162,6 +165,71 @@ public:
return ec;
}
+ // Wait for the descriptor to become ready to read, ready to write, or to have
+ // pending error conditions.
+ boost::system::error_code wait(implementation_type& impl,
+ posix::descriptor_base::wait_type w, boost::system::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 = boost::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 =
+ boost_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 = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_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_ = boost::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,
@@ -196,11 +264,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef descriptor_write_op<ConstBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.descriptor_, buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "descriptor", &impl, "async_write_some"));
+ BOOST_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<boost::asio::const_buffer,
@@ -219,12 +287,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "descriptor",
- &impl, "async_write_some(null_buffers)"));
+ BOOST_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;
@@ -264,11 +331,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef descriptor_read_op<MutableBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.descriptor_, buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "descriptor", &impl, "async_read_some"));
+ BOOST_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<boost::asio::mutable_buffer,
@@ -287,12 +354,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "descriptor",
- &impl, "async_read_some(null_buffers)"));
+ BOOST_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;
diff --git a/boost/asio/detail/reactive_null_buffers_op.hpp b/boost/asio/detail/reactive_null_buffers_op.hpp
index 4b1c7fedbf..0983b8a52e 100644
--- a/boost/asio/detail/reactive_null_buffers_op.hpp
+++ b/boost/asio/detail/reactive_null_buffers_op.hpp
@@ -16,10 +16,10 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -39,22 +39,24 @@ public:
&reactive_null_buffers_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static bool do_perform(reactor_op*)
+ static status do_perform(reactor_op*)
{
- return true;
+ return done;
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -72,7 +74,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/reactive_serial_port_service.hpp b/boost/asio/detail/reactive_serial_port_service.hpp
index 4976fbd08e..225f0828f5 100644
--- a/boost/asio/detail/reactive_serial_port_service.hpp
+++ b/boost/asio/detail/reactive_serial_port_service.hpp
@@ -23,7 +23,7 @@
#include <string>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/serial_port_base.hpp>
#include <boost/asio/detail/descriptor_ops.hpp>
#include <boost/asio/detail/reactive_descriptor_service.hpp>
@@ -35,7 +35,8 @@ namespace asio {
namespace detail {
// Extend reactive_descriptor_service to provide serial port support.
-class reactive_serial_port_service
+class reactive_serial_port_service :
+ public service_base<reactive_serial_port_service>
{
public:
// The native type of a serial port.
@@ -45,10 +46,10 @@ public:
typedef reactive_descriptor_service::implementation_type implementation_type;
BOOST_ASIO_DECL reactive_serial_port_service(
- boost::asio::io_service& io_service);
+ boost::asio::io_context& io_context);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Construct a new serial port implementation.
void construct(implementation_type& impl)
@@ -190,8 +191,8 @@ private:
static boost::system::error_code store_option(const void* option,
termios& storage, boost::system::error_code& ec)
{
- return static_cast<const SettableSerialPortOption*>(option)->store(
- storage, ec);
+ static_cast<const SettableSerialPortOption*>(option)->store(storage, ec);
+ return ec;
}
// Helper function to set a serial port option.
@@ -208,7 +209,8 @@ private:
static boost::system::error_code load_option(void* option,
const termios& storage, boost::system::error_code& ec)
{
- return static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+ static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+ return ec;
}
// Helper function to get a serial port option.
diff --git a/boost/asio/detail/reactive_socket_accept_op.hpp b/boost/asio/detail/reactive_socket_accept_op.hpp
index fec6bddb55..ca996b2ab5 100644
--- a/boost/asio/detail/reactive_socket_accept_op.hpp
+++ b/boost/asio/detail/reactive_socket_accept_op.hpp
@@ -16,10 +16,10 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_holder.hpp>
#include <boost/asio/detail/socket_ops.hpp>
@@ -42,40 +42,48 @@ public:
state_(state),
peer_(peer),
protocol_(protocol),
- peer_endpoint_(peer_endpoint)
+ peer_endpoint_(peer_endpoint),
+ addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0)
{
}
- static bool do_perform(reactor_op* base)
+ static status do_perform(reactor_op* base)
{
reactive_socket_accept_op_base* o(
static_cast<reactive_socket_accept_op_base*>(base));
- std::size_t addrlen = o->peer_endpoint_ ? o->peer_endpoint_->capacity() : 0;
socket_type new_socket = invalid_socket;
- bool result = socket_ops::non_blocking_accept(o->socket_,
- o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0,
- o->peer_endpoint_ ? &addrlen : 0, o->ec_, new_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);
- // On success, assign new connection to peer socket object.
- if (new_socket != invalid_socket)
- {
- socket_holder new_socket_holder(new_socket);
- if (o->peer_endpoint_)
- o->peer_endpoint_->resize(addrlen);
- if (!o->peer_.assign(o->protocol_, new_socket, o->ec_))
- new_socket_holder.release();
- }
+ BOOST_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>
@@ -92,17 +100,23 @@ public:
protocol, peer_endpoint, &reactive_socket_accept_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::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();
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -120,7 +134,72 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+#if defined(BOOST_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:
+ BOOST_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_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const boost::system::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 = { boost::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();
+
+ BOOST_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,
+ boost::system::error_code, typename Protocol::socket>
+ handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_,
+ BOOST_ASIO_MOVE_CAST(typename Protocol::socket)(*o));
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
@@ -129,6 +208,8 @@ private:
Handler handler_;
};
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
} // namespace detail
} // namespace asio
} // namespace boost
diff --git a/boost/asio/detail/reactive_socket_connect_op.hpp b/boost/asio/detail/reactive_socket_connect_op.hpp
index 809d63b7ae..410da203ad 100644
--- a/boost/asio/detail/reactive_socket_connect_op.hpp
+++ b/boost/asio/detail/reactive_socket_connect_op.hpp
@@ -16,10 +16,10 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_ops.hpp>
@@ -38,12 +38,17 @@ public:
{
}
- static bool do_perform(reactor_op* base)
+ static status do_perform(reactor_op* base)
{
reactive_socket_connect_op_base* o(
static_cast<reactive_socket_connect_op_base*>(base));
- return socket_ops::non_blocking_connect(o->socket_, o->ec_);
+ status result = socket_ops::non_blocking_connect(
+ o->socket_, o->ec_) ? done : not_done;
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_connect", o->ec_));
+
+ return result;
}
private:
@@ -61,9 +66,10 @@ public:
&reactive_socket_connect_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
@@ -71,8 +77,9 @@ public:
reactive_socket_connect_op* o
(static_cast<reactive_socket_connect_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -90,7 +97,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/reactive_socket_recv_op.hpp b/boost/asio/detail/reactive_socket_recv_op.hpp
index 751160c48f..ea7d84a0c5 100644
--- a/boost/asio/detail/reactive_socket_recv_op.hpp
+++ b/boost/asio/detail/reactive_socket_recv_op.hpp
@@ -16,10 +16,10 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_ops.hpp>
@@ -44,7 +44,7 @@ public:
{
}
- static bool do_perform(reactor_op* base)
+ static status do_perform(reactor_op* base)
{
reactive_socket_recv_op_base* o(
static_cast<reactive_socket_recv_op_base*>(base));
@@ -52,10 +52,20 @@ public:
buffer_sequence_adapter<boost::asio::mutable_buffer,
MutableBufferSequence> bufs(o->buffers_);
- return socket_ops::non_blocking_recv(o->socket_,
+ 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_);
+ 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;
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recv",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
}
private:
@@ -79,17 +89,19 @@ public:
buffers, flags, &reactive_socket_recv_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -107,7 +119,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/reactive_socket_recvfrom_op.hpp b/boost/asio/detail/reactive_socket_recvfrom_op.hpp
index 14829a0d75..9631465f24 100644
--- a/boost/asio/detail/reactive_socket_recvfrom_op.hpp
+++ b/boost/asio/detail/reactive_socket_recvfrom_op.hpp
@@ -16,10 +16,10 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_ops.hpp>
@@ -45,7 +45,7 @@ public:
{
}
- static bool do_perform(reactor_op* base)
+ static status do_perform(reactor_op* base)
{
reactive_socket_recvfrom_op_base* o(
static_cast<reactive_socket_recvfrom_op_base*>(base));
@@ -54,14 +54,17 @@ public:
MutableBufferSequence> bufs(o->buffers_);
std::size_t addr_len = o->sender_endpoint_.capacity();
- bool result = socket_ops::non_blocking_recvfrom(o->socket_,
+ 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_);
+ o->ec_, o->bytes_transferred_) ? done : not_done;
if (result && !o->ec_)
o->sender_endpoint_.resize(addr_len);
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvfrom",
+ o->ec_, o->bytes_transferred_));
+
return result;
}
@@ -88,9 +91,10 @@ public:
&reactive_socket_recvfrom_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
@@ -98,8 +102,9 @@ public:
reactive_socket_recvfrom_op* o(
static_cast<reactive_socket_recvfrom_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -117,7 +122,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/reactive_socket_recvmsg_op.hpp b/boost/asio/detail/reactive_socket_recvmsg_op.hpp
index fed5d01098..c48b1aba7e 100644
--- a/boost/asio/detail/reactive_socket_recvmsg_op.hpp
+++ b/boost/asio/detail/reactive_socket_recvmsg_op.hpp
@@ -16,10 +16,10 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/socket_base.hpp>
@@ -45,7 +45,7 @@ public:
{
}
- static bool do_perform(reactor_op* base)
+ static status do_perform(reactor_op* base)
{
reactive_socket_recvmsg_op_base* o(
static_cast<reactive_socket_recvmsg_op_base*>(base));
@@ -53,10 +53,15 @@ public:
buffer_sequence_adapter<boost::asio::mutable_buffer,
MutableBufferSequence> bufs(o->buffers_);
- return socket_ops::non_blocking_recvmsg(o->socket_,
+ status result = socket_ops::non_blocking_recvmsg(o->socket_,
bufs.buffers(), bufs.count(),
o->in_flags_, o->out_flags_,
- o->ec_, o->bytes_transferred_);
+ o->ec_, o->bytes_transferred_) ? done : not_done;
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvmsg",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
}
private:
@@ -80,9 +85,10 @@ public:
in_flags, out_flags, &reactive_socket_recvmsg_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
@@ -90,8 +96,9 @@ public:
reactive_socket_recvmsg_op* o(
static_cast<reactive_socket_recvmsg_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -109,7 +116,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/reactive_socket_send_op.hpp b/boost/asio/detail/reactive_socket_send_op.hpp
index 776117b6f7..01bb58f9ae 100644
--- a/boost/asio/detail/reactive_socket_send_op.hpp
+++ b/boost/asio/detail/reactive_socket_send_op.hpp
@@ -16,10 +16,10 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_ops.hpp>
@@ -34,16 +34,17 @@ class reactive_socket_send_op_base : public reactor_op
{
public:
reactive_socket_send_op_base(socket_type socket,
- const ConstBufferSequence& buffers,
+ 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 bool do_perform(reactor_op* base)
+ static status do_perform(reactor_op* base)
{
reactive_socket_send_op_base* o(
static_cast<reactive_socket_send_op_base*>(base));
@@ -51,13 +52,24 @@ public:
buffer_sequence_adapter<boost::asio::const_buffer,
ConstBufferSequence> bufs(o->buffers_);
- return socket_ops::non_blocking_send(o->socket_,
+ status result = socket_ops::non_blocking_send(o->socket_,
bufs.buffers(), bufs.count(), o->flags_,
- o->ec_, o->bytes_transferred_);
+ 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;
+
+ BOOST_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_;
};
@@ -70,23 +82,25 @@ public:
BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op);
reactive_socket_send_op(socket_type socket,
- const ConstBufferSequence& buffers,
+ socket_ops::state_type state, const ConstBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
: reactive_socket_send_op_base<ConstBufferSequence>(socket,
- buffers, flags, &reactive_socket_send_op::do_complete),
+ state, buffers, flags, &reactive_socket_send_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -104,7 +118,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/reactive_socket_sendto_op.hpp b/boost/asio/detail/reactive_socket_sendto_op.hpp
index 134c767c86..47a2656e22 100644
--- a/boost/asio/detail/reactive_socket_sendto_op.hpp
+++ b/boost/asio/detail/reactive_socket_sendto_op.hpp
@@ -16,10 +16,10 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_ops.hpp>
@@ -44,7 +44,7 @@ public:
{
}
- static bool do_perform(reactor_op* base)
+ static status do_perform(reactor_op* base)
{
reactive_socket_sendto_op_base* o(
static_cast<reactive_socket_sendto_op_base*>(base));
@@ -52,10 +52,15 @@ public:
buffer_sequence_adapter<boost::asio::const_buffer,
ConstBufferSequence> bufs(o->buffers_);
- return socket_ops::non_blocking_sendto(o->socket_,
+ 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_);
+ o->ec_, o->bytes_transferred_) ? done : not_done;
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_sendto",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
}
private:
@@ -79,17 +84,19 @@ public:
buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -107,7 +114,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/reactive_socket_service.hpp b/boost/asio/detail/reactive_socket_service.hpp
index d5a6e08eab..186cf35336 100644
--- a/boost/asio/detail/reactive_socket_service.hpp
+++ b/boost/asio/detail/reactive_socket_service.hpp
@@ -21,10 +21,10 @@
#include <boost/asio/buffer.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/socket_base.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/reactive_null_buffers_op.hpp>
#include <boost/asio/detail/reactive_socket_accept_op.hpp>
@@ -46,6 +46,7 @@ namespace detail {
template <typename Protocol>
class reactive_socket_service :
+ public service_base<reactive_socket_service<Protocol> >,
public reactive_socket_service_base
{
public:
@@ -73,11 +74,18 @@ public:
};
// Constructor.
- reactive_socket_service(boost::asio::io_service& io_service)
- : reactive_socket_service_base(io_service)
+ reactive_socket_service(boost::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)
@@ -196,6 +204,14 @@ public:
return endpoint;
}
+ // Disable sends or receives on the socket.
+ boost::system::error_code shutdown(base_implementation_type& impl,
+ socket_base::shutdown_type what, boost::system::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>
@@ -217,7 +233,7 @@ public:
boost::system::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_write(impl.socket_, impl.state_, ec);
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -237,11 +253,11 @@ public:
typedef reactive_socket_sendto_op<ConstBufferSequence,
endpoint_type, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send_to"));
+ BOOST_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;
@@ -258,12 +274,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
- &impl, "async_send_to(null_buffers)"));
+ BOOST_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;
@@ -297,7 +312,7 @@ public:
boost::system::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ 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();
@@ -320,14 +335,13 @@ public:
typedef reactive_socket_recvfrom_op<MutableBufferSequence,
endpoint_type, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
int protocol = impl.protocol_.type();
p.p = new (p.v) op(impl.socket_, protocol,
buffers, sender_endpoint, flags, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
- &impl, "async_receive_from"));
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive_from"));
start_op(impl,
(flags & socket_base::message_out_of_band)
@@ -348,12 +362,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
- &impl, "async_receive_from(null_buffers)"));
+ BOOST_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();
@@ -387,15 +400,44 @@ public:
{
if (peer_endpoint)
peer_endpoint->resize(addr_len);
- if (!peer.assign(impl.protocol_, new_socket.get(), ec))
+ peer.assign(impl.protocol_, new_socket.get(), ec);
+ if (!ec)
new_socket.release();
}
return ec;
}
- // Start an asynchronous accept. The peer and peer_endpoint objects
- // must be valid until the accept's handler is invoked.
+#if defined(BOOST_ASIO_HAS_MOVE)
+ // Accept a new connection.
+ typename Protocol::socket accept(implementation_type& impl,
+ io_context* peer_io_context, endpoint_type* peer_endpoint,
+ boost::system::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(BOOST_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)
@@ -406,17 +448,43 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_accept_op<Socket, Protocol, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, impl.state_, peer,
impl.protocol_, peer_endpoint, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_accept"));
+ BOOST_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(BOOST_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,
+ boost::asio::io_context* peer_io_context,
+ endpoint_type* peer_endpoint, Handler& handler)
+ {
+ bool is_continuation =
+ boost_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 = { boost::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);
+
+ BOOST_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(BOOST_ASIO_HAS_MOVE)
+
// Connect the socket to the specified endpoint.
boost::system::error_code connect(implementation_type& impl,
const endpoint_type& peer_endpoint, boost::system::error_code& ec)
@@ -437,11 +505,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_connect_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect"));
+ BOOST_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());
diff --git a/boost/asio/detail/reactive_socket_service_base.hpp b/boost/asio/detail/reactive_socket_service_base.hpp
index fb2aa5d028..17c694a3cd 100644
--- a/boost/asio/detail/reactive_socket_service_base.hpp
+++ b/boost/asio/detail/reactive_socket_service_base.hpp
@@ -22,14 +22,15 @@
#include <boost/asio/buffer.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/socket_base.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactive_null_buffers_op.hpp>
#include <boost/asio/detail/reactive_socket_recv_op.hpp>
#include <boost/asio/detail/reactive_socket_recvmsg_op.hpp>
#include <boost/asio/detail/reactive_socket_send_op.hpp>
+#include <boost/asio/detail/reactive_wait_op.hpp>
#include <boost/asio/detail/reactor.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_holder.hpp>
@@ -63,10 +64,10 @@ public:
// Constructor.
BOOST_ASIO_DECL reactive_socket_service_base(
- boost::asio::io_service& io_service);
+ boost::asio::io_context& io_context);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void base_shutdown();
// Construct a new socket implementation.
BOOST_ASIO_DECL void construct(base_implementation_type& impl);
@@ -93,6 +94,10 @@ public:
BOOST_ASIO_DECL boost::system::error_code close(
base_implementation_type& impl, boost::system::error_code& ec);
+ // Release ownership of the socket.
+ BOOST_ASIO_DECL socket_type release(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
// Get the native socket representation.
native_handle_type native_handle(base_implementation_type& impl)
{
@@ -163,14 +168,71 @@ public:
return ec;
}
- // Disable sends or receives on the socket.
- boost::system::error_code shutdown(base_implementation_type& impl,
- socket_base::shutdown_type what, boost::system::error_code& ec)
+ // Wait for the socket to become ready to read, ready to write, or to have
+ // pending error conditions.
+ boost::system::error_code wait(base_implementation_type& impl,
+ socket_base::wait_type w, boost::system::error_code& ec)
{
- socket_ops::shutdown(impl.socket_, what, 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 = boost::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 =
+ boost_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 = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ BOOST_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_ = boost::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,
@@ -189,7 +251,7 @@ public:
socket_base::message_flags, boost::system::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_write(impl.socket_, impl.state_, ec);
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -207,11 +269,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_send_op<ConstBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
- p.p = new (p.v) op(impl.socket_, buffers, flags, handler);
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send"));
+ BOOST_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)
@@ -231,12 +293,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
- &impl, "async_send(null_buffers)"));
+ BOOST_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;
@@ -260,7 +321,7 @@ public:
socket_base::message_flags, boost::system::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -278,11 +339,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive"));
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive"));
start_op(impl,
(flags & socket_base::message_out_of_band)
@@ -306,12 +367,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
- &impl, "async_receive(null_buffers)"));
+ BOOST_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)
@@ -341,7 +401,7 @@ public:
socket_base::message_flags& out_flags, boost::system::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ 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.
@@ -363,12 +423,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_recvmsg_op<MutableBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, buffers, in_flags, out_flags, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
- &impl, "async_receive_with_flags"));
+ BOOST_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)
@@ -390,12 +449,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl,
- "async_receive_with_flags(null_buffers)"));
+ BOOST_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.
@@ -432,6 +490,9 @@ protected:
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_;
};
diff --git a/boost/asio/detail/reactive_wait_op.hpp b/boost/asio/detail/reactive_wait_op.hpp
new file mode 100644
index 0000000000..9bc4e2c1c5
--- /dev/null
+++ b/boost/asio/detail/reactive_wait_op.hpp
@@ -0,0 +1,92 @@
+//
+// detail/reactive_wait_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_WAIT_OP_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_WAIT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class reactive_wait_op : public reactor_op
+{
+public:
+ BOOST_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_(BOOST_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 boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ BOOST_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, boost::system::error_code>
+ handler(o->handler_, o->ec_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_WAIT_OP_HPP
diff --git a/boost/asio/detail/reactor.hpp b/boost/asio/detail/reactor.hpp
index 1a4ace8776..e65df12863 100644
--- a/boost/asio/detail/reactor.hpp
+++ b/boost/asio/detail/reactor.hpp
@@ -23,7 +23,7 @@
# include <boost/asio/detail/kqueue_reactor.hpp>
#elif defined(BOOST_ASIO_HAS_DEV_POLL)
# include <boost/asio/detail/dev_poll_reactor.hpp>
-#elif defined(BOOST_ASIO_WINDOWS_RUNTIME)
+#elif defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME)
# include <boost/asio/detail/null_reactor.hpp>
#else
# include <boost/asio/detail/select_reactor.hpp>
diff --git a/boost/asio/detail/reactor_fwd.hpp b/boost/asio/detail/reactor_fwd.hpp
index 6b2e49f5a4..d14ed4cf9c 100644
--- a/boost/asio/detail/reactor_fwd.hpp
+++ b/boost/asio/detail/reactor_fwd.hpp
@@ -21,7 +21,7 @@ namespace boost {
namespace asio {
namespace detail {
-#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+#if defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME)
typedef class null_reactor reactor;
#elif defined(BOOST_ASIO_HAS_IOCP)
typedef class select_reactor reactor;
diff --git a/boost/asio/detail/reactor_op.hpp b/boost/asio/detail/reactor_op.hpp
index c5964dea37..c2540545d5 100644
--- a/boost/asio/detail/reactor_op.hpp
+++ b/boost/asio/detail/reactor_op.hpp
@@ -34,14 +34,18 @@ public:
// 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.
- bool perform()
+ status perform()
{
return perform_func_(this);
}
protected:
- typedef bool (*perform_func_type)(reactor_op*);
+ typedef status (*perform_func_type)(reactor_op*);
reactor_op(perform_func_type perform_func, func_type complete_func)
: operation(complete_func),
diff --git a/boost/asio/detail/recycling_allocator.hpp b/boost/asio/detail/recycling_allocator.hpp
new file mode 100644
index 0000000000..050e8bdfa0
--- /dev/null
+++ b/boost/asio/detail/recycling_allocator.hpp
@@ -0,0 +1,106 @@
+//
+// detail/recycling_allocator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP
+#define BOOST_ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/thread_context.hpp>
+#include <boost/asio/detail/thread_info_base.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP
diff --git a/boost/asio/detail/resolve_endpoint_op.hpp b/boost/asio/detail/resolve_endpoint_op.hpp
index 0b7060ad6b..4a2c06798a 100644
--- a/boost/asio/detail/resolve_endpoint_op.hpp
+++ b/boost/asio/detail/resolve_endpoint_op.hpp
@@ -17,14 +17,14 @@
#include <boost/asio/detail/config.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/ip/basic_resolver_iterator.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/ip/basic_resolver_results.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
-#include <boost/asio/detail/operation.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/resolve_op.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -34,35 +34,37 @@ namespace asio {
namespace detail {
template <typename Protocol, typename Handler>
-class resolve_endpoint_op : public operation
+class resolve_endpoint_op : public resolve_op
{
public:
BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op);
typedef typename Protocol::endpoint endpoint_type;
- typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type;
+ typedef boost::asio::ip::basic_resolver_results<Protocol> results_type;
resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token,
- const endpoint_type& endpoint, io_service_impl& ios, Handler& handler)
- : operation(&resolve_endpoint_op::do_complete),
+ const endpoint_type& endpoint, io_context_impl& ioc, Handler& handler)
+ : resolve_op(&resolve_endpoint_op::do_complete),
cancel_token_(cancel_token),
endpoint_(endpoint),
- io_service_impl_(ios),
+ io_context_impl_(ioc),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- if (owner && owner != &o->io_service_impl_)
+ if (owner && owner != &o->io_context_impl_)
{
- // The operation is being run on the worker io_service. Time to perform
+ // The operation is being run on the worker io_context. Time to perform
// the resolver operation.
// Perform the blocking endpoint resolution operation.
@@ -71,18 +73,18 @@ public:
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->iter_ = iterator_type::create(o->endpoint_, host_name, service_name);
+ o->results_ = results_type::create(o->endpoint_, host_name, service_name);
- // Pass operation back to main io_service for completion.
- o->io_service_impl_.post_deferred_completion(o);
+ // 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_service. The completion
+ // The operation has been returned to the main io_context. The completion
// handler is ready to be delivered.
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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,
@@ -90,8 +92,8 @@ public:
// 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, boost::system::error_code, iterator_type>
- handler(o->handler_, o->ec_, o->iter_);
+ detail::binder2<Handler, boost::system::error_code, results_type>
+ handler(o->handler_, o->ec_, o->results_);
p.h = boost::asio::detail::addressof(handler.handler_);
p.reset();
@@ -99,7 +101,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
@@ -108,10 +110,9 @@ public:
private:
socket_ops::weak_cancel_token_type cancel_token_;
endpoint_type endpoint_;
- io_service_impl& io_service_impl_;
+ io_context_impl& io_context_impl_;
Handler handler_;
- boost::system::error_code ec_;
- iterator_type iter_;
+ results_type results_;
};
} // namespace detail
diff --git a/boost/asio/detail/resolve_op.hpp b/boost/asio/detail/resolve_op.hpp
index 435e27026f..99f9772f97 100644
--- a/boost/asio/detail/resolve_op.hpp
+++ b/boost/asio/detail/resolve_op.hpp
@@ -17,16 +17,7 @@
#include <boost/asio/detail/config.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/ip/basic_resolver_iterator.hpp>
-#include <boost/asio/ip/basic_resolver_query.hpp>
-#include <boost/asio/detail/addressof.hpp>
-#include <boost/asio/detail/bind_handler.hpp>
-#include <boost/asio/detail/fenced_block.hpp>
-#include <boost/asio/detail/handler_alloc_helpers.hpp>
-#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/operation.hpp>
-#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -34,94 +25,17 @@ namespace boost {
namespace asio {
namespace detail {
-template <typename Protocol, typename Handler>
class resolve_op : public operation
{
public:
- BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_op);
-
- typedef boost::asio::ip::basic_resolver_query<Protocol> query_type;
- typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type;
-
- resolve_op(socket_ops::weak_cancel_token_type cancel_token,
- const query_type& query, io_service_impl& ios, Handler& handler)
- : operation(&resolve_op::do_complete),
- cancel_token_(cancel_token),
- query_(query),
- io_service_impl_(ios),
- handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
- addrinfo_(0)
- {
- }
+ // The error code to be passed to the completion handler.
+ boost::system::error_code ec_;
- ~resolve_op()
+protected:
+ resolve_op(func_type complete_func)
+ : operation(complete_func)
{
- if (addrinfo_)
- socket_ops::freeaddrinfo(addrinfo_);
}
-
- static void do_complete(io_service_impl* owner, operation* base,
- const boost::system::error_code& /*ec*/,
- std::size_t /*bytes_transferred*/)
- {
- // Take ownership of the operation object.
- resolve_op* o(static_cast<resolve_op*>(base));
- ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
-
- if (owner && owner != &o->io_service_impl_)
- {
- // The operation is being run on the worker io_service. 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_service for completion.
- o->io_service_impl_.post_deferred_completion(o);
- p.v = p.p = 0;
- }
- else
- {
- // The operation has been returned to the main io_service. The completion
- // handler is ready to be delivered.
-
- BOOST_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, boost::system::error_code, iterator_type>
- handler(o->handler_, o->ec_, iterator_type());
- p.h = boost::asio::detail::addressof(handler.handler_);
- if (o->addrinfo_)
- {
- handler.arg2_ = iterator_type::create(o->addrinfo_,
- o->query_.host_name(), o->query_.service_name());
- }
- p.reset();
-
- if (owner)
- {
- fenced_block b(fenced_block::half);
- BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
- BOOST_ASIO_HANDLER_INVOCATION_END;
- }
- }
- }
-
-private:
- socket_ops::weak_cancel_token_type cancel_token_;
- query_type query_;
- io_service_impl& io_service_impl_;
- Handler handler_;
- boost::system::error_code ec_;
- boost::asio::detail::addrinfo_type* addrinfo_;
};
} // namespace detail
diff --git a/boost/asio/detail/resolve_query_op.hpp b/boost/asio/detail/resolve_query_op.hpp
new file mode 100644
index 0000000000..6e5c431941
--- /dev/null
+++ b/boost/asio/detail/resolve_query_op.hpp
@@ -0,0 +1,136 @@
+//
+// detail/resolve_query_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_RESOLVE_QUERY_OP_HPP
+#define BOOST_ASIO_DETAIL_RESOLVE_QUERY_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/ip/basic_resolver_query.hpp>
+#include <boost/asio/ip/basic_resolver_results.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/resolve_op.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler>
+class resolve_query_op : public resolve_op
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_query_op);
+
+ typedef boost::asio::ip::basic_resolver_query<Protocol> query_type;
+ typedef boost::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_(BOOST_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 boost::system::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 = { boost::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_);
+
+ BOOST_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, boost::system::error_code, results_type>
+ handler(o->handler_, o->ec_, results_type());
+ p.h = boost::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);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+ w.complete(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ query_type query_;
+ io_context_impl& io_context_impl_;
+ Handler handler_;
+ boost::asio::detail::addrinfo_type* addrinfo_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_RESOLVE_QUERY_OP_HPP
diff --git a/boost/asio/detail/resolver_service.hpp b/boost/asio/detail/resolver_service.hpp
index f73742e9b0..bda1139eb7 100644
--- a/boost/asio/detail/resolver_service.hpp
+++ b/boost/asio/detail/resolver_service.hpp
@@ -19,11 +19,12 @@
#if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
-#include <boost/asio/ip/basic_resolver_iterator.hpp>
#include <boost/asio/ip/basic_resolver_query.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/ip/basic_resolver_results.hpp>
+#include <boost/asio/detail/concurrency_hint.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/resolve_endpoint_op.hpp>
-#include <boost/asio/detail/resolve_op.hpp>
+#include <boost/asio/detail/resolve_query_op.hpp>
#include <boost/asio/detail/resolver_service_base.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -33,7 +34,9 @@ namespace asio {
namespace detail {
template <typename Protocol>
-class resolver_service : public resolver_service_base
+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
@@ -46,17 +49,30 @@ public:
// The query type.
typedef boost::asio::ip::basic_resolver_query<Protocol> query_type;
- // The iterator type.
- typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type;
+ // The results type.
+ typedef boost::asio::ip::basic_resolver_results<Protocol> results_type;
// Constructor.
- resolver_service(boost::asio::io_service& io_service)
- : resolver_service_base(io_service)
+ resolver_service(boost::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(boost::asio::io_context::fork_event fork_ev)
+ {
+ this->base_notify_fork(fork_ev);
+ }
+
// Resolve a query to a list of entries.
- iterator_type resolve(implementation_type&, const query_type& query,
+ results_type resolve(implementation_type&, const query_type& query,
boost::system::error_code& ec)
{
boost::asio::detail::addrinfo_type* address_info = 0;
@@ -65,7 +81,7 @@ public:
query.service_name().c_str(), query.hints(), &address_info, ec);
auto_addrinfo auto_address_info(address_info);
- return ec ? iterator_type() : iterator_type::create(
+ return ec ? results_type() : results_type::create(
address_info, query.host_name(), query.service_name());
}
@@ -75,20 +91,20 @@ public:
const query_type& query, Handler& handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef resolve_op<Protocol, Handler> op;
+ typedef resolve_query_op<Protocol, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
- p.p = new (p.v) op(impl, query, io_service_impl_, handler);
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl, query, io_context_impl_, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "resolver", &impl, "async_resolve"));
+ BOOST_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.
- iterator_type resolve(implementation_type&,
+ results_type resolve(implementation_type&,
const endpoint_type& endpoint, boost::system::error_code& ec)
{
char host_name[NI_MAXHOST];
@@ -97,7 +113,7 @@ public:
host_name, NI_MAXHOST, service_name, NI_MAXSERV,
endpoint.protocol().type(), ec);
- return ec ? iterator_type() : iterator_type::create(
+ return ec ? results_type() : results_type::create(
endpoint, host_name, service_name);
}
@@ -109,11 +125,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef resolve_endpoint_op<Protocol, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
- p.p = new (p.v) op(impl, endpoint, io_service_impl_, handler);
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl, endpoint, io_context_impl_, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "resolver", &impl, "async_resolve"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_impl_.context(),
+ *p.p, "resolver", &impl, 0, "async_resolve"));
start_resolve_op(p.p);
p.v = p.p = 0;
diff --git a/boost/asio/detail/resolver_service_base.hpp b/boost/asio/detail/resolver_service_base.hpp
index 1a4180c166..818e20b02b 100644
--- a/boost/asio/detail/resolver_service_base.hpp
+++ b/boost/asio/detail/resolver_service_base.hpp
@@ -17,10 +17,11 @@
#include <boost/asio/detail/config.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/executor_work_guard.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/noncopyable.hpp>
-#include <boost/asio/detail/operation.hpp>
+#include <boost/asio/detail/resolve_op.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
#include <boost/asio/detail/scoped_ptr.hpp>
@@ -40,17 +41,17 @@ public:
typedef socket_ops::shared_cancel_token_type implementation_type;
// Constructor.
- BOOST_ASIO_DECL resolver_service_base(boost::asio::io_service& io_service);
+ BOOST_ASIO_DECL resolver_service_base(boost::asio::io_context& io_context);
// Destructor.
BOOST_ASIO_DECL ~resolver_service_base();
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void base_shutdown();
// Perform any fork-related housekeeping.
- BOOST_ASIO_DECL void fork_service(
- boost::asio::io_service::fork_event fork_ev);
+ BOOST_ASIO_DECL void base_notify_fork(
+ boost::asio::io_context::fork_event fork_ev);
// Construct a new resolver implementation.
BOOST_ASIO_DECL void construct(implementation_type& impl);
@@ -58,12 +59,21 @@ public:
// Destroy a resolver implementation.
BOOST_ASIO_DECL void destroy(implementation_type&);
+ // Move-construct a new resolver implementation.
+ BOOST_ASIO_DECL void move_construct(implementation_type& impl,
+ implementation_type& other_impl);
+
+ // Move-assign from another resolver implementation.
+ BOOST_ASIO_DECL void move_assign(implementation_type& impl,
+ resolver_service_base& other_service,
+ implementation_type& other_impl);
+
// Cancel pending asynchronous operations.
BOOST_ASIO_DECL void cancel(implementation_type& impl);
protected:
// Helper function to start an asynchronous resolve operation.
- BOOST_ASIO_DECL void start_resolve_op(operation* op);
+ BOOST_ASIO_DECL void start_resolve_op(resolve_op* op);
#if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// Helper class to perform exception-safe cleanup of addrinfo objects.
@@ -92,29 +102,30 @@ protected:
};
#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
- // Helper class to run the work io_service in a thread.
- class work_io_service_runner;
+ // 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.
BOOST_ASIO_DECL void start_work_thread();
- // The io_service implementation used to post completions.
- io_service_impl& io_service_impl_;
+ // The io_context implementation used to post completions.
+ io_context_impl& io_context_impl_;
private:
// Mutex to protect access to internal data.
boost::asio::detail::mutex mutex_;
- // Private io_service used for performing asynchronous host resolution.
- boost::asio::detail::scoped_ptr<boost::asio::io_service> work_io_service_;
+ // Private io_context used for performing asynchronous host resolution.
+ boost::asio::detail::scoped_ptr<boost::asio::io_context> work_io_context_;
- // The work io_service implementation used to post completions.
- io_service_impl& work_io_service_impl_;
+ // The work io_context implementation used to post completions.
+ io_context_impl& work_io_context_impl_;
- // Work for the private io_service to perform.
- boost::asio::detail::scoped_ptr<boost::asio::io_service::work> work_;
+ // Work for the private io_context to perform.
+ boost::asio::executor_work_guard<
+ boost::asio::io_context::executor_type> work_;
- // Thread used for running the work io_service's run loop.
+ // Thread used for running the work io_context's run loop.
boost::asio::detail::scoped_ptr<boost::asio::detail::thread> work_thread_;
};
diff --git a/boost/asio/detail/task_io_service.hpp b/boost/asio/detail/scheduler.hpp
index 5184ea5a58..1d64a062c8 100644
--- a/boost/asio/detail/task_io_service.hpp
+++ b/boost/asio/detail/scheduler.hpp
@@ -1,6 +1,6 @@
//
-// detail/task_io_service.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
@@ -8,8 +8,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP
-#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP
+#ifndef BOOST_ASIO_DETAIL_SCHEDULER_HPP
+#define BOOST_ASIO_DETAIL_SCHEDULER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -17,17 +17,15 @@
#include <boost/asio/detail/config.hpp>
-#if !defined(BOOST_ASIO_HAS_IOCP)
-
#include <boost/system/error_code.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/execution_context.hpp>
#include <boost/asio/detail/atomic_count.hpp>
-#include <boost/asio/detail/call_stack.hpp>
-#include <boost/asio/detail/event.hpp>
-#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/conditionally_enabled_event.hpp>
+#include <boost/asio/detail/conditionally_enabled_mutex.hpp>
#include <boost/asio/detail/op_queue.hpp>
#include <boost/asio/detail/reactor_fwd.hpp>
-#include <boost/asio/detail/task_io_service_operation.hpp>
+#include <boost/asio/detail/scheduler_operation.hpp>
+#include <boost/asio/detail/thread_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -35,21 +33,22 @@ namespace boost {
namespace asio {
namespace detail {
-struct task_io_service_thread_info;
+struct scheduler_thread_info;
-class task_io_service
- : public boost::asio::detail::service_base<task_io_service>
+class scheduler
+ : public execution_context_service_base<scheduler>,
+ public thread_context
{
public:
- typedef task_io_service_operation operation;
+ typedef scheduler_operation operation;
// Constructor. Specifies the number of concurrent threads that are likely to
- // run the io_service. If set to 1 certain optimisation are performed.
- BOOST_ASIO_DECL task_io_service(boost::asio::io_service& io_service,
- std::size_t concurrency_hint = 0);
+ // run the scheduler. If set to 1 certain optimisation are performed.
+ BOOST_ASIO_DECL scheduler(boost::asio::execution_context& ctx,
+ int concurrency_hint = 0);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Initialise the task, if required.
BOOST_ASIO_DECL void init_task();
@@ -60,6 +59,10 @@ public:
// Run until interrupted or one operation is performed.
BOOST_ASIO_DECL std::size_t run_one(boost::system::error_code& ec);
+ // Run until timeout, interrupted, or one operation is performed.
+ BOOST_ASIO_DECL std::size_t wait_one(
+ long usec, boost::system::error_code& ec);
+
// Poll for operations without blocking.
BOOST_ASIO_DECL std::size_t poll(boost::system::error_code& ec);
@@ -69,11 +72,11 @@ public:
// Interrupt the event processing loop.
BOOST_ASIO_DECL void stop();
- // Determine whether the io_service is stopped.
+ // Determine whether the scheduler is stopped.
BOOST_ASIO_DECL bool stopped() const;
- // Reset in preparation for a subsequent run invocation.
- BOOST_ASIO_DECL void reset();
+ // Restart in preparation for a subsequent run invocation.
+ BOOST_ASIO_DECL void restart();
// Notify that some work has started.
void work_started()
@@ -81,6 +84,10 @@ public:
++outstanding_work_;
}
+ // Used to compensate for a forthcoming work_finished call. Must be called
+ // from within a scheduler-owned thread.
+ BOOST_ASIO_DECL void compensating_work_started();
+
// Notify that some work has finished.
void work_finished()
{
@@ -94,14 +101,6 @@ public:
return thread_call_stack::contains(this) != 0;
}
- // Request invocation of the given handler.
- template <typename Handler>
- void dispatch(Handler& handler);
-
- // Request invocation of the given handler and return immediately.
- template <typename Handler>
- void post(Handler& handler);
-
// Request invocation of the given operation and return immediately. Assumes
// that work_started() has not yet been called for the operation.
BOOST_ASIO_DECL void post_immediate_completion(
@@ -115,22 +114,38 @@ public:
// that work_started() was previously called for each operation.
BOOST_ASIO_DECL void post_deferred_completions(op_queue<operation>& ops);
- // Process unfinished operations as part of a shutdown_service operation.
- // Assumes that work_started() was previously called for the operations.
+ // Enqueue the given operation following a failed attempt to dispatch the
+ // operation for immediate invocation.
+ BOOST_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.
BOOST_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:
- // Structure containing thread-specific data.
- typedef task_io_service_thread_info thread_info;
+ // The mutex type used by this scheduler.
+ typedef conditionally_enabled_mutex mutex;
- // Enqueue the given operation following a failed attempt to dispatch the
- // operation for immediate invocation.
- BOOST_ASIO_DECL void do_dispatch(operation* op);
+ // 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.
BOOST_ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock,
thread_info& this_thread, const boost::system::error_code& ec);
+ // Run at most one operation with a timeout. May block.
+ BOOST_ASIO_DECL std::size_t do_wait_one(mutex::scoped_lock& lock,
+ thread_info& this_thread, long usec, const boost::system::error_code& ec);
+
// Poll for at most one operation.
BOOST_ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock,
thread_info& this_thread, const boost::system::error_code& ec);
@@ -183,8 +198,8 @@ private:
// Flag to indicate that the dispatcher has been shut down.
bool shutdown_;
- // Per-thread call stack to track the state of each thread in the io_service.
- typedef call_stack<task_io_service, thread_info> thread_call_stack;
+ // The concurrency hint used to initialise the scheduler.
+ const int concurrency_hint_;
};
} // namespace detail
@@ -193,11 +208,8 @@ private:
#include <boost/asio/detail/pop_options.hpp>
-#include <boost/asio/detail/impl/task_io_service.hpp>
#if defined(BOOST_ASIO_HEADER_ONLY)
-# include <boost/asio/detail/impl/task_io_service.ipp>
+# include <boost/asio/detail/impl/scheduler.ipp>
#endif // defined(BOOST_ASIO_HEADER_ONLY)
-#endif // !defined(BOOST_ASIO_HAS_IOCP)
-
-#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP
+#endif // BOOST_ASIO_DETAIL_SCHEDULER_HPP
diff --git a/boost/asio/detail/task_io_service_operation.hpp b/boost/asio/detail/scheduler_operation.hpp
index 91bee25cb4..54a8a7a206 100644
--- a/boost/asio/detail/task_io_service_operation.hpp
+++ b/boost/asio/detail/scheduler_operation.hpp
@@ -1,6 +1,6 @@
//
-// detail/task_io_service_operation.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/scheduler_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
@@ -8,8 +8,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP
-#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP
+#ifndef BOOST_ASIO_DETAIL_SCHEDULER_OPERATION_HPP
+#define BOOST_ASIO_DETAIL_SCHEDULER_OPERATION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -25,17 +25,19 @@ namespace boost {
namespace asio {
namespace detail {
-class task_io_service;
+class scheduler;
// Base class for all operations. A function pointer is used instead of virtual
// functions to avoid the associated overhead.
-class task_io_service_operation BOOST_ASIO_INHERIT_TRACKED_HANDLER
+class scheduler_operation BOOST_ASIO_INHERIT_TRACKED_HANDLER
{
public:
- void complete(task_io_service& owner,
- const boost::system::error_code& ec, std::size_t bytes_transferred)
+ typedef scheduler_operation operation_type;
+
+ void complete(void* owner, const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
{
- func_(&owner, this, ec, bytes_transferred);
+ func_(owner, this, ec, bytes_transferred);
}
void destroy()
@@ -44,11 +46,11 @@ public:
}
protected:
- typedef void (*func_type)(task_io_service*,
- task_io_service_operation*,
+ typedef void (*func_type)(void*,
+ scheduler_operation*,
const boost::system::error_code&, std::size_t);
- task_io_service_operation(func_type func)
+ scheduler_operation(func_type func)
: next_(0),
func_(func),
task_result_(0)
@@ -56,16 +58,16 @@ protected:
}
// Prevents deletion through this type.
- ~task_io_service_operation()
+ ~scheduler_operation()
{
}
private:
friend class op_queue_access;
- task_io_service_operation* next_;
+ scheduler_operation* next_;
func_type func_;
protected:
- friend class task_io_service;
+ friend class scheduler;
unsigned int task_result_; // Passed into bytes transferred.
};
@@ -75,4 +77,4 @@ protected:
#include <boost/asio/detail/pop_options.hpp>
-#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP
+#endif // BOOST_ASIO_DETAIL_SCHEDULER_OPERATION_HPP
diff --git a/boost/asio/detail/task_io_service_thread_info.hpp b/boost/asio/detail/scheduler_thread_info.hpp
index 0af044c009..79d64783c2 100644
--- a/boost/asio/detail/task_io_service_thread_info.hpp
+++ b/boost/asio/detail/scheduler_thread_info.hpp
@@ -1,6 +1,6 @@
//
-// detail/task_io_service_thread_info.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// detail/scheduler_thread_info.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
@@ -8,8 +8,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef BOOST_ASIO_DETAIL_TASK_IO_SERVICE_THREAD_INFO_HPP
-#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_THREAD_INFO_HPP
+#ifndef BOOST_ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP
+#define BOOST_ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -24,12 +24,12 @@ namespace boost {
namespace asio {
namespace detail {
-class task_io_service;
-class task_io_service_operation;
+class scheduler;
+class scheduler_operation;
-struct task_io_service_thread_info : public thread_info_base
+struct scheduler_thread_info : public thread_info_base
{
- op_queue<task_io_service_operation> private_op_queue;
+ op_queue<scheduler_operation> private_op_queue;
long private_outstanding_work;
};
@@ -39,4 +39,4 @@ struct task_io_service_thread_info : public thread_info_base
#include <boost/asio/detail/pop_options.hpp>
-#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_THREAD_INFO_HPP
+#endif // BOOST_ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP
diff --git a/boost/asio/detail/scoped_ptr.hpp b/boost/asio/detail/scoped_ptr.hpp
index fd471631e1..80ced171cd 100644
--- a/boost/asio/detail/scoped_ptr.hpp
+++ b/boost/asio/detail/scoped_ptr.hpp
@@ -64,6 +64,14 @@ public:
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&);
diff --git a/boost/asio/detail/select_reactor.hpp b/boost/asio/detail/select_reactor.hpp
index d6f75242e5..030c092250 100644
--- a/boost/asio/detail/select_reactor.hpp
+++ b/boost/asio/detail/select_reactor.hpp
@@ -35,7 +35,7 @@
#include <boost/asio/detail/timer_queue_base.hpp>
#include <boost/asio/detail/timer_queue_set.hpp>
#include <boost/asio/detail/wait_op.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/execution_context.hpp>
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/thread.hpp>
@@ -48,7 +48,7 @@ namespace asio {
namespace detail {
class select_reactor
- : public boost::asio::detail::service_base<select_reactor>
+ : public execution_context_service_base<select_reactor>
{
public:
#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
@@ -65,17 +65,17 @@ public:
};
// Constructor.
- BOOST_ASIO_DECL select_reactor(boost::asio::io_service& io_service);
+ BOOST_ASIO_DECL select_reactor(boost::asio::execution_context& ctx);
// Destructor.
BOOST_ASIO_DECL ~select_reactor();
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Recreate internal descriptors following a fork.
- BOOST_ASIO_DECL void fork_service(
- boost::asio::io_service::fork_event fork_ev);
+ BOOST_ASIO_DECL void notify_fork(
+ boost::asio::execution_context::fork_event fork_ev);
// Initialise the task, but only if the reactor is not in its own thread.
BOOST_ASIO_DECL void init_task();
@@ -93,7 +93,7 @@ public:
// Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op, bool is_continuation)
{
- io_service_.post_immediate_completion(op, is_continuation);
+ scheduler_.post_immediate_completion(op, is_continuation);
}
// Start a new operation. The reactor operation will be performed when the
@@ -149,8 +149,14 @@ public:
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.
- BOOST_ASIO_DECL void run(bool block, op_queue<operation>& ops);
+ BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops);
// Interrupt the select loop.
BOOST_ASIO_DECL void interrupt();
@@ -159,9 +165,6 @@ private:
#if defined(BOOST_ASIO_HAS_IOCP)
// Run the select loop in the thread.
BOOST_ASIO_DECL void run_thread();
-
- // Entry point for the select loop thread.
- BOOST_ASIO_DECL static void call_run_thread(select_reactor* reactor);
#endif // defined(BOOST_ASIO_HAS_IOCP)
// Helper function to add a new timer queue.
@@ -171,15 +174,20 @@ private:
BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
// Get the timeout value for the select call.
- BOOST_ASIO_DECL timeval* get_timeout(timeval& tv);
+ BOOST_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.
BOOST_ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
const boost::system::error_code& ec);
- // The io_service implementation used to post completions.
- io_service_impl& io_service_;
+ // The scheduler implementation used to post completions.
+# if defined(BOOST_ASIO_HAS_IOCP)
+ typedef class win_iocp_io_context scheduler_type;
+# else // defined(BOOST_ASIO_HAS_IOCP)
+ typedef class scheduler scheduler_type;
+# endif // defined(BOOST_ASIO_HAS_IOCP)
+ scheduler_type& scheduler_;
// Mutex to protect access to internal data.
boost::asio::detail::mutex mutex_;
@@ -197,6 +205,10 @@ private:
timer_queue_set timer_queues_;
#if defined(BOOST_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_;
diff --git a/boost/asio/detail/service_registry.hpp b/boost/asio/detail/service_registry.hpp
index b5fa85bd01..7218848e4c 100644
--- a/boost/asio/detail/service_registry.hpp
+++ b/boost/asio/detail/service_registry.hpp
@@ -19,12 +19,16 @@
#include <typeinfo>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/noncopyable.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+#include <boost/asio/execution_context.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
+
+class io_context;
+
namespace detail {
template <typename T>
@@ -34,27 +38,34 @@ class service_registry
: private noncopyable
{
public:
- // Constructor. Adds the initial service.
- template <typename Service, typename Arg>
- service_registry(boost::asio::io_service& o,
- Service* initial_service, Arg arg);
+ // Constructor.
+ BOOST_ASIO_DECL service_registry(execution_context& owner);
// Destructor.
BOOST_ASIO_DECL ~service_registry();
+ // Shutdown all services.
+ BOOST_ASIO_DECL void shutdown_services();
+
+ // Destroy all services.
+ BOOST_ASIO_DECL void destroy_services();
+
// Notify all services of a fork event.
- BOOST_ASIO_DECL void notify_fork(boost::asio::io_service::fork_event fork_ev);
+ BOOST_ASIO_DECL void notify_fork(execution_context::fork_event fork_ev);
- // Get the first service object cast to the specified type. Called during
- // io_service construction and so performs no locking or type checking.
+ // 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& first_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();
+ 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.
@@ -66,70 +77,79 @@ public:
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(BOOST_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(BOOST_ASIO_NO_TYPEID)
+
// Initialise a service's key based on its id.
- BOOST_ASIO_DECL static void init_key(
- boost::asio::io_service::service::key& key,
- const boost::asio::io_service::id& id);
+ BOOST_ASIO_DECL static void init_key_from_id(
+ execution_context::service::key& key,
+ const execution_context::id& id);
#if !defined(BOOST_ASIO_NO_TYPEID)
// Initialise a service's key based on its id.
template <typename Service>
- static void init_key(boost::asio::io_service::service::key& key,
- const boost::asio::detail::service_id<Service>& /*id*/);
+ static void init_key_from_id(execution_context::service::key& key,
+ const service_id<Service>& /*id*/);
#endif // !defined(BOOST_ASIO_NO_TYPEID)
// Check if a service matches the given id.
BOOST_ASIO_DECL static bool keys_match(
- const boost::asio::io_service::service::key& key1,
- const boost::asio::io_service::service::key& key2);
+ 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 boost::asio::io_service::service*
- (*factory_type)(boost::asio::io_service&);
+ typedef execution_context::service*(*factory_type)(void*);
// Factory function for creating a service instance.
- template <typename Service>
- static boost::asio::io_service::service* create(
- boost::asio::io_service& owner);
+ template <typename Service, typename Owner>
+ static execution_context::service* create(void* owner);
// Destroy a service instance.
- BOOST_ASIO_DECL static void destroy(
- boost::asio::io_service::service* service);
+ BOOST_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
{
- boost::asio::io_service::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.
- BOOST_ASIO_DECL boost::asio::io_service::service* do_use_service(
- const boost::asio::io_service::service::key& key,
- factory_type factory);
+ BOOST_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.
BOOST_ASIO_DECL void do_add_service(
- const boost::asio::io_service::service::key& key,
- boost::asio::io_service::service* new_service);
+ const execution_context::service::key& key,
+ execution_context::service* new_service);
// Check whether a service object with the specified key already exists.
BOOST_ASIO_DECL bool do_has_service(
- const boost::asio::io_service::service::key& key) const;
+ const execution_context::service::key& key) const;
// Mutex to protect access to internal data.
mutable boost::asio::detail::mutex mutex_;
// The owner of this service registry and the services it contains.
- boost::asio::io_service& owner_;
+ execution_context& owner_;
// The first service in the list of contained services.
- boost::asio::io_service::service* first_service_;
+ execution_context::service* first_service_;
};
} // namespace detail
diff --git a/boost/asio/detail/shared_ptr.hpp b/boost/asio/detail/shared_ptr.hpp
deleted file mode 100644
index f26c645121..0000000000
--- a/boost/asio/detail/shared_ptr.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// detail/shared_ptr.hpp
-// ~~~~~~~~~~~~~~~~~~~~~
-//
-// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef BOOST_ASIO_DETAIL_SHARED_PTR_HPP
-#define BOOST_ASIO_DETAIL_SHARED_PTR_HPP
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1200)
-# pragma once
-#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-
-#include <boost/asio/detail/config.hpp>
-
-#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-# include <memory>
-#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-# include <boost/shared_ptr.hpp>
-#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-
-namespace boost {
-namespace asio {
-namespace detail {
-
-#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-using std::shared_ptr;
-#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-using boost::shared_ptr;
-#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-
-} // namespace detail
-} // namespace asio
-} // namespace boost
-
-#endif // BOOST_ASIO_DETAIL_SHARED_PTR_HPP
diff --git a/boost/asio/detail/signal_handler.hpp b/boost/asio/detail/signal_handler.hpp
index edad41b8ee..6ea723a27a 100644
--- a/boost/asio/detail/signal_handler.hpp
+++ b/boost/asio/detail/signal_handler.hpp
@@ -16,10 +16,12 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/handler_work.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/signal_op.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -38,17 +40,19 @@ public:
: signal_op(&signal_handler::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(h))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
// Take ownership of the handler object.
signal_handler* h(static_cast<signal_handler*>(base));
ptr p = { boost::asio::detail::addressof(h->handler_), h, h };
+ handler_work<Handler> w(h->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((h));
+ BOOST_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
@@ -66,7 +70,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/signal_set_service.hpp b/boost/asio/detail/signal_set_service.hpp
index a023ebb66f..f27f8652c4 100644
--- a/boost/asio/detail/signal_set_service.hpp
+++ b/boost/asio/detail/signal_set_service.hpp
@@ -20,9 +20,9 @@
#include <cstddef>
#include <signal.h>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/op_queue.hpp>
#include <boost/asio/detail/signal_handler.hpp>
#include <boost/asio/detail/signal_op.hpp>
@@ -48,7 +48,8 @@ extern BOOST_ASIO_DECL struct signal_state* get_signal_state();
extern "C" BOOST_ASIO_DECL void boost_asio_signal_handler(int signal_number);
-class signal_set_service
+class signal_set_service :
+ public service_base<signal_set_service>
{
public:
// Type used for tracking an individual signal registration.
@@ -109,17 +110,17 @@ public:
};
// Constructor.
- BOOST_ASIO_DECL signal_set_service(boost::asio::io_service& io_service);
+ BOOST_ASIO_DECL signal_set_service(boost::asio::io_context& io_context);
// Destructor.
BOOST_ASIO_DECL ~signal_set_service();
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Perform fork-related housekeeping.
- BOOST_ASIO_DECL void fork_service(
- boost::asio::io_service::fork_event fork_ev);
+ BOOST_ASIO_DECL void notify_fork(
+ boost::asio::io_context::fork_event fork_ev);
// Construct a new signal_set implementation.
BOOST_ASIO_DECL void construct(implementation_type& impl);
@@ -150,11 +151,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef signal_handler<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "signal_set", &impl, "async_wait"));
+ BOOST_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;
@@ -179,8 +180,8 @@ private:
// Helper function to start a wait operation.
BOOST_ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op);
- // The io_service instance used for dispatching handlers.
- io_service_impl& io_service_;
+ // The io_context instance used for dispatching handlers.
+ io_context_impl& io_context_;
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
diff --git a/boost/asio/detail/socket_ops.hpp b/boost/asio/detail/socket_ops.hpp
index 136a3f01f7..8d39ab8737 100644
--- a/boost/asio/detail/socket_ops.hpp
+++ b/boost/asio/detail/socket_ops.hpp
@@ -18,9 +18,8 @@
#include <boost/asio/detail/config.hpp>
#include <boost/system/error_code.hpp>
-#include <boost/asio/detail/shared_ptr.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/socket_types.hpp>
-#include <boost/asio/detail/weak_ptr.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -265,12 +264,16 @@ BOOST_ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds,
fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec);
BOOST_ASIO_DECL int poll_read(socket_type s,
- state_type state, boost::system::error_code& ec);
+ state_type state, int msec, boost::system::error_code& ec);
BOOST_ASIO_DECL int poll_write(socket_type s,
- state_type state, boost::system::error_code& ec);
+ state_type state, int msec, boost::system::error_code& ec);
-BOOST_ASIO_DECL int poll_connect(socket_type s, boost::system::error_code& ec);
+BOOST_ASIO_DECL int poll_error(socket_type s,
+ state_type state, int msec, boost::system::error_code& ec);
+
+BOOST_ASIO_DECL int poll_connect(socket_type s,
+ int msec, boost::system::error_code& ec);
#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
diff --git a/boost/asio/detail/socket_types.hpp b/boost/asio/detail/socket_types.hpp
index 0768f70077..ca9fc83a29 100644
--- a/boost/asio/detail/socket_types.hpp
+++ b/boost/asio/detail/socket_types.hpp
@@ -59,7 +59,8 @@
# include <sys/ioctl.h>
# if (defined(__MACH__) && defined(__APPLE__)) \
|| defined(__FreeBSD__) || defined(__NetBSD__) \
- || defined(__OpenBSD__) || defined(__linux__)
+ || defined(__OpenBSD__) || defined(__linux__) \
+ || defined(__EMSCRIPTEN__)
# include <poll.h>
# elif !defined(__SYMBIAN32__)
# include <sys/poll.h>
@@ -152,6 +153,7 @@ typedef int signed_size_type;
# define BOOST_ASIO_OS_DEF_SO_DONTROUTE 0x10
# define BOOST_ASIO_OS_DEF_SO_KEEPALIVE 0x8
# define BOOST_ASIO_OS_DEF_SO_LINGER 0x80
+# define BOOST_ASIO_OS_DEF_SO_OOBINLINE 0x100
# define BOOST_ASIO_OS_DEF_SO_SNDBUF 0x1001
# define BOOST_ASIO_OS_DEF_SO_RCVBUF 0x1002
# define BOOST_ASIO_OS_DEF_SO_SNDLOWAT 0x1003
@@ -236,6 +238,7 @@ typedef int signed_size_type;
# define BOOST_ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE
# define BOOST_ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE
# define BOOST_ASIO_OS_DEF_SO_LINGER SO_LINGER
+# define BOOST_ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE
# define BOOST_ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF
# define BOOST_ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF
# define BOOST_ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT
@@ -351,6 +354,7 @@ typedef int signed_size_type;
# define BOOST_ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE
# define BOOST_ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE
# define BOOST_ASIO_OS_DEF_SO_LINGER SO_LINGER
+# define BOOST_ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE
# define BOOST_ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF
# define BOOST_ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF
# define BOOST_ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT
diff --git a/boost/asio/detail/solaris_fenced_block.hpp b/boost/asio/detail/solaris_fenced_block.hpp
index 2aef0229f1..5653a8b4c4 100644
--- a/boost/asio/detail/solaris_fenced_block.hpp
+++ b/boost/asio/detail/solaris_fenced_block.hpp
@@ -20,6 +20,7 @@
#if defined(__sun)
#include <atomic.h>
+#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/push_options.hpp>
diff --git a/boost/asio/detail/std_global.hpp b/boost/asio/detail/std_global.hpp
new file mode 100644
index 0000000000..f0936e5ea9
--- /dev/null
+++ b/boost/asio/detail/std_global.hpp
@@ -0,0 +1,72 @@
+//
+// detail/std_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_STD_GLOBAL_HPP
+#define BOOST_ASIO_DETAIL_STD_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if defined(BOOST_ASIO_HAS_STD_CALL_ONCE)
+
+#include <exception>
+#include <mutex>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // defined(BOOST_ASIO_HAS_STD_CALL_ONCE)
+
+#endif // BOOST_ASIO_DETAIL_STD_GLOBAL_HPP
diff --git a/boost/asio/detail/std_thread.hpp b/boost/asio/detail/std_thread.hpp
index cd2a61dac2..35bcc1722c 100644
--- a/boost/asio/detail/std_thread.hpp
+++ b/boost/asio/detail/std_thread.hpp
@@ -52,6 +52,12 @@ public:
thread_.join();
}
+ // Get number of CPUs.
+ static std::size_t hardware_concurrency()
+ {
+ return std::thread::hardware_concurrency();
+ }
+
private:
std::thread thread_;
};
diff --git a/boost/asio/detail/strand_executor_service.hpp b/boost/asio/detail/strand_executor_service.hpp
new file mode 100644
index 0000000000..38728d4610
--- /dev/null
+++ b/boost/asio/detail/strand_executor_service.hpp
@@ -0,0 +1,140 @@
+//
+// detail/strand_executor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/atomic_count.hpp>
+#include <boost/asio/detail/executor_op.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/op_queue.hpp>
+#include <boost/asio/detail/scheduler_operation.hpp>
+#include <boost/asio/detail/scoped_ptr.hpp>
+#include <boost/asio/execution_context.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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:
+ BOOST_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_;
+
+ // 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.
+ BOOST_ASIO_DECL explicit strand_executor_service(execution_context& context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ BOOST_ASIO_DECL void shutdown();
+
+ // Create a new strand_executor implementation.
+ BOOST_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,
+ BOOST_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,
+ BOOST_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,
+ BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a);
+
+ // Determine whether the strand is running in the current thread.
+ BOOST_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.
+ BOOST_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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/impl/strand_executor_service.hpp>
+#if defined(BOOST_ASIO_HEADER_ONLY)
+# include <boost/asio/detail/impl/strand_executor_service.ipp>
+#endif // defined(BOOST_ASIO_HEADER_ONLY)
+
+#endif // BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
diff --git a/boost/asio/detail/strand_service.hpp b/boost/asio/detail/strand_service.hpp
index 8a94e58e36..e9d05b3ae7 100644
--- a/boost/asio/detail/strand_service.hpp
+++ b/boost/asio/detail/strand_service.hpp
@@ -16,7 +16,7 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/op_queue.hpp>
#include <boost/asio/detail/operation.hpp>
@@ -75,20 +75,20 @@ public:
typedef strand_impl* implementation_type;
- // Construct a new strand service for the specified io_service.
- BOOST_ASIO_DECL explicit strand_service(boost::asio::io_service& io_service);
+ // Construct a new strand service for the specified io_context.
+ BOOST_ASIO_DECL explicit strand_service(boost::asio::io_context& io_context);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Construct a new strand implementation.
BOOST_ASIO_DECL void construct(implementation_type& impl);
- // Request the io_service to invoke the given handler.
+ // Request the io_context to invoke the given handler.
template <typename Handler>
void dispatch(implementation_type& impl, Handler& handler);
- // Request the io_service to invoke the given handler and return immediately.
+ // Request the io_context to invoke the given handler and return immediately.
template <typename Handler>
void post(implementation_type& impl, Handler& handler);
@@ -105,12 +105,12 @@ private:
BOOST_ASIO_DECL void do_post(implementation_type& impl,
operation* op, bool is_continuation);
- BOOST_ASIO_DECL static void do_complete(io_service_impl* owner,
+ BOOST_ASIO_DECL static void do_complete(void* owner,
operation* base, const boost::system::error_code& ec,
std::size_t bytes_transferred);
- // The io_service implementation used to post completions.
- io_service_impl& io_service_;
+ // The io_context implementation used to post completions.
+ io_context_impl& io_context_;
// Mutex to protect access to the array of implementations.
boost::asio::detail::mutex mutex_;
diff --git a/boost/asio/detail/string_view.hpp b/boost/asio/detail/string_view.hpp
new file mode 100644
index 0000000000..3d0a24f4c6
--- /dev/null
+++ b/boost/asio/detail/string_view.hpp
@@ -0,0 +1,47 @@
+//
+// detail/string_view.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_STRING_VIEW_HPP
+#define BOOST_ASIO_DETAIL_STRING_VIEW_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW)
+
+#if defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+# include <experimental/string_view>
+#else // defined(BOOST_ASIO_HAS_EXPERIMENTAL_STRING_VIEW)
+# include <string_view>
+#endif // defined(BOOST_ASIO_HAS_EXPERIMENTAL_STRING_VIEW)
+
+namespace boost {
+namespace asio {
+
+#if defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+using std::experimental::basic_string_view;
+using std::experimental::string_view;
+#else // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+using std::basic_string_view;
+using std::string_view;
+#endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+
+} // namespace asio
+} // namespace boost
+
+# define BOOST_ASIO_STRING_VIEW_PARAM boost::asio::string_view
+#else // defined(BOOST_ASIO_HAS_STD_STRING_VIEW)
+# define BOOST_ASIO_STRING_VIEW_PARAM const std::string&
+#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW)
+
+#endif // BOOST_ASIO_DETAIL_STRING_VIEW_HPP
diff --git a/boost/asio/detail/thread.hpp b/boost/asio/detail/thread.hpp
index f385fc85a1..e10040e972 100644
--- a/boost/asio/detail/thread.hpp
+++ b/boost/asio/detail/thread.hpp
@@ -20,8 +20,10 @@
#if !defined(BOOST_ASIO_HAS_THREADS)
# include <boost/asio/detail/null_thread.hpp>
#elif defined(BOOST_ASIO_WINDOWS)
-# if defined(BOOST_ASIO_WINDOWS_APP) || defined(UNDER_CE)
-# include <boost/asio/detail/winapi_thread.hpp>
+# if defined(UNDER_CE)
+# include <boost/asio/detail/wince_thread.hpp>
+# elif defined(BOOST_ASIO_WINDOWS_APP)
+# include <boost/asio/detail/winapp_thread.hpp>
# else
# include <boost/asio/detail/win_thread.hpp>
# endif
@@ -40,8 +42,10 @@ namespace detail {
#if !defined(BOOST_ASIO_HAS_THREADS)
typedef null_thread thread;
#elif defined(BOOST_ASIO_WINDOWS)
-# if defined(BOOST_ASIO_WINDOWS_APP) || defined(UNDER_CE)
-typedef winapi_thread thread;
+# if defined(UNDER_CE)
+typedef wince_thread thread;
+# elif defined(BOOST_ASIO_WINDOWS_APP)
+typedef winapp_thread thread;
# else
typedef win_thread thread;
# endif
diff --git a/boost/asio/detail/thread_context.hpp b/boost/asio/detail/thread_context.hpp
new file mode 100644
index 0000000000..8c059ccb02
--- /dev/null
+++ b/boost/asio/detail/thread_context.hpp
@@ -0,0 +1,44 @@
+//
+// detail/thread_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_THREAD_CONTEXT_HPP
+#define BOOST_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 <boost/asio/detail/call_stack.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_THREAD_CONTEXT_HPP
diff --git a/boost/asio/detail/thread_group.hpp b/boost/asio/detail/thread_group.hpp
new file mode 100644
index 0000000000..2451e8f3b7
--- /dev/null
+++ b/boost/asio/detail/thread_group.hpp
@@ -0,0 +1,91 @@
+//
+// detail/thread_group.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_THREAD_GROUP_HPP
+#define BOOST_ASIO_DETAIL_THREAD_GROUP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/scoped_ptr.hpp>
+#include <boost/asio/detail/thread.hpp>
+
+namespace boost {
+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)
+ {
+ }
+
+ boost::asio::detail::thread thread_;
+ item* next_;
+ };
+
+ // The first thread in the group.
+ item* first_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_THREAD_GROUP_HPP
diff --git a/boost/asio/detail/thread_info_base.hpp b/boost/asio/detail/thread_info_base.hpp
index 3baa8ef39f..c0dc322f41 100644
--- a/boost/asio/detail/thread_info_base.hpp
+++ b/boost/asio/detail/thread_info_base.hpp
@@ -42,13 +42,15 @@ public:
static void* allocate(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_)
{
void* const pointer = this_thread->reusable_memory_;
this_thread->reusable_memory_ = 0;
unsigned char* const mem = static_cast<unsigned char*>(pointer);
- if (static_cast<std::size_t>(mem[0]) >= size)
+ if (static_cast<std::size_t>(mem[0]) >= chunks)
{
mem[size] = mem[0];
return pointer;
@@ -57,16 +59,16 @@ public:
::operator delete(pointer);
}
- void* const pointer = ::operator new(size + 1);
+ void* const pointer = ::operator new(chunks * chunk_size + 1);
unsigned char* const mem = static_cast<unsigned char*>(pointer);
- mem[size] = (size <= UCHAR_MAX) ? static_cast<unsigned char>(size) : 0;
+ mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0;
return pointer;
}
static void deallocate(thread_info_base* this_thread,
void* pointer, std::size_t size)
{
- if (size <= UCHAR_MAX)
+ if (size <= chunk_size * UCHAR_MAX)
{
if (this_thread && this_thread->reusable_memory_ == 0)
{
@@ -81,6 +83,7 @@ public:
}
private:
+ enum { chunk_size = 4 };
void* reusable_memory_;
};
diff --git a/boost/asio/detail/timer_queue.hpp b/boost/asio/detail/timer_queue.hpp
index cb848dfb3a..f8d48babad 100644
--- a/boost/asio/detail/timer_queue.hpp
+++ b/boost/asio/detail/timer_queue.hpp
@@ -47,7 +47,11 @@ public:
class per_timer_data
{
public:
- per_timer_data() : next_(0), prev_(0) {}
+ per_timer_data() :
+ heap_index_((std::numeric_limits<std::size_t>::max)()),
+ next_(0), prev_(0)
+ {
+ }
private:
friend class timer_queue;
@@ -189,6 +193,29 @@ public:
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_ = &target;
+
+ if (timers_ == &source)
+ timers_ = &target;
+ if (source.prev_)
+ source.prev_->next_ = &target;
+ if (source.next_)
+ source.next_->prev_= &target;
+ 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)
diff --git a/boost/asio/detail/timer_queue_ptime.hpp b/boost/asio/detail/timer_queue_ptime.hpp
index 0693acca83..d1934f1375 100644
--- a/boost/asio/detail/timer_queue_ptime.hpp
+++ b/boost/asio/detail/timer_queue_ptime.hpp
@@ -15,13 +15,15 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+#include <boost/asio/detail/config.hpp>
+
+#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
+
#include <boost/asio/time_traits.hpp>
#include <boost/asio/detail/timer_queue.hpp>
#include <boost/asio/detail/push_options.hpp>
-#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
-
namespace boost {
namespace asio {
namespace detail {
@@ -76,6 +78,10 @@ public:
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.
+ BOOST_ASIO_DECL void move_timer(per_timer_data& target,
+ per_timer_data& source);
+
private:
timer_queue<forwarding_posix_time_traits> impl_;
};
@@ -84,12 +90,12 @@ private:
} // namespace asio
} // namespace boost
-#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
-
#include <boost/asio/detail/pop_options.hpp>
#if defined(BOOST_ASIO_HEADER_ONLY)
# include <boost/asio/detail/impl/timer_queue_ptime.ipp>
#endif // defined(BOOST_ASIO_HEADER_ONLY)
+#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
+
#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP
diff --git a/boost/asio/detail/timer_scheduler.hpp b/boost/asio/detail/timer_scheduler.hpp
index 49dc113d10..290d0b0680 100644
--- a/boost/asio/detail/timer_scheduler.hpp
+++ b/boost/asio/detail/timer_scheduler.hpp
@@ -21,7 +21,7 @@
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
# include <boost/asio/detail/winrt_timer_scheduler.hpp>
#elif defined(BOOST_ASIO_HAS_IOCP)
-# include <boost/asio/detail/win_iocp_io_service.hpp>
+# include <boost/asio/detail/win_iocp_io_context.hpp>
#elif defined(BOOST_ASIO_HAS_EPOLL)
# include <boost/asio/detail/epoll_reactor.hpp>
#elif defined(BOOST_ASIO_HAS_KQUEUE)
diff --git a/boost/asio/detail/timer_scheduler_fwd.hpp b/boost/asio/detail/timer_scheduler_fwd.hpp
index bf732a63d3..de3d3bd350 100644
--- a/boost/asio/detail/timer_scheduler_fwd.hpp
+++ b/boost/asio/detail/timer_scheduler_fwd.hpp
@@ -24,7 +24,7 @@ namespace detail {
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
typedef class winrt_timer_scheduler timer_scheduler;
#elif defined(BOOST_ASIO_HAS_IOCP)
-typedef class win_iocp_io_service timer_scheduler;
+typedef class win_iocp_io_context timer_scheduler;
#elif defined(BOOST_ASIO_HAS_EPOLL)
typedef class epoll_reactor timer_scheduler;
#elif defined(BOOST_ASIO_HAS_KQUEUE)
diff --git a/boost/asio/detail/type_traits.hpp b/boost/asio/detail/type_traits.hpp
index 53a73a0eb1..1556e597e0 100644
--- a/boost/asio/detail/type_traits.hpp
+++ b/boost/asio/detail/type_traits.hpp
@@ -21,6 +21,11 @@
# include <type_traits>
#else // defined(BOOST_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>
@@ -28,6 +33,7 @@
# 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(BOOST_ASIO_HAS_TYPE_TRAITS)
namespace boost {
@@ -35,23 +41,39 @@ namespace asio {
#if defined(BOOST_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;
+using std::result_of;
+using std::true_type;
#else // defined(BOOST_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(BOOST_ASIO_HAS_STD_TYPE_TRAITS)
} // namespace asio
diff --git a/boost/asio/detail/variadic_templates.hpp b/boost/asio/detail/variadic_templates.hpp
index 6d55bc7a7c..228a6542e9 100644
--- a/boost/asio/detail/variadic_templates.hpp
+++ b/boost/asio/detail/variadic_templates.hpp
@@ -34,27 +34,83 @@
# define BOOST_ASIO_VARIADIC_TARGS(n) BOOST_ASIO_VARIADIC_TARGS_##n
-# define BOOST_ASIO_VARIADIC_TARGS_1 x1
-# define BOOST_ASIO_VARIADIC_TARGS_2 x1, x2
-# define BOOST_ASIO_VARIADIC_TARGS_3 x1, x2, x3
-# define BOOST_ASIO_VARIADIC_TARGS_4 x1, x2, x3, x4
-# define BOOST_ASIO_VARIADIC_TARGS_5 x1, x2, x3, x4, x5
-
-# define BOOST_ASIO_VARIADIC_PARAMS(n) BOOST_ASIO_VARIADIC_PARAMS_##n
-
-# define BOOST_ASIO_VARIADIC_PARAMS_1 T1 x1
-# define BOOST_ASIO_VARIADIC_PARAMS_2 T1 x1, T2 x2
-# define BOOST_ASIO_VARIADIC_PARAMS_3 T1 x1, T2 x2, T3 x3
-# define BOOST_ASIO_VARIADIC_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4
-# define BOOST_ASIO_VARIADIC_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5
-
-# define BOOST_ASIO_VARIADIC_ARGS(n) BOOST_ASIO_VARIADIC_ARGS_##n
-
-# define BOOST_ASIO_VARIADIC_ARGS_1 x1
-# define BOOST_ASIO_VARIADIC_ARGS_2 x1, x2
-# define BOOST_ASIO_VARIADIC_ARGS_3 x1, x2, x3
-# define BOOST_ASIO_VARIADIC_ARGS_4 x1, x2, x3, x4
-# define BOOST_ASIO_VARIADIC_ARGS_5 x1, x2, x3, x4, x5
+# define BOOST_ASIO_VARIADIC_TARGS_1 T1
+# define BOOST_ASIO_VARIADIC_TARGS_2 T1, T2
+# define BOOST_ASIO_VARIADIC_TARGS_3 T1, T2, T3
+# define BOOST_ASIO_VARIADIC_TARGS_4 T1, T2, T3, T4
+# define BOOST_ASIO_VARIADIC_TARGS_5 T1, T2, T3, T4, T5
+
+# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n) \
+ BOOST_ASIO_VARIADIC_BYVAL_PARAMS_##n
+
+# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_1 T1 x1
+# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_2 T1 x1, T2 x2
+# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_3 T1 x1, T2 x2, T3 x3
+# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4
+# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5
+
+# define BOOST_ASIO_VARIADIC_BYVAL_ARGS(n) \
+ BOOST_ASIO_VARIADIC_BYVAL_ARGS_##n
+
+# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_1 x1
+# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_2 x1, x2
+# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_3 x1, x2, x3
+# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_4 x1, x2, x3, x4
+# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_5 x1, x2, x3, x4, x5
+
+# define BOOST_ASIO_VARIADIC_MOVE_PARAMS(n) \
+ BOOST_ASIO_VARIADIC_MOVE_PARAMS_##n
+
+# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_1 \
+ BOOST_ASIO_MOVE_ARG(T1) x1
+# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_2 \
+ BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2
+# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_3 \
+ BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \
+ BOOST_ASIO_MOVE_ARG(T3) x3
+# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_4 \
+ BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \
+ BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4
+# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_5 \
+ BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \
+ BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4, \
+ BOOST_ASIO_MOVE_ARG(T5) x5
+
+# define BOOST_ASIO_VARIADIC_MOVE_ARGS(n) \
+ BOOST_ASIO_VARIADIC_MOVE_ARGS_##n
+
+# define BOOST_ASIO_VARIADIC_MOVE_ARGS_1 \
+ BOOST_ASIO_MOVE_CAST(T1)(x1)
+# define BOOST_ASIO_VARIADIC_MOVE_ARGS_2 \
+ BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2)
+# define BOOST_ASIO_VARIADIC_MOVE_ARGS_3 \
+ BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \
+ BOOST_ASIO_MOVE_CAST(T3)(x3)
+# define BOOST_ASIO_VARIADIC_MOVE_ARGS_4 \
+ BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \
+ BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4)
+# define BOOST_ASIO_VARIADIC_MOVE_ARGS_5 \
+ BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \
+ BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4), \
+ BOOST_ASIO_MOVE_CAST(T5)(x5)
+
+# define BOOST_ASIO_VARIADIC_DECAY(n) \
+ BOOST_ASIO_VARIADIC_DECAY_##n
+
+# define BOOST_ASIO_VARIADIC_DECAY_1 \
+ typename decay<T1>::type
+# define BOOST_ASIO_VARIADIC_DECAY_2 \
+ typename decay<T1>::type, typename decay<T2>::type
+# define BOOST_ASIO_VARIADIC_DECAY_3 \
+ typename decay<T1>::type, typename decay<T2>::type, \
+ typename decay<T3>::type
+# define BOOST_ASIO_VARIADIC_DECAY_4 \
+ typename decay<T1>::type, typename decay<T2>::type, \
+ typename decay<T3>::type, typename decay<T4>::type
+# define BOOST_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 BOOST_ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5)
diff --git a/boost/asio/detail/wait_handler.hpp b/boost/asio/detail/wait_handler.hpp
index 440dae1f18..5d520e8fb1 100644
--- a/boost/asio/detail/wait_handler.hpp
+++ b/boost/asio/detail/wait_handler.hpp
@@ -16,12 +16,12 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/wait_op.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -39,17 +39,19 @@ public:
: wait_op(&wait_handler::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(h))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
// Take ownership of the handler object.
wait_handler* h(static_cast<wait_handler*>(base));
ptr p = { boost::asio::detail::addressof(h->handler_), h, h };
+ handler_work<Handler> w(h->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((h));
+ BOOST_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
@@ -67,7 +69,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/weak_ptr.hpp b/boost/asio/detail/weak_ptr.hpp
deleted file mode 100644
index 1870c0e0e8..0000000000
--- a/boost/asio/detail/weak_ptr.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// detail/weak_ptr.hpp
-// ~~~~~~~~~~~~~~~~~~~
-//
-// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef BOOST_ASIO_DETAIL_WEAK_PTR_HPP
-#define BOOST_ASIO_DETAIL_WEAK_PTR_HPP
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1200)
-# pragma once
-#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-
-#include <boost/asio/detail/config.hpp>
-
-#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-# include <memory>
-#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-# include <boost/weak_ptr.hpp>
-#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-
-namespace boost {
-namespace asio {
-namespace detail {
-
-#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-using std::weak_ptr;
-#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-using boost::weak_ptr;
-#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
-
-} // namespace detail
-} // namespace asio
-} // namespace boost
-
-#endif // BOOST_ASIO_DETAIL_WEAK_PTR_HPP
diff --git a/boost/asio/detail/win_event.hpp b/boost/asio/detail/win_event.hpp
index 7a7d54fac6..4c00068010 100644
--- a/boost/asio/detail/win_event.hpp
+++ b/boost/asio/detail/win_event.hpp
@@ -112,6 +112,27 @@ public:
}
}
+ // Timed wait for the event to become signalled.
+ template <typename Lock>
+ bool wait_for_usec(Lock& lock, long usec)
+ {
+ BOOST_ASIO_ASSERT(lock.locked());
+ if ((state_ & 1) == 0)
+ {
+ state_ += 2;
+ lock.unlock();
+ DWORD msec = usec > 0 ? (usec < 1000 ? 1 : usec / 1000) : 0;
+#if defined(BOOST_ASIO_WINDOWS_APP)
+ ::WaitForMultipleObjectsEx(2, events_, false, msec, false);
+#else // defined(BOOST_ASIO_WINDOWS_APP)
+ ::WaitForMultipleObjects(2, events_, false, msec);
+#endif // defined(BOOST_ASIO_WINDOWS_APP)
+ lock.lock();
+ state_ -= 2;
+ }
+ return (state_ & 1) != 0;
+ }
+
private:
HANDLE events_[2];
std::size_t state_;
diff --git a/boost/asio/detail/win_fenced_block.hpp b/boost/asio/detail/win_fenced_block.hpp
index dba1d5355d..c6e5601361 100644
--- a/boost/asio/detail/win_fenced_block.hpp
+++ b/boost/asio/detail/win_fenced_block.hpp
@@ -20,6 +20,7 @@
#if defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE)
#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/push_options.hpp>
diff --git a/boost/asio/detail/win_global.hpp b/boost/asio/detail/win_global.hpp
new file mode 100644
index 0000000000..5a43902a7c
--- /dev/null
+++ b/boost/asio/detail/win_global.hpp
@@ -0,0 +1,75 @@
+//
+// detail/win_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_WIN_GLOBAL_HPP
+#define BOOST_ASIO_DETAIL_WIN_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/static_mutex.hpp>
+#include <boost/asio/detail/tss_ptr.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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_ = BOOST_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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_GLOBAL_HPP
diff --git a/boost/asio/detail/win_iocp_handle_read_op.hpp b/boost/asio/detail/win_iocp_handle_read_op.hpp
index fda3cc1e77..67d0ccc296 100644
--- a/boost/asio/detail/win_iocp_handle_read_op.hpp
+++ b/boost/asio/detail/win_iocp_handle_read_op.hpp
@@ -21,12 +21,12 @@
#if defined(BOOST_ASIO_HAS_IOCP)
#include <boost/asio/error.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -47,9 +47,10 @@ public:
buffers_(buffers),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& result_ec,
std::size_t bytes_transferred)
{
@@ -58,8 +59,9 @@ public:
// Take ownership of the operation object.
win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
if (owner)
@@ -90,7 +92,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/win_iocp_handle_service.hpp b/boost/asio/detail/win_iocp_handle_service.hpp
index 29f24f90c5..876fb68cb8 100644
--- a/boost/asio/detail/win_iocp_handle_service.hpp
+++ b/boost/asio/detail/win_iocp_handle_service.hpp
@@ -21,16 +21,16 @@
#if defined(BOOST_ASIO_HAS_IOCP)
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/cstdint.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/win_iocp_handle_read_op.hpp>
#include <boost/asio/detail/win_iocp_handle_write_op.hpp>
-#include <boost/asio/detail/win_iocp_io_service.hpp>
+#include <boost/asio/detail/win_iocp_io_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -38,7 +38,8 @@ namespace boost {
namespace asio {
namespace detail {
-class win_iocp_handle_service
+class win_iocp_handle_service :
+ public service_base<win_iocp_handle_service>
{
public:
// The native type of a stream handle.
@@ -75,10 +76,10 @@ public:
implementation_type* prev_;
};
- BOOST_ASIO_DECL win_iocp_handle_service(boost::asio::io_service& io_service);
+ BOOST_ASIO_DECL win_iocp_handle_service(boost::asio::io_context& io_context);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Construct a new handle implementation.
BOOST_ASIO_DECL void construct(implementation_type& impl);
@@ -149,11 +150,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "handle", &impl, "async_write_some"));
+ BOOST_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<boost::asio::const_buffer,
@@ -170,11 +171,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "handle", &impl, "async_write_some_at"));
+ BOOST_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<boost::asio::const_buffer,
@@ -211,11 +212,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "handle", &impl, "async_read_some"));
+ BOOST_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<boost::asio::mutable_buffer,
@@ -233,11 +234,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "handle", &impl, "async_read_some_at"));
+ BOOST_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<boost::asio::mutable_buffer,
@@ -300,7 +301,7 @@ private:
// The IOCP service used for running asynchronous operations and dispatching
// handlers.
- win_iocp_io_service& iocp_service_;
+ win_iocp_io_context& iocp_service_;
// Mutex to protect access to the linked list of implementations.
mutex mutex_;
diff --git a/boost/asio/detail/win_iocp_handle_write_op.hpp b/boost/asio/detail/win_iocp_handle_write_op.hpp
index a53db910a8..b6b1483265 100644
--- a/boost/asio/detail/win_iocp_handle_write_op.hpp
+++ b/boost/asio/detail/win_iocp_handle_write_op.hpp
@@ -21,12 +21,12 @@
#if defined(BOOST_ASIO_HAS_IOCP)
#include <boost/asio/error.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -46,16 +46,18 @@ public:
buffers_(buffers),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
if (owner)
@@ -82,7 +84,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/win_iocp_io_service.hpp b/boost/asio/detail/win_iocp_io_context.hpp
index 0abb9fe89a..c53b9eb9c3 100644
--- a/boost/asio/detail/win_iocp_io_service.hpp
+++ b/boost/asio/detail/win_iocp_io_context.hpp
@@ -1,5 +1,5 @@
//
-// detail/win_iocp_io_service.hpp
+// detail/win_iocp_io_context.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
@@ -8,8 +8,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
-#define BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
+#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP
+#define BOOST_ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -19,19 +19,19 @@
#if defined(BOOST_ASIO_HAS_IOCP)
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/call_stack.hpp>
#include <boost/asio/detail/limits.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/op_queue.hpp>
#include <boost/asio/detail/scoped_ptr.hpp>
#include <boost/asio/detail/socket_types.hpp>
#include <boost/asio/detail/thread.hpp>
+#include <boost/asio/detail/thread_context.hpp>
#include <boost/asio/detail/timer_queue_base.hpp>
#include <boost/asio/detail/timer_queue_set.hpp>
#include <boost/asio/detail/wait_op.hpp>
#include <boost/asio/detail/win_iocp_operation.hpp>
#include <boost/asio/detail/win_iocp_thread_info.hpp>
+#include <boost/asio/execution_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -41,18 +41,18 @@ namespace detail {
class wait_op;
-class win_iocp_io_service
- : public boost::asio::detail::service_base<win_iocp_io_service>
+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.
- BOOST_ASIO_DECL win_iocp_io_service(boost::asio::io_service& io_service,
- size_t concurrency_hint = 0);
+ BOOST_ASIO_DECL win_iocp_io_context(boost::asio::execution_context& ctx,
+ int concurrency_hint = -1);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Initialise the task. Nothing to do here.
void init_task()
@@ -69,6 +69,9 @@ public:
// Run until stopped or one operation is performed.
BOOST_ASIO_DECL size_t run_one(boost::system::error_code& ec);
+ // Run until timeout, interrupted, or one operation is performed.
+ BOOST_ASIO_DECL size_t wait_one(long usec, boost::system::error_code& ec);
+
// Poll for operations without blocking.
BOOST_ASIO_DECL size_t poll(boost::system::error_code& ec);
@@ -78,14 +81,14 @@ public:
// Stop the event processing loop.
BOOST_ASIO_DECL void stop();
- // Determine whether the io_service is stopped.
+ // Determine whether the io_context is stopped.
bool stopped() const
{
return ::InterlockedExchangeAdd(&stopped_, 0) != 0;
}
- // Reset in preparation for a subsequent run invocation.
- void reset()
+ // Restart in preparation for a subsequent run invocation.
+ void restart()
{
::InterlockedExchange(&stopped_, 0);
}
@@ -109,14 +112,6 @@ public:
return thread_call_stack::contains(this) != 0;
}
- // Request invocation of the given handler.
- template <typename Handler>
- void dispatch(Handler& handler);
-
- // Request invocation of the given handler and return immediately.
- template <typename Handler>
- void post(Handler& handler);
-
// 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)
@@ -150,8 +145,15 @@ public:
post_deferred_completion(op);
}
- // Process unfinished operations as part of a shutdown_service operation.
- // Assumes that work_started() was previously called for the operations.
+ // 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.
BOOST_ASIO_DECL void abandon_operations(op_queue<operation>& ops);
// Called after starting an overlapped I/O operation that did not complete
@@ -193,6 +195,18 @@ public:
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;
@@ -205,7 +219,7 @@ private:
// 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).
- BOOST_ASIO_DECL size_t do_one(bool block, boost::system::error_code& ec);
+ BOOST_ASIO_DECL size_t do_one(DWORD msec, boost::system::error_code& ec);
// Helper to calculate the GetQueuedCompletionStatus timeout.
BOOST_ASIO_DECL static DWORD get_gqcs_timeout();
@@ -296,9 +310,8 @@ private:
// The operations that are ready to dispatch.
op_queue<win_iocp_operation> completed_ops_;
- // Per-thread call stack to track the state of each thread in the io_service.
- typedef call_stack<win_iocp_io_service,
- win_iocp_thread_info> thread_call_stack;
+ // The concurrency hint used to initialise the io_context.
+ const int concurrency_hint_;
};
} // namespace detail
@@ -307,11 +320,11 @@ private:
#include <boost/asio/detail/pop_options.hpp>
-#include <boost/asio/detail/impl/win_iocp_io_service.hpp>
+#include <boost/asio/detail/impl/win_iocp_io_context.hpp>
#if defined(BOOST_ASIO_HEADER_ONLY)
-# include <boost/asio/detail/impl/win_iocp_io_service.ipp>
+# include <boost/asio/detail/impl/win_iocp_io_context.ipp>
#endif // defined(BOOST_ASIO_HEADER_ONLY)
#endif // defined(BOOST_ASIO_HAS_IOCP)
-#endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
+#endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP
diff --git a/boost/asio/detail/win_iocp_null_buffers_op.hpp b/boost/asio/detail/win_iocp_null_buffers_op.hpp
index 905d7a664e..318331a125 100644
--- a/boost/asio/detail/win_iocp_null_buffers_op.hpp
+++ b/boost/asio/detail/win_iocp_null_buffers_op.hpp
@@ -19,12 +19,12 @@
#if defined(BOOST_ASIO_HAS_IOCP)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/error.hpp>
@@ -48,14 +48,15 @@ public:
cancel_token_(cancel_token),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static bool do_perform(reactor_op*)
+ static status do_perform(reactor_op*)
{
- return true;
+ return done;
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& result_ec,
std::size_t bytes_transferred)
{
@@ -64,8 +65,9 @@ public:
// Take ownership of the operation object.
win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
// The reactor may have stored a result in the operation object.
if (o->ec_)
@@ -100,7 +102,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/win_iocp_operation.hpp b/boost/asio/detail/win_iocp_operation.hpp
index 232930344b..fcb79a933b 100644
--- a/boost/asio/detail/win_iocp_operation.hpp
+++ b/boost/asio/detail/win_iocp_operation.hpp
@@ -30,7 +30,7 @@ namespace boost {
namespace asio {
namespace detail {
-class win_iocp_io_service;
+class win_iocp_io_context;
// Base class for all operations. A function pointer is used instead of virtual
// functions to avoid the associated overhead.
@@ -39,11 +39,12 @@ class win_iocp_operation
BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER
{
public:
- void complete(win_iocp_io_service& owner,
- const boost::system::error_code& ec,
+ typedef win_iocp_operation operation_type;
+
+ void complete(void* owner, const boost::system::error_code& ec,
std::size_t bytes_transferred)
{
- func_(&owner, this, ec, bytes_transferred);
+ func_(owner, this, ec, bytes_transferred);
}
void destroy()
@@ -53,7 +54,7 @@ public:
protected:
typedef void (*func_type)(
- win_iocp_io_service*, win_iocp_operation*,
+ void*, win_iocp_operation*,
const boost::system::error_code&, std::size_t);
win_iocp_operation(func_type func)
@@ -80,7 +81,7 @@ protected:
private:
friend class op_queue_access;
- friend class win_iocp_io_service;
+ friend class win_iocp_io_context;
win_iocp_operation* next_;
func_type func_;
long ready_;
diff --git a/boost/asio/detail/win_iocp_overlapped_op.hpp b/boost/asio/detail/win_iocp_overlapped_op.hpp
index 6d0e4bfcc2..4b26db3f43 100644
--- a/boost/asio/detail/win_iocp_overlapped_op.hpp
+++ b/boost/asio/detail/win_iocp_overlapped_op.hpp
@@ -20,11 +20,11 @@
#if defined(BOOST_ASIO_HAS_IOCP)
#include <boost/asio/error.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -43,16 +43,18 @@ public:
: operation(&win_iocp_overlapped_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -70,7 +72,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/win_iocp_overlapped_ptr.hpp b/boost/asio/detail/win_iocp_overlapped_ptr.hpp
index 5d252c6fb1..fc51fd6c59 100644
--- a/boost/asio/detail/win_iocp_overlapped_ptr.hpp
+++ b/boost/asio/detail/win_iocp_overlapped_ptr.hpp
@@ -19,12 +19,12 @@
#if defined(BOOST_ASIO_HAS_IOCP)
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/win_iocp_overlapped_op.hpp>
-#include <boost/asio/detail/win_iocp_io_service.hpp>
+#include <boost/asio/detail/win_iocp_io_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -47,11 +47,11 @@ public:
// Construct an win_iocp_overlapped_ptr to contain the specified handler.
template <typename Handler>
explicit win_iocp_overlapped_ptr(
- boost::asio::io_service& io_service, BOOST_ASIO_MOVE_ARG(Handler) handler)
+ boost::asio::io_context& io_context, BOOST_ASIO_MOVE_ARG(Handler) handler)
: ptr_(0),
iocp_service_(0)
{
- this->reset(io_service, BOOST_ASIO_MOVE_CAST(Handler)(handler));
+ this->reset(io_context, BOOST_ASIO_MOVE_CAST(Handler)(handler));
}
// Destructor automatically frees the OVERLAPPED object unless released.
@@ -75,22 +75,21 @@ public:
// Reset to contain the specified handler, freeing any current OVERLAPPED
// object.
template <typename Handler>
- void reset(boost::asio::io_service& io_service, Handler handler)
+ void reset(boost::asio::io_context& io_context, Handler handler)
{
typedef win_iocp_overlapped_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "io_service",
- &io_service.impl_, "overlapped"));
+ BOOST_ASIO_HANDLER_CREATION((io_context, *p.p,
+ "io_context", &io_context.impl_, 0, "overlapped"));
- io_service.impl_.work_started();
+ io_context.impl_.work_started();
reset();
ptr_ = p.p;
p.v = p.p = 0;
- iocp_service_ = &io_service.impl_;
+ iocp_service_ = &io_context.impl_;
}
// Get the contained OVERLAPPED object.
@@ -132,7 +131,7 @@ public:
private:
win_iocp_operation* ptr_;
- win_iocp_io_service* iocp_service_;
+ win_iocp_io_context* iocp_service_;
};
} // namespace detail
diff --git a/boost/asio/detail/win_iocp_serial_port_service.hpp b/boost/asio/detail/win_iocp_serial_port_service.hpp
index 6b21f96535..4b641f0c73 100644
--- a/boost/asio/detail/win_iocp_serial_port_service.hpp
+++ b/boost/asio/detail/win_iocp_serial_port_service.hpp
@@ -22,7 +22,7 @@
#include <string>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/win_iocp_handle_service.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -32,7 +32,8 @@ namespace asio {
namespace detail {
// Extend win_iocp_handle_service to provide serial port support.
-class win_iocp_serial_port_service
+class win_iocp_serial_port_service :
+ public service_base<win_iocp_serial_port_service>
{
public:
// The native type of a serial port.
@@ -43,10 +44,10 @@ public:
// Constructor.
BOOST_ASIO_DECL win_iocp_serial_port_service(
- boost::asio::io_service& io_service);
+ boost::asio::io_context& io_context);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Construct a new serial port implementation.
void construct(implementation_type& impl)
@@ -185,8 +186,8 @@ private:
static boost::system::error_code store_option(const void* option,
::DCB& storage, boost::system::error_code& ec)
{
- return static_cast<const SettableSerialPortOption*>(option)->store(
- storage, ec);
+ static_cast<const SettableSerialPortOption*>(option)->store(storage, ec);
+ return ec;
}
// Helper function to set a serial port option.
@@ -203,7 +204,8 @@ private:
static boost::system::error_code load_option(void* option,
const ::DCB& storage, boost::system::error_code& ec)
{
- return static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+ static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+ return ec;
}
// Helper function to get a serial port option.
diff --git a/boost/asio/detail/win_iocp_socket_accept_op.hpp b/boost/asio/detail/win_iocp_socket_accept_op.hpp
index d296103c54..f05be5465d 100644
--- a/boost/asio/detail/win_iocp_socket_accept_op.hpp
+++ b/boost/asio/detail/win_iocp_socket_accept_op.hpp
@@ -19,12 +19,12 @@
#if defined(BOOST_ASIO_HAS_IOCP)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/win_iocp_socket_service_base.hpp>
@@ -55,6 +55,7 @@ public:
enable_connection_aborted_(enable_connection_aborted),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
socket_holder& new_socket()
@@ -72,7 +73,7 @@ public:
return sizeof(sockaddr_storage_type) + 16;
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& result_ec,
std::size_t /*bytes_transferred*/)
{
@@ -81,6 +82,7 @@ public:
// Take ownership of the operation object.
win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
if (owner)
{
@@ -121,7 +123,7 @@ public:
*o->peer_endpoint_ = peer_endpoint;
}
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -139,7 +141,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
@@ -156,6 +158,136 @@ private:
Handler handler_;
};
+#if defined(BOOST_ASIO_HAS_MOVE)
+
+template <typename Protocol, typename Handler>
+class win_iocp_socket_move_accept_op : public operation
+{
+public:
+ BOOST_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, boost::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_(BOOST_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 boost::system::error_code& result_ec,
+ std::size_t /*bytes_transferred*/)
+ {
+ boost::system::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 = { boost::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 == boost::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;
+ }
+
+ BOOST_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,
+ boost::system::error_code, typename Protocol::socket>
+ handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), ec,
+ BOOST_ASIO_MOVE_CAST(typename Protocol::socket)(o->peer_));
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+ w.complete(handler, handler.handler_);
+ BOOST_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(BOOST_ASIO_HAS_MOVE)
+
} // namespace detail
} // namespace asio
} // namespace boost
diff --git a/boost/asio/detail/win_iocp_socket_connect_op.hpp b/boost/asio/detail/win_iocp_socket_connect_op.hpp
index e987c6b6c4..829597ae9c 100644
--- a/boost/asio/detail/win_iocp_socket_connect_op.hpp
+++ b/boost/asio/detail/win_iocp_socket_connect_op.hpp
@@ -19,11 +19,11 @@
#if defined(BOOST_ASIO_HAS_IOCP)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/error.hpp>
@@ -44,12 +44,13 @@ public:
{
}
- static bool do_perform(reactor_op* base)
+ 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_);
+ return socket_ops::non_blocking_connect(
+ o->socket_, o->ec_) ? done : not_done;
}
socket_type socket_;
@@ -67,9 +68,10 @@ public:
&win_iocp_socket_connect_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& result_ec,
std::size_t /*bytes_transferred*/)
{
@@ -79,6 +81,7 @@ public:
win_iocp_socket_connect_op* o(
static_cast<win_iocp_socket_connect_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
if (owner)
{
@@ -88,7 +91,7 @@ public:
ec = o->ec_;
}
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -106,7 +109,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/win_iocp_socket_recv_op.hpp b/boost/asio/detail/win_iocp_socket_recv_op.hpp
index 4202822d17..46f5dcd3f5 100644
--- a/boost/asio/detail/win_iocp_socket_recv_op.hpp
+++ b/boost/asio/detail/win_iocp_socket_recv_op.hpp
@@ -19,12 +19,12 @@
#if defined(BOOST_ASIO_HAS_IOCP)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/error.hpp>
@@ -50,9 +50,10 @@ public:
buffers_(buffers),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& result_ec,
std::size_t bytes_transferred)
{
@@ -61,8 +62,9 @@ public:
// Take ownership of the operation object.
win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
// Check whether buffers are still valid.
@@ -94,7 +96,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp b/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp
index 21ca4fb331..b9437c3a60 100644
--- a/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp
+++ b/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp
@@ -19,12 +19,12 @@
#if defined(BOOST_ASIO_HAS_IOCP)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/error.hpp>
@@ -51,6 +51,7 @@ public:
buffers_(buffers),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
int& endpoint_size()
@@ -58,7 +59,7 @@ public:
return endpoint_size_;
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& result_ec,
std::size_t bytes_transferred)
{
@@ -68,8 +69,9 @@ public:
win_iocp_socket_recvfrom_op* o(
static_cast<win_iocp_socket_recvfrom_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
// Check whether buffers are still valid.
@@ -101,7 +103,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp b/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp
index 5179bb2945..51747c55e8 100644
--- a/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp
+++ b/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp
@@ -19,12 +19,12 @@
#if defined(BOOST_ASIO_HAS_IOCP)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/error.hpp>
@@ -52,9 +52,10 @@ public:
out_flags_(out_flags),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& result_ec,
std::size_t bytes_transferred)
{
@@ -64,8 +65,9 @@ public:
win_iocp_socket_recvmsg_op* o(
static_cast<win_iocp_socket_recvmsg_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
// Check whether buffers are still valid.
@@ -95,7 +97,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/win_iocp_socket_send_op.hpp b/boost/asio/detail/win_iocp_socket_send_op.hpp
index c9abc0e664..48951c2508 100644
--- a/boost/asio/detail/win_iocp_socket_send_op.hpp
+++ b/boost/asio/detail/win_iocp_socket_send_op.hpp
@@ -19,12 +19,12 @@
#if defined(BOOST_ASIO_HAS_IOCP)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/error.hpp>
@@ -48,9 +48,10 @@ public:
buffers_(buffers),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code& result_ec,
std::size_t bytes_transferred)
{
@@ -59,8 +60,9 @@ public:
// Take ownership of the operation object.
win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
// Check whether buffers are still valid.
@@ -89,7 +91,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/win_iocp_socket_service.hpp b/boost/asio/detail/win_iocp_socket_service.hpp
index 179798c8d9..ed1cd1edd5 100644
--- a/boost/asio/detail/win_iocp_socket_service.hpp
+++ b/boost/asio/detail/win_iocp_socket_service.hpp
@@ -21,22 +21,22 @@
#include <cstring>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/socket_base.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/operation.hpp>
-#include <boost/asio/detail/reactor.hpp>
#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/select_reactor.hpp>
#include <boost/asio/detail/socket_holder.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
-#include <boost/asio/detail/win_iocp_io_service.hpp>
+#include <boost/asio/detail/win_iocp_io_context.hpp>
#include <boost/asio/detail/win_iocp_null_buffers_op.hpp>
#include <boost/asio/detail/win_iocp_socket_accept_op.hpp>
#include <boost/asio/detail/win_iocp_socket_connect_op.hpp>
@@ -51,7 +51,9 @@ namespace asio {
namespace detail {
template <typename Protocol>
-class win_iocp_socket_service : public win_iocp_socket_service_base
+class win_iocp_socket_service :
+ public service_base<win_iocp_socket_service<Protocol> >,
+ public win_iocp_socket_service_base
{
public:
// The protocol type.
@@ -128,11 +130,18 @@ public:
};
// Constructor.
- win_iocp_socket_service(boost::asio::io_service& io_service)
- : win_iocp_socket_service_base(io_service)
+ win_iocp_socket_service(boost::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)
@@ -279,6 +288,14 @@ public:
return endpoint;
}
+ // Disable sends or receives on the socket.
+ boost::system::error_code shutdown(base_implementation_type& impl,
+ socket_base::shutdown_type what, boost::system::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>
@@ -300,7 +317,7 @@ public:
boost::system::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_write(impl.socket_, impl.state_, ec);
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -315,11 +332,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send_to"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_send_to"));
buffer_sequence_adapter<boost::asio::const_buffer,
ConstBufferSequence> bufs(buffers);
@@ -338,14 +355,13 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
- &impl, "async_send_to(null_buffers)"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_send_to(null_buffers)"));
- start_reactor_op(impl, reactor::write_op, p.p);
+ start_reactor_op(impl, select_reactor::write_op, p.p);
p.v = p.p = 0;
}
@@ -377,7 +393,7 @@ public:
socket_base::message_flags, boost::system::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ 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();
@@ -397,11 +413,11 @@ public:
typedef win_iocp_socket_recvfrom_op<
MutableBufferSequence, endpoint_type, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive_from"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_receive_from"));
buffer_sequence_adapter<boost::asio::mutable_buffer,
MutableBufferSequence> bufs(buffers);
@@ -420,12 +436,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl,
- "async_receive_from(null_buffers)"));
+ BOOST_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();
@@ -456,13 +471,42 @@ public:
{
if (peer_endpoint)
peer_endpoint->resize(addr_len);
- if (!peer.assign(impl.protocol_, new_socket.get(), ec))
+ peer.assign(impl.protocol_, new_socket.get(), ec);
+ if (!ec)
new_socket.release();
}
return ec;
}
+#if defined(BOOST_ASIO_HAS_MOVE)
+ // Accept a new connection.
+ typename Protocol::socket accept(implementation_type& impl,
+ io_context* peer_io_context, endpoint_type* peer_endpoint,
+ boost::system::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(BOOST_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>
@@ -472,14 +516,14 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ 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);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_accept"));
+ BOOST_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(),
@@ -488,6 +532,35 @@ public:
p.v = p.p = 0;
}
+#if defined(BOOST_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,
+ boost::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 = { boost::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);
+
+ BOOST_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(BOOST_ASIO_HAS_MOVE)
+
// Connect the socket to the specified endpoint.
boost::system::error_code connect(implementation_type& impl,
const endpoint_type& peer_endpoint, boost::system::error_code& ec)
@@ -505,11 +578,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_connect_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect"));
+ BOOST_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);
diff --git a/boost/asio/detail/win_iocp_socket_service_base.hpp b/boost/asio/detail/win_iocp_socket_service_base.hpp
index 8ecf219598..2af1546712 100644
--- a/boost/asio/detail/win_iocp_socket_service_base.hpp
+++ b/boost/asio/detail/win_iocp_socket_service_base.hpp
@@ -20,27 +20,28 @@
#if defined(BOOST_ASIO_HAS_IOCP)
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/socket_base.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/operation.hpp>
-#include <boost/asio/detail/reactor.hpp>
#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/select_reactor.hpp>
#include <boost/asio/detail/socket_holder.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
-#include <boost/asio/detail/win_iocp_io_service.hpp>
+#include <boost/asio/detail/win_iocp_io_context.hpp>
#include <boost/asio/detail/win_iocp_null_buffers_op.hpp>
#include <boost/asio/detail/win_iocp_socket_connect_op.hpp>
#include <boost/asio/detail/win_iocp_socket_send_op.hpp>
#include <boost/asio/detail/win_iocp_socket_recv_op.hpp>
#include <boost/asio/detail/win_iocp_socket_recvmsg_op.hpp>
+#include <boost/asio/detail/win_iocp_wait_op.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -69,7 +70,7 @@ public:
socket_ops::shared_cancel_token_type cancel_token_;
// Per-descriptor data used by the reactor.
- reactor::per_descriptor_data reactor_data_;
+ select_reactor::per_descriptor_data reactor_data_;
#if defined(BOOST_ASIO_ENABLE_CANCELIO)
// The ID of the thread from which it is safe to cancel asynchronous
@@ -86,10 +87,10 @@ public:
// Constructor.
BOOST_ASIO_DECL win_iocp_socket_service_base(
- boost::asio::io_service& io_service);
+ boost::asio::io_context& io_context);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void base_shutdown();
// Construct a new socket implementation.
BOOST_ASIO_DECL void construct(base_implementation_type& impl);
@@ -116,6 +117,10 @@ public:
BOOST_ASIO_DECL boost::system::error_code close(
base_implementation_type& impl, boost::system::error_code& ec);
+ // Release ownership of the socket.
+ BOOST_ASIO_DECL socket_type release(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
// Cancel all operations associated with the socket.
BOOST_ASIO_DECL boost::system::error_code cancel(
base_implementation_type& impl, boost::system::error_code& ec);
@@ -180,14 +185,68 @@ public:
return ec;
}
- // Disable sends or receives on the socket.
- boost::system::error_code shutdown(base_implementation_type& impl,
- socket_base::shutdown_type what, boost::system::error_code& ec)
+ // Wait for the socket to become ready to read, ready to write, or to have
+ // pending error conditions.
+ boost::system::error_code wait(base_implementation_type& impl,
+ socket_base::wait_type w, boost::system::error_code& ec)
{
- socket_ops::shutdown(impl.socket_, what, 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 = boost::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 =
+ boost_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 = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
+
+ BOOST_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_ = boost::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,
@@ -206,7 +265,7 @@ public:
socket_base::message_flags, boost::system::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_write(impl.socket_, impl.state_, ec);
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -221,11 +280,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_send"));
buffer_sequence_adapter<boost::asio::const_buffer,
ConstBufferSequence> bufs(buffers);
@@ -244,14 +303,13 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
- &impl, "async_send(null_buffers)"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_send(null_buffers)"));
- start_reactor_op(impl, reactor::write_op, p.p);
+ start_reactor_op(impl, select_reactor::write_op, p.p);
p.v = p.p = 0;
}
@@ -273,7 +331,7 @@ public:
socket_base::message_flags, boost::system::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -288,11 +346,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_recv_op<MutableBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_receive"));
buffer_sequence_adapter<boost::asio::mutable_buffer,
MutableBufferSequence> bufs(buffers);
@@ -311,12 +369,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
- &impl, "async_receive(null_buffers)"));
+ BOOST_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;
@@ -343,7 +400,7 @@ public:
socket_base::message_flags& out_flags, boost::system::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ 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.
@@ -362,12 +419,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_recvmsg_op<MutableBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, buffers, out_flags, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket",
- &impl, "async_receive_with_flags"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_receive_with_flags"));
buffer_sequence_adapter<boost::asio::mutable_buffer,
MutableBufferSequence> bufs(buffers);
@@ -385,12 +441,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_null_buffers_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl,
- "async_receive_with_flags(null_buffers)"));
+ BOOST_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;
@@ -464,9 +519,9 @@ protected:
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_service and a pointer to it is cached in
+ // new one is obtained from the io_context and a pointer to it is cached in
// this service.
- BOOST_ASIO_DECL reactor& get_reactor();
+ BOOST_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,
@@ -478,6 +533,15 @@ protected:
BOOST_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.
+ BOOST_ASIO_DECL nt_set_info_fn get_nt_set_info();
+
// Helper function to emulate InterlockedCompareExchangePointer functionality
// for:
// - very old Platform SDKs; and
@@ -490,20 +554,23 @@ protected:
// - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
BOOST_ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val);
- // The io_service used to obtain the reactor, if required.
- boost::asio::io_service& io_service_;
+ // The io_context used to obtain the reactor, if required.
+ boost::asio::io_context& io_context_;
// The IOCP service used for running asynchronous operations and dispatching
// handlers.
- win_iocp_io_service& iocp_service_;
+ win_iocp_io_context& iocp_service_;
// The reactor used for performing connect operations. This object is created
// only if needed.
- reactor* reactor_;
+ 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.
boost::asio::detail::mutex mutex_;
diff --git a/boost/asio/detail/win_iocp_wait_op.hpp b/boost/asio/detail/win_iocp_wait_op.hpp
new file mode 100644
index 0000000000..c5bc4a273f
--- /dev/null
+++ b/boost/asio/detail/win_iocp_wait_op.hpp
@@ -0,0 +1,123 @@
+//
+// detail/win_iocp_wait_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP
+#define BOOST_ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/error.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class win_iocp_wait_op : public reactor_op
+{
+public:
+ BOOST_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_(BOOST_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 boost::system::error_code& result_ec,
+ std::size_t /*bytes_transferred*/)
+ {
+ boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ BOOST_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 = boost::asio::error::operation_aborted;
+ else
+ ec = boost::asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. 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, boost::system::error_code>
+ handler(o->handler_, ec);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+#endif // BOOST_ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP
diff --git a/boost/asio/detail/win_object_handle_service.hpp b/boost/asio/detail/win_object_handle_service.hpp
index 3383657304..1e94a304eb 100644
--- a/boost/asio/detail/win_object_handle_service.hpp
+++ b/boost/asio/detail/win_object_handle_service.hpp
@@ -20,11 +20,11 @@
#if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/wait_handler.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -32,7 +32,8 @@ namespace boost {
namespace asio {
namespace detail {
-class win_object_handle_service
+class win_object_handle_service :
+ public service_base<win_object_handle_service>
{
public:
// The native type of an object handle.
@@ -80,10 +81,10 @@ public:
// Constructor.
BOOST_ASIO_DECL win_object_handle_service(
- boost::asio::io_service& io_service);
+ boost::asio::io_context& io_context);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Construct a new handle implementation.
BOOST_ASIO_DECL void construct(implementation_type& impl);
@@ -135,11 +136,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef wait_handler<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "object_handle", &impl, "async_wait"));
+ BOOST_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;
@@ -157,8 +158,8 @@ private:
static BOOST_ASIO_DECL VOID CALLBACK wait_callback(
PVOID param, BOOLEAN timeout);
- // The io_service implementation used to post completions.
- io_service_impl& io_service_;
+ // The io_context implementation used to post completions.
+ io_context_impl& io_context_;
// Mutex to protect access to internal state.
mutex mutex_;
diff --git a/boost/asio/detail/win_thread.hpp b/boost/asio/detail/win_thread.hpp
index a138d92ee8..f063330e1d 100644
--- a/boost/asio/detail/win_thread.hpp
+++ b/boost/asio/detail/win_thread.hpp
@@ -21,6 +21,7 @@
&& !defined(BOOST_ASIO_WINDOWS_APP) \
&& !defined(UNDER_CE)
+#include <cstddef>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/socket_types.hpp>
@@ -79,6 +80,9 @@ public:
// Wait for the thread to exit.
BOOST_ASIO_DECL void join();
+ // Get number of CPUs.
+ BOOST_ASIO_DECL static std::size_t hardware_concurrency();
+
private:
friend BOOST_ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);
diff --git a/boost/asio/detail/winapi_thread.hpp b/boost/asio/detail/winapp_thread.hpp
index 79aba9b519..4b57d228f6 100644
--- a/boost/asio/detail/winapi_thread.hpp
+++ b/boost/asio/detail/winapp_thread.hpp
@@ -1,5 +1,5 @@
//
-// detail/winapi_thread.hpp
+// detail/winapp_thread.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
@@ -8,8 +8,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#ifndef BOOST_ASIO_DETAIL_WINAPI_THREAD_HPP
-#define BOOST_ASIO_DETAIL_WINAPI_THREAD_HPP
+#ifndef BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP
+#define BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -17,8 +17,7 @@
#include <boost/asio/detail/config.hpp>
-#if defined(BOOST_ASIO_WINDOWS)
-#if defined(BOOST_ASIO_WINDOWS_APP) || defined(UNDER_CE)
+#if defined(BOOST_ASIO_WINDOWS) && defined(BOOST_ASIO_WINDOWS_APP)
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/scoped_ptr.hpp>
@@ -32,19 +31,19 @@ namespace boost {
namespace asio {
namespace detail {
-DWORD WINAPI winapi_thread_function(LPVOID arg);
+DWORD WINAPI winapp_thread_function(LPVOID arg);
-class winapi_thread
+class winapp_thread
: private noncopyable
{
public:
// Constructor.
template <typename Function>
- winapi_thread(Function f, unsigned int = 0)
+ winapp_thread(Function f, unsigned int = 0)
{
scoped_ptr<func_base> arg(new func<Function>(f));
DWORD thread_id = 0;
- thread_ = ::CreateThread(0, 0, winapi_thread_function,
+ thread_ = ::CreateThread(0, 0, winapp_thread_function,
arg.get(), 0, &thread_id);
if (!thread_)
{
@@ -57,7 +56,7 @@ public:
}
// Destructor.
- ~winapi_thread()
+ ~winapp_thread()
{
::CloseHandle(thread_);
}
@@ -65,15 +64,19 @@ public:
// Wait for the thread to exit.
void join()
{
-#if defined(BOOST_ASIO_WINDOWS_APP)
::WaitForSingleObjectEx(thread_, INFINITE, false);
-#else // defined(BOOST_ASIO_WINDOWS_APP)
- ::WaitForSingleObject(thread_, INFINITE);
-#endif // defined(BOOST_ASIO_WINDOWS_APP)
+ }
+
+ // 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 winapi_thread_function(LPVOID arg);
+ friend DWORD WINAPI winapp_thread_function(LPVOID arg);
class func_base
{
@@ -104,10 +107,10 @@ private:
::HANDLE thread_;
};
-inline DWORD WINAPI winapi_thread_function(LPVOID arg)
+inline DWORD WINAPI winapp_thread_function(LPVOID arg)
{
- scoped_ptr<winapi_thread::func_base> func(
- static_cast<winapi_thread::func_base*>(arg));
+ scoped_ptr<winapp_thread::func_base> func(
+ static_cast<winapp_thread::func_base*>(arg));
func->run();
return 0;
}
@@ -118,7 +121,6 @@ inline DWORD WINAPI winapi_thread_function(LPVOID arg)
#include <boost/asio/detail/pop_options.hpp>
-#endif // defined(BOOST_ASIO_WINDOWS_APP) || defined(UNDER_CE)
-#endif // defined(BOOST_ASIO_WINDOWS)
+#endif // defined(BOOST_ASIO_WINDOWS) && defined(BOOST_ASIO_WINDOWS_APP)
-#endif // BOOST_ASIO_DETAIL_WINAPI_THREAD_HPP
+#endif // BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP
diff --git a/boost/asio/detail/wince_thread.hpp b/boost/asio/detail/wince_thread.hpp
new file mode 100644
index 0000000000..bc14d71207
--- /dev/null
+++ b/boost/asio/detail/wince_thread.hpp
@@ -0,0 +1,126 @@
+//
+// detail/wince_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_WINCE_THREAD_HPP
+#define BOOST_ASIO_DETAIL_WINCE_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
+
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/scoped_ptr.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/throw_error.hpp>
+#include <boost/asio/error.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+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();
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ boost::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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
+
+#endif // BOOST_ASIO_DETAIL_WINCE_THREAD_HPP
diff --git a/boost/asio/detail/winrt_async_manager.hpp b/boost/asio/detail/winrt_async_manager.hpp
index d6d823d689..7af5357633 100644
--- a/boost/asio/detail/winrt_async_manager.hpp
+++ b/boost/asio/detail/winrt_async_manager.hpp
@@ -23,7 +23,7 @@
#include <boost/asio/detail/atomic_count.hpp>
#include <boost/asio/detail/winrt_async_op.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -36,9 +36,9 @@ class winrt_async_manager
{
public:
// Constructor.
- winrt_async_manager(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<winrt_async_manager>(io_service),
- io_service_(use_service<io_service_impl>(io_service)),
+ winrt_async_manager(boost::asio::io_context& io_context)
+ : boost::asio::detail::service_base<winrt_async_manager>(io_context),
+ io_context_(use_service<io_context_impl>(io_context)),
outstanding_ops_(1)
{
}
@@ -49,7 +49,7 @@ public:
}
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
+ void shutdown()
{
if (--outstanding_ops_ > 0)
{
@@ -186,12 +186,12 @@ public:
boost::system::system_category());
break;
}
- io_service_.post_deferred_completion(handler);
+ io_context_.post_deferred_completion(handler);
if (--outstanding_ops_ == 0)
promise_.set_value();
});
- io_service_.work_started();
+ io_context_.work_started();
++outstanding_ops_;
action->Completed = on_completed;
}
@@ -223,12 +223,12 @@ public:
boost::system::system_category());
break;
}
- io_service_.post_deferred_completion(handler);
+ io_context_.post_deferred_completion(handler);
if (--outstanding_ops_ == 0)
promise_.set_value();
});
- io_service_.work_started();
+ io_context_.work_started();
++outstanding_ops_;
operation->Completed = on_completed;
}
@@ -264,19 +264,19 @@ public:
boost::system::system_category());
break;
}
- io_service_.post_deferred_completion(handler);
+ io_context_.post_deferred_completion(handler);
if (--outstanding_ops_ == 0)
promise_.set_value();
});
- io_service_.work_started();
+ io_context_.work_started();
++outstanding_ops_;
operation->Completed = on_completed;
}
private:
- // The io_service implementation used to post completed handlers.
- io_service_impl& io_service_;
+ // The io_context implementation used to post completed handlers.
+ io_context_impl& io_context_;
// Count of outstanding operations.
atomic_count outstanding_ops_;
diff --git a/boost/asio/detail/winrt_resolve_op.hpp b/boost/asio/detail/winrt_resolve_op.hpp
index 12d56933b1..7a98345a09 100644
--- a/boost/asio/detail/winrt_resolve_op.hpp
+++ b/boost/asio/detail/winrt_resolve_op.hpp
@@ -19,13 +19,13 @@
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/winrt_async_op.hpp>
-#include <boost/asio/ip/basic_resolver_iterator.hpp>
+#include <boost/asio/ip/basic_resolver_results.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -45,7 +45,7 @@ public:
typedef typename Protocol::endpoint endpoint_type;
typedef boost::asio::ip::basic_resolver_query<Protocol> query_type;
- typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type;
+ typedef boost::asio::ip::basic_resolver_results<Protocol> results_type;
winrt_resolve_op(const query_type& query, Handler& handler)
: winrt_async_op<
@@ -55,24 +55,25 @@ public:
query_(query),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::error_code&, std::size_t)
{
// Take ownership of the operation object.
winrt_resolve_op* o(static_cast<winrt_resolve_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
- iterator_type iterator = iterator_type();
+ results_type results = results_type();
if (!o->ec_)
{
try
{
- iterator = iterator_type::create(
- o->result_, o->query_.hints(),
+ results = results_type::create(o->result_, o->query_.hints(),
o->query_.host_name(), o->query_.service_name());
}
catch (Platform::Exception^ e)
@@ -88,8 +89,8 @@ public:
// 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, boost::system::error_code, iterator_type>
- handler(o->handler_, o->ec_, iterator);
+ detail::binder2<Handler, boost::system::error_code, results_type>
+ handler(o->handler_, o->ec_, results);
p.h = boost::asio::detail::addressof(handler.handler_);
p.reset();
@@ -97,8 +98,8 @@ public:
if (owner)
{
fenced_block b(fenced_block::half);
- BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/winrt_resolver_service.hpp b/boost/asio/detail/winrt_resolver_service.hpp
index dfd1dddeb2..30e50e4f00 100644
--- a/boost/asio/detail/winrt_resolver_service.hpp
+++ b/boost/asio/detail/winrt_resolver_service.hpp
@@ -19,10 +19,10 @@
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
-#include <boost/asio/ip/basic_resolver_iterator.hpp>
#include <boost/asio/ip/basic_resolver_query.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/ip/basic_resolver_results.hpp>
#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/winrt_async_manager.hpp>
#include <boost/asio/detail/winrt_resolve_op.hpp>
@@ -35,7 +35,8 @@ namespace asio {
namespace detail {
template <typename Protocol>
-class winrt_resolver_service
+class winrt_resolver_service :
+ public service_base<winrt_resolver_service<Protocol> >
{
public:
// The implementation type of the resolver. A cancellation token is used to
@@ -49,13 +50,14 @@ public:
// The query type.
typedef boost::asio::ip::basic_resolver_query<Protocol> query_type;
- // The iterator type.
- typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type;
+ // The results type.
+ typedef boost::asio::ip::basic_resolver_results<Protocol> results_type;
// Constructor.
- winrt_resolver_service(boost::asio::io_service& io_service)
- : io_service_(use_service<io_service_impl>(io_service)),
- async_manager_(use_service<winrt_async_manager>(io_service))
+ winrt_resolver_service(boost::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))
{
}
@@ -65,12 +67,12 @@ public:
}
// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
+ void shutdown()
{
}
// Perform any fork-related housekeeping.
- void fork_service(boost::asio::io_service::fork_event)
+ void notify_fork(boost::asio::io_context::fork_event)
{
}
@@ -79,6 +81,18 @@ public:
{
}
+ // 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&)
{
@@ -90,7 +104,7 @@ public:
}
// Resolve a query to a list of entries.
- iterator_type resolve(implementation_type&,
+ results_type resolve(implementation_type&,
const query_type& query, boost::system::error_code& ec)
{
try
@@ -102,9 +116,9 @@ public:
winrt_utils::string(query.service_name())), ec);
if (ec)
- return iterator_type();
+ return results_type();
- return iterator_type::create(
+ return results_type::create(
endpoint_pairs, query.hints(),
query.host_name(), query.service_name());
}
@@ -112,13 +126,13 @@ public:
{
ec = boost::system::error_code(e->HResult,
boost::system::system_category());
- return iterator_type();
+ return results_type();
}
}
// Asynchronously resolve a query to a list of entries.
template <typename Handler>
- void async_resolve(implementation_type&,
+ void async_resolve(implementation_type& impl,
const query_type& query, Handler& handler)
{
bool is_continuation =
@@ -127,11 +141,12 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef winrt_resolve_op<Protocol, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(query, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "resolver", &impl, "async_resolve"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_.context(),
+ *p.p, "resolver", &impl, 0, "async_resolve"));
+ (void)impl;
try
{
@@ -145,17 +160,17 @@ public:
{
p.p->ec_ = boost::system::error_code(
e->HResult, boost::system::system_category());
- io_service_.post_immediate_completion(p.p, is_continuation);
+ io_context_.post_immediate_completion(p.p, is_continuation);
p.v = p.p = 0;
}
}
// Resolve an endpoint to a list of entries.
- iterator_type resolve(implementation_type&,
+ results_type resolve(implementation_type&,
const endpoint_type&, boost::system::error_code& ec)
{
ec = boost::asio::error::operation_not_supported;
- return iterator_type();
+ return results_type();
}
// Asynchronously resolve an endpoint to a list of entries.
@@ -164,13 +179,13 @@ public:
const endpoint_type&, Handler& handler)
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
- const iterator_type iterator;
- io_service_.get_io_service().post(
- detail::bind_handler(handler, ec, iterator));
+ const results_type results;
+ io_context_.get_io_context().post(
+ detail::bind_handler(handler, ec, results));
}
private:
- io_service_impl& io_service_;
+ io_context_impl& io_context_;
winrt_async_manager& async_manager_;
};
diff --git a/boost/asio/detail/winrt_socket_connect_op.hpp b/boost/asio/detail/winrt_socket_connect_op.hpp
index 548f7d631a..6fc1ab0c7f 100644
--- a/boost/asio/detail/winrt_socket_connect_op.hpp
+++ b/boost/asio/detail/winrt_socket_connect_op.hpp
@@ -19,12 +19,12 @@
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/winrt_async_op.hpp>
#include <boost/asio/error.hpp>
@@ -45,16 +45,18 @@ public:
: winrt_async_op<void>(&winrt_socket_connect_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_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
@@ -71,8 +73,8 @@ public:
if (owner)
{
fenced_block b(fenced_block::half);
- BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/winrt_socket_recv_op.hpp b/boost/asio/detail/winrt_socket_recv_op.hpp
index 2cbbb3c8d8..137ed5a118 100644
--- a/boost/asio/detail/winrt_socket_recv_op.hpp
+++ b/boost/asio/detail/winrt_socket_recv_op.hpp
@@ -19,12 +19,12 @@
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/winrt_async_op.hpp>
#include <boost/asio/error.hpp>
@@ -47,16 +47,18 @@ public:
buffers_(buffers),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
// Check whether buffers are still valid.
@@ -91,7 +93,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/winrt_socket_send_op.hpp b/boost/asio/detail/winrt_socket_send_op.hpp
index 591d9536c3..301c4127a6 100644
--- a/boost/asio/detail/winrt_socket_send_op.hpp
+++ b/boost/asio/detail/winrt_socket_send_op.hpp
@@ -19,12 +19,12 @@
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/winrt_async_op.hpp>
#include <boost/asio/error.hpp>
@@ -46,16 +46,18 @@ public:
buffers_(buffers),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
+ handler_work<Handler>::start(handler_);
}
- static void do_complete(io_service_impl* owner, operation* base,
+ static void do_complete(void* owner, operation* base,
const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
- BOOST_ASIO_HANDLER_COMPLETION((o));
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
// Check whether buffers are still valid.
@@ -82,7 +84,7 @@ public:
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
- boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
+ w.complete(handler, handler.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
diff --git a/boost/asio/detail/winrt_ssocket_service.hpp b/boost/asio/detail/winrt_ssocket_service.hpp
index b9b1910e78..a1e15db545 100644
--- a/boost/asio/detail/winrt_ssocket_service.hpp
+++ b/boost/asio/detail/winrt_ssocket_service.hpp
@@ -20,8 +20,8 @@
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/winrt_socket_connect_op.hpp>
#include <boost/asio/detail/winrt_ssocket_service_base.hpp>
#include <boost/asio/detail/winrt_utils.hpp>
@@ -34,6 +34,7 @@ namespace detail {
template <typename Protocol>
class winrt_ssocket_service :
+ public service_base<winrt_ssocket_service<Protocol> >,
public winrt_ssocket_service_base
{
public:
@@ -61,11 +62,18 @@ public:
};
// Constructor.
- winrt_ssocket_service(boost::asio::io_service& io_service)
- : winrt_ssocket_service_base(io_service)
+ winrt_ssocket_service(boost::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)
@@ -213,11 +221,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef winrt_socket_connect_op<Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect"));
+ BOOST_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;
diff --git a/boost/asio/detail/winrt_ssocket_service_base.hpp b/boost/asio/detail/winrt_ssocket_service_base.hpp
index 88e5674576..c18722466f 100644
--- a/boost/asio/detail/winrt_ssocket_service_base.hpp
+++ b/boost/asio/detail/winrt_ssocket_service_base.hpp
@@ -21,10 +21,10 @@
#include <boost/asio/buffer.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#include <boost/asio/socket_base.hpp>
-#include <boost/asio/detail/addressof.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/socket_types.hpp>
#include <boost/asio/detail/winrt_async_manager.hpp>
#include <boost/asio/detail/winrt_socket_recv_op.hpp>
@@ -63,10 +63,10 @@ public:
// Constructor.
BOOST_ASIO_DECL winrt_ssocket_service_base(
- boost::asio::io_service& io_service);
+ boost::asio::io_context& io_context);
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void base_shutdown();
// Construct a new socket implementation.
BOOST_ASIO_DECL void construct(base_implementation_type&);
@@ -93,6 +93,10 @@ public:
BOOST_ASIO_DECL boost::system::error_code close(
base_implementation_type& impl, boost::system::error_code& ec);
+ // Release ownership of the socket.
+ BOOST_ASIO_DECL native_handle_type release(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
// Get the native socket representation.
native_handle_type native_handle(base_implementation_type& impl)
{
@@ -200,11 +204,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef winrt_socket_send_op<ConstBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_.context(),
+ *p.p, "socket", &impl, 0, "async_send"));
start_send_op(impl,
buffer_sequence_adapter<boost::asio::const_buffer,
@@ -220,7 +224,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.get_io_service().post(
+ io_context_.get_io_context().post(
detail::bind_handler(handler, ec, bytes_transferred));
}
@@ -256,11 +260,11 @@ public:
// Allocate and construct an operation to wrap the handler.
typedef winrt_socket_recv_op<MutableBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
- boost_asio_handler_alloc_helpers::allocate(
- sizeof(op), handler), 0 };
+ op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
- BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive"));
+ BOOST_ASIO_HANDLER_CREATION((io_context_.context(),
+ *p.p, "socket", &impl, 0, "async_receive"));
start_receive_op(impl,
buffer_sequence_adapter<boost::asio::mutable_buffer,
@@ -276,7 +280,7 @@ public:
{
boost::system::error_code ec = boost::asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
- io_service_.get_io_service().post(
+ io_context_.get_io_context().post(
detail::bind_handler(handler, ec, bytes_transferred));
}
@@ -329,8 +333,8 @@ protected:
winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
bool is_continuation);
- // The io_service implementation used for delivering completions.
- io_service_impl& io_service_;
+ // 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_;
diff --git a/boost/asio/detail/winrt_timer_scheduler.hpp b/boost/asio/detail/winrt_timer_scheduler.hpp
index 8b119b2724..9dd9d050ce 100644
--- a/boost/asio/detail/winrt_timer_scheduler.hpp
+++ b/boost/asio/detail/winrt_timer_scheduler.hpp
@@ -28,7 +28,7 @@
#include <boost/asio/detail/timer_queue_base.hpp>
#include <boost/asio/detail/timer_queue_set.hpp>
#include <boost/asio/detail/wait_op.hpp>
-#include <boost/asio/io_service.hpp>
+#include <boost/asio/io_context.hpp>
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/thread.hpp>
@@ -45,17 +45,17 @@ class winrt_timer_scheduler
{
public:
// Constructor.
- BOOST_ASIO_DECL winrt_timer_scheduler(boost::asio::io_service& io_service);
+ BOOST_ASIO_DECL winrt_timer_scheduler(boost::asio::io_context& io_context);
// Destructor.
BOOST_ASIO_DECL ~winrt_timer_scheduler();
// Destroy all user-defined handler objects owned by the service.
- BOOST_ASIO_DECL void shutdown_service();
+ BOOST_ASIO_DECL void shutdown();
// Recreate internal descriptors following a fork.
- BOOST_ASIO_DECL void fork_service(
- boost::asio::io_service::fork_event fork_ev);
+ BOOST_ASIO_DECL void notify_fork(
+ boost::asio::io_context::fork_event fork_ev);
// Initialise the task. No effect as this class uses its own thread.
BOOST_ASIO_DECL void init_task();
@@ -82,6 +82,12 @@ public:
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.
BOOST_ASIO_DECL void run_thread();
@@ -95,8 +101,8 @@ private:
// Helper function to remove a timer queue.
BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
- // The io_service implementation used to post completions.
- io_service_impl& io_service_;
+ // The io_context implementation used to post completions.
+ io_context_impl& io_context_;
// Mutex used to protect internal variables.
boost::asio::detail::mutex mutex_;
diff --git a/boost/asio/detail/winrt_utils.hpp b/boost/asio/detail/winrt_utils.hpp
index 351aa62f23..0aebacbbb9 100644
--- a/boost/asio/detail/winrt_utils.hpp
+++ b/boost/asio/detail/winrt_utils.hpp
@@ -23,13 +23,12 @@
#include <cstdlib>
#include <future>
#include <locale>
-#include <memory>
#include <robuffer.h>
#include <windows.storage.streams.h>
#include <wrl/implements.h>
#include <boost/asio/buffer.hpp>
#include <boost/system/error_code.hpp>
-#include <boost/asio/detail/addressof.hpp>
+#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -84,7 +83,8 @@ inline Windows::Storage::Streams::IBuffer^ buffer_dup(
const ConstBufferSequence& buffers)
{
using Microsoft::WRL::ComPtr;
- std::size_t size = boost::asio::buffer_size(buffers);
+ using boost::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;
diff --git a/boost/asio/detail/work_dispatcher.hpp b/boost/asio/detail/work_dispatcher.hpp
new file mode 100644
index 0000000000..7ccacd5546
--- /dev/null
+++ b/boost/asio/detail/work_dispatcher.hpp
@@ -0,0 +1,74 @@
+//
+// detail/work_dispatcher.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_WORK_DISPATCHER_HPP
+#define BOOST_ASIO_DETAIL_WORK_DISPATCHER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/associated_allocator.hpp>
+#include <boost/asio/executor_work_guard.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class work_dispatcher
+{
+public:
+ work_dispatcher(Handler& handler)
+ : work_((get_associated_executor)(handler)),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
+ {
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE)
+ work_dispatcher(const work_dispatcher& other)
+ : work_(other.work_),
+ handler_(other.handler_)
+ {
+ }
+
+ work_dispatcher(work_dispatcher&& other)
+ : work_(BOOST_ASIO_MOVE_CAST(executor_work_guard<
+ typename associated_executor<Handler>::type>)(other.work_)),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_))
+ {
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
+ void operator()()
+ {
+ typename associated_allocator<Handler>::type alloc(
+ (get_associated_allocator)(handler_));
+ work_.get_executor().dispatch(
+ BOOST_ASIO_MOVE_CAST(Handler)(handler_), alloc);
+ work_.reset();
+ }
+
+private:
+ executor_work_guard<typename associated_executor<Handler>::type> work_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WORK_DISPATCHER_HPP