Update io_context::executor_type to standard executor form.
This commit is contained in:
parent
e61acbcb42
commit
4cd27fffd4
@ -342,6 +342,7 @@ nobase_include_HEADERS = \
|
||||
asio/impl/handler_alloc_hook.ipp \
|
||||
asio/impl/io_context.hpp \
|
||||
asio/impl/io_context.ipp \
|
||||
asio/impl/multiple_exceptions.ipp \
|
||||
asio/impl/post.hpp \
|
||||
asio/impl/read_at.hpp \
|
||||
asio/impl/read.hpp \
|
||||
@ -415,6 +416,7 @@ nobase_include_HEADERS = \
|
||||
asio/local/detail/endpoint.hpp \
|
||||
asio/local/detail/impl/endpoint.ipp \
|
||||
asio/local/stream_protocol.hpp \
|
||||
asio/multiple_exceptions.hpp \
|
||||
asio/packaged_task.hpp \
|
||||
asio/placeholders.hpp \
|
||||
asio/posix/basic_descriptor.hpp \
|
||||
|
@ -117,6 +117,7 @@
|
||||
#include "asio/local/connect_pair.hpp"
|
||||
#include "asio/local/datagram_protocol.hpp"
|
||||
#include "asio/local/stream_protocol.hpp"
|
||||
#include "asio/multiple_exceptions.hpp"
|
||||
#include "asio/packaged_task.hpp"
|
||||
#include "asio/placeholders.hpp"
|
||||
#include "asio/posix/basic_descriptor.hpp"
|
||||
|
@ -1108,6 +1108,30 @@
|
||||
# endif // !defined(ASIO_DISABLE_STD_INVOKE_RESULT)
|
||||
#endif // !defined(ASIO_HAS_STD_INVOKE_RESULT)
|
||||
|
||||
// Standard library support for std::exception_ptr and std::current_exception.
|
||||
#if !defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
# if !defined(ASIO_DISABLE_STD_EXCEPTION_PTR)
|
||||
# if defined(__clang__)
|
||||
# if defined(ASIO_HAS_CLANG_LIBCXX)
|
||||
# define ASIO_HAS_STD_EXCEPTION_PTR 1
|
||||
# elif (__cplusplus >= 201103)
|
||||
# define ASIO_HAS_STD_EXCEPTION_PTR 1
|
||||
# endif // (__cplusplus >= 201103)
|
||||
# elif defined(__GNUC__)
|
||||
# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
|
||||
# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define ASIO_HAS_STD_EXCEPTION_PTR 1
|
||||
# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
|
||||
# endif // defined(__GNUC__)
|
||||
# if defined(ASIO_MSVC)
|
||||
# if (_MSC_VER >= 1800)
|
||||
# define ASIO_HAS_STD_EXCEPTION_PTR 1
|
||||
# endif // (_MSC_VER >= 1800)
|
||||
# endif // defined(ASIO_MSVC)
|
||||
# endif // !defined(ASIO_DISABLE_STD_EXCEPTION_PTR)
|
||||
#endif // !defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
|
||||
// Standard library support for std::source_location.
|
||||
#if !defined(ASIO_HAS_STD_SOURCE_LOCATION)
|
||||
# if !defined(ASIO_DISABLE_STD_SOURCE_LOCATION)
|
||||
|
@ -324,6 +324,12 @@ void scheduler::compensating_work_started()
|
||||
++static_cast<thread_info*>(this_thread)->private_outstanding_work;
|
||||
}
|
||||
|
||||
void scheduler::capture_current_exception()
|
||||
{
|
||||
if (thread_info_base* this_thread = thread_call_stack::contains(this))
|
||||
this_thread->capture_current_exception();
|
||||
}
|
||||
|
||||
void scheduler::post_immediate_completion(
|
||||
scheduler::operation* op, bool is_continuation)
|
||||
{
|
||||
@ -448,6 +454,7 @@ std::size_t scheduler::do_run_one(mutex::scoped_lock& lock,
|
||||
|
||||
// Complete the operation. May throw an exception. Deletes the object.
|
||||
o->complete(this, ec, task_result);
|
||||
this_thread.rethrow_pending_exception();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -528,6 +535,7 @@ std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock,
|
||||
|
||||
// Complete the operation. May throw an exception. Deletes the object.
|
||||
o->complete(this, ec, task_result);
|
||||
this_thread.rethrow_pending_exception();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -582,6 +590,7 @@ std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock,
|
||||
|
||||
// Complete the operation. May throw an exception. Deletes the object.
|
||||
o->complete(this, ec, task_result);
|
||||
this_thread.rethrow_pending_exception();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ size_t win_iocp_io_context::run(asio::error_code& ec)
|
||||
thread_call_stack::context ctx(this, this_thread);
|
||||
|
||||
size_t n = 0;
|
||||
while (do_one(INFINITE, ec))
|
||||
while (do_one(INFINITE, this_thread, ec))
|
||||
if (n != (std::numeric_limits<size_t>::max)())
|
||||
++n;
|
||||
return n;
|
||||
@ -218,7 +218,7 @@ size_t win_iocp_io_context::run_one(asio::error_code& ec)
|
||||
win_iocp_thread_info this_thread;
|
||||
thread_call_stack::context ctx(this, this_thread);
|
||||
|
||||
return do_one(INFINITE, ec);
|
||||
return do_one(INFINITE, this_thread, ec);
|
||||
}
|
||||
|
||||
size_t win_iocp_io_context::wait_one(long usec, asio::error_code& ec)
|
||||
@ -233,7 +233,7 @@ size_t win_iocp_io_context::wait_one(long usec, asio::error_code& ec)
|
||||
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);
|
||||
return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), this_thread, ec);
|
||||
}
|
||||
|
||||
size_t win_iocp_io_context::poll(asio::error_code& ec)
|
||||
@ -249,7 +249,7 @@ size_t win_iocp_io_context::poll(asio::error_code& ec)
|
||||
thread_call_stack::context ctx(this, this_thread);
|
||||
|
||||
size_t n = 0;
|
||||
while (do_one(0, ec))
|
||||
while (do_one(0, this_thread, ec))
|
||||
if (n != (std::numeric_limits<size_t>::max)())
|
||||
++n;
|
||||
return n;
|
||||
@ -267,7 +267,7 @@ size_t win_iocp_io_context::poll_one(asio::error_code& ec)
|
||||
win_iocp_thread_info this_thread;
|
||||
thread_call_stack::context ctx(this, this_thread);
|
||||
|
||||
return do_one(0, ec);
|
||||
return do_one(0, this_thread, ec);
|
||||
}
|
||||
|
||||
void win_iocp_io_context::stop()
|
||||
@ -287,6 +287,12 @@ void win_iocp_io_context::stop()
|
||||
}
|
||||
}
|
||||
|
||||
void win_iocp_io_context::capture_current_exception()
|
||||
{
|
||||
if (thread_info_base* this_thread = thread_call_stack::contains(this))
|
||||
this_thread->capture_current_exception();
|
||||
}
|
||||
|
||||
void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op)
|
||||
{
|
||||
// Flag the operation as ready.
|
||||
@ -396,7 +402,8 @@ void win_iocp_io_context::on_completion(win_iocp_operation* op,
|
||||
}
|
||||
}
|
||||
|
||||
size_t win_iocp_io_context::do_one(DWORD msec, asio::error_code& ec)
|
||||
size_t win_iocp_io_context::do_one(DWORD msec,
|
||||
win_iocp_thread_info& this_thread, asio::error_code& ec)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
@ -458,6 +465,7 @@ size_t win_iocp_io_context::do_one(DWORD msec, asio::error_code& ec)
|
||||
(void)on_exit;
|
||||
|
||||
op->complete(this, result_ec, bytes_transferred);
|
||||
this_thread.rethrow_pending_exception();
|
||||
ec = asio::error_code();
|
||||
return 1;
|
||||
}
|
||||
|
@ -104,6 +104,9 @@ public:
|
||||
return thread_call_stack::contains(this) != 0;
|
||||
}
|
||||
|
||||
/// Capture the current exception so it can be rethrown from a run function.
|
||||
ASIO_DECL void capture_current_exception();
|
||||
|
||||
// Request invocation of the given operation and return immediately. Assumes
|
||||
// that work_started() has not yet been called for the operation.
|
||||
ASIO_DECL void post_immediate_completion(
|
||||
|
@ -15,10 +15,18 @@
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include "asio/detail/noncopyable.hpp"
|
||||
|
||||
#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
|
||||
&& !defined(ASIO_NO_EXCEPTIONS)
|
||||
# include <exception>
|
||||
# include "asio/multiple_exceptions.hpp"
|
||||
#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
// && !defined(ASIO_NO_EXCEPTIONS)
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
@ -44,6 +52,11 @@ public:
|
||||
};
|
||||
|
||||
thread_info_base()
|
||||
#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
|
||||
&& !defined(ASIO_NO_EXCEPTIONS)
|
||||
: has_pending_exception_(0)
|
||||
#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
// && !defined(ASIO_NO_EXCEPTIONS)
|
||||
{
|
||||
for (int i = 0; i < max_mem_index; ++i)
|
||||
reusable_memory_[i] = 0;
|
||||
@ -111,10 +124,55 @@ public:
|
||||
::operator delete(pointer);
|
||||
}
|
||||
|
||||
void capture_current_exception()
|
||||
{
|
||||
#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
|
||||
&& !defined(ASIO_NO_EXCEPTIONS)
|
||||
switch (has_pending_exception_)
|
||||
{
|
||||
case 0:
|
||||
has_pending_exception_ = 1;
|
||||
pending_exception_ = std::current_exception();
|
||||
break;
|
||||
case 1:
|
||||
has_pending_exception_ = 2;
|
||||
pending_exception_ =
|
||||
std::make_exception_ptr<multiple_exceptions>(
|
||||
multiple_exceptions(pending_exception_));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
// && !defined(ASIO_NO_EXCEPTIONS)
|
||||
}
|
||||
|
||||
void rethrow_pending_exception()
|
||||
{
|
||||
#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
|
||||
&& !defined(ASIO_NO_EXCEPTIONS)
|
||||
if (has_pending_exception_ > 0)
|
||||
{
|
||||
has_pending_exception_ = 0;
|
||||
std::exception_ptr ex(
|
||||
ASIO_MOVE_CAST(std::exception_ptr)(
|
||||
pending_exception_));
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
// && !defined(ASIO_NO_EXCEPTIONS)
|
||||
}
|
||||
|
||||
private:
|
||||
enum { chunk_size = 4 };
|
||||
enum { max_mem_index = 3 };
|
||||
void* reusable_memory_[max_mem_index];
|
||||
|
||||
#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
|
||||
&& !defined(ASIO_NO_EXCEPTIONS)
|
||||
int has_pending_exception_;
|
||||
std::exception_ptr pending_exception_;
|
||||
#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
// && !defined(ASIO_NO_EXCEPTIONS)
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
@ -114,6 +114,9 @@ public:
|
||||
return thread_call_stack::contains(this) != 0;
|
||||
}
|
||||
|
||||
/// Capture the current exception so it can be rethrown from a run function.
|
||||
ASIO_DECL void capture_current_exception();
|
||||
|
||||
// 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)
|
||||
@ -221,7 +224,8 @@ 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).
|
||||
ASIO_DECL size_t do_one(DWORD msec, asio::error_code& ec);
|
||||
ASIO_DECL size_t do_one(DWORD msec,
|
||||
win_iocp_thread_info& this_thread, asio::error_code& ec);
|
||||
|
||||
// Helper to calculate the GetQueuedCompletionStatus timeout.
|
||||
ASIO_DECL static DWORD get_gqcs_timeout();
|
||||
|
@ -228,32 +228,133 @@ io_context::wrap(Handler handler)
|
||||
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
inline io_context&
|
||||
io_context::executor_type::context() const ASIO_NOEXCEPT
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
io_context::basic_executor_type<Allocator, Bits>&
|
||||
io_context::basic_executor_type<Allocator, Bits>::operator=(
|
||||
const basic_executor_type& other) ASIO_NOEXCEPT
|
||||
{
|
||||
return io_context_;
|
||||
if (this != &other)
|
||||
{
|
||||
io_context* old_io_context = io_context_;
|
||||
io_context_ = other.io_context_;
|
||||
allocator_ = other.allocator_;
|
||||
bits_ = other.bits_;
|
||||
if (Bits & outstanding_work_tracked)
|
||||
{
|
||||
if (io_context_)
|
||||
io_context_->impl_.work_started();
|
||||
if (old_io_context)
|
||||
old_io_context->impl_.work_finished();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void
|
||||
io_context::executor_type::on_work_started() const ASIO_NOEXCEPT
|
||||
#if defined(ASIO_HAS_MOVE)
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
io_context::basic_executor_type<Allocator, Bits>&
|
||||
io_context::basic_executor_type<Allocator, Bits>::operator=(
|
||||
basic_executor_type&& other) ASIO_NOEXCEPT
|
||||
{
|
||||
io_context_.impl_.work_started();
|
||||
if (this != &other)
|
||||
{
|
||||
io_context_ = other.io_context_;
|
||||
allocator_ = std::move(other.allocator_);
|
||||
bits_ = other.bits_;
|
||||
if (Bits & outstanding_work_tracked)
|
||||
other.io_context_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif // defined(ASIO_HAS_MOVE)
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
inline bool io_context::basic_executor_type<Allocator,
|
||||
Bits>::running_in_this_thread() const ASIO_NOEXCEPT
|
||||
{
|
||||
return io_context_->impl_.can_dispatch();
|
||||
}
|
||||
|
||||
inline void
|
||||
io_context::executor_type::on_work_finished() const ASIO_NOEXCEPT
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
template <typename Function>
|
||||
void io_context::basic_executor_type<Allocator, Bits>::execute(
|
||||
ASIO_MOVE_ARG(Function) f) const
|
||||
{
|
||||
io_context_.impl_.work_finished();
|
||||
typedef typename decay<Function>::type function_type;
|
||||
|
||||
// Invoke immediately if the blocking.possibly property is enabled and we are
|
||||
// already inside the thread pool.
|
||||
if ((bits_ & blocking_never) == 0 && io_context_->impl_.can_dispatch())
|
||||
{
|
||||
// Make a local, non-const copy of the function.
|
||||
function_type tmp(ASIO_MOVE_CAST(Function)(f));
|
||||
|
||||
#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
|
||||
&& !defined(ASIO_NO_EXCEPTIONS)
|
||||
try
|
||||
{
|
||||
#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
// && !defined(ASIO_NO_EXCEPTIONS)
|
||||
detail::fenced_block b(detail::fenced_block::full);
|
||||
asio_handler_invoke_helpers::invoke(tmp, tmp);
|
||||
return;
|
||||
#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
|
||||
&& !defined(ASIO_NO_EXCEPTIONS)
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
io_context_->impl_.capture_current_exception();
|
||||
return;
|
||||
}
|
||||
#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
// && !defined(ASIO_NO_EXCEPTIONS)
|
||||
}
|
||||
|
||||
// Allocate and construct an operation to wrap the function.
|
||||
typedef detail::executor_op<function_type, Allocator, detail::operation> op;
|
||||
typename op::ptr p = { detail::addressof(allocator_),
|
||||
op::ptr::allocate(allocator_), 0 };
|
||||
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), allocator_);
|
||||
|
||||
ASIO_HANDLER_CREATION((*io_context_, *p.p,
|
||||
"io_context", io_context_, 0, "execute"));
|
||||
|
||||
io_context_->impl_.post_immediate_completion(p.p,
|
||||
(bits_ & relationship_continuation) != 0);
|
||||
p.v = p.p = 0;
|
||||
}
|
||||
|
||||
template <typename Function, typename Allocator>
|
||||
void io_context::executor_type::dispatch(
|
||||
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
|
||||
#if !defined(ASIO_NO_TS_EXECUTORS)
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
inline io_context& io_context::basic_executor_type<
|
||||
Allocator, Bits>::context() const ASIO_NOEXCEPT
|
||||
{
|
||||
return *io_context_;
|
||||
}
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
inline void io_context::basic_executor_type<Allocator,
|
||||
Bits>::on_work_started() const ASIO_NOEXCEPT
|
||||
{
|
||||
io_context_->impl_.work_started();
|
||||
}
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
inline void io_context::basic_executor_type<Allocator,
|
||||
Bits>::on_work_finished() const ASIO_NOEXCEPT
|
||||
{
|
||||
io_context_->impl_.work_finished();
|
||||
}
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
template <typename Function, typename OtherAllocator>
|
||||
void io_context::basic_executor_type<Allocator, Bits>::dispatch(
|
||||
ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
|
||||
{
|
||||
typedef typename decay<Function>::type function_type;
|
||||
|
||||
// Invoke immediately if we are already inside the thread pool.
|
||||
if (io_context_.impl_.can_dispatch())
|
||||
if (io_context_->impl_.can_dispatch())
|
||||
{
|
||||
// Make a local, non-const copy of the function.
|
||||
function_type tmp(ASIO_MOVE_CAST(Function)(f));
|
||||
@ -264,58 +365,58 @@ void io_context::executor_type::dispatch(
|
||||
}
|
||||
|
||||
// Allocate and construct an operation to wrap the function.
|
||||
typedef detail::executor_op<function_type, Allocator, detail::operation> op;
|
||||
typedef detail::executor_op<function_type,
|
||||
OtherAllocator, detail::operation> op;
|
||||
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
|
||||
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
|
||||
|
||||
ASIO_HANDLER_CREATION((this->context(), *p.p,
|
||||
"io_context", &this->context(), 0, "dispatch"));
|
||||
ASIO_HANDLER_CREATION((*io_context_, *p.p,
|
||||
"io_context", io_context_, 0, "dispatch"));
|
||||
|
||||
io_context_.impl_.post_immediate_completion(p.p, false);
|
||||
io_context_->impl_.post_immediate_completion(p.p, false);
|
||||
p.v = p.p = 0;
|
||||
}
|
||||
|
||||
template <typename Function, typename Allocator>
|
||||
void io_context::executor_type::post(
|
||||
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
template <typename Function, typename OtherAllocator>
|
||||
void io_context::basic_executor_type<Allocator, Bits>::post(
|
||||
ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
|
||||
{
|
||||
typedef typename decay<Function>::type function_type;
|
||||
|
||||
// Allocate and construct an operation to wrap the function.
|
||||
typedef detail::executor_op<function_type, Allocator, detail::operation> op;
|
||||
typedef detail::executor_op<function_type,
|
||||
OtherAllocator, detail::operation> op;
|
||||
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
|
||||
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
|
||||
|
||||
ASIO_HANDLER_CREATION((this->context(), *p.p,
|
||||
"io_context", &this->context(), 0, "post"));
|
||||
ASIO_HANDLER_CREATION((*io_context_, *p.p,
|
||||
"io_context", io_context_, 0, "post"));
|
||||
|
||||
io_context_.impl_.post_immediate_completion(p.p, false);
|
||||
io_context_->impl_.post_immediate_completion(p.p, false);
|
||||
p.v = p.p = 0;
|
||||
}
|
||||
|
||||
template <typename Function, typename Allocator>
|
||||
void io_context::executor_type::defer(
|
||||
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
template <typename Function, typename OtherAllocator>
|
||||
void io_context::basic_executor_type<Allocator, Bits>::defer(
|
||||
ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
|
||||
{
|
||||
typedef typename decay<Function>::type function_type;
|
||||
|
||||
// Allocate and construct an operation to wrap the function.
|
||||
typedef detail::executor_op<function_type, Allocator, detail::operation> op;
|
||||
typedef detail::executor_op<function_type,
|
||||
OtherAllocator, detail::operation> op;
|
||||
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
|
||||
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
|
||||
|
||||
ASIO_HANDLER_CREATION((this->context(), *p.p,
|
||||
"io_context", &this->context(), 0, "defer"));
|
||||
ASIO_HANDLER_CREATION((*io_context_, *p.p,
|
||||
"io_context", io_context_, 0, "defer"));
|
||||
|
||||
io_context_.impl_.post_immediate_completion(p.p, true);
|
||||
io_context_->impl_.post_immediate_completion(p.p, true);
|
||||
p.v = p.p = 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
io_context::executor_type::running_in_this_thread() const ASIO_NOEXCEPT
|
||||
{
|
||||
return io_context_.impl_.can_dispatch();
|
||||
}
|
||||
#endif // !defined(ASIO_NO_TS_EXECUTORS)
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
inline io_context::work::work(asio::io_context& io_context)
|
||||
|
49
asio/include/asio/impl/multiple_exceptions.ipp
Normal file
49
asio/include/asio/impl/multiple_exceptions.ipp
Normal file
@ -0,0 +1,49 @@
|
||||
//
|
||||
// impl/multiple_exceptions.ipp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP
|
||||
#define ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include "asio/multiple_exceptions.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
|
||||
#if defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
|
||||
multiple_exceptions::multiple_exceptions(
|
||||
std::exception_ptr first) ASIO_NOEXCEPT
|
||||
: first_(ASIO_MOVE_CAST(std::exception_ptr)(first))
|
||||
{
|
||||
}
|
||||
|
||||
const char* multiple_exceptions::what() const ASIO_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
return "multiple exceptions";
|
||||
}
|
||||
|
||||
std::exception_ptr multiple_exceptions::first_exception() const
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP
|
@ -25,6 +25,7 @@
|
||||
#include "asio/impl/executor.ipp"
|
||||
#include "asio/impl/handler_alloc_hook.ipp"
|
||||
#include "asio/impl/io_context.ipp"
|
||||
#include "asio/impl/multiple_exceptions.ipp"
|
||||
#include "asio/impl/serial_port_base.ipp"
|
||||
#include "asio/impl/system_context.ipp"
|
||||
#include "asio/impl/thread_pool.ipp"
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "asio/async_result.hpp"
|
||||
#include "asio/detail/wrapped_handler.hpp"
|
||||
#include "asio/error_code.hpp"
|
||||
#include "asio/execution.hpp"
|
||||
#include "asio/execution_context.hpp"
|
||||
|
||||
#if defined(ASIO_HAS_CHRONO)
|
||||
@ -46,6 +47,13 @@ namespace detail {
|
||||
#else
|
||||
typedef class scheduler io_context_impl;
|
||||
#endif
|
||||
|
||||
struct io_context_bits
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1);
|
||||
ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 2);
|
||||
ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 4);
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// Provides core I/O functionality.
|
||||
@ -184,8 +192,14 @@ private:
|
||||
#endif
|
||||
|
||||
public:
|
||||
class executor_type;
|
||||
friend class executor_type;
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
class basic_executor_type;
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
friend class basic_executor_type;
|
||||
|
||||
/// Executor used to submit functions to an io_context.
|
||||
typedef basic_executor_type<std::allocator<void>, 0> executor_type;
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
class work;
|
||||
@ -620,10 +634,215 @@ private:
|
||||
impl_type& impl_;
|
||||
};
|
||||
|
||||
/// Executor used to submit functions to an io_context.
|
||||
class io_context::executor_type
|
||||
namespace detail {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Executor implementation type used to submit functions to an io_context.
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
class io_context::basic_executor_type : detail::io_context_bits
|
||||
{
|
||||
public:
|
||||
/// Copy construtor.
|
||||
basic_executor_type(
|
||||
const basic_executor_type& other) ASIO_NOEXCEPT
|
||||
: io_context_(other.io_context_),
|
||||
allocator_(other.allocator_),
|
||||
bits_(other.bits_)
|
||||
{
|
||||
if (Bits & outstanding_work_tracked)
|
||||
if (io_context_)
|
||||
io_context_->impl_.work_started();
|
||||
}
|
||||
|
||||
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
||||
/// Move construtor.
|
||||
basic_executor_type(basic_executor_type&& other) ASIO_NOEXCEPT
|
||||
: io_context_(other.io_context_),
|
||||
allocator_(ASIO_MOVE_CAST(Allocator)(other.allocator_)),
|
||||
bits_(other.bits_)
|
||||
{
|
||||
if (Bits & outstanding_work_tracked)
|
||||
other.io_context_ = 0;
|
||||
}
|
||||
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
/// Destructor.
|
||||
~basic_executor_type()
|
||||
{
|
||||
if (Bits & outstanding_work_tracked)
|
||||
if (io_context_)
|
||||
io_context_->impl_.work_finished();
|
||||
}
|
||||
|
||||
/// Assignment operator.
|
||||
basic_executor_type& operator=(
|
||||
const basic_executor_type& other) ASIO_NOEXCEPT;
|
||||
|
||||
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
||||
/// Move assignment operator.
|
||||
basic_executor_type& operator=(
|
||||
basic_executor_type&& other) ASIO_NOEXCEPT;
|
||||
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
/// Obtain an executor with the @c blocking.possibly property.
|
||||
ASIO_CONSTEXPR basic_executor_type require(
|
||||
execution::blocking_t::possibly_t) const
|
||||
{
|
||||
return basic_executor_type(io_context_,
|
||||
allocator_, bits_ & ~blocking_never);
|
||||
}
|
||||
|
||||
/// Obtain an executor with the @c blocking.never property.
|
||||
ASIO_CONSTEXPR basic_executor_type require(
|
||||
execution::blocking_t::never_t) const
|
||||
{
|
||||
return basic_executor_type(io_context_,
|
||||
allocator_, bits_ | blocking_never);
|
||||
}
|
||||
|
||||
/// Obtain an executor with the @c relationship.fork property.
|
||||
ASIO_CONSTEXPR basic_executor_type require(
|
||||
execution::relationship_t::fork_t) const
|
||||
{
|
||||
return basic_executor_type(io_context_,
|
||||
allocator_, bits_ & ~relationship_continuation);
|
||||
}
|
||||
|
||||
/// Obtain an executor with the @c relationship.continuation property.
|
||||
ASIO_CONSTEXPR basic_executor_type require(
|
||||
execution::relationship_t::continuation_t) const
|
||||
{
|
||||
return basic_executor_type(io_context_,
|
||||
allocator_, bits_ | relationship_continuation);
|
||||
}
|
||||
|
||||
/// Obtain an executor with the @c outstanding_work.tracked property.
|
||||
ASIO_CONSTEXPR basic_executor_type<Allocator,
|
||||
ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>
|
||||
require(execution::outstanding_work_t::tracked_t) const
|
||||
{
|
||||
return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(
|
||||
io_context_, allocator_, bits_);
|
||||
}
|
||||
|
||||
/// Obtain an executor with the @c outstanding_work.untracked property.
|
||||
ASIO_CONSTEXPR basic_executor_type<Allocator,
|
||||
ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>
|
||||
require(execution::outstanding_work_t::untracked_t) const
|
||||
{
|
||||
return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(
|
||||
io_context_, allocator_, bits_);
|
||||
}
|
||||
|
||||
/// Obtain an executor with the specified @c allocator property.
|
||||
template <typename OtherAllocator>
|
||||
ASIO_CONSTEXPR basic_executor_type<OtherAllocator, Bits>
|
||||
require(execution::allocator_t<OtherAllocator> a) const
|
||||
{
|
||||
return basic_executor_type<OtherAllocator, Bits>(
|
||||
io_context_, a.value(), bits_);
|
||||
}
|
||||
|
||||
/// Obtain an executor with the default @c allocator property.
|
||||
ASIO_CONSTEXPR basic_executor_type<std::allocator<void>, Bits>
|
||||
require(execution::allocator_t<void>) const
|
||||
{
|
||||
return basic_executor_type<std::allocator<void>, Bits>(
|
||||
io_context_, std::allocator<void>(), bits_);
|
||||
}
|
||||
|
||||
/// Query the current value of the @c mapping property.
|
||||
static ASIO_CONSTEXPR execution::mapping_t query(
|
||||
execution::mapping_t) ASIO_NOEXCEPT
|
||||
{
|
||||
return execution::mapping.thread;
|
||||
}
|
||||
|
||||
/// Query the current value of the @c context property.
|
||||
io_context& query(execution::context_t) const ASIO_NOEXCEPT
|
||||
{
|
||||
return *io_context_;
|
||||
}
|
||||
|
||||
/// Query the current value of the @c blocking property.
|
||||
ASIO_CONSTEXPR execution::blocking_t query(
|
||||
execution::blocking_t) const ASIO_NOEXCEPT
|
||||
{
|
||||
return (bits_ & blocking_never)
|
||||
? execution::blocking_t(execution::blocking.never)
|
||||
: execution::blocking_t(execution::blocking.possibly);
|
||||
}
|
||||
|
||||
/// Query the current value of the @c relationship property.
|
||||
ASIO_CONSTEXPR execution::relationship_t query(
|
||||
execution::relationship_t) const ASIO_NOEXCEPT
|
||||
{
|
||||
return (bits_ & relationship_continuation)
|
||||
? execution::relationship_t(execution::relationship.continuation)
|
||||
: execution::relationship_t(execution::relationship.fork);
|
||||
}
|
||||
|
||||
/// Query the current value of the @c outstanding_work property.
|
||||
static ASIO_CONSTEXPR execution::outstanding_work_t query(
|
||||
execution::outstanding_work_t) ASIO_NOEXCEPT
|
||||
{
|
||||
return (Bits & outstanding_work_tracked)
|
||||
? execution::outstanding_work_t(execution::outstanding_work.tracked)
|
||||
: execution::outstanding_work_t(execution::outstanding_work.untracked);
|
||||
}
|
||||
|
||||
/// Query the current value of the @c allocator property.
|
||||
template <typename OtherAllocator>
|
||||
ASIO_CONSTEXPR Allocator query(
|
||||
execution::allocator_t<OtherAllocator>) const ASIO_NOEXCEPT
|
||||
{
|
||||
return allocator_;
|
||||
}
|
||||
|
||||
/// Query the current value of the @c allocator property.
|
||||
ASIO_CONSTEXPR Allocator query(
|
||||
execution::allocator_t<void>) const ASIO_NOEXCEPT
|
||||
{
|
||||
return allocator_;
|
||||
}
|
||||
|
||||
/// Determine whether the io_context is running in the current thread.
|
||||
/**
|
||||
* @return @c true if the current thread is running the io_context. Otherwise
|
||||
* returns @c false.
|
||||
*/
|
||||
bool running_in_this_thread() const ASIO_NOEXCEPT;
|
||||
|
||||
/// Compare two executors for equality.
|
||||
/**
|
||||
* Two executors are equal if they refer to the same underlying io_context.
|
||||
*/
|
||||
friend bool operator==(const basic_executor_type& a,
|
||||
const basic_executor_type& b) ASIO_NOEXCEPT
|
||||
{
|
||||
return a.io_context_ == b.io_context_
|
||||
&& a.allocator_ == b.allocator_
|
||||
&& a.bits_ == b.bits_;
|
||||
}
|
||||
|
||||
/// Compare two executors for inequality.
|
||||
/**
|
||||
* Two executors are equal if they refer to the same underlying io_context.
|
||||
*/
|
||||
friend bool operator!=(const basic_executor_type& a,
|
||||
const basic_executor_type& b) ASIO_NOEXCEPT
|
||||
{
|
||||
return a.io_context_ != b.io_context_
|
||||
|| a.allocator_ != b.allocator_
|
||||
|| a.bits_ != b.bits_;
|
||||
}
|
||||
|
||||
/// Execution function.
|
||||
template <typename Function>
|
||||
void execute(ASIO_MOVE_ARG(Function) f) const;
|
||||
|
||||
#if !defined(ASIO_NO_TS_EXECUTORS)
|
||||
/// Obtain the underlying execution context.
|
||||
io_context& context() const ASIO_NOEXCEPT;
|
||||
|
||||
@ -657,8 +876,9 @@ public:
|
||||
* @param a An allocator that may be used by the executor to allocate the
|
||||
* internal storage needed for function invocation.
|
||||
*/
|
||||
template <typename Function, typename Allocator>
|
||||
void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
|
||||
template <typename Function, typename OtherAllocator>
|
||||
void dispatch(ASIO_MOVE_ARG(Function) f,
|
||||
const OtherAllocator& a) const;
|
||||
|
||||
/// Request the io_context to invoke the given function object.
|
||||
/**
|
||||
@ -673,8 +893,9 @@ public:
|
||||
* @param a An allocator that may be used by the executor to allocate the
|
||||
* internal storage needed for function invocation.
|
||||
*/
|
||||
template <typename Function, typename Allocator>
|
||||
void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
|
||||
template <typename Function, typename OtherAllocator>
|
||||
void post(ASIO_MOVE_ARG(Function) f,
|
||||
const OtherAllocator& a) const;
|
||||
|
||||
/// Request the io_context to invoke the given function object.
|
||||
/**
|
||||
@ -693,44 +914,45 @@ public:
|
||||
* @param a An allocator that may be used by the executor to allocate the
|
||||
* internal storage needed for function invocation.
|
||||
*/
|
||||
template <typename Function, typename Allocator>
|
||||
void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
|
||||
|
||||
/// Determine whether the io_context is running in the current thread.
|
||||
/**
|
||||
* @return @c true if the current thread is running the io_context. Otherwise
|
||||
* returns @c false.
|
||||
*/
|
||||
bool running_in_this_thread() const ASIO_NOEXCEPT;
|
||||
|
||||
/// Compare two executors for equality.
|
||||
/**
|
||||
* Two executors are equal if they refer to the same underlying io_context.
|
||||
*/
|
||||
friend bool operator==(const executor_type& a,
|
||||
const executor_type& b) ASIO_NOEXCEPT
|
||||
{
|
||||
return &a.io_context_ == &b.io_context_;
|
||||
}
|
||||
|
||||
/// Compare two executors for inequality.
|
||||
/**
|
||||
* Two executors are equal if they refer to the same underlying io_context.
|
||||
*/
|
||||
friend bool operator!=(const executor_type& a,
|
||||
const executor_type& b) ASIO_NOEXCEPT
|
||||
{
|
||||
return &a.io_context_ != &b.io_context_;
|
||||
}
|
||||
template <typename Function, typename OtherAllocator>
|
||||
void defer(ASIO_MOVE_ARG(Function) f,
|
||||
const OtherAllocator& a) const;
|
||||
#endif // !defined(ASIO_NO_TS_EXECUTORS)
|
||||
|
||||
private:
|
||||
friend class io_context;
|
||||
template <typename, unsigned int> friend class basic_executor_type;
|
||||
|
||||
// Constructor.
|
||||
explicit executor_type(io_context& i) : io_context_(i) {}
|
||||
// Constructor used by io_context::get_executor().
|
||||
explicit basic_executor_type(io_context& i) ASIO_NOEXCEPT
|
||||
: io_context_(&i),
|
||||
allocator_(),
|
||||
bits_(0)
|
||||
{
|
||||
if (Bits & outstanding_work_tracked)
|
||||
io_context_->impl_.work_started();
|
||||
}
|
||||
|
||||
// Constructor used by require().
|
||||
basic_executor_type(io_context* i,
|
||||
const Allocator& a, unsigned int bits) ASIO_NOEXCEPT
|
||||
: io_context_(i),
|
||||
allocator_(a),
|
||||
bits_(bits)
|
||||
{
|
||||
if (Bits & outstanding_work_tracked)
|
||||
if (io_context_)
|
||||
io_context_->impl_.work_started();
|
||||
}
|
||||
|
||||
// The underlying io_context.
|
||||
io_context& io_context_;
|
||||
io_context* io_context_;
|
||||
|
||||
// The allocator used for execution functions.
|
||||
Allocator allocator_;
|
||||
|
||||
// The runtime-switched properties of the io_context executor.
|
||||
unsigned int bits_;
|
||||
};
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
@ -854,6 +1076,266 @@ template <typename Type>
|
||||
asio::detail::service_id<Type> service_base<Type>::id;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#if !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
namespace execution {
|
||||
|
||||
#if !defined(ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT)
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
struct is_executor<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>
|
||||
> : true_type
|
||||
{
|
||||
};
|
||||
|
||||
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT)
|
||||
|
||||
} // namespace execution
|
||||
namespace traits {
|
||||
|
||||
#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
|
||||
|
||||
template <typename Allocator, unsigned int Bits, typename Function>
|
||||
struct execute_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
Function
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
|
||||
typedef void result_type;
|
||||
};
|
||||
|
||||
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
|
||||
|
||||
#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
struct require_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::blocking_t::possibly_t
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
|
||||
typedef asio::io_context::basic_executor_type<
|
||||
Allocator, Bits> result_type;
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
struct require_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::blocking_t::never_t
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
|
||||
typedef asio::io_context::basic_executor_type<
|
||||
Allocator, Bits> result_type;
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
struct require_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::relationship_t::fork_t
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
|
||||
typedef asio::io_context::basic_executor_type<
|
||||
Allocator, Bits> result_type;
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
struct require_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::relationship_t::continuation_t
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
|
||||
typedef asio::io_context::basic_executor_type<
|
||||
Allocator, Bits> result_type;
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
struct require_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::outstanding_work_t::tracked_t
|
||||
> : asio::detail::io_context_bits
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
|
||||
typedef asio::io_context::basic_executor_type<
|
||||
Allocator, Bits | outstanding_work_tracked> result_type;
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
struct require_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::outstanding_work_t::untracked_t
|
||||
> : asio::detail::io_context_bits
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
|
||||
typedef asio::io_context::basic_executor_type<
|
||||
Allocator, Bits & ~outstanding_work_tracked> result_type;
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
struct require_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::allocator_t<void>
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
|
||||
typedef asio::io_context::basic_executor_type<
|
||||
std::allocator<void>, Bits> result_type;
|
||||
};
|
||||
|
||||
template <unsigned int Bits,
|
||||
typename Allocator, typename OtherAllocator>
|
||||
struct require_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::allocator_t<OtherAllocator>
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
|
||||
typedef asio::io_context::basic_executor_type<
|
||||
OtherAllocator, Bits> result_type;
|
||||
};
|
||||
|
||||
#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
|
||||
|
||||
#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
|
||||
|
||||
template <typename Allocator, unsigned int Bits, typename Property>
|
||||
struct query_static_constexpr_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
Property,
|
||||
typename asio::enable_if<
|
||||
asio::is_convertible<
|
||||
Property,
|
||||
asio::execution::outstanding_work_t
|
||||
>::value
|
||||
>::type
|
||||
> : asio::detail::io_context_bits
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
|
||||
typedef asio::execution::outstanding_work_t result_type;
|
||||
|
||||
static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
|
||||
{
|
||||
return (Bits & outstanding_work_tracked)
|
||||
? execution::outstanding_work_t(execution::outstanding_work.tracked)
|
||||
: execution::outstanding_work_t(execution::outstanding_work.untracked);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits, typename Property>
|
||||
struct query_static_constexpr_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
Property,
|
||||
typename asio::enable_if<
|
||||
asio::is_convertible<
|
||||
Property,
|
||||
asio::execution::mapping_t
|
||||
>::value
|
||||
>::type
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
|
||||
typedef asio::execution::mapping_t::thread_t result_type;
|
||||
|
||||
static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT
|
||||
{
|
||||
return result_type();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
|
||||
|
||||
#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
|
||||
|
||||
template <typename Allocator, unsigned int Bits, typename Property>
|
||||
struct query_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
Property,
|
||||
typename asio::enable_if<
|
||||
asio::is_convertible<
|
||||
Property,
|
||||
asio::execution::blocking_t
|
||||
>::value
|
||||
>::type
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
|
||||
typedef asio::execution::blocking_t result_type;
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits, typename Property>
|
||||
struct query_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
Property,
|
||||
typename asio::enable_if<
|
||||
asio::is_convertible<
|
||||
Property,
|
||||
asio::execution::relationship_t
|
||||
>::value
|
||||
>::type
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
|
||||
typedef asio::execution::relationship_t result_type;
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
struct query_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::context_t
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
|
||||
typedef asio::io_context& result_type;
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits>
|
||||
struct query_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::allocator_t<void>
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
|
||||
typedef Allocator result_type;
|
||||
};
|
||||
|
||||
template <typename Allocator, unsigned int Bits, typename OtherAllocator>
|
||||
struct query_member<
|
||||
asio::io_context::basic_executor_type<Allocator, Bits>,
|
||||
asio::execution::allocator_t<OtherAllocator>
|
||||
>
|
||||
{
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
|
||||
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
|
||||
typedef Allocator result_type;
|
||||
};
|
||||
|
||||
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
|
||||
|
||||
} // namespace traits
|
||||
|
||||
#endif // !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
58
asio/include/asio/multiple_exceptions.hpp
Normal file
58
asio/include/asio/multiple_exceptions.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// multiple_exceptions.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef ASIO_MULTIPLE_EXCEPTIONS_HPP
|
||||
#define ASIO_MULTIPLE_EXCEPTIONS_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include <exception>
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
|
||||
#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \
|
||||
|| defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
/// Exception thrown when there are multiple pending exceptions to rethrow.
|
||||
class multiple_exceptions
|
||||
: public std::exception
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
ASIO_DECL multiple_exceptions(
|
||||
std::exception_ptr first) ASIO_NOEXCEPT;
|
||||
|
||||
/// Obtain message associated with exception.
|
||||
ASIO_DECL virtual const char* what() const
|
||||
ASIO_NOEXCEPT_OR_NOTHROW;
|
||||
|
||||
/// Obtain a pointer to the first exception.
|
||||
ASIO_DECL std::exception_ptr first_exception() const;
|
||||
|
||||
private:
|
||||
std::exception_ptr first_;
|
||||
};
|
||||
|
||||
#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
// || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#if defined(ASIO_HEADER_ONLY)
|
||||
# include "asio/impl/multiple_exceptions.ipp"
|
||||
#endif // defined(ASIO_HEADER_ONLY)
|
||||
|
||||
#endif // ASIO_MULTIPLE_EXCEPTIONS_HPP
|
@ -354,9 +354,232 @@ void io_context_service_test()
|
||||
ASIO_CHECK(!asio::has_service<test_service>(ioc3));
|
||||
}
|
||||
|
||||
void io_context_executor_query_test()
|
||||
{
|
||||
io_context ioc;
|
||||
|
||||
ASIO_CHECK(
|
||||
&asio::query(ioc.get_executor(),
|
||||
asio::execution::context)
|
||||
== &ioc);
|
||||
|
||||
ASIO_CHECK(
|
||||
asio::query(ioc.get_executor(),
|
||||
asio::execution::blocking)
|
||||
== asio::execution::blocking.possibly);
|
||||
|
||||
ASIO_CHECK(
|
||||
asio::query(ioc.get_executor(),
|
||||
asio::execution::blocking.possibly)
|
||||
== asio::execution::blocking.possibly);
|
||||
|
||||
ASIO_CHECK(
|
||||
asio::query(ioc.get_executor(),
|
||||
asio::execution::outstanding_work)
|
||||
== asio::execution::outstanding_work.untracked);
|
||||
|
||||
ASIO_CHECK(
|
||||
asio::query(ioc.get_executor(),
|
||||
asio::execution::outstanding_work.untracked)
|
||||
== asio::execution::outstanding_work.untracked);
|
||||
|
||||
ASIO_CHECK(
|
||||
asio::query(ioc.get_executor(),
|
||||
asio::execution::relationship)
|
||||
== asio::execution::relationship.fork);
|
||||
|
||||
ASIO_CHECK(
|
||||
asio::query(ioc.get_executor(),
|
||||
asio::execution::relationship.fork)
|
||||
== asio::execution::relationship.fork);
|
||||
|
||||
ASIO_CHECK(
|
||||
asio::query(ioc.get_executor(),
|
||||
asio::execution::mapping)
|
||||
== asio::execution::mapping.thread);
|
||||
|
||||
ASIO_CHECK(
|
||||
asio::query(ioc.get_executor(),
|
||||
asio::execution::allocator)
|
||||
== std::allocator<void>());
|
||||
}
|
||||
|
||||
void io_context_executor_execute_test()
|
||||
{
|
||||
io_context ioc;
|
||||
int count = 0;
|
||||
|
||||
asio::execution::execute(ioc.get_executor(),
|
||||
bindns::bind(increment, &count));
|
||||
|
||||
// No handlers can be called until run() is called.
|
||||
ASIO_CHECK(!ioc.stopped());
|
||||
ASIO_CHECK(count == 0);
|
||||
|
||||
ioc.run();
|
||||
|
||||
// The run() call will not return until all work has finished.
|
||||
ASIO_CHECK(ioc.stopped());
|
||||
ASIO_CHECK(count == 1);
|
||||
|
||||
count = 0;
|
||||
ioc.restart();
|
||||
asio::execution::execute(
|
||||
asio::require(ioc.get_executor(),
|
||||
asio::execution::blocking.possibly),
|
||||
bindns::bind(increment, &count));
|
||||
|
||||
// No handlers can be called until run() is called.
|
||||
ASIO_CHECK(!ioc.stopped());
|
||||
ASIO_CHECK(count == 0);
|
||||
|
||||
ioc.run();
|
||||
|
||||
// The run() call will not return until all work has finished.
|
||||
ASIO_CHECK(ioc.stopped());
|
||||
ASIO_CHECK(count == 1);
|
||||
|
||||
count = 0;
|
||||
ioc.restart();
|
||||
asio::execution::execute(
|
||||
asio::require(ioc.get_executor(),
|
||||
asio::execution::blocking.never),
|
||||
bindns::bind(increment, &count));
|
||||
|
||||
// No handlers can be called until run() is called.
|
||||
ASIO_CHECK(!ioc.stopped());
|
||||
ASIO_CHECK(count == 0);
|
||||
|
||||
ioc.run();
|
||||
|
||||
// The run() call will not return until all work has finished.
|
||||
ASIO_CHECK(ioc.stopped());
|
||||
ASIO_CHECK(count == 1);
|
||||
|
||||
count = 0;
|
||||
ioc.restart();
|
||||
ASIO_CHECK(!ioc.stopped());
|
||||
|
||||
asio::execution::execute(
|
||||
asio::require(ioc.get_executor(),
|
||||
asio::execution::blocking.never,
|
||||
asio::execution::outstanding_work.tracked),
|
||||
bindns::bind(increment, &count));
|
||||
|
||||
// No handlers can be called until run() is called.
|
||||
ASIO_CHECK(!ioc.stopped());
|
||||
ASIO_CHECK(count == 0);
|
||||
|
||||
ioc.run();
|
||||
|
||||
// The run() call will not return until all work has finished.
|
||||
ASIO_CHECK(ioc.stopped());
|
||||
ASIO_CHECK(count == 1);
|
||||
|
||||
count = 0;
|
||||
ioc.restart();
|
||||
asio::execution::execute(
|
||||
asio::require(ioc.get_executor(),
|
||||
asio::execution::blocking.never,
|
||||
asio::execution::outstanding_work.untracked),
|
||||
bindns::bind(increment, &count));
|
||||
|
||||
// No handlers can be called until run() is called.
|
||||
ASIO_CHECK(!ioc.stopped());
|
||||
ASIO_CHECK(count == 0);
|
||||
|
||||
ioc.run();
|
||||
|
||||
// The run() call will not return until all work has finished.
|
||||
ASIO_CHECK(ioc.stopped());
|
||||
ASIO_CHECK(count == 1);
|
||||
|
||||
count = 0;
|
||||
ioc.restart();
|
||||
asio::execution::execute(
|
||||
asio::require(ioc.get_executor(),
|
||||
asio::execution::blocking.never,
|
||||
asio::execution::outstanding_work.untracked,
|
||||
asio::execution::relationship.fork),
|
||||
bindns::bind(increment, &count));
|
||||
|
||||
// No handlers can be called until run() is called.
|
||||
ASIO_CHECK(!ioc.stopped());
|
||||
ASIO_CHECK(count == 0);
|
||||
|
||||
ioc.run();
|
||||
|
||||
// The run() call will not return until all work has finished.
|
||||
ASIO_CHECK(ioc.stopped());
|
||||
ASIO_CHECK(count == 1);
|
||||
|
||||
count = 0;
|
||||
ioc.restart();
|
||||
asio::execution::execute(
|
||||
asio::require(ioc.get_executor(),
|
||||
asio::execution::blocking.never,
|
||||
asio::execution::outstanding_work.untracked,
|
||||
asio::execution::relationship.continuation),
|
||||
bindns::bind(increment, &count));
|
||||
|
||||
// No handlers can be called until run() is called.
|
||||
ASIO_CHECK(!ioc.stopped());
|
||||
ASIO_CHECK(count == 0);
|
||||
|
||||
ioc.run();
|
||||
|
||||
// The run() call will not return until all work has finished.
|
||||
ASIO_CHECK(ioc.stopped());
|
||||
ASIO_CHECK(count == 1);
|
||||
|
||||
count = 0;
|
||||
ioc.restart();
|
||||
asio::execution::execute(
|
||||
asio::prefer(
|
||||
asio::require(ioc.get_executor(),
|
||||
asio::execution::blocking.never,
|
||||
asio::execution::outstanding_work.untracked,
|
||||
asio::execution::relationship.continuation),
|
||||
asio::execution::allocator(std::allocator<void>())),
|
||||
bindns::bind(increment, &count));
|
||||
|
||||
// No handlers can be called until run() is called.
|
||||
ASIO_CHECK(!ioc.stopped());
|
||||
ASIO_CHECK(count == 0);
|
||||
|
||||
ioc.run();
|
||||
|
||||
// The run() call will not return until all work has finished.
|
||||
ASIO_CHECK(ioc.stopped());
|
||||
ASIO_CHECK(count == 1);
|
||||
|
||||
count = 0;
|
||||
ioc.restart();
|
||||
asio::execution::execute(
|
||||
asio::prefer(
|
||||
asio::require(ioc.get_executor(),
|
||||
asio::execution::blocking.never,
|
||||
asio::execution::outstanding_work.untracked,
|
||||
asio::execution::relationship.continuation),
|
||||
asio::execution::allocator),
|
||||
bindns::bind(increment, &count));
|
||||
|
||||
// No handlers can be called until run() is called.
|
||||
ASIO_CHECK(!ioc.stopped());
|
||||
ASIO_CHECK(count == 0);
|
||||
|
||||
ioc.run();
|
||||
|
||||
// The run() call will not return until all work has finished.
|
||||
ASIO_CHECK(ioc.stopped());
|
||||
ASIO_CHECK(count == 1);
|
||||
}
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"io_context",
|
||||
ASIO_TEST_CASE(io_context_test)
|
||||
ASIO_TEST_CASE(io_context_service_test)
|
||||
ASIO_TEST_CASE(io_context_executor_query_test)
|
||||
ASIO_TEST_CASE(io_context_executor_execute_test)
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user