update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -2,7 +2,7 @@
// detail/array.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/array_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/assert.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/atomic_count.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -32,12 +32,34 @@ namespace detail {
#if !defined(BOOST_ASIO_HAS_THREADS)
typedef long atomic_count;
inline void increment(atomic_count& a, long b) { a += b; }
inline void decrement(atomic_count& a, long b) { a -= b; }
inline void ref_count_up(atomic_count& a) { ++a; }
inline bool ref_count_down(atomic_count& a) { return --a == 0; }
#elif defined(BOOST_ASIO_HAS_STD_ATOMIC)
typedef std::atomic<long> atomic_count;
inline void increment(atomic_count& a, long b) { a += b; }
inline void decrement(atomic_count& a, long b) { a -= b; }
inline void ref_count_up(atomic_count& a)
{
a.fetch_add(1, std::memory_order_relaxed);
}
inline bool ref_count_down(atomic_count& a)
{
if (a.fetch_sub(1, std::memory_order_release) == 1)
{
std::atomic_thread_fence(std::memory_order_acquire);
return true;
}
return false;
}
#else // defined(BOOST_ASIO_HAS_STD_ATOMIC)
typedef boost::detail::atomic_count atomic_count;
inline void increment(atomic_count& a, long b) { while (b > 0) ++a, --b; }
inline void decrement(atomic_count& a, long b) { while (b > 0) --a, --b; }
inline void ref_count_up(atomic_count& a) { ++a; }
inline bool ref_count_down(atomic_count& a) { return --a == 0; }
#endif // defined(BOOST_ASIO_HAS_STD_ATOMIC)
} // namespace detail

View File

@@ -0,0 +1,165 @@
//
// detail/base_from_cancellation_state.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP
#define BOOST_ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_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_cancellation_slot.hpp>
#include <boost/asio/cancellation_state.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename Handler, typename = void>
class base_from_cancellation_state
{
public:
typedef cancellation_slot cancellation_slot_type;
cancellation_slot_type get_cancellation_slot() const BOOST_ASIO_NOEXCEPT
{
return cancellation_state_.slot();
}
cancellation_state get_cancellation_state() const BOOST_ASIO_NOEXCEPT
{
return cancellation_state_;
}
protected:
explicit base_from_cancellation_state(const Handler& handler)
: cancellation_state_(
boost::asio::get_associated_cancellation_slot(handler))
{
}
template <typename Filter>
base_from_cancellation_state(const Handler& handler, Filter filter)
: cancellation_state_(
boost::asio::get_associated_cancellation_slot(handler), filter, filter)
{
}
template <typename InFilter, typename OutFilter>
base_from_cancellation_state(const Handler& handler,
BOOST_ASIO_MOVE_ARG(InFilter) in_filter,
BOOST_ASIO_MOVE_ARG(OutFilter) out_filter)
: cancellation_state_(
boost::asio::get_associated_cancellation_slot(handler),
BOOST_ASIO_MOVE_CAST(InFilter)(in_filter),
BOOST_ASIO_MOVE_CAST(OutFilter)(out_filter))
{
}
void reset_cancellation_state(const Handler& handler)
{
cancellation_state_ = cancellation_state(
boost::asio::get_associated_cancellation_slot(handler));
}
template <typename Filter>
void reset_cancellation_state(const Handler& handler, Filter filter)
{
cancellation_state_ = cancellation_state(
boost::asio::get_associated_cancellation_slot(handler), filter, filter);
}
template <typename InFilter, typename OutFilter>
void reset_cancellation_state(const Handler& handler,
BOOST_ASIO_MOVE_ARG(InFilter) in_filter,
BOOST_ASIO_MOVE_ARG(OutFilter) out_filter)
{
cancellation_state_ = cancellation_state(
boost::asio::get_associated_cancellation_slot(handler),
BOOST_ASIO_MOVE_CAST(InFilter)(in_filter),
BOOST_ASIO_MOVE_CAST(OutFilter)(out_filter));
}
cancellation_type_t cancelled() const BOOST_ASIO_NOEXCEPT
{
return cancellation_state_.cancelled();
}
private:
cancellation_state cancellation_state_;
};
template <typename Handler>
class base_from_cancellation_state<Handler,
typename enable_if<
is_same<
typename associated_cancellation_slot<
Handler, cancellation_slot
>::asio_associated_cancellation_slot_is_unspecialised,
void
>::value
>::type>
{
public:
cancellation_state get_cancellation_state() const BOOST_ASIO_NOEXCEPT
{
return cancellation_state();
}
protected:
explicit base_from_cancellation_state(const Handler&)
{
}
template <typename Filter>
base_from_cancellation_state(const Handler&, Filter)
{
}
template <typename InFilter, typename OutFilter>
base_from_cancellation_state(const Handler&,
BOOST_ASIO_MOVE_ARG(InFilter),
BOOST_ASIO_MOVE_ARG(OutFilter))
{
}
void reset_cancellation_state(const Handler&)
{
}
template <typename Filter>
void reset_cancellation_state(const Handler&, Filter)
{
}
template <typename InFilter, typename OutFilter>
void reset_cancellation_state(const Handler&,
BOOST_ASIO_MOVE_ARG(InFilter),
BOOST_ASIO_MOVE_ARG(OutFilter))
{
}
BOOST_ASIO_CONSTEXPR cancellation_type_t cancelled() const BOOST_ASIO_NOEXCEPT
{
return cancellation_type::none;
}
};
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP

View File

@@ -2,7 +2,7 @@
// detail/base_from_completion_cond.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/bind_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,8 +16,7 @@
#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/associator.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>
@@ -29,6 +28,113 @@ namespace boost {
namespace asio {
namespace detail {
template <typename Handler>
class binder0
{
public:
template <typename T>
binder0(int, BOOST_ASIO_MOVE_ARG(T) handler)
: handler_(BOOST_ASIO_MOVE_CAST(T)(handler))
{
}
binder0(Handler& handler)
: handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
}
#if defined(BOOST_ASIO_HAS_MOVE)
binder0(const binder0& other)
: handler_(other.handler_)
{
}
binder0(binder0&& other)
: handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_))
{
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
void operator()()
{
BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)();
}
void operator()() const
{
handler_();
}
//private:
Handler handler_;
};
template <typename Handler>
inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,
binder0<Handler>* this_handler)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
return asio_handler_allocate_is_no_longer_used();
#else // defined(BOOST_ASIO_NO_DEPRECATED)
return boost_asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler>
inline asio_handler_deallocate_is_deprecated
asio_handler_deallocate(void* pointer, std::size_t size,
binder0<Handler>* this_handler)
{
boost_asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_deallocate_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler>
inline bool asio_handler_is_continuation(
binder0<Handler>* this_handler)
{
return boost_asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Function, typename Handler>
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(Function& function,
binder0<Handler>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Function, typename Handler>
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(const Function& function,
binder0<Handler>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler>
inline binder0<typename decay<Handler>::type> bind_handler(
BOOST_ASIO_MOVE_ARG(Handler) handler)
{
return binder0<typename decay<Handler>::type>(
0, BOOST_ASIO_MOVE_CAST(Handler)(handler));
}
template <typename Handler, typename Arg1>
class binder1
{
@@ -62,7 +168,8 @@ public:
void operator()()
{
handler_(static_cast<const Arg1&>(arg1_));
BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)(
static_cast<const Arg1&>(arg1_));
}
void operator()() const
@@ -76,19 +183,29 @@ public:
};
template <typename Handler, typename Arg1>
inline void* asio_handler_allocate(std::size_t size,
inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,
binder1<Handler, Arg1>* this_handler)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
return asio_handler_allocate_is_no_longer_used();
#else // defined(BOOST_ASIO_NO_DEPRECATED)
return boost_asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
inline asio_handler_deallocate_is_deprecated
asio_handler_deallocate(void* pointer, std::size_t size,
binder1<Handler, Arg1>* this_handler)
{
boost_asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_deallocate_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1>
@@ -100,19 +217,27 @@ inline bool asio_handler_is_continuation(
}
template <typename Function, typename Handler, typename Arg1>
inline void asio_handler_invoke(Function& function,
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(Function& function,
binder1<Handler, Arg1>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Function, typename Handler, typename Arg1>
inline void asio_handler_invoke(const Function& function,
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(const Function& function,
binder1<Handler, Arg1>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1>
@@ -161,7 +286,8 @@ public:
void operator()()
{
handler_(static_cast<const Arg1&>(arg1_),
BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)(
static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_));
}
@@ -177,19 +303,29 @@ public:
};
template <typename Handler, typename Arg1, typename Arg2>
inline void* asio_handler_allocate(std::size_t size,
inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,
binder2<Handler, Arg1, Arg2>* this_handler)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
return asio_handler_allocate_is_no_longer_used();
#else // defined(BOOST_ASIO_NO_DEPRECATED)
return boost_asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
inline asio_handler_deallocate_is_deprecated
asio_handler_deallocate(void* pointer, std::size_t size,
binder2<Handler, Arg1, Arg2>* this_handler)
{
boost_asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_deallocate_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2>
@@ -201,19 +337,27 @@ inline bool asio_handler_is_continuation(
}
template <typename Function, typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_invoke(Function& function,
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(Function& function,
binder2<Handler, Arg1, Arg2>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Function, typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_invoke(const Function& function,
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(const Function& function,
binder2<Handler, Arg1, Arg2>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2>
@@ -267,8 +411,10 @@ public:
void operator()()
{
handler_(static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_));
BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)(
static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_));
}
void operator()() const
@@ -284,19 +430,29 @@ public:
};
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline void* asio_handler_allocate(std::size_t size,
inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
return asio_handler_allocate_is_no_longer_used();
#else // defined(BOOST_ASIO_NO_DEPRECATED)
return boost_asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
inline asio_handler_deallocate_is_deprecated
asio_handler_deallocate(void* pointer, std::size_t size,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
boost_asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_deallocate_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
@@ -309,20 +465,28 @@ inline bool asio_handler_is_continuation(
template <typename Function, typename Handler,
typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_invoke(Function& function,
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(Function& function,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Function, typename Handler,
typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_invoke(const Function& function,
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(const Function& function,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
@@ -382,8 +546,10 @@ public:
void operator()()
{
handler_(static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),
BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)(
static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_));
}
@@ -402,20 +568,30 @@ public:
template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void* asio_handler_allocate(std::size_t size,
inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
return asio_handler_allocate_is_no_longer_used();
#else // defined(BOOST_ASIO_NO_DEPRECATED)
return boost_asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
inline asio_handler_deallocate_is_deprecated
asio_handler_deallocate(void* pointer, std::size_t size,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
boost_asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_deallocate_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1,
@@ -429,20 +605,28 @@ inline bool asio_handler_is_continuation(
template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void asio_handler_invoke(Function& function,
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(Function& function,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void asio_handler_invoke(const Function& function,
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(const Function& function,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1,
@@ -507,9 +691,12 @@ public:
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_));
BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)(
static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_),
static_cast<const Arg5&>(arg5_));
}
void operator()() const
@@ -528,20 +715,30 @@ public:
template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline void* asio_handler_allocate(std::size_t size,
inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
return asio_handler_allocate_is_no_longer_used();
#else // defined(BOOST_ASIO_NO_DEPRECATED)
return boost_asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
inline asio_handler_deallocate_is_deprecated
asio_handler_deallocate(void* pointer, std::size_t size,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
boost_asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_deallocate_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2,
@@ -555,20 +752,28 @@ inline bool asio_handler_is_continuation(
template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4, typename Arg5>
inline void asio_handler_invoke(Function& function,
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(Function& function,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4, typename Arg5>
inline void asio_handler_invoke(const Function& function,
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(const Function& function,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
boost_asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2,
@@ -602,7 +807,8 @@ public:
void operator()()
{
handler_(BOOST_ASIO_MOVE_CAST(Arg1)(arg1_));
BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)(
BOOST_ASIO_MOVE_CAST(Arg1)(arg1_));
}
//private:
@@ -611,19 +817,29 @@ public:
};
template <typename Handler, typename Arg1>
inline void* asio_handler_allocate(std::size_t size,
inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,
move_binder1<Handler, Arg1>* this_handler)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
return asio_handler_allocate_is_no_longer_used();
#else // defined(BOOST_ASIO_NO_DEPRECATED)
return boost_asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
inline asio_handler_deallocate_is_deprecated
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_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_deallocate_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1>
@@ -635,11 +851,15 @@ inline bool asio_handler_is_continuation(
}
template <typename Function, typename Handler, typename Arg1>
inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function,
inline asio_handler_invoke_is_deprecated
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_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2>
@@ -663,7 +883,8 @@ public:
void operator()()
{
handler_(static_cast<const Arg1&>(arg1_),
BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)(
static_cast<const Arg1&>(arg1_),
BOOST_ASIO_MOVE_CAST(Arg2)(arg2_));
}
@@ -674,19 +895,29 @@ public:
};
template <typename Handler, typename Arg1, typename Arg2>
inline void* asio_handler_allocate(std::size_t size,
inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,
move_binder2<Handler, Arg1, Arg2>* this_handler)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
return asio_handler_allocate_is_no_longer_used();
#else // defined(BOOST_ASIO_NO_DEPRECATED)
return boost_asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
inline asio_handler_deallocate_is_deprecated
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_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_deallocate_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Handler, typename Arg1, typename Arg2>
@@ -698,113 +929,211 @@ inline bool asio_handler_is_continuation(
}
template <typename Function, typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function,
inline asio_handler_invoke_is_deprecated
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_);
#if defined(BOOST_ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
} // namespace detail
template <typename Handler, typename Arg1, typename Allocator>
struct associated_allocator<detail::binder1<Handler, Arg1>, Allocator>
template <template <typename, typename> class Associator,
typename Handler, typename DefaultCandidate>
struct associator<Associator,
detail::binder0<Handler>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
typedef typename associated_allocator<Handler, Allocator>::type type;
static type get(const detail::binder1<Handler, Arg1>& h,
const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
static typename Associator<Handler, DefaultCandidate>::type
get(const detail::binder0<Handler>& h) BOOST_ASIO_NOEXCEPT
{
return associated_allocator<Handler, Allocator>::get(h.handler_, a);
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
typename Associator<Handler, DefaultCandidate>::type)
get(const detail::binder0<Handler>& h,
const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
Associator<Handler, DefaultCandidate>::get(h.handler_, c)))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <typename Handler, typename Arg1, typename Arg2, typename Allocator>
struct associated_allocator<detail::binder2<Handler, Arg1, Arg2>, Allocator>
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename DefaultCandidate>
struct associator<Associator,
detail::binder1<Handler, Arg1>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
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
static typename Associator<Handler, DefaultCandidate>::type
get(const detail::binder1<Handler, Arg1>& h) BOOST_ASIO_NOEXCEPT
{
return associated_allocator<Handler, Allocator>::get(h.handler_, a);
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
typename Associator<Handler, DefaultCandidate>::type)
get(const detail::binder1<Handler, Arg1>& h,
const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
Associator<Handler, DefaultCandidate>::get(h.handler_, c)))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <typename Handler, typename Arg1, typename Executor>
struct associated_executor<detail::binder1<Handler, Arg1>, Executor>
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2,
typename DefaultCandidate>
struct associator<Associator,
detail::binder2<Handler, Arg1, Arg2>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
typedef typename associated_executor<Handler, Executor>::type type;
static type get(const detail::binder1<Handler, Arg1>& h,
const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
static typename Associator<Handler, DefaultCandidate>::type
get(const detail::binder2<Handler, Arg1, Arg2>& h) BOOST_ASIO_NOEXCEPT
{
return associated_executor<Handler, Executor>::get(h.handler_, ex);
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
typename Associator<Handler, DefaultCandidate>::type)
get(const detail::binder2<Handler, Arg1, Arg2>& h,
const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
Associator<Handler, DefaultCandidate>::get(h.handler_, c)))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <typename Handler, typename Arg1, typename Arg2, typename Executor>
struct associated_executor<detail::binder2<Handler, Arg1, Arg2>, Executor>
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename DefaultCandidate>
struct associator<Associator,
detail::binder3<Handler, Arg1, Arg2, Arg3>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
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
static typename Associator<Handler, DefaultCandidate>::type
get(const detail::binder3<Handler, Arg1, Arg2, Arg3>& h) BOOST_ASIO_NOEXCEPT
{
return associated_executor<Handler, Executor>::get(h.handler_, ex);
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
typename Associator<Handler, DefaultCandidate>::type)
get(const detail::binder3<Handler, Arg1, Arg2, Arg3>& h,
const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
Associator<Handler, DefaultCandidate>::get(h.handler_, c)))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename DefaultCandidate>
struct associator<Associator,
detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type
get(const detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>& h)
BOOST_ASIO_NOEXCEPT
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
typename Associator<Handler, DefaultCandidate>::type)
get(const detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>& h,
const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
Associator<Handler, DefaultCandidate>::get(h.handler_, c)))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5, typename DefaultCandidate>
struct associator<Associator,
detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type
get(const detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>& h)
BOOST_ASIO_NOEXCEPT
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
typename Associator<Handler, DefaultCandidate>::type)
get(const detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>& h,
const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
Associator<Handler, DefaultCandidate>::get(h.handler_, c)))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
#if defined(BOOST_ASIO_HAS_MOVE)
template <typename Handler, typename Arg1, typename Allocator>
struct associated_allocator<detail::move_binder1<Handler, Arg1>, Allocator>
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename DefaultCandidate>
struct associator<Associator,
detail::move_binder1<Handler, Arg1>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
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
static typename Associator<Handler, DefaultCandidate>::type
get(const detail::move_binder1<Handler, Arg1>& h) BOOST_ASIO_NOEXCEPT
{
return associated_allocator<Handler, Allocator>::get(h.handler_, a);
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
typename Associator<Handler, DefaultCandidate>::type)
get(const detail::move_binder1<Handler, Arg1>& h,
const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
Associator<Handler, DefaultCandidate>::get(h.handler_, c)))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <typename Handler, typename Arg1, typename Arg2, typename Allocator>
struct associated_allocator<
detail::move_binder2<Handler, Arg1, Arg2>, Allocator>
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2,
typename DefaultCandidate>
struct associator<Associator,
detail::move_binder2<Handler, Arg1, Arg2>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
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
static typename Associator<Handler, DefaultCandidate>::type
get(const detail::move_binder2<Handler, Arg1, Arg2>& h) BOOST_ASIO_NOEXCEPT
{
return associated_allocator<Handler, Allocator>::get(h.handler_, a);
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
};
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
static BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(
typename Associator<Handler, DefaultCandidate>::type)
get(const detail::move_binder2<Handler, Arg1, Arg2>& h,
const DefaultCandidate& c) BOOST_ASIO_NOEXCEPT
BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX((
Associator<Handler, DefaultCandidate>::get(h.handler_, c)))
{
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);
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};

View File

@@ -0,0 +1,110 @@
//
// detail/blocking_executor_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_BLOCKING_EXECUTOR_OP_HPP
#define BOOST_ASIO_DETAIL_BLOCKING_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/event.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/scheduler_operation.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename Operation = scheduler_operation>
class blocking_executor_op_base : public Operation
{
public:
blocking_executor_op_base(typename Operation::func_type complete_func)
: Operation(complete_func),
is_complete_(false)
{
}
void wait()
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
while (!is_complete_)
event_.wait(lock);
}
protected:
struct do_complete_cleanup
{
~do_complete_cleanup()
{
boost::asio::detail::mutex::scoped_lock lock(op_->mutex_);
op_->is_complete_ = true;
op_->event_.unlock_and_signal_one_for_destruction(lock);
}
blocking_executor_op_base* op_;
};
private:
boost::asio::detail::mutex mutex_;
boost::asio::detail::event event_;
bool is_complete_;
};
template <typename Handler, typename Operation = scheduler_operation>
class blocking_executor_op : public blocking_executor_op_base<Operation>
{
public:
blocking_executor_op(Handler& h)
: blocking_executor_op_base<Operation>(&blocking_executor_op::do_complete),
handler_(h)
{
}
static void do_complete(void* owner, Operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
BOOST_ASIO_ASSUME(base != 0);
blocking_executor_op* o(static_cast<blocking_executor_op*>(base));
typename blocking_executor_op_base<Operation>::do_complete_cleanup
on_exit = { o };
(void)on_exit;
BOOST_ASIO_HANDLER_COMPLETION((*o));
// Make the upcall if required.
if (owner)
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN(());
boost_asio_handler_invoke_helpers::invoke(o->handler_, o->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_BLOCKING_EXECUTOR_OP_HPP

View File

@@ -2,7 +2,7 @@
// detail/buffer_resize_guard.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/buffer_sequence_adapter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -19,6 +19,7 @@
#include <boost/asio/buffer.hpp>
#include <boost/asio/detail/array_fwd.hpp>
#include <boost/asio/detail/socket_types.hpp>
#include <boost/asio/registered_buffer.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -105,6 +106,9 @@ class buffer_sequence_adapter
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = false };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
: count_(0), total_buffer_size_(0)
{
@@ -128,6 +132,11 @@ public:
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -154,6 +163,16 @@ public:
boost::asio::buffer_sequence_end(buffer_sequence));
}
enum { linearisation_storage_size = 8192 };
static Buffer linearise(const Buffers& buffer_sequence,
const boost::asio::mutable_buffer& storage)
{
return buffer_sequence_adapter::linearise(
boost::asio::buffer_sequence_begin(buffer_sequence),
boost::asio::buffer_sequence_end(buffer_sequence), storage);
}
private:
template <typename Iterator>
void init(Iterator begin, Iterator end)
@@ -202,6 +221,30 @@ private:
return Buffer();
}
template <typename Iterator>
static Buffer linearise(Iterator begin, Iterator end,
const boost::asio::mutable_buffer& storage)
{
boost::asio::mutable_buffer unused_storage = storage;
Iterator iter = begin;
while (iter != end && unused_storage.size() != 0)
{
Buffer buffer(*iter);
++iter;
if (buffer.size() == 0)
continue;
if (unused_storage.size() == storage.size())
{
if (iter == end)
return buffer;
if (buffer.size() >= unused_storage.size())
return buffer;
}
unused_storage += boost::asio::buffer_copy(unused_storage, buffer);
}
return Buffer(storage.data(), storage.size() - unused_storage.size());
}
native_buffer_type buffers_[max_buffers];
std::size_t count_;
std::size_t total_buffer_size_;
@@ -212,6 +255,9 @@ class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffer>
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = true };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter(
const boost::asio::mutable_buffer& buffer_sequence)
{
@@ -234,6 +280,11 @@ public:
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -254,6 +305,14 @@ public:
return Buffer(buffer_sequence);
}
enum { linearisation_storage_size = 1 };
static Buffer linearise(const boost::asio::mutable_buffer& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence);
}
private:
native_buffer_type buffer_;
std::size_t total_buffer_size_;
@@ -264,6 +323,9 @@ class buffer_sequence_adapter<Buffer, boost::asio::const_buffer>
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = true };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter(
const boost::asio::const_buffer& buffer_sequence)
{
@@ -286,6 +348,11 @@ public:
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -306,6 +373,14 @@ public:
return Buffer(buffer_sequence);
}
enum { linearisation_storage_size = 1 };
static Buffer linearise(const boost::asio::const_buffer& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence);
}
private:
native_buffer_type buffer_;
std::size_t total_buffer_size_;
@@ -318,6 +393,9 @@ class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffers_1>
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = true };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter(
const boost::asio::mutable_buffers_1& buffer_sequence)
{
@@ -340,6 +418,11 @@ public:
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -360,6 +443,14 @@ public:
return Buffer(buffer_sequence);
}
enum { linearisation_storage_size = 1 };
static Buffer linearise(const boost::asio::mutable_buffers_1& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence);
}
private:
native_buffer_type buffer_;
std::size_t total_buffer_size_;
@@ -370,6 +461,9 @@ class buffer_sequence_adapter<Buffer, boost::asio::const_buffers_1>
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = true };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter(
const boost::asio::const_buffers_1& buffer_sequence)
{
@@ -392,6 +486,11 @@ public:
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -412,6 +511,14 @@ public:
return Buffer(buffer_sequence);
}
enum { linearisation_storage_size = 1 };
static Buffer linearise(const boost::asio::const_buffers_1& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence);
}
private:
native_buffer_type buffer_;
std::size_t total_buffer_size_;
@@ -419,11 +526,162 @@ private:
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
template <typename Buffer>
class buffer_sequence_adapter<Buffer, boost::asio::mutable_registered_buffer>
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = true };
enum { is_registered_buffer = true };
explicit buffer_sequence_adapter(
const boost::asio::mutable_registered_buffer& buffer_sequence)
{
init_native_buffer(buffer_, buffer_sequence.buffer());
total_buffer_size_ = buffer_sequence.size();
registered_id_ = buffer_sequence.id();
}
native_buffer_type* buffers()
{
return &buffer_;
}
std::size_t count() const
{
return 1;
}
std::size_t total_size() const
{
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_id_;
}
bool all_empty() const
{
return total_buffer_size_ == 0;
}
static bool all_empty(
const boost::asio::mutable_registered_buffer& buffer_sequence)
{
return buffer_sequence.size() == 0;
}
static void validate(
const boost::asio::mutable_registered_buffer& buffer_sequence)
{
buffer_sequence.data();
}
static Buffer first(
const boost::asio::mutable_registered_buffer& buffer_sequence)
{
return Buffer(buffer_sequence.buffer());
}
enum { linearisation_storage_size = 1 };
static Buffer linearise(
const boost::asio::mutable_registered_buffer& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence.buffer());
}
private:
native_buffer_type buffer_;
std::size_t total_buffer_size_;
registered_buffer_id registered_id_;
};
template <typename Buffer>
class buffer_sequence_adapter<Buffer, boost::asio::const_registered_buffer>
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = true };
enum { is_registered_buffer = true };
explicit buffer_sequence_adapter(
const boost::asio::const_registered_buffer& buffer_sequence)
{
init_native_buffer(buffer_, buffer_sequence.buffer());
total_buffer_size_ = buffer_sequence.size();
registered_id_ = buffer_sequence.id();
}
native_buffer_type* buffers()
{
return &buffer_;
}
std::size_t count() const
{
return 1;
}
std::size_t total_size() const
{
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_id_;
}
bool all_empty() const
{
return total_buffer_size_ == 0;
}
static bool all_empty(
const boost::asio::const_registered_buffer& buffer_sequence)
{
return buffer_sequence.size() == 0;
}
static void validate(
const boost::asio::const_registered_buffer& buffer_sequence)
{
buffer_sequence.data();
}
static Buffer first(
const boost::asio::const_registered_buffer& buffer_sequence)
{
return Buffer(buffer_sequence.buffer());
}
enum { linearisation_storage_size = 1 };
static Buffer linearise(
const boost::asio::const_registered_buffer& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence.buffer());
}
private:
native_buffer_type buffer_;
std::size_t total_buffer_size_;
registered_buffer_id registered_id_;
};
template <typename Buffer, typename Elem>
class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = false };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter(
const boost::array<Elem, 2>& buffer_sequence)
{
@@ -447,6 +705,11 @@ public:
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -469,6 +732,19 @@ public:
? buffer_sequence[0] : buffer_sequence[1]);
}
enum { linearisation_storage_size = 8192 };
static Buffer linearise(const boost::array<Elem, 2>& buffer_sequence,
const boost::asio::mutable_buffer& storage)
{
if (buffer_sequence[0].size() == 0)
return Buffer(buffer_sequence[1]);
if (buffer_sequence[1].size() == 0)
return Buffer(buffer_sequence[0]);
return Buffer(storage.data(),
boost::asio::buffer_copy(storage, buffer_sequence));
}
private:
native_buffer_type buffers_[2];
std::size_t total_buffer_size_;
@@ -481,6 +757,9 @@ class buffer_sequence_adapter<Buffer, std::array<Elem, 2> >
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = false };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter(
const std::array<Elem, 2>& buffer_sequence)
{
@@ -504,6 +783,11 @@ public:
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -526,6 +810,19 @@ public:
? buffer_sequence[0] : buffer_sequence[1]);
}
enum { linearisation_storage_size = 8192 };
static Buffer linearise(const std::array<Elem, 2>& buffer_sequence,
const boost::asio::mutable_buffer& storage)
{
if (buffer_sequence[0].size() == 0)
return Buffer(buffer_sequence[1]);
if (buffer_sequence[1].size() == 0)
return Buffer(buffer_sequence[0]);
return Buffer(storage.data(),
boost::asio::buffer_copy(storage, buffer_sequence));
}
private:
native_buffer_type buffers_[2];
std::size_t total_buffer_size_;

View File

@@ -2,7 +2,7 @@
// detail/buffered_stream_storage.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -0,0 +1,91 @@
//
// detail/bulk_executor_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_BULK_EXECUTOR_OP_HPP
#define BOOST_ASIO_DETAIL_BULK_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/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/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 bulk_executor_op : public Operation
{
public:
BOOST_ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(bulk_executor_op);
template <typename H>
bulk_executor_op(BOOST_ASIO_MOVE_ARG(H) h,
const Alloc& allocator, std::size_t i)
: Operation(&bulk_executor_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(H)(h)),
allocator_(allocator),
index_(i)
{
}
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.
BOOST_ASIO_ASSUME(base != 0);
bulk_executor_op* o(static_cast<bulk_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.
detail::binder1<Handler, std::size_t> handler(o->handler_, o->index_);
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.handler_);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
private:
Handler handler_;
Alloc allocator_;
std::size_t index_;
};
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_BULK_EXECUTOR_OP_HPP

View File

@@ -2,7 +2,7 @@
// detail/call_stack.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/chrono.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/chrono_time_traits.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/completion_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -28,17 +28,17 @@ namespace boost {
namespace asio {
namespace detail {
template <typename Handler>
template <typename Handler, typename IoExecutor>
class completion_handler : public operation
{
public:
BOOST_ASIO_DEFINE_HANDLER_PTR(completion_handler);
completion_handler(Handler& h)
completion_handler(Handler& h, const IoExecutor& io_ex)
: operation(&completion_handler::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(h))
handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)),
work_(handler_, io_ex)
{
handler_work<Handler>::start(handler_);
}
static void do_complete(void* owner, operation* base,
@@ -48,10 +48,14 @@ public:
// 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));
// Take ownership of the operation's outstanding work.
handler_work<Handler, IoExecutor> w(
BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
h->work_));
// 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
@@ -74,6 +78,7 @@ public:
private:
Handler handler_;
handler_work<Handler, IoExecutor> work_;
};
} // namespace detail

View File

@@ -0,0 +1,330 @@
//
// detail/composed_work.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_COMPOSED_WORK_HPP
#define BOOST_ASIO_DETAIL_COMPOSED_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/detail/type_traits.hpp>
#include <boost/asio/detail/variadic_templates.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/execution/outstanding_work.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/is_executor.hpp>
#include <boost/asio/system_executor.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename Executor, typename = void>
class composed_work_guard
{
public:
typedef typename decay<
typename prefer_result<Executor,
execution::outstanding_work_t::tracked_t
>::type
>::type executor_type;
composed_work_guard(const Executor& ex)
: executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
void reset()
{
}
executor_type get_executor() const BOOST_ASIO_NOEXCEPT
{
return executor_;
}
private:
executor_type executor_;
};
template <>
struct composed_work_guard<system_executor>
{
public:
typedef system_executor executor_type;
composed_work_guard(const system_executor&)
{
}
void reset()
{
}
executor_type get_executor() const BOOST_ASIO_NOEXCEPT
{
return system_executor();
}
};
#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
template <typename Executor>
struct composed_work_guard<Executor,
typename enable_if<
!execution::is_executor<Executor>::value
>::type> : executor_work_guard<Executor>
{
composed_work_guard(const Executor& ex)
: executor_work_guard<Executor>(ex)
{
}
};
#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
template <typename>
struct composed_io_executors;
template <>
struct composed_io_executors<void()>
{
composed_io_executors() BOOST_ASIO_NOEXCEPT
: head_(system_executor())
{
}
typedef system_executor head_type;
system_executor head_;
};
inline composed_io_executors<void()> make_composed_io_executors()
{
return composed_io_executors<void()>();
}
template <typename Head>
struct composed_io_executors<void(Head)>
{
explicit composed_io_executors(const Head& ex) BOOST_ASIO_NOEXCEPT
: head_(ex)
{
}
typedef Head head_type;
Head head_;
};
template <typename Head>
inline composed_io_executors<void(Head)>
make_composed_io_executors(const Head& head)
{
return composed_io_executors<void(Head)>(head);
}
#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Head, typename... Tail>
struct composed_io_executors<void(Head, Tail...)>
{
explicit composed_io_executors(const Head& head,
const Tail&... tail) BOOST_ASIO_NOEXCEPT
: head_(head),
tail_(tail...)
{
}
void reset()
{
head_.reset();
tail_.reset();
}
typedef Head head_type;
Head head_;
composed_io_executors<void(Tail...)> tail_;
};
template <typename Head, typename... Tail>
inline composed_io_executors<void(Head, Tail...)>
make_composed_io_executors(const Head& head, const Tail&... tail)
{
return composed_io_executors<void(Head, Tail...)>(head, tail...);
}
#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
#define BOOST_ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF(n) \
template <typename Head, BOOST_ASIO_VARIADIC_TPARAMS(n)> \
struct composed_io_executors<void(Head, BOOST_ASIO_VARIADIC_TARGS(n))> \
{ \
explicit composed_io_executors(const Head& head, \
BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) BOOST_ASIO_NOEXCEPT \
: head_(head), \
tail_(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) \
{ \
} \
\
void reset() \
{ \
head_.reset(); \
tail_.reset(); \
} \
\
typedef Head head_type; \
Head head_; \
composed_io_executors<void(BOOST_ASIO_VARIADIC_TARGS(n))> tail_; \
}; \
\
template <typename Head, BOOST_ASIO_VARIADIC_TPARAMS(n)> \
inline composed_io_executors<void(Head, BOOST_ASIO_VARIADIC_TARGS(n))> \
make_composed_io_executors(const Head& head, \
BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) \
{ \
return composed_io_executors< \
void(Head, BOOST_ASIO_VARIADIC_TARGS(n))>( \
head, BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)); \
} \
/**/
BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF)
#undef BOOST_ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF
#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
template <typename>
struct composed_work;
template <>
struct composed_work<void()>
{
typedef composed_io_executors<void()> executors_type;
composed_work(const executors_type&) BOOST_ASIO_NOEXCEPT
: head_(system_executor())
{
}
void reset()
{
head_.reset();
}
typedef system_executor head_type;
composed_work_guard<system_executor> head_;
};
template <typename Head>
struct composed_work<void(Head)>
{
typedef composed_io_executors<void(Head)> executors_type;
explicit composed_work(const executors_type& ex) BOOST_ASIO_NOEXCEPT
: head_(ex.head_)
{
}
void reset()
{
head_.reset();
}
typedef Head head_type;
composed_work_guard<Head> head_;
};
#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Head, typename... Tail>
struct composed_work<void(Head, Tail...)>
{
typedef composed_io_executors<void(Head, Tail...)> executors_type;
explicit composed_work(const executors_type& ex) BOOST_ASIO_NOEXCEPT
: head_(ex.head_),
tail_(ex.tail_)
{
}
void reset()
{
head_.reset();
tail_.reset();
}
typedef Head head_type;
composed_work_guard<Head> head_;
composed_work<void(Tail...)> tail_;
};
#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
#define BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF(n) \
template <typename Head, BOOST_ASIO_VARIADIC_TPARAMS(n)> \
struct composed_work<void(Head, BOOST_ASIO_VARIADIC_TARGS(n))> \
{ \
typedef composed_io_executors<void(Head, \
BOOST_ASIO_VARIADIC_TARGS(n))> executors_type; \
\
explicit composed_work(const executors_type& ex) BOOST_ASIO_NOEXCEPT \
: head_(ex.head_), \
tail_(ex.tail_) \
{ \
} \
\
void reset() \
{ \
head_.reset(); \
tail_.reset(); \
} \
\
typedef Head head_type; \
composed_work_guard<Head> head_; \
composed_work<void(BOOST_ASIO_VARIADIC_TARGS(n))> tail_; \
}; \
/**/
BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF)
#undef BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF
#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
template <typename IoObject>
inline typename IoObject::executor_type
get_composed_io_executor(IoObject& io_object,
typename enable_if<
!is_executor<IoObject>::value
>::type* = 0,
typename enable_if<
!execution::is_executor<IoObject>::value
>::type* = 0)
{
return io_object.get_executor();
}
template <typename Executor>
inline const Executor& get_composed_io_executor(const Executor& ex,
typename enable_if<
is_executor<Executor>::value
|| execution::is_executor<Executor>::value
>::type* = 0)
{
return ex;
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_COMPOSED_WORK_HPP

View File

@@ -2,7 +2,7 @@
// detail/concurrency_hint.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/conditionally_enabled_event.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -65,6 +65,14 @@ public:
event_.unlock_and_signal_one(lock);
}
// Unlock the mutex and signal one waiter who may destroy us.
void unlock_and_signal_one_for_destruction(
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)

View File

@@ -2,7 +2,7 @@
// detail/conditionally_enabled_mutex.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// detail/consuming_buffers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -20,6 +20,7 @@
#include <boost/asio/buffer.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/limits.hpp>
#include <boost/asio/registered_buffer.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -270,6 +271,42 @@ public:
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
template <>
class consuming_buffers<mutable_buffer,
mutable_registered_buffer, const mutable_buffer*>
: public consuming_single_buffer<mutable_registered_buffer>
{
public:
explicit consuming_buffers(const mutable_registered_buffer& buffer)
: consuming_single_buffer<mutable_registered_buffer>(buffer)
{
}
};
template <>
class consuming_buffers<const_buffer,
mutable_registered_buffer, const mutable_buffer*>
: public consuming_single_buffer<mutable_registered_buffer>
{
public:
explicit consuming_buffers(const mutable_registered_buffer& buffer)
: consuming_single_buffer<mutable_registered_buffer>(buffer)
{
}
};
template <>
class consuming_buffers<const_buffer,
const_registered_buffer, const const_buffer*>
: public consuming_single_buffer<const_registered_buffer>
{
public:
explicit consuming_buffers(const const_registered_buffer& buffer)
: consuming_single_buffer<const_registered_buffer>(buffer)
{
}
};
template <typename Buffer, typename Elem>
class consuming_buffers<Buffer, boost::array<Elem, 2>,
typename boost::array<Elem, 2>::const_iterator>

View File

@@ -2,7 +2,7 @@
// detail/cstddef.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/cstdint.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -39,6 +39,7 @@ using std::int64_t;
using std::int_least64_t;
using std::uint64_t;
using std::uint_least64_t;
using std::uintptr_t;
using std::uintmax_t;
#else // defined(BOOST_ASIO_HAS_CSTDINT)
using boost::int16_t;
@@ -53,6 +54,7 @@ using boost::int64_t;
using boost::int_least64_t;
using boost::uint64_t;
using boost::uint_least64_t;
using boost::uintptr_t;
using boost::uintmax_t;
#endif // defined(BOOST_ASIO_HAS_CSTDINT)

View File

@@ -2,7 +2,7 @@
// detail/date_time_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,6 +17,8 @@
#include <boost/asio/detail/config.hpp>
#include <cstddef>
#include <boost/asio/associated_cancellation_slot.hpp>
#include <boost/asio/cancellation_type.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/detail/bind_handler.hpp>
@@ -98,7 +100,7 @@ public:
cancel(impl, ec);
}
// Move-construct a new serial port implementation.
// Move-construct a new timer implementation.
void move_construct(implementation_type& impl,
implementation_type& other_impl)
{
@@ -111,7 +113,7 @@ public:
other_impl.might_have_pending_waits = false;
}
// Move-assign from another serial port implementation.
// Move-assign from another timer implementation.
void move_assign(implementation_type& impl,
deadline_timer_service& other_service,
implementation_type& other_impl)
@@ -130,6 +132,21 @@ public:
other_impl.might_have_pending_waits = false;
}
// Move-construct a new timer implementation.
void converting_move_construct(implementation_type& impl,
deadline_timer_service&, implementation_type& other_impl)
{
move_construct(impl, other_impl);
}
// Move-assign from another timer implementation.
void converting_move_assign(implementation_type& impl,
deadline_timer_service& other_service,
implementation_type& other_impl)
{
move_assign(impl, other_service, other_impl);
}
// Cancel any asynchronous wait operations associated with the timer.
std::size_t cancel(implementation_type& impl, boost::system::error_code& ec)
{
@@ -231,12 +248,22 @@ public:
void async_wait(implementation_type& impl,
Handler& handler, const IoExecutor& io_ex)
{
typename associated_cancellation_slot<Handler>::type slot
= boost::asio::get_associated_cancellation_slot(handler);
// Allocate and construct an operation to wrap the handler.
typedef wait_handler<Handler, IoExecutor> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler, io_ex);
// Optionally register for per-operation cancellation.
if (slot.is_connected())
{
p.p->cancellation_key_ =
&slot.template emplace<op_cancellation>(this, &impl.timer_data);
}
impl.might_have_pending_waits = true;
BOOST_ASIO_HANDLER_CREATION((scheduler_.context(),
@@ -266,6 +293,34 @@ private:
#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
}
// Helper class used to implement per-operation cancellation.
class op_cancellation
{
public:
op_cancellation(deadline_timer_service* s,
typename timer_queue<Time_Traits>::per_timer_data* p)
: service_(s),
timer_data_(p)
{
}
void operator()(cancellation_type_t type)
{
if (!!(type &
(cancellation_type::terminal
| cancellation_type::partial
| cancellation_type::total)))
{
service_->scheduler_.cancel_timer_by_key(
service_->timer_queue_, timer_data_, this);
}
}
private:
deadline_timer_service* service_;
typename timer_queue<Time_Traits>::per_timer_data* timer_data_;
};
// The queue of timers.
timer_queue<Time_Traits> timer_queue_;

View File

@@ -2,7 +2,7 @@
// detail/dependent_type.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/descriptor_ops.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -24,6 +24,7 @@
#include <cstddef>
#include <boost/asio/error.hpp>
#include <boost/system/error_code.hpp>
#include <boost/asio/detail/cstdint.hpp>
#include <boost/asio/detail/socket_types.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -51,18 +52,26 @@ enum
typedef unsigned char state_type;
template <typename ReturnType>
inline ReturnType error_wrapper(ReturnType return_value,
boost::system::error_code& ec)
inline void get_last_error(
boost::system::error_code& ec, bool is_error_condition)
{
ec = boost::system::error_code(errno,
boost::asio::error::get_system_category());
return return_value;
if (!is_error_condition)
{
boost::asio::error::clear(ec);
}
else
{
ec = boost::system::error_code(errno,
boost::asio::error::get_system_category());
}
}
BOOST_ASIO_DECL int open(const char* path, int flags,
boost::system::error_code& ec);
BOOST_ASIO_DECL int open(const char* path, int flags, unsigned mode,
boost::system::error_code& ec);
BOOST_ASIO_DECL int close(int d, state_type& state,
boost::system::error_code& ec);
@@ -77,17 +86,66 @@ typedef iovec buf;
BOOST_ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs,
std::size_t count, bool all_empty, boost::system::error_code& ec);
BOOST_ASIO_DECL std::size_t sync_read1(int d, state_type state, void* data,
std::size_t size, boost::system::error_code& ec);
BOOST_ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count,
boost::system::error_code& ec, std::size_t& bytes_transferred);
BOOST_ASIO_DECL bool non_blocking_read1(int d, void* data, std::size_t size,
boost::system::error_code& ec, std::size_t& bytes_transferred);
BOOST_ASIO_DECL std::size_t sync_write(int d, state_type state,
const buf* bufs, std::size_t count, bool all_empty,
boost::system::error_code& ec);
BOOST_ASIO_DECL std::size_t sync_write1(int d, state_type state,
const void* data, std::size_t size, boost::system::error_code& ec);
BOOST_ASIO_DECL bool non_blocking_write(int d,
const buf* bufs, std::size_t count,
boost::system::error_code& ec, std::size_t& bytes_transferred);
BOOST_ASIO_DECL bool non_blocking_write1(int d,
const void* data, std::size_t size,
boost::system::error_code& ec, std::size_t& bytes_transferred);
#if defined(BOOST_ASIO_HAS_FILE)
BOOST_ASIO_DECL std::size_t sync_read_at(int d, state_type state,
uint64_t offset, buf* bufs, std::size_t count, bool all_empty,
boost::system::error_code& ec);
BOOST_ASIO_DECL std::size_t sync_read_at1(int d, state_type state,
uint64_t offset, void* data, std::size_t size,
boost::system::error_code& ec);
BOOST_ASIO_DECL bool non_blocking_read_at(int d, uint64_t offset,
buf* bufs, std::size_t count, boost::system::error_code& ec,
std::size_t& bytes_transferred);
BOOST_ASIO_DECL bool non_blocking_read_at1(int d, uint64_t offset,
void* data, std::size_t size, boost::system::error_code& ec,
std::size_t& bytes_transferred);
BOOST_ASIO_DECL std::size_t sync_write_at(int d, state_type state,
uint64_t offset, const buf* bufs, std::size_t count, bool all_empty,
boost::system::error_code& ec);
BOOST_ASIO_DECL std::size_t sync_write_at1(int d, state_type state,
uint64_t offset, const void* data, std::size_t size,
boost::system::error_code& ec);
BOOST_ASIO_DECL bool non_blocking_write_at(int d,
uint64_t offset, const buf* bufs, std::size_t count,
boost::system::error_code& ec, std::size_t& bytes_transferred);
BOOST_ASIO_DECL bool non_blocking_write_at1(int d,
uint64_t offset, const void* data, std::size_t size,
boost::system::error_code& ec, std::size_t& bytes_transferred);
#endif // defined(BOOST_ASIO_HAS_FILE)
BOOST_ASIO_DECL int ioctl(int d, state_type& state, long cmd,
ioctl_arg_type* arg, boost::system::error_code& ec);

View File

@@ -2,7 +2,7 @@
// detail/descriptor_read_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -26,6 +26,7 @@
#include <boost/asio/detail/handler_work.hpp>
#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -37,9 +38,11 @@ template <typename MutableBufferSequence>
class descriptor_read_op_base : public reactor_op
{
public:
descriptor_read_op_base(int descriptor,
const MutableBufferSequence& buffers, func_type complete_func)
: reactor_op(&descriptor_read_op_base::do_perform, complete_func),
descriptor_read_op_base(const boost::system::error_code& success_ec,
int descriptor, const MutableBufferSequence& buffers,
func_type complete_func)
: reactor_op(success_ec,
&descriptor_read_op_base::do_perform, complete_func),
descriptor_(descriptor),
buffers_(buffers)
{
@@ -47,14 +50,27 @@ public:
static status do_perform(reactor_op* base)
{
BOOST_ASIO_ASSUME(base != 0);
descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base));
buffer_sequence_adapter<boost::asio::mutable_buffer,
MutableBufferSequence> bufs(o->buffers_);
typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
MutableBufferSequence> bufs_type;
status result = descriptor_ops::non_blocking_read(o->descriptor_,
bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
? done : not_done;
status result;
if (bufs_type::is_single_buffer)
{
result = descriptor_ops::non_blocking_read1(o->descriptor_,
bufs_type::first(o->buffers_).data(),
bufs_type::first(o->buffers_).size(),
o->ec_, o->bytes_transferred_) ? done : not_done;
}
else
{
bufs_type bufs(o->buffers_);
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_));
@@ -72,16 +88,19 @@ class descriptor_read_op
: public descriptor_read_op_base<MutableBufferSequence>
{
public:
typedef Handler handler_type;
typedef IoExecutor io_executor_type;
BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_read_op);
descriptor_read_op(int descriptor, const MutableBufferSequence& buffers,
descriptor_read_op(const boost::system::error_code& success_ec,
int descriptor, const MutableBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
: descriptor_read_op_base<MutableBufferSequence>(
: descriptor_read_op_base<MutableBufferSequence>(success_ec,
descriptor, buffers, &descriptor_read_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
work_(handler_, io_ex)
{
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@@ -89,12 +108,19 @@ public:
std::size_t /*bytes_transferred*/)
{
// Take ownership of the handler object.
BOOST_ASIO_ASSUME(base != 0);
descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
BOOST_ASIO_HANDLER_COMPLETION((*o));
// Take ownership of the operation's outstanding work.
handler_work<Handler, IoExecutor> w(
BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
o->work_));
BOOST_ASIO_ERROR_LOCATION(o->ec_);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated
@@ -116,9 +142,41 @@ public:
}
}
static void do_immediate(operation* base, bool, const void* io_ex)
{
// Take ownership of the handler object.
BOOST_ASIO_ASSUME(base != 0);
descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
BOOST_ASIO_HANDLER_COMPLETION((*o));
// Take ownership of the operation's outstanding work.
immediate_handler_work<Handler, IoExecutor> w(
BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
o->work_));
BOOST_ASIO_ERROR_LOCATION(o->ec_);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated
// with the handler. Consequently, a local copy of the handler is required
// to ensure that any owning sub-object remains valid until after we have
// deallocated the memory here.
detail::binder2<Handler, boost::system::error_code, std::size_t>
handler(o->handler_, o->ec_, o->bytes_transferred_);
p.h = boost::asio::detail::addressof(handler.handler_);
p.reset();
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
w.complete(handler, handler.handler_, io_ex);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
private:
Handler handler_;
IoExecutor io_executor_;
handler_work<Handler, IoExecutor> work_;
};
} // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/descriptor_write_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -37,9 +37,11 @@ template <typename ConstBufferSequence>
class descriptor_write_op_base : public reactor_op
{
public:
descriptor_write_op_base(int descriptor,
const ConstBufferSequence& buffers, func_type complete_func)
: reactor_op(&descriptor_write_op_base::do_perform, complete_func),
descriptor_write_op_base(const boost::system::error_code& success_ec,
int descriptor, const ConstBufferSequence& buffers,
func_type complete_func)
: reactor_op(success_ec,
&descriptor_write_op_base::do_perform, complete_func),
descriptor_(descriptor),
buffers_(buffers)
{
@@ -47,14 +49,27 @@ public:
static status do_perform(reactor_op* base)
{
BOOST_ASIO_ASSUME(base != 0);
descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base));
buffer_sequence_adapter<boost::asio::const_buffer,
ConstBufferSequence> bufs(o->buffers_);
typedef buffer_sequence_adapter<boost::asio::const_buffer,
ConstBufferSequence> bufs_type;
status result = descriptor_ops::non_blocking_write(o->descriptor_,
bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
? done : not_done;
status result;
if (bufs_type::is_single_buffer)
{
result = descriptor_ops::non_blocking_write1(o->descriptor_,
bufs_type::first(o->buffers_).data(),
bufs_type::first(o->buffers_).size(),
o->ec_, o->bytes_transferred_) ? done : not_done;
}
else
{
bufs_type bufs(o->buffers_);
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_));
@@ -72,16 +87,19 @@ class descriptor_write_op
: public descriptor_write_op_base<ConstBufferSequence>
{
public:
typedef Handler handler_type;
typedef IoExecutor io_executor_type;
BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_write_op);
descriptor_write_op(int descriptor, const ConstBufferSequence& buffers,
descriptor_write_op(const boost::system::error_code& success_ec,
int descriptor, const ConstBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
: descriptor_write_op_base<ConstBufferSequence>(
: descriptor_write_op_base<ConstBufferSequence>(success_ec,
descriptor, buffers, &descriptor_write_op::do_complete),
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
work_(handler_, io_ex)
{
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@@ -89,12 +107,19 @@ public:
std::size_t /*bytes_transferred*/)
{
// Take ownership of the handler object.
BOOST_ASIO_ASSUME(base != 0);
descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
BOOST_ASIO_HANDLER_COMPLETION((*o));
// Take ownership of the operation's outstanding work.
handler_work<Handler, IoExecutor> w(
BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
o->work_));
BOOST_ASIO_ERROR_LOCATION(o->ec_);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated
@@ -116,9 +141,41 @@ public:
}
}
static void do_immediate(operation* base, bool, const void* io_ex)
{
// Take ownership of the handler object.
BOOST_ASIO_ASSUME(base != 0);
descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
BOOST_ASIO_HANDLER_COMPLETION((*o));
// Take ownership of the operation's outstanding work.
immediate_handler_work<Handler, IoExecutor> w(
BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
o->work_));
BOOST_ASIO_ERROR_LOCATION(o->ec_);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated
// with the handler. Consequently, a local copy of the handler is required
// to ensure that any owning sub-object remains valid until after we have
// deallocated the memory here.
detail::binder2<Handler, boost::system::error_code, std::size_t>
handler(o->handler_, o->ec_, o->bytes_transferred_);
p.h = boost::asio::detail::addressof(handler.handler_);
p.reset();
BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
w.complete(handler, handler.handler_, io_ex);
BOOST_ASIO_HANDLER_INVOCATION_END;
}
private:
Handler handler_;
IoExecutor io_executor_;
handler_work<Handler, IoExecutor> work_;
};
} // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/dev_poll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -28,6 +28,7 @@
#include <boost/asio/detail/op_queue.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/reactor_op_queue.hpp>
#include <boost/asio/detail/scheduler_task.hpp>
#include <boost/asio/detail/select_interrupter.hpp>
#include <boost/asio/detail/socket_types.hpp>
#include <boost/asio/detail/timer_queue_base.hpp>
@@ -42,7 +43,8 @@ namespace asio {
namespace detail {
class dev_poll_reactor
: public execution_context_service_base<dev_poll_reactor>
: public execution_context_service_base<dev_poll_reactor>,
public scheduler_task
{
public:
enum op_types { read_op = 0, write_op = 1,
@@ -85,22 +87,43 @@ public:
per_descriptor_data& source_descriptor_data);
// Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op, bool is_continuation)
{
scheduler_.post_immediate_completion(op, is_continuation);
}
void post_immediate_completion(operation* op, bool is_continuation) const;
// Post a reactor operation for immediate completion.
BOOST_ASIO_DECL static void call_post_immediate_completion(
operation* op, bool is_continuation, const void* self);
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor,
per_descriptor_data&, reactor_op* op,
bool is_continuation, bool allow_speculative);
bool is_continuation, bool allow_speculative,
void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg);
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
void start_op(int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data, reactor_op* op,
bool is_continuation, bool allow_speculative)
{
start_op(op_type, descriptor, descriptor_data,
op, is_continuation, allow_speculative,
&dev_poll_reactor::call_post_immediate_completion, this);
}
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
// Cancel all operations associated with the given descriptor and key. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
BOOST_ASIO_DECL void cancel_ops_by_key(socket_type descriptor,
per_descriptor_data& descriptor_data,
int op_type, void* cancellation_key);
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor. The reactor resources associated with
// the descriptor must be released by calling cleanup_descriptor_data.
@@ -139,6 +162,12 @@ public:
typename timer_queue<Time_Traits>::per_timer_data& timer,
std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
// Cancel the timer operations associated with the given key.
template <typename Time_Traits>
void cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key);
// Move the timer operations associated with the given timer.
template <typename Time_Traits>
void move_timer(timer_queue<Time_Traits>& queue,

View File

@@ -2,7 +2,7 @@
// detail/epoll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -25,6 +25,7 @@
#include <boost/asio/detail/object_pool.hpp>
#include <boost/asio/detail/op_queue.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/scheduler_task.hpp>
#include <boost/asio/detail/select_interrupter.hpp>
#include <boost/asio/detail/socket_types.hpp>
#include <boost/asio/detail/timer_queue_base.hpp>
@@ -43,7 +44,8 @@ namespace asio {
namespace detail {
class epoll_reactor
: public execution_context_service_base<epoll_reactor>
: public execution_context_service_base<epoll_reactor>,
public scheduler_task
{
private:
// The mutex type used by this reactor.
@@ -115,16 +117,30 @@ public:
per_descriptor_data& source_descriptor_data);
// Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op, bool is_continuation)
{
scheduler_.post_immediate_completion(op, is_continuation);
}
void post_immediate_completion(operation* op, bool is_continuation) const;
// Post a reactor operation for immediate completion.
BOOST_ASIO_DECL static void call_post_immediate_completion(
operation* op, bool is_continuation, const void* self);
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data, reactor_op* op,
bool is_continuation, bool allow_speculative);
bool is_continuation, bool allow_speculative,
void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg);
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
void start_op(int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data, reactor_op* op,
bool is_continuation, bool allow_speculative)
{
start_op(op_type, descriptor, descriptor_data,
op, is_continuation, allow_speculative,
&epoll_reactor::call_post_immediate_completion, this);
}
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
@@ -132,6 +148,13 @@ public:
BOOST_ASIO_DECL void cancel_ops(socket_type descriptor,
per_descriptor_data& descriptor_data);
// Cancel all operations associated with the given descriptor and key. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
BOOST_ASIO_DECL void cancel_ops_by_key(socket_type descriptor,
per_descriptor_data& descriptor_data,
int op_type, void* cancellation_key);
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor. The reactor resources associated with
// the descriptor must be released by calling cleanup_descriptor_data.
@@ -171,6 +194,12 @@ public:
typename timer_queue<Time_Traits>::per_timer_data& timer,
std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
// Cancel the timer operations associated with the given key.
template <typename Time_Traits>
void cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key);
// Move the timer operations associated with the given timer.
template <typename Time_Traits>
void move_timer(timer_queue<Time_Traits>& queue,

View File

@@ -2,7 +2,7 @@
// detail/event.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/eventfd_select_interrupter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -41,7 +41,7 @@ public:
// Interrupt the select call.
BOOST_ASIO_DECL void interrupt();
// Reset the select interrupt. Returns true if the call was interrupted.
// Reset the select interrupter. Returns true if the reset was successful.
BOOST_ASIO_DECL bool reset();
// Get the read descriptor to be passed to select.

View File

@@ -0,0 +1,42 @@
//
// detail/exception.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_EXCEPTION_HPP
#define BOOST_ASIO_DETAIL_EXCEPTION_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_EXCEPTION_PTR)
# include <exception>
#else // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
# include <boost/exception_ptr.hpp>
#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
namespace boost {
namespace asio {
#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
using std::exception_ptr;
using std::current_exception;
using std::rethrow_exception;
#else // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
using boost::exception_ptr;
using boost::current_exception;
using boost::rethrow_exception;
#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
} // namespace asio
} // namespace boost
#endif // BOOST_ASIO_DETAIL_EXCEPTION_HPP

View File

@@ -2,7 +2,7 @@
// detail/executor_function.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,6 +17,8 @@
#include <boost/asio/detail/config.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>
@@ -24,57 +26,80 @@ namespace boost {
namespace asio {
namespace detail {
class executor_function_base
#if defined(BOOST_ASIO_HAS_MOVE)
// Lightweight, move-only function object wrapper.
class executor_function
{
public:
void complete()
template <typename F, typename Alloc>
explicit executor_function(F f, const Alloc& a)
{
func_(this, true);
// Allocate and construct an object to wrap the function.
typedef impl<F, Alloc> impl_type;
typename impl_type::ptr p = {
detail::addressof(a), impl_type::ptr::allocate(a), 0 };
impl_ = new (p.v) impl_type(BOOST_ASIO_MOVE_CAST(F)(f), a);
p.v = 0;
}
void destroy()
executor_function(executor_function&& other) BOOST_ASIO_NOEXCEPT
: impl_(other.impl_)
{
func_(this, false);
other.impl_ = 0;
}
protected:
typedef void (*func_type)(executor_function_base*, bool);
executor_function_base(func_type func)
: func_(func)
~executor_function()
{
if (impl_)
impl_->complete_(impl_, false);
}
// Prevents deletion through this type.
~executor_function_base()
void operator()()
{
if (impl_)
{
impl_base* i = impl_;
impl_ = 0;
i->complete_(i, true);
}
}
private:
func_type func_;
};
template <typename Function, typename Alloc>
class executor_function : public executor_function_base
{
public:
BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(
thread_info_base::executor_function_tag, executor_function);
template <typename F>
executor_function(BOOST_ASIO_MOVE_ARG(F) f, const Alloc& allocator)
: executor_function_base(&executor_function::do_complete),
function_(BOOST_ASIO_MOVE_CAST(F)(f)),
allocator_(allocator)
// Base class for polymorphic function implementations.
struct impl_base
{
}
void (*complete_)(impl_base*, bool);
};
static void do_complete(executor_function_base* base, bool call)
// Polymorphic function implementation.
template <typename Function, typename Alloc>
struct impl : impl_base
{
BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(
thread_info_base::executor_function_tag, impl);
template <typename F>
impl(BOOST_ASIO_MOVE_ARG(F) f, const Alloc& a)
: function_(BOOST_ASIO_MOVE_CAST(F)(f)),
allocator_(a)
{
complete_ = &executor_function::complete<Function, Alloc>;
}
Function function_;
Alloc allocator_;
};
// Helper to complete function invocation.
template <typename Function, typename Alloc>
static void complete(impl_base* base, bool call)
{
// Take ownership of the function object.
executor_function* o(static_cast<executor_function*>(base));
Alloc allocator(o->allocator_);
ptr p = { detail::addressof(allocator), o, o };
impl<Function, Alloc>* i(static_cast<impl<Function, Alloc>*>(base));
Alloc allocator(i->allocator_);
typename impl<Function, Alloc>::ptr p = {
detail::addressof(allocator), i, i };
// Make a copy of the function so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
@@ -82,19 +107,94 @@ public:
// associated with the function. Consequently, a local copy of the function
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Function function(BOOST_ASIO_MOVE_CAST(Function)(o->function_));
Function function(BOOST_ASIO_MOVE_CAST(Function)(i->function_));
p.reset();
// Make the upcall if required.
if (call)
{
function();
boost_asio_handler_invoke_helpers::invoke(function, function);
}
}
impl_base* impl_;
};
#else // defined(BOOST_ASIO_HAS_MOVE)
// Not so lightweight, copyable function object wrapper.
class executor_function
{
public:
template <typename F, typename Alloc>
explicit executor_function(const F& f, const Alloc&)
: impl_(new impl<typename decay<F>::type>(f))
{
}
void operator()()
{
impl_->complete_(impl_.get());
}
private:
Function function_;
Alloc allocator_;
// Base class for polymorphic function implementations.
struct impl_base
{
void (*complete_)(impl_base*);
};
// Polymorphic function implementation.
template <typename F>
struct impl : impl_base
{
impl(const F& f)
: function_(f)
{
complete_ = &executor_function::complete<F>;
}
F function_;
};
// Helper to complete function invocation.
template <typename F>
static void complete(impl_base* i)
{
static_cast<impl<F>*>(i)->function_();
}
shared_ptr<impl_base> impl_;
};
#endif // defined(BOOST_ASIO_HAS_MOVE)
// Lightweight, non-owning, copyable function object wrapper.
class executor_function_view
{
public:
template <typename F>
explicit executor_function_view(F& f) BOOST_ASIO_NOEXCEPT
: complete_(&executor_function_view::complete<F>),
function_(&f)
{
}
void operator()()
{
complete_(function_);
}
private:
// Helper to complete function invocation.
template <typename F>
static void complete(void* f)
{
(*static_cast<F*>(f))();
}
void (*complete_)(void*);
void* function_;
};
} // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/executor_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -47,6 +47,7 @@ public:
std::size_t /*bytes_transferred*/)
{
// Take ownership of the handler object.
BOOST_ASIO_ASSUME(base != 0);
executor_op* o(static_cast<executor_op*>(base));
Alloc allocator(o->allocator_);
ptr p = { detail::addressof(allocator), o, o };

View File

@@ -2,7 +2,7 @@
// detail/fd_set_adapter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/functional.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -34,6 +34,12 @@ using boost::function;
#endif // defined(BOOST_ASIO_HAS_STD_FUNCTION)
} // namespace detail
#if defined(BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER)
using std::ref;
using std::reference_wrapper;
#endif // defined(BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER)
} // namespace asio
} // namespace boost

View File

@@ -2,7 +2,7 @@
// detail/future.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/gcc_arm_fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/gcc_hppa_fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/gcc_sync_fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/gcc_x86_fenced_block.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -56,7 +56,7 @@ private:
{
int r = 0, m = 1;
__asm__ __volatile__ (
"xchgl %0, %1" :
"xchg{l} %0, %1" :
"=r"(r), "=m"(m) :
"0"(1), "m"(m) :
"memory", "cc");

View File

@@ -2,7 +2,7 @@
// detail/global.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/handler_alloc_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -19,6 +19,7 @@
#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/recycling_allocator.hpp>
#include <boost/asio/detail/thread_info_base.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/handler_alloc_hook.hpp>
@@ -29,12 +30,45 @@
// boost_asio_handler_alloc_helpers namespace is defined here for that purpose.
namespace boost_asio_handler_alloc_helpers {
#if defined(BOOST_ASIO_NO_DEPRECATED)
template <typename Handler>
inline void* allocate(std::size_t s, Handler& h)
inline void error_if_hooks_are_defined(Handler& h)
{
using boost::asio::asio_handler_allocate;
// If you get an error here it is because some of your handlers still
// overload asio_handler_allocate, but this hook is no longer used.
(void)static_cast<boost::asio::asio_handler_allocate_is_no_longer_used>(
asio_handler_allocate(static_cast<std::size_t>(0),
boost::asio::detail::addressof(h)));
using boost::asio::asio_handler_deallocate;
// If you get an error here it is because some of your handlers still
// overload asio_handler_deallocate, but this hook is no longer used.
(void)static_cast<boost::asio::asio_handler_deallocate_is_no_longer_used>(
asio_handler_deallocate(static_cast<void*>(0),
static_cast<std::size_t>(0), boost::asio::detail::addressof(h)));
}
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
template <typename Handler>
inline void* allocate(std::size_t s, Handler& h,
std::size_t align = BOOST_ASIO_DEFAULT_ALIGN)
{
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
return ::operator new(s);
return boost::asio::aligned_new(align, s);
#elif defined(BOOST_ASIO_NO_DEPRECATED)
// The asio_handler_allocate hook is no longer used to obtain memory.
(void)&error_if_hooks_are_defined<Handler>;
(void)h;
# if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
return boost::asio::detail::thread_info_base::allocate(
boost::asio::detail::thread_context::top_of_thread_call_stack(),
s, align);
# else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
return boost::asio::aligned_new(align, s);
# endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
#else
(void)align;
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(s, boost::asio::detail::addressof(h));
#endif
@@ -44,7 +78,18 @@ template <typename Handler>
inline void deallocate(void* p, std::size_t s, Handler& h)
{
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
::operator delete(p);
boost::asio::aligned_delete(p);
#elif defined(BOOST_ASIO_NO_DEPRECATED)
// The asio_handler_allocate hook is no longer used to obtain memory.
(void)&error_if_hooks_are_defined<Handler>;
(void)h;
#if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
boost::asio::detail::thread_info_base::deallocate(
boost::asio::detail::thread_context::top_of_thread_call_stack(), p, s);
#else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
(void)s;
boost::asio::aligned_delete(p);
#endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
#else
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(p, s, boost::asio::detail::addressof(h));
@@ -83,7 +128,8 @@ public:
T* allocate(std::size_t n)
{
return static_cast<T*>(
boost_asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_));
boost_asio_handler_alloc_helpers::allocate(
sizeof(T) * n, handler_, BOOST_ASIO_ALIGNOF(T)));
}
void deallocate(T* p, std::size_t n)

View File

@@ -2,7 +2,7 @@
// detail/handler_cont_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/handler_invoke_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -26,12 +26,29 @@
// namespace is defined here for that purpose.
namespace boost_asio_handler_invoke_helpers {
#if defined(BOOST_ASIO_NO_DEPRECATED)
template <typename Function, typename Context>
inline void error_if_hook_is_defined(Function& function, Context& context)
{
using boost::asio::asio_handler_invoke;
// If you get an error here it is because some of your handlers still
// overload asio_handler_invoke, but this hook is no longer used.
(void)static_cast<boost::asio::asio_handler_invoke_is_no_longer_used>(
asio_handler_invoke(function, boost::asio::detail::addressof(context)));
}
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
template <typename Function, typename Context>
inline void invoke(Function& function, Context& context)
{
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
Function tmp(function);
tmp();
#elif defined(BOOST_ASIO_NO_DEPRECATED)
// The asio_handler_invoke hook is no longer used to invoke the function.
(void)&error_if_hook_is_defined<Function, Context>;
(void)context;
function();
#else
using boost::asio::asio_handler_invoke;
asio_handler_invoke(function, boost::asio::detail::addressof(context));
@@ -44,6 +61,12 @@ inline void invoke(const Function& function, Context& context)
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
Function tmp(function);
tmp();
#elif defined(BOOST_ASIO_NO_DEPRECATED)
// The asio_handler_invoke hook is no longer used to invoke the function.
(void)&error_if_hook_is_defined<const Function, Context>;
(void)context;
Function tmp(function);
tmp();
#else
using boost::asio::asio_handler_invoke;
asio_handler_invoke(function, boost::asio::detail::addressof(context));

View File

@@ -2,7 +2,7 @@
// detail/handler_tracking.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -90,6 +90,28 @@ public:
// Initialise the tracking system.
BOOST_ASIO_DECL static void init();
class location
{
public:
// Constructor adds a location to the stack.
BOOST_ASIO_DECL explicit location(const char* file,
int line, const char* func);
// Destructor removes a location from the stack.
BOOST_ASIO_DECL ~location();
private:
// Disallow copying and assignment.
location(const location&) BOOST_ASIO_DELETED;
location& operator=(const location&) BOOST_ASIO_DELETED;
friend class handler_tracking;
const char* file_;
int line_;
const char* func_;
location* next_;
};
// Record the creation of a tracked handler.
BOOST_ASIO_DECL static void creation(
execution_context& context, tracked_handler& h,
@@ -178,6 +200,9 @@ private:
# define BOOST_ASIO_HANDLER_TRACKING_INIT \
boost::asio::detail::handler_tracking::init()
# define BOOST_ASIO_HANDLER_LOCATION(args) \
boost::asio::detail::handler_tracking::location tracked_location args
# define BOOST_ASIO_HANDLER_CREATION(args) \
boost::asio::detail::handler_tracking::creation args
@@ -214,6 +239,7 @@ private:
# define BOOST_ASIO_INHERIT_TRACKED_HANDLER
# define BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER
# define BOOST_ASIO_HANDLER_TRACKING_INIT (void)0
# define BOOST_ASIO_HANDLER_LOCATION(loc) (void)0
# define BOOST_ASIO_HANDLER_CREATION(args) (void)0
# define BOOST_ASIO_HANDLER_COMPLETION(args) (void)0
# define BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0

View File

@@ -2,7 +2,7 @@
// detail/handler_type_requirements.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -65,7 +65,7 @@ template <typename Handler>
auto zero_arg_copyable_handler_test(Handler h, void*)
-> decltype(
sizeof(Handler(static_cast<const Handler&>(h))),
((h)()),
(BOOST_ASIO_MOVE_OR_LVALUE(Handler)(h)()),
char(0));
template <typename Handler>
@@ -75,7 +75,7 @@ template <typename Handler, typename Arg1>
auto one_arg_handler_test(Handler h, Arg1* a1)
-> decltype(
sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
((h)(*a1)),
(BOOST_ASIO_MOVE_OR_LVALUE(Handler)(h)(*a1)),
char(0));
template <typename Handler>
@@ -85,7 +85,7 @@ template <typename Handler, typename Arg1, typename Arg2>
auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2)
-> decltype(
sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
((h)(*a1, *a2)),
(BOOST_ASIO_MOVE_OR_LVALUE(Handler)(h)(*a1, *a2)),
char(0));
template <typename Handler>
@@ -95,7 +95,8 @@ 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))),
(BOOST_ASIO_MOVE_OR_LVALUE(Handler)(h)(
*a1, BOOST_ASIO_MOVE_CAST(Arg2)(*a2))),
char(0));
template <typename Handler>
@@ -117,9 +118,11 @@ template <typename T> const T& clvref(T);
#if defined(BOOST_ASIO_HAS_MOVE)
template <typename T> T rvref();
template <typename T> T rvref(T);
template <typename T> T rorlvref();
#else // defined(BOOST_ASIO_HAS_MOVE)
template <typename T> const T& rvref();
template <typename T> const T& rvref(T);
template <typename T> T& rorlvref();
#endif // defined(BOOST_ASIO_HAS_MOVE)
template <typename T> char argbyv(T);
@@ -146,7 +149,7 @@ struct handler_type_requirements
boost::asio::detail::clvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()(), \
char(0))> BOOST_ASIO_UNUSED_TYPEDEF
@@ -171,7 +174,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>(), \
boost::asio::detail::lvref<const std::size_t>()), \
@@ -198,7 +201,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>(), \
boost::asio::detail::lvref<const std::size_t>()), \
@@ -224,7 +227,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>()), \
char(0))> BOOST_ASIO_UNUSED_TYPEDEF
@@ -250,7 +253,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>(), \
boost::asio::detail::rvref<socket_type>()), \
@@ -276,7 +279,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>()), \
char(0))> BOOST_ASIO_UNUSED_TYPEDEF
@@ -302,7 +305,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>(), \
boost::asio::detail::lvref<const endpoint_type>()), \
@@ -329,7 +332,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>(), \
boost::asio::detail::lvref<const iter_type>()), \
@@ -356,7 +359,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>(), \
boost::asio::detail::lvref<const range_type>()), \
@@ -382,7 +385,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>()), \
char(0))> BOOST_ASIO_UNUSED_TYPEDEF
@@ -408,7 +411,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>(), \
boost::asio::detail::lvref<const int>()), \
@@ -434,7 +437,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>()), \
char(0))> BOOST_ASIO_UNUSED_TYPEDEF
@@ -460,7 +463,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>(), \
boost::asio::detail::lvref<const std::size_t>()), \
@@ -486,7 +489,7 @@ struct handler_type_requirements
boost::asio::detail::rvref< \
asio_true_handler_type>())) + \
sizeof( \
boost::asio::detail::lvref< \
boost::asio::detail::rorlvref< \
asio_true_handler_type>()( \
boost::asio::detail::lvref<const boost::system::error_code>()), \
char(0))> BOOST_ASIO_UNUSED_TYPEDEF

View File

@@ -2,7 +2,7 @@
// detail/handler_work.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,94 +16,546 @@
#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/associated_immediate_executor.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/initiate_dispatch.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/work_dispatcher.hpp>
#include <boost/asio/execution/allocator.hpp>
#include <boost/asio/execution/blocking.hpp>
#include <boost/asio/execution/execute.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/execution/outstanding_work.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/prefer.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
class executor;
class io_context;
#if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
class any_completion_executor;
class any_io_executor;
#endif // !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
namespace execution {
#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
template <typename...> class any_executor;
#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
template <typename, typename, typename, typename, typename,
typename, typename, typename, typename> class any_executor;
#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
} // namespace execution
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 IoExecutor = system_executor, typename HandlerExecutor
= typename associated_executor<Handler, IoExecutor>::type>
class handler_work
template <typename Executor, typename CandidateExecutor = void,
typename IoContext = io_context,
typename PolymorphicExecutor = executor, typename = void>
class handler_work_base
{
public:
explicit handler_work(Handler& handler) BOOST_ASIO_NOEXCEPT
: io_executor_(),
executor_(boost::asio::get_associated_executor(handler, io_executor_))
explicit handler_work_base(int, int, const Executor& ex) BOOST_ASIO_NOEXCEPT
: executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
: io_executor_(io_ex),
executor_(boost::asio::get_associated_executor(handler, io_executor_))
template <typename OtherExecutor>
handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
const OtherExecutor& /*candidate*/) BOOST_ASIO_NOEXCEPT
: executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
static void start(Handler& handler) BOOST_ASIO_NOEXCEPT
handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
: executor_(other.executor_)
{
HandlerExecutor ex(boost::asio::get_associated_executor(handler));
ex.on_work_started();
}
static void start(Handler& handler,
const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
#if defined(BOOST_ASIO_HAS_MOVE)
handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
: executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
{
HandlerExecutor ex(boost::asio::get_associated_executor(handler, io_ex));
ex.on_work_started();
io_ex.on_work_started();
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
bool owns_work() const BOOST_ASIO_NOEXCEPT
{
return true;
}
~handler_work()
template <typename Function, typename Handler>
void dispatch(Function& function, Handler& handler)
{
io_executor_.on_work_finished();
executor_.on_work_finished();
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost::asio::prefer(executor_,
execution::allocator((get_associated_allocator)(handler))
).execute(BOOST_ASIO_MOVE_CAST(Function)(function));
#else // defined(BOOST_ASIO_NO_DEPRECATED)
execution::execute(
boost::asio::prefer(executor_,
execution::allocator((get_associated_allocator)(handler))),
BOOST_ASIO_MOVE_CAST(Function)(function));
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
template <typename Function>
void complete(Function& function, Handler& handler)
private:
typedef typename decay<
typename prefer_result<Executor,
execution::outstanding_work_t::tracked_t
>::type
>::type executor_type;
executor_type executor_;
};
template <typename Executor, typename CandidateExecutor,
typename IoContext, typename PolymorphicExecutor>
class handler_work_base<Executor, CandidateExecutor,
IoContext, PolymorphicExecutor,
typename enable_if<
!execution::is_executor<Executor>::value
&& (!is_same<Executor, PolymorphicExecutor>::value
|| !is_same<CandidateExecutor, void>::value)
>::type>
{
public:
explicit handler_work_base(int, int, const Executor& ex) BOOST_ASIO_NOEXCEPT
: executor_(ex),
owns_work_(true)
{
executor_.on_work_started();
}
handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
const Executor& candidate) BOOST_ASIO_NOEXCEPT
: executor_(ex),
owns_work_(ex != candidate)
{
if (owns_work_)
executor_.on_work_started();
}
template <typename OtherExecutor>
handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
const OtherExecutor& /*candidate*/) BOOST_ASIO_NOEXCEPT
: executor_(ex),
owns_work_(true)
{
executor_.on_work_started();
}
handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
: executor_(other.executor_),
owns_work_(other.owns_work_)
{
if (owns_work_)
executor_.on_work_started();
}
#if defined(BOOST_ASIO_HAS_MOVE)
handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
: executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)),
owns_work_(other.owns_work_)
{
other.owns_work_ = false;
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
~handler_work_base()
{
if (owns_work_)
executor_.on_work_finished();
}
bool owns_work() const BOOST_ASIO_NOEXCEPT
{
return owns_work_;
}
template <typename Function, typename Handler>
void dispatch(Function& function, Handler& handler)
{
executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function),
boost::asio::get_associated_allocator(handler));
}
private:
// Disallow copying and assignment.
handler_work(const handler_work&);
handler_work& operator=(const handler_work&);
IoExecutor io_executor_;
HandlerExecutor executor_;
Executor executor_;
bool owns_work_;
};
// 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, system_executor>
template <typename Executor, typename IoContext, typename PolymorphicExecutor>
class handler_work_base<Executor, void, IoContext, PolymorphicExecutor,
typename enable_if<
is_same<
Executor,
typename IoContext::executor_type
>::value
>::type>
{
public:
explicit handler_work(Handler&) BOOST_ASIO_NOEXCEPT {}
static void start(Handler&) BOOST_ASIO_NOEXCEPT {}
~handler_work() {}
explicit handler_work_base(int, int, const Executor&)
{
}
bool owns_work() const BOOST_ASIO_NOEXCEPT
{
return false;
}
template <typename Function, typename Handler>
void dispatch(Function& function, Handler& handler)
{
// When using a native implementation, I/O completion handlers are
// already dispatched according to the execution context's executor's
// rules. We can call the function directly.
boost_asio_handler_invoke_helpers::invoke(function, handler);
}
};
template <typename Executor, typename IoContext>
class handler_work_base<Executor, void, IoContext, Executor>
{
public:
explicit handler_work_base(int, int, const Executor& ex) BOOST_ASIO_NOEXCEPT
#if !defined(BOOST_ASIO_NO_TYPEID)
: executor_(
ex.target_type() == typeid(typename IoContext::executor_type)
? Executor() : ex)
#else // !defined(BOOST_ASIO_NO_TYPEID)
: executor_(ex)
#endif // !defined(BOOST_ASIO_NO_TYPEID)
{
if (executor_)
executor_.on_work_started();
}
handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
const Executor& candidate) BOOST_ASIO_NOEXCEPT
: executor_(ex != candidate ? ex : Executor())
{
if (executor_)
executor_.on_work_started();
}
template <typename OtherExecutor>
handler_work_base(const Executor& ex,
const OtherExecutor&) BOOST_ASIO_NOEXCEPT
: executor_(ex)
{
executor_.on_work_started();
}
handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
: executor_(other.executor_)
{
if (executor_)
executor_.on_work_started();
}
#if defined(BOOST_ASIO_HAS_MOVE)
handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
: executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_))
{
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
~handler_work_base()
{
if (executor_)
executor_.on_work_finished();
}
bool owns_work() const BOOST_ASIO_NOEXCEPT
{
return !!executor_;
}
template <typename Function, typename Handler>
void dispatch(Function& function, Handler& handler)
{
executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function),
boost::asio::get_associated_allocator(handler));
}
private:
Executor executor_;
};
template <
#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
typename... SupportableProperties,
#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9,
#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
typename CandidateExecutor, typename IoContext,
typename PolymorphicExecutor>
class handler_work_base<
#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
execution::any_executor<SupportableProperties...>,
#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>,
#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
CandidateExecutor, IoContext, PolymorphicExecutor>
{
public:
typedef
#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
execution::any_executor<SupportableProperties...>
#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>
#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
executor_type;
explicit handler_work_base(int, int,
const executor_type& ex) BOOST_ASIO_NOEXCEPT
#if !defined(BOOST_ASIO_NO_TYPEID)
: executor_(
ex.target_type() == typeid(typename IoContext::executor_type)
? executor_type()
: boost::asio::prefer(ex, execution::outstanding_work.tracked))
#else // !defined(BOOST_ASIO_NO_TYPEID)
: executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
#endif // !defined(BOOST_ASIO_NO_TYPEID)
{
}
handler_work_base(bool base1_owns_work, const executor_type& ex,
const executor_type& candidate) BOOST_ASIO_NOEXCEPT
: executor_(
!base1_owns_work && ex == candidate
? executor_type()
: boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
template <typename OtherExecutor>
handler_work_base(bool /*base1_owns_work*/, const executor_type& ex,
const OtherExecutor& /*candidate*/) BOOST_ASIO_NOEXCEPT
: executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
: executor_(other.executor_)
{
}
#if defined(BOOST_ASIO_HAS_MOVE)
handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
: executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
{
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
bool owns_work() const BOOST_ASIO_NOEXCEPT
{
return !!executor_;
}
template <typename Function, typename Handler>
void dispatch(Function& function, Handler&)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
executor_.execute(BOOST_ASIO_MOVE_CAST(Function)(function));
#else // defined(BOOST_ASIO_NO_DEPRECATED)
execution::execute(executor_, BOOST_ASIO_MOVE_CAST(Function)(function));
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
private:
executor_type executor_;
};
#if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
template <typename Executor, typename CandidateExecutor,
typename IoContext, typename PolymorphicExecutor>
class handler_work_base<
Executor, CandidateExecutor,
IoContext, PolymorphicExecutor,
typename enable_if<
is_same<Executor, any_completion_executor>::value
|| is_same<Executor, any_io_executor>::value
>::type>
{
public:
typedef Executor executor_type;
explicit handler_work_base(int, int,
const executor_type& ex) BOOST_ASIO_NOEXCEPT
#if !defined(BOOST_ASIO_NO_TYPEID)
: executor_(
ex.target_type() == typeid(typename IoContext::executor_type)
? executor_type()
: boost::asio::prefer(ex, execution::outstanding_work.tracked))
#else // !defined(BOOST_ASIO_NO_TYPEID)
: executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
#endif // !defined(BOOST_ASIO_NO_TYPEID)
{
}
handler_work_base(bool base1_owns_work, const executor_type& ex,
const executor_type& candidate) BOOST_ASIO_NOEXCEPT
: executor_(
!base1_owns_work && ex == candidate
? executor_type()
: boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
template <typename OtherExecutor>
handler_work_base(bool /*base1_owns_work*/, const executor_type& ex,
const OtherExecutor& /*candidate*/) BOOST_ASIO_NOEXCEPT
: executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
: executor_(other.executor_)
{
}
#if defined(BOOST_ASIO_HAS_MOVE)
handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
: executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
{
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
bool owns_work() const BOOST_ASIO_NOEXCEPT
{
return !!executor_;
}
template <typename Function, typename Handler>
void dispatch(Function& function, Handler&)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
executor_.execute(BOOST_ASIO_MOVE_CAST(Function)(function));
#else // defined(BOOST_ASIO_NO_DEPRECATED)
execution::execute(executor_, BOOST_ASIO_MOVE_CAST(Function)(function));
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
private:
executor_type executor_;
};
#endif // !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
template <typename Handler, typename IoExecutor, typename = void>
class handler_work :
handler_work_base<IoExecutor>,
handler_work_base<typename associated_executor<
Handler, IoExecutor>::type, IoExecutor>
{
public:
typedef handler_work_base<IoExecutor> base1_type;
typedef handler_work_base<typename associated_executor<
Handler, IoExecutor>::type, IoExecutor> base2_type;
handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
: base1_type(0, 0, io_ex),
base2_type(base1_type::owns_work(),
boost::asio::get_associated_executor(handler, io_ex), io_ex)
{
}
template <typename Function>
void complete(Function& function, Handler& handler)
{
boost_asio_handler_invoke_helpers::invoke(function, handler);
if (!base1_type::owns_work() && !base2_type::owns_work())
{
// When using a native implementation, I/O completion handlers are
// already dispatched according to the execution context's executor's
// rules. We can call the function directly.
boost_asio_handler_invoke_helpers::invoke(function, handler);
}
else
{
base2_type::dispatch(function, handler);
}
}
};
template <typename Handler, typename IoExecutor>
class handler_work<
Handler, IoExecutor,
typename enable_if<
is_same<
typename associated_executor<Handler,
IoExecutor>::asio_associated_executor_is_unspecialised,
void
>::value
>::type> : handler_work_base<IoExecutor>
{
public:
typedef handler_work_base<IoExecutor> base1_type;
handler_work(Handler&, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
: base1_type(0, 0, io_ex)
{
}
template <typename Function>
void complete(Function& function, Handler& handler)
{
if (!base1_type::owns_work())
{
// When using a native implementation, I/O completion handlers are
// already dispatched according to the execution context's executor's
// rules. We can call the function directly.
boost_asio_handler_invoke_helpers::invoke(function, handler);
}
else
{
base1_type::dispatch(function, handler);
}
}
};
template <typename Handler, typename IoExecutor>
class immediate_handler_work
{
public:
typedef handler_work<Handler, IoExecutor> handler_work_type;
explicit immediate_handler_work(BOOST_ASIO_MOVE_ARG(handler_work_type) w)
: handler_work_(BOOST_ASIO_MOVE_CAST(handler_work_type)(w))
{
}
template <typename Function>
void complete(Function& function, Handler& handler, const void* io_ex)
{
typedef typename associated_immediate_executor<Handler, IoExecutor>::type
immediate_ex_type;
immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
handler, *static_cast<const IoExecutor*>(io_ex));
(initiate_dispatch_with_executor<immediate_ex_type>(immediate_ex))(
BOOST_ASIO_MOVE_CAST(Function)(function));
}
private:
// Disallow copying and assignment.
handler_work(const handler_work&);
handler_work& operator=(const handler_work&);
handler_work_type handler_work_;
};
} // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/hash_map.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/impl/buffer_sequence_adapter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/impl/descriptor_ops.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -33,10 +33,16 @@ namespace descriptor_ops {
int open(const char* path, int flags, boost::system::error_code& ec)
{
errno = 0;
int result = error_wrapper(::open(path, flags), ec);
if (result >= 0)
ec = boost::system::error_code();
int result = ::open(path, flags);
get_last_error(ec, result < 0);
return result;
}
int open(const char* path, int flags,
unsigned mode, boost::system::error_code& ec)
{
int result = ::open(path, flags, mode);
get_last_error(ec, result < 0);
return result;
}
@@ -45,8 +51,8 @@ int close(int d, state_type& state, boost::system::error_code& ec)
int result = 0;
if (d != -1)
{
errno = 0;
result = error_wrapper(::close(d), ec);
result = ::close(d);
get_last_error(ec, result < 0);
if (result != 0
&& (ec == boost::asio::error::would_block
@@ -58,23 +64,32 @@ int close(int d, state_type& state, boost::system::error_code& ec)
// current OS where this behaviour is seen, Windows, says that the socket
// remains open. Therefore we'll put the descriptor back into blocking
// mode and have another attempt at closing it.
#if defined(__SYMBIAN32__)
#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
int flags = ::fcntl(d, F_GETFL, 0);
if (flags >= 0)
::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);
#else // defined(__SYMBIAN32__)
#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
ioctl_arg_type arg = 0;
# if defined(ENOTTY)
result = ::ioctl(d, FIONBIO, &arg);
get_last_error(ec, result < 0);
if (ec.value() == ENOTTY)
{
int flags = ::fcntl(d, F_GETFL, 0);
if (flags >= 0)
::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);
}
# else // defined(ENOTTY)
::ioctl(d, FIONBIO, &arg);
#endif // defined(__SYMBIAN32__)
# endif // defined(ENOTTY)
#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
state &= ~non_blocking;
errno = 0;
result = error_wrapper(::close(d), ec);
result = ::close(d);
get_last_error(ec, result < 0);
}
}
if (result == 0)
ec = boost::system::error_code();
return result;
}
@@ -87,23 +102,36 @@ bool set_user_non_blocking(int d, state_type& state,
return false;
}
errno = 0;
#if defined(__SYMBIAN32__)
int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
int result = ::fcntl(d, F_GETFL, 0);
get_last_error(ec, result < 0);
if (result >= 0)
{
errno = 0;
int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
result = error_wrapper(::fcntl(d, F_SETFL, flag), ec);
result = ::fcntl(d, F_SETFL, flag);
get_last_error(ec, result < 0);
}
#else // defined(__SYMBIAN32__)
#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
ioctl_arg_type arg = (value ? 1 : 0);
int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
#endif // defined(__SYMBIAN32__)
int result = ::ioctl(d, FIONBIO, &arg);
get_last_error(ec, result < 0);
# if defined(ENOTTY)
if (ec.value() == ENOTTY)
{
result = ::fcntl(d, F_GETFL, 0);
get_last_error(ec, result < 0);
if (result >= 0)
{
int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
result = ::fcntl(d, F_SETFL, flag);
get_last_error(ec, result < 0);
}
}
# endif // defined(ENOTTY)
#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
if (result >= 0)
{
ec = boost::system::error_code();
if (value)
state |= user_set_non_blocking;
else
@@ -137,23 +165,36 @@ bool set_internal_non_blocking(int d, state_type& state,
return false;
}
errno = 0;
#if defined(__SYMBIAN32__)
int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
int result = ::fcntl(d, F_GETFL, 0);
get_last_error(ec, result < 0);
if (result >= 0)
{
errno = 0;
int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
result = error_wrapper(::fcntl(d, F_SETFL, flag), ec);
result = ::fcntl(d, F_SETFL, flag);
get_last_error(ec, result < 0);
}
#else // defined(__SYMBIAN32__)
#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
ioctl_arg_type arg = (value ? 1 : 0);
int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
#endif // defined(__SYMBIAN32__)
int result = ::ioctl(d, FIONBIO, &arg);
get_last_error(ec, result < 0);
# if defined(ENOTTY)
if (ec.value() == ENOTTY)
{
result = ::fcntl(d, F_GETFL, 0);
get_last_error(ec, result < 0);
if (result >= 0)
{
int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
result = ::fcntl(d, F_SETFL, flag);
get_last_error(ec, result < 0);
}
}
# endif // defined(ENOTTY)
#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
if (result >= 0)
{
ec = boost::system::error_code();
if (value)
state |= internal_non_blocking;
else
@@ -176,7 +217,7 @@ std::size_t sync_read(int d, state_type state, buf* bufs,
// A request to read 0 bytes on a stream is a no-op.
if (all_empty)
{
ec = boost::system::error_code();
boost::asio::error::clear(ec);
return 0;
}
@@ -184,9 +225,54 @@ std::size_t sync_read(int d, state_type state, buf* bufs,
for (;;)
{
// Try to complete the operation without blocking.
errno = 0;
signed_size_type bytes = error_wrapper(::readv(
d, bufs, static_cast<int>(count)), ec);
signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count));
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes > 0)
return bytes;
// Check for EOF.
if (bytes == 0)
{
ec = boost::asio::error::eof;
return 0;
}
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != boost::asio::error::would_block
&& ec != boost::asio::error::try_again))
return 0;
// Wait for descriptor to become ready.
if (descriptor_ops::poll_read(d, 0, ec) < 0)
return 0;
}
}
std::size_t sync_read1(int d, state_type state, void* data,
std::size_t size, boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to read 0 bytes on a stream is a no-op.
if (size == 0)
{
boost::asio::error::clear(ec);
return 0;
}
// Read some data.
for (;;)
{
// Try to complete the operation without blocking.
signed_size_type bytes = ::read(d, data, size);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes > 0)
@@ -217,9 +303,8 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count,
for (;;)
{
// Read some data.
errno = 0;
signed_size_type bytes = error_wrapper(::readv(
d, bufs, static_cast<int>(count)), ec);
signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count));
get_last_error(ec, bytes < 0);
// Check for end of stream.
if (bytes == 0)
@@ -228,6 +313,13 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count,
return true;
}
// Check if operation succeeded.
if (bytes > 0)
{
bytes_transferred = bytes;
return true;
}
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
continue;
@@ -237,15 +329,46 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count,
|| ec == boost::asio::error::try_again)
return false;
// Operation is complete.
// Operation failed.
bytes_transferred = 0;
return true;
}
}
bool non_blocking_read1(int d, void* data, std::size_t size,
boost::system::error_code& ec, std::size_t& bytes_transferred)
{
for (;;)
{
// Read some data.
signed_size_type bytes = ::read(d, data, size);
get_last_error(ec, bytes < 0);
// Check for end of stream.
if (bytes == 0)
{
ec = boost::asio::error::eof;
return true;
}
// Check if operation succeeded.
if (bytes > 0)
{
ec = boost::system::error_code();
bytes_transferred = bytes;
return true;
}
else
bytes_transferred = 0;
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return false;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
@@ -262,7 +385,7 @@ std::size_t sync_write(int d, state_type state, const buf* bufs,
// A request to write 0 bytes on a stream is a no-op.
if (all_empty)
{
ec = boost::system::error_code();
boost::asio::error::clear(ec);
return 0;
}
@@ -270,9 +393,47 @@ std::size_t sync_write(int d, state_type state, const buf* bufs,
for (;;)
{
// Try to complete the operation without blocking.
errno = 0;
signed_size_type bytes = error_wrapper(::writev(
d, bufs, static_cast<int>(count)), ec);
signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count));
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes > 0)
return bytes;
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != boost::asio::error::would_block
&& ec != boost::asio::error::try_again))
return 0;
// Wait for descriptor to become ready.
if (descriptor_ops::poll_write(d, 0, ec) < 0)
return 0;
}
}
std::size_t sync_write1(int d, state_type state, const void* data,
std::size_t size, boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to write 0 bytes on a stream is a no-op.
if (size == 0)
{
boost::asio::error::clear(ec);
return 0;
}
// Write some data.
for (;;)
{
// Try to complete the operation without blocking.
signed_size_type bytes = ::write(d, data, size);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes > 0)
@@ -296,9 +457,15 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count,
for (;;)
{
// Write some data.
errno = 0;
signed_size_type bytes = error_wrapper(::writev(
d, bufs, static_cast<int>(count)), ec);
signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count));
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes >= 0)
{
bytes_transferred = bytes;
return true;
}
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
@@ -309,19 +476,360 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count,
|| ec == boost::asio::error::try_again)
return false;
// Operation is complete.
if (bytes >= 0)
{
ec = boost::system::error_code();
bytes_transferred = bytes;
}
else
bytes_transferred = 0;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
bool non_blocking_write1(int d, const void* data, std::size_t size,
boost::system::error_code& ec, std::size_t& bytes_transferred)
{
for (;;)
{
// Write some data.
signed_size_type bytes = ::write(d, data, size);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes >= 0)
{
bytes_transferred = bytes;
return true;
}
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return false;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
#if defined(BOOST_ASIO_HAS_FILE)
std::size_t sync_read_at(int d, state_type state, uint64_t offset,
buf* bufs, std::size_t count, bool all_empty, boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to read 0 bytes on a stream is a no-op.
if (all_empty)
{
boost::asio::error::clear(ec);
return 0;
}
// Read some data.
for (;;)
{
// Try to complete the operation without blocking.
signed_size_type bytes = ::preadv(d, bufs, static_cast<int>(count), offset);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes > 0)
return bytes;
// Check for EOF.
if (bytes == 0)
{
ec = boost::asio::error::eof;
return 0;
}
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != boost::asio::error::would_block
&& ec != boost::asio::error::try_again))
return 0;
// Wait for descriptor to become ready.
if (descriptor_ops::poll_read(d, 0, ec) < 0)
return 0;
}
}
std::size_t sync_read_at1(int d, state_type state, uint64_t offset,
void* data, std::size_t size, boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to read 0 bytes on a stream is a no-op.
if (size == 0)
{
boost::asio::error::clear(ec);
return 0;
}
// Read some data.
for (;;)
{
// Try to complete the operation without blocking.
signed_size_type bytes = ::pread(d, data, size, offset);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes > 0)
return bytes;
// Check for EOF.
if (bytes == 0)
{
ec = boost::asio::error::eof;
return 0;
}
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != boost::asio::error::would_block
&& ec != boost::asio::error::try_again))
return 0;
// Wait for descriptor to become ready.
if (descriptor_ops::poll_read(d, 0, ec) < 0)
return 0;
}
}
bool non_blocking_read_at(int d, uint64_t offset, buf* bufs, std::size_t count,
boost::system::error_code& ec, std::size_t& bytes_transferred)
{
for (;;)
{
// Read some data.
signed_size_type bytes = ::preadv(d, bufs, static_cast<int>(count), offset);
get_last_error(ec, bytes < 0);
// Check for EOF.
if (bytes == 0)
{
ec = boost::asio::error::eof;
return true;
}
// Check if operation succeeded.
if (bytes > 0)
{
bytes_transferred = bytes;
return true;
}
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return false;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
bool non_blocking_read_at1(int d, uint64_t offset, void* data, std::size_t size,
boost::system::error_code& ec, std::size_t& bytes_transferred)
{
for (;;)
{
// Read some data.
signed_size_type bytes = ::pread(d, data, size, offset);
get_last_error(ec, bytes < 0);
// Check for EOF.
if (bytes == 0)
{
ec = boost::asio::error::eof;
return true;
}
// Check if operation succeeded.
if (bytes > 0)
{
bytes_transferred = bytes;
return true;
}
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return false;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
std::size_t sync_write_at(int d, state_type state, uint64_t offset,
const buf* bufs, std::size_t count, bool all_empty,
boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to write 0 bytes on a stream is a no-op.
if (all_empty)
{
boost::asio::error::clear(ec);
return 0;
}
// Write some data.
for (;;)
{
// Try to complete the operation without blocking.
signed_size_type bytes = ::pwritev(d,
bufs, static_cast<int>(count), offset);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes > 0)
return bytes;
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != boost::asio::error::would_block
&& ec != boost::asio::error::try_again))
return 0;
// Wait for descriptor to become ready.
if (descriptor_ops::poll_write(d, 0, ec) < 0)
return 0;
}
}
std::size_t sync_write_at1(int d, state_type state, uint64_t offset,
const void* data, std::size_t size, boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to write 0 bytes on a stream is a no-op.
if (size == 0)
{
boost::asio::error::clear(ec);
return 0;
}
// Write some data.
for (;;)
{
// Try to complete the operation without blocking.
signed_size_type bytes = ::pwrite(d, data, size, offset);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes > 0)
return bytes;
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != boost::asio::error::would_block
&& ec != boost::asio::error::try_again))
return 0;
// Wait for descriptor to become ready.
if (descriptor_ops::poll_write(d, 0, ec) < 0)
return 0;
}
}
bool non_blocking_write_at(int d, uint64_t offset,
const buf* bufs, std::size_t count,
boost::system::error_code& ec, std::size_t& bytes_transferred)
{
for (;;)
{
// Write some data.
signed_size_type bytes = ::pwritev(d,
bufs, static_cast<int>(count), offset);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes >= 0)
{
bytes_transferred = bytes;
return true;
}
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return false;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
bool non_blocking_write_at1(int d, uint64_t offset,
const void* data, std::size_t size,
boost::system::error_code& ec, std::size_t& bytes_transferred)
{
for (;;)
{
// Write some data.
signed_size_type bytes = ::pwrite(d, data, size, offset);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes >= 0)
{
bytes_transferred = bytes;
return true;
}
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return false;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
#endif // defined(BOOST_ASIO_HAS_FILE)
int ioctl(int d, state_type& state, long cmd,
ioctl_arg_type* arg, boost::system::error_code& ec)
{
@@ -331,13 +839,11 @@ int ioctl(int d, state_type& state, long cmd,
return -1;
}
errno = 0;
int result = error_wrapper(::ioctl(d, cmd, arg), ec);
int result = ::ioctl(d, cmd, arg);
get_last_error(ec, result < 0);
if (result >= 0)
{
ec = boost::system::error_code();
// When updating the non-blocking mode we always perform the ioctl syscall,
// even if the flags would otherwise indicate that the descriptor is
// already in the correct state. This ensures that the underlying
@@ -371,10 +877,8 @@ int fcntl(int d, int cmd, boost::system::error_code& ec)
return -1;
}
errno = 0;
int result = error_wrapper(::fcntl(d, cmd), ec);
if (result != -1)
ec = boost::system::error_code();
int result = ::fcntl(d, cmd);
get_last_error(ec, result < 0);
return result;
}
@@ -386,10 +890,8 @@ int fcntl(int d, int cmd, long arg, boost::system::error_code& ec)
return -1;
}
errno = 0;
int result = error_wrapper(::fcntl(d, cmd, arg), ec);
if (result != -1)
ec = boost::system::error_code();
int result = ::fcntl(d, cmd, arg);
get_last_error(ec, result < 0);
return result;
}
@@ -406,13 +908,11 @@ int poll_read(int d, state_type state, boost::system::error_code& ec)
fds.events = POLLIN;
fds.revents = 0;
int timeout = (state & user_set_non_blocking) ? 0 : -1;
errno = 0;
int result = error_wrapper(::poll(&fds, 1, timeout), ec);
int result = ::poll(&fds, 1, timeout);
get_last_error(ec, result < 0);
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();
if (state & user_set_non_blocking)
ec = boost::asio::error::would_block;
return result;
}
@@ -429,13 +929,11 @@ int poll_write(int d, state_type state, boost::system::error_code& ec)
fds.events = POLLOUT;
fds.revents = 0;
int timeout = (state & user_set_non_blocking) ? 0 : -1;
errno = 0;
int result = error_wrapper(::poll(&fds, 1, timeout), ec);
int result = ::poll(&fds, 1, timeout);
get_last_error(ec, result < 0);
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();
if (state & user_set_non_blocking)
ec = boost::asio::error::would_block;
return result;
}
@@ -452,13 +950,11 @@ int poll_error(int d, state_type state, boost::system::error_code& ec)
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);
int result = ::poll(&fds, 1, timeout);
get_last_error(ec, result < 0);
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();
if (state & user_set_non_blocking)
ec = boost::asio::error::would_block;
return result;
}

View File

@@ -2,7 +2,7 @@
// detail/impl/dev_poll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -19,12 +19,20 @@
#if defined(BOOST_ASIO_HAS_DEV_POLL)
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
inline void dev_poll_reactor::post_immediate_completion(
operation* op, bool is_continuation) const
{
scheduler_.post_immediate_completion(op, is_continuation);
}
template <typename Time_Traits>
void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
@@ -69,6 +77,18 @@ std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
return n;
}
template <typename Time_Traits>
void dev_poll_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
template <typename Time_Traits>
void dev_poll_reactor::move_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& target,

View File

@@ -2,7 +2,7 @@
// detail/impl/dev_poll_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -21,6 +21,7 @@
#include <boost/asio/detail/dev_poll_reactor.hpp>
#include <boost/asio/detail/assert.hpp>
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
@@ -148,15 +149,24 @@ void dev_poll_reactor::move_descriptor(socket_type,
{
}
void dev_poll_reactor::call_post_immediate_completion(
operation* op, bool is_continuation, const void* self)
{
static_cast<const dev_poll_reactor*>(self)->post_immediate_completion(
op, is_continuation);
}
void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
dev_poll_reactor::per_descriptor_data&, reactor_op* op,
bool is_continuation, bool allow_speculative)
bool is_continuation, bool allow_speculative,
void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -169,7 +179,7 @@ void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
if (op->perform())
{
lock.unlock();
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
}
@@ -202,6 +212,19 @@ void dev_poll_reactor::cancel_ops(socket_type descriptor,
cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted);
}
void dev_poll_reactor::cancel_ops_by_key(socket_type descriptor,
dev_poll_reactor::per_descriptor_data&,
int op_type, void* cancellation_key)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
bool need_interrupt = op_queue_[op_type].cancel_operations_by_key(
descriptor, ops, cancellation_key, boost::asio::error::operation_aborted);
scheduler_.post_deferred_completions(ops);
if (need_interrupt)
interrupter_.interrupt();
}
void dev_poll_reactor::deregister_descriptor(socket_type descriptor,
dev_poll_reactor::per_descriptor_data&, bool)
{

View File

@@ -2,7 +2,7 @@
// detail/impl/epoll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,12 +17,20 @@
#if defined(BOOST_ASIO_HAS_EPOLL)
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
inline void epoll_reactor::post_immediate_completion(
operation* op, bool is_continuation) const
{
scheduler_.post_immediate_completion(op, is_continuation);
}
template <typename Time_Traits>
void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
@@ -67,6 +75,18 @@ std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
return n;
}
template <typename Time_Traits>
void epoll_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
template <typename Time_Traits>
void epoll_reactor::move_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& target,

View File

@@ -2,7 +2,7 @@
// detail/impl/epoll_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -22,6 +22,7 @@
#include <cstddef>
#include <sys/epoll.h>
#include <boost/asio/detail/epoll_reactor.hpp>
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
@@ -229,14 +230,23 @@ void epoll_reactor::move_descriptor(socket_type,
source_descriptor_data = 0;
}
void epoll_reactor::call_post_immediate_completion(
operation* op, bool is_continuation, const void* self)
{
static_cast<const epoll_reactor*>(self)->post_immediate_completion(
op, is_continuation);
}
void epoll_reactor::start_op(int op_type, socket_type descriptor,
epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op,
bool is_continuation, bool allow_speculative)
bool is_continuation, bool allow_speculative,
void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg)
{
if (!descriptor_data)
{
op->ec_ = boost::asio::error::bad_descriptor;
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -244,7 +254,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
if (descriptor_data->shutdown_)
{
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -262,7 +272,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
if (descriptor_data->registered_events_ != 0)
descriptor_data->try_speculative_[op_type] = false;
descriptor_lock.unlock();
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
}
@@ -270,7 +280,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
if (descriptor_data->registered_events_ == 0)
{
op->ec_ = boost::asio::error::operation_not_supported;
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -289,7 +299,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());
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
}
@@ -298,7 +308,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;
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
else
@@ -343,6 +353,35 @@ void epoll_reactor::cancel_ops(socket_type,
scheduler_.post_deferred_completions(ops);
}
void epoll_reactor::cancel_ops_by_key(socket_type,
epoll_reactor::per_descriptor_data& descriptor_data,
int op_type, void* cancellation_key)
{
if (!descriptor_data)
return;
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
op_queue<operation> ops;
op_queue<reactor_op> other_ops;
while (reactor_op* op = descriptor_data->op_queue_[op_type].front())
{
descriptor_data->op_queue_[op_type].pop();
if (op->cancellation_key_ == cancellation_key)
{
op->ec_ = boost::asio::error::operation_aborted;
ops.push(op);
}
else
other_ops.push(op);
}
descriptor_data->op_queue_[op_type].push(other_ops);
descriptor_lock.unlock();
scheduler_.post_deferred_completions(ops);
}
void epoll_reactor::deregister_descriptor(socket_type descriptor,
epoll_reactor::per_descriptor_data& descriptor_data, bool closing)
{

View File

@@ -2,7 +2,7 @@
// detail/impl/eventfd_select_interrupter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -23,11 +23,11 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
# include <asm/unistd.h>
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
# include <sys/eventfd.h>
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
#include <boost/asio/detail/cstdint.hpp>
#include <boost/asio/detail/eventfd_select_interrupter.hpp>
#include <boost/asio/detail/throw_error.hpp>
@@ -46,14 +46,14 @@ eventfd_select_interrupter::eventfd_select_interrupter()
void eventfd_select_interrupter::open_descriptors()
{
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
if (read_descriptor_ != -1)
{
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
}
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
write_descriptor_ = read_descriptor_ =
::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
@@ -70,7 +70,7 @@ void eventfd_select_interrupter::open_descriptors()
::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
}
}
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
if (read_descriptor_ == -1)
{
@@ -135,8 +135,7 @@ bool eventfd_select_interrupter::reset()
int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
if (bytes_read < 0 && errno == EINTR)
continue;
bool was_interrupted = (bytes_read > 0);
return was_interrupted;
return true;
}
}
else
@@ -146,12 +145,19 @@ bool eventfd_select_interrupter::reset()
// Clear all data from the pipe.
char data[1024];
int bytes_read = ::read(read_descriptor_, data, sizeof(data));
if (bytes_read < 0 && errno == EINTR)
if (bytes_read == sizeof(data))
continue;
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = ::read(read_descriptor_, data, sizeof(data));
return was_interrupted;
if (bytes_read > 0)
return true;
if (bytes_read == 0)
return false;
if (errno == EINTR)
continue;
if (errno == EWOULDBLOCK)
return true;
if (errno == EAGAIN)
return true;
return false;
}
}
}

View File

@@ -2,7 +2,7 @@
// detail/impl/handler_tracking.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -74,11 +74,12 @@ struct handler_tracking::tracking_state
static_mutex mutex_;
uint64_t next_id_;
tss_ptr<completion>* current_completion_;
tss_ptr<location>* current_location_;
};
handler_tracking::tracking_state* handler_tracking::get_state()
{
static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0 };
static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0, 0 };
return &state;
}
@@ -91,6 +92,25 @@ void handler_tracking::init()
static_mutex::scoped_lock lock(state->mutex_);
if (state->current_completion_ == 0)
state->current_completion_ = new tss_ptr<completion>;
if (state->current_location_ == 0)
state->current_location_ = new tss_ptr<location>;
}
handler_tracking::location::location(
const char* file, int line, const char* func)
: file_(file),
line_(line),
func_(func),
next_(*get_state()->current_location_)
{
if (file_)
*get_state()->current_location_ = this;
}
handler_tracking::location::~location()
{
if (file_)
*get_state()->current_location_ = next_;
}
void handler_tracking::creation(execution_context&,
@@ -110,6 +130,24 @@ void handler_tracking::creation(execution_context&,
if (completion* current_completion = *state->current_completion_)
current_id = current_completion->id_;
for (location* current_location = *state->current_location_;
current_location; current_location = current_location->next_)
{
write_line(
#if defined(BOOST_ASIO_WINDOWS)
"@asio|%I64u.%06I64u|%I64u^%I64u|%s%s%.80s%s(%.80s:%d)\n",
#else // defined(BOOST_ASIO_WINDOWS)
"@asio|%llu.%06llu|%llu^%llu|%s%s%.80s%s(%.80s:%d)\n",
#endif // defined(BOOST_ASIO_WINDOWS)
timestamp.seconds, timestamp.microseconds,
current_id, h.id_,
current_location == *state->current_location_ ? "in " : "called from ",
current_location->func_ ? "'" : "",
current_location->func_ ? current_location->func_ : "",
current_location->func_ ? "' " : "",
current_location->file_, current_location->line_);
}
write_line(
#if defined(BOOST_ASIO_WINDOWS)
"@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n",
@@ -328,7 +366,9 @@ void handler_tracking::write_line(const char* format, ...)
va_start(args, format);
char line[256] = "";
#if defined(BOOST_ASIO_HAS_SECURE_RTL)
#if defined(BOOST_ASIO_HAS_SNPRINTF)
int length = vsnprintf(line, sizeof(line), format, args);
#elif defined(BOOST_ASIO_HAS_SECURE_RTL)
int length = vsprintf_s(line, sizeof(line), format, args);
#else // defined(BOOST_ASIO_HAS_SECURE_RTL)
int length = vsprintf(line, format, args);

View File

@@ -0,0 +1,207 @@
//
// detail/impl/io_uring_descriptor_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_IO_URING_DESCRIPTOR_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_IO_URING_DESCRIPTOR_SERVICE_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_HAS_IO_URING)
#include <boost/asio/error.hpp>
#include <boost/asio/detail/io_uring_descriptor_service.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
io_uring_descriptor_service::io_uring_descriptor_service(
execution_context& context)
: execution_context_service_base<io_uring_descriptor_service>(context),
io_uring_service_(boost::asio::use_service<io_uring_service>(context))
{
io_uring_service_.init_task();
}
void io_uring_descriptor_service::shutdown()
{
}
void io_uring_descriptor_service::construct(
io_uring_descriptor_service::implementation_type& impl)
{
impl.descriptor_ = -1;
impl.state_ = 0;
impl.io_object_data_ = 0;
}
void io_uring_descriptor_service::move_construct(
io_uring_descriptor_service::implementation_type& impl,
io_uring_descriptor_service::implementation_type& other_impl)
BOOST_ASIO_NOEXCEPT
{
impl.descriptor_ = other_impl.descriptor_;
other_impl.descriptor_ = -1;
impl.state_ = other_impl.state_;
other_impl.state_ = 0;
impl.io_object_data_ = other_impl.io_object_data_;
other_impl.io_object_data_ = 0;
}
void io_uring_descriptor_service::move_assign(
io_uring_descriptor_service::implementation_type& impl,
io_uring_descriptor_service& /*other_service*/,
io_uring_descriptor_service::implementation_type& other_impl)
{
destroy(impl);
impl.descriptor_ = other_impl.descriptor_;
other_impl.descriptor_ = -1;
impl.state_ = other_impl.state_;
other_impl.state_ = 0;
impl.io_object_data_ = other_impl.io_object_data_;
other_impl.io_object_data_ = 0;
}
void io_uring_descriptor_service::destroy(
io_uring_descriptor_service::implementation_type& impl)
{
if (is_open(impl))
{
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"descriptor", &impl, impl.descriptor_, "close"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
boost::system::error_code ignored_ec;
descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
}
}
boost::system::error_code io_uring_descriptor_service::assign(
io_uring_descriptor_service::implementation_type& impl,
const native_handle_type& native_descriptor, boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
io_uring_service_.register_io_object(impl.io_object_data_);
impl.descriptor_ = native_descriptor;
impl.state_ = descriptor_ops::possible_dup;
ec = success_ec_;
return ec;
}
boost::system::error_code io_uring_descriptor_service::close(
io_uring_descriptor_service::implementation_type& impl,
boost::system::error_code& ec)
{
if (is_open(impl))
{
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"descriptor", &impl, impl.descriptor_, "close"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
descriptor_ops::close(impl.descriptor_, impl.state_, ec);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
}
else
{
ec = success_ec_;
}
// The descriptor is closed by the OS even if close() returns an error.
//
// (Actually, POSIX says the state of the descriptor is unspecified. On
// Linux the descriptor is apparently closed anyway; e.g. see
// http://lkml.org/lkml/2005/9/10/129
construct(impl);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
io_uring_descriptor_service::native_handle_type
io_uring_descriptor_service::release(
io_uring_descriptor_service::implementation_type& impl)
{
native_handle_type descriptor = impl.descriptor_;
if (is_open(impl))
{
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"descriptor", &impl, impl.descriptor_, "release"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
construct(impl);
}
return descriptor;
}
boost::system::error_code io_uring_descriptor_service::cancel(
io_uring_descriptor_service::implementation_type& impl,
boost::system::error_code& ec)
{
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"descriptor", &impl, impl.descriptor_, "cancel"));
io_uring_service_.cancel_ops(impl.io_object_data_);
ec = success_ec_;
return ec;
}
void io_uring_descriptor_service::start_op(
io_uring_descriptor_service::implementation_type& impl,
int op_type, io_uring_operation* op, bool is_continuation, bool noop)
{
if (!noop)
{
io_uring_service_.start_op(op_type,
impl.io_object_data_, op, is_continuation);
}
else
{
io_uring_service_.post_immediate_completion(op, is_continuation);
}
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING)
#endif // BOOST_ASIO_DETAIL_IMPL_IO_URING_DESCRIPTOR_SERVICE_IPP

View File

@@ -0,0 +1,142 @@
//
// detail/impl/io_uring_file_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_IO_URING_FILE_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_IO_URING_FILE_SERVICE_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_HAS_FILE) \
&& defined(BOOST_ASIO_HAS_IO_URING)
#include <cstring>
#include <sys/stat.h>
#include <boost/asio/detail/io_uring_file_service.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
io_uring_file_service::io_uring_file_service(
execution_context& context)
: execution_context_service_base<io_uring_file_service>(context),
descriptor_service_(context)
{
}
void io_uring_file_service::shutdown()
{
descriptor_service_.shutdown();
}
boost::system::error_code io_uring_file_service::open(
io_uring_file_service::implementation_type& impl,
const char* path, file_base::flags open_flags,
boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
descriptor_ops::state_type state = 0;
int fd = descriptor_ops::open(path, static_cast<int>(open_flags), 0777, ec);
if (fd < 0)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
// We're done. Take ownership of the serial port descriptor.
if (descriptor_service_.assign(impl, fd, ec))
{
boost::system::error_code ignored_ec;
descriptor_ops::close(fd, state, ignored_ec);
}
(void)::posix_fadvise(native_handle(impl), 0, 0,
impl.is_stream_ ? POSIX_FADV_SEQUENTIAL : POSIX_FADV_RANDOM);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
uint64_t io_uring_file_service::size(
const io_uring_file_service::implementation_type& impl,
boost::system::error_code& ec) const
{
struct stat s;
int result = ::fstat(native_handle(impl), &s);
descriptor_ops::get_last_error(ec, result != 0);
BOOST_ASIO_ERROR_LOCATION(ec);
return !ec ? s.st_size : 0;
}
boost::system::error_code io_uring_file_service::resize(
io_uring_file_service::implementation_type& impl,
uint64_t n, boost::system::error_code& ec)
{
int result = ::ftruncate(native_handle(impl), n);
descriptor_ops::get_last_error(ec, result != 0);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
boost::system::error_code io_uring_file_service::sync_all(
io_uring_file_service::implementation_type& impl,
boost::system::error_code& ec)
{
int result = ::fsync(native_handle(impl));
descriptor_ops::get_last_error(ec, result != 0);
return ec;
}
boost::system::error_code io_uring_file_service::sync_data(
io_uring_file_service::implementation_type& impl,
boost::system::error_code& ec)
{
#if defined(_POSIX_SYNCHRONIZED_IO)
int result = ::fdatasync(native_handle(impl));
#else // defined(_POSIX_SYNCHRONIZED_IO)
int result = ::fsync(native_handle(impl));
#endif // defined(_POSIX_SYNCHRONIZED_IO)
descriptor_ops::get_last_error(ec, result != 0);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
uint64_t io_uring_file_service::seek(
io_uring_file_service::implementation_type& impl, int64_t offset,
file_base::seek_basis whence, boost::system::error_code& ec)
{
int64_t result = ::lseek(native_handle(impl), offset, whence);
descriptor_ops::get_last_error(ec, result < 0);
BOOST_ASIO_ERROR_LOCATION(ec);
return !ec ? static_cast<uint64_t>(result) : 0;
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_FILE)
// && defined(BOOST_ASIO_HAS_IO_URING)
#endif // BOOST_ASIO_DETAIL_IMPL_IO_URING_FILE_SERVICE_IPP

View File

@@ -0,0 +1,114 @@
//
// detail/impl/io_uring_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_IO_URING_SERVICE_HPP
#define BOOST_ASIO_DETAIL_IMPL_IO_URING_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#if defined(BOOST_ASIO_HAS_IO_URING)
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
inline void io_uring_service::post_immediate_completion(
operation* op, bool is_continuation)
{
scheduler_.post_immediate_completion(op, is_continuation);
}
template <typename Time_Traits>
void io_uring_service::add_timer_queue(timer_queue<Time_Traits>& queue)
{
do_add_timer_queue(queue);
}
template <typename Time_Traits>
void io_uring_service::remove_timer_queue(timer_queue<Time_Traits>& queue)
{
do_remove_timer_queue(queue);
}
template <typename Time_Traits>
void io_uring_service::schedule_timer(timer_queue<Time_Traits>& queue,
const typename Time_Traits::time_type& time,
typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
{
mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
scheduler_.post_immediate_completion(op, false);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
scheduler_.work_started();
if (earliest)
{
update_timeout();
post_submit_sqes_op(lock);
}
}
template <typename Time_Traits>
std::size_t io_uring_service::cancel_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& timer,
std::size_t max_cancelled)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
lock.unlock();
scheduler_.post_deferred_completions(ops);
return n;
}
template <typename Time_Traits>
void io_uring_service::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
template <typename Time_Traits>
void io_uring_service::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
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING)
#endif // BOOST_ASIO_DETAIL_IMPL_IO_URING_SERVICE_HPP

View File

@@ -0,0 +1,916 @@
//
// detail/impl/io_uring_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_IO_URING_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_IO_URING_SERVICE_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_HAS_IO_URING)
#include <cstddef>
#include <sys/eventfd.h>
#include <boost/asio/detail/io_uring_service.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/scheduler.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 {
io_uring_service::io_uring_service(boost::asio::execution_context& ctx)
: execution_context_service_base<io_uring_service>(ctx),
scheduler_(use_service<scheduler>(ctx)),
mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
outstanding_work_(0),
submit_sqes_op_(this),
pending_sqes_(0),
pending_submit_sqes_op_(false),
shutdown_(false),
timeout_(),
registration_mutex_(mutex_.enabled()),
reactor_(use_service<reactor>(ctx)),
reactor_data_(),
event_fd_(-1)
{
reactor_.init_task();
init_ring();
register_with_reactor();
}
io_uring_service::~io_uring_service()
{
if (ring_.ring_fd != -1)
::io_uring_queue_exit(&ring_);
if (event_fd_ != -1)
::close(event_fd_);
}
void io_uring_service::shutdown()
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
lock.unlock();
op_queue<operation> ops;
// Cancel all outstanding operations.
while (io_object* io_obj = registered_io_objects_.first())
{
for (int i = 0; i < max_ops; ++i)
{
if (!io_obj->queues_[i].op_queue_.empty())
{
ops.push(io_obj->queues_[i].op_queue_);
if (::io_uring_sqe* sqe = get_sqe())
::io_uring_prep_cancel(sqe, &io_obj->queues_[i], 0);
}
}
io_obj->shutdown_ = true;
registered_io_objects_.free(io_obj);
}
// Cancel the timeout operation.
if (::io_uring_sqe* sqe = get_sqe())
::io_uring_prep_cancel(sqe, &timeout_, IOSQE_IO_DRAIN);
submit_sqes();
// Wait for all completions to come back.
for (; outstanding_work_ > 0; --outstanding_work_)
{
::io_uring_cqe* cqe = 0;
if (::io_uring_wait_cqe(&ring_, &cqe) != 0)
break;
}
timer_queues_.get_all_timers(ops);
scheduler_.abandon_operations(ops);
}
void io_uring_service::notify_fork(
boost::asio::execution_context::fork_event fork_ev)
{
switch (fork_ev)
{
case boost::asio::execution_context::fork_prepare:
{
// Cancel all outstanding operations. They will be restarted
// after the fork completes.
mutex::scoped_lock registration_lock(registration_mutex_);
for (io_object* io_obj = registered_io_objects_.first();
io_obj != 0; io_obj = io_obj->next_)
{
mutex::scoped_lock io_object_lock(io_obj->mutex_);
for (int i = 0; i < max_ops; ++i)
{
if (!io_obj->queues_[i].op_queue_.empty()
&& !io_obj->queues_[i].cancel_requested_)
{
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
::io_uring_prep_cancel(sqe, &io_obj->queues_[i], 0);
}
}
}
// Cancel the timeout operation.
{
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
::io_uring_prep_cancel(sqe, &timeout_, IOSQE_IO_DRAIN);
submit_sqes();
}
// Wait for all completions to come back, and post all completed I/O
// queues to the scheduler. Note that some operations may have already
// completed, or were explicitly cancelled. All others will be
// automatically restarted.
op_queue<operation> ops;
for (; outstanding_work_ > 0; --outstanding_work_)
{
::io_uring_cqe* cqe = 0;
if (::io_uring_wait_cqe(&ring_, &cqe) != 0)
break;
if (void* ptr = ::io_uring_cqe_get_data(cqe))
{
if (ptr != this && ptr != &timer_queues_ && ptr != &timeout_)
{
io_queue* io_q = static_cast<io_queue*>(ptr);
io_q->set_result(cqe->res);
ops.push(io_q);
}
}
}
scheduler_.post_deferred_completions(ops);
// Restart and eventfd operation.
register_with_reactor();
}
break;
case boost::asio::execution_context::fork_parent:
// Restart the timeout and eventfd operations.
update_timeout();
register_with_reactor();
break;
case boost::asio::execution_context::fork_child:
{
// The child process gets a new io_uring instance.
::io_uring_queue_exit(&ring_);
init_ring();
register_with_reactor();
}
break;
default:
break;
}
}
void io_uring_service::init_task()
{
scheduler_.init_task();
}
void io_uring_service::register_io_object(
io_uring_service::per_io_object_data& io_obj)
{
io_obj = allocate_io_object();
mutex::scoped_lock io_object_lock(io_obj->mutex_);
io_obj->service_ = this;
io_obj->shutdown_ = false;
for (int i = 0; i < max_ops; ++i)
{
io_obj->queues_[i].io_object_ = io_obj;
io_obj->queues_[i].cancel_requested_ = false;
}
}
void io_uring_service::register_internal_io_object(
io_uring_service::per_io_object_data& io_obj,
int op_type, io_uring_operation* op)
{
io_obj = allocate_io_object();
mutex::scoped_lock io_object_lock(io_obj->mutex_);
io_obj->service_ = this;
io_obj->shutdown_ = false;
for (int i = 0; i < max_ops; ++i)
{
io_obj->queues_[i].io_object_ = io_obj;
io_obj->queues_[i].cancel_requested_ = false;
}
io_obj->queues_[op_type].op_queue_.push(op);
io_object_lock.unlock();
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
op->prepare(sqe);
::io_uring_sqe_set_data(sqe, &io_obj->queues_[op_type]);
post_submit_sqes_op(lock);
}
else
{
boost::system::error_code ec(ENOBUFS,
boost::asio::error::get_system_category());
boost::asio::detail::throw_error(ec, "io_uring_get_sqe");
}
}
void io_uring_service::register_buffers(const ::iovec* v, unsigned n)
{
int result = ::io_uring_register_buffers(&ring_, v, n);
if (result < 0)
{
boost::system::error_code ec(-result,
boost::asio::error::get_system_category());
boost::asio::detail::throw_error(ec, "io_uring_register_buffers");
}
}
void io_uring_service::unregister_buffers()
{
(void)::io_uring_unregister_buffers(&ring_);
}
void io_uring_service::start_op(int op_type,
io_uring_service::per_io_object_data& io_obj,
io_uring_operation* op, bool is_continuation)
{
if (!io_obj)
{
op->ec_ = boost::asio::error::bad_descriptor;
post_immediate_completion(op, is_continuation);
return;
}
mutex::scoped_lock io_object_lock(io_obj->mutex_);
if (io_obj->shutdown_)
{
io_object_lock.unlock();
post_immediate_completion(op, is_continuation);
return;
}
if (io_obj->queues_[op_type].op_queue_.empty())
{
if (op->perform(false))
{
io_object_lock.unlock();
scheduler_.post_immediate_completion(op, is_continuation);
}
else
{
io_obj->queues_[op_type].op_queue_.push(op);
io_object_lock.unlock();
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
op->prepare(sqe);
::io_uring_sqe_set_data(sqe, &io_obj->queues_[op_type]);
scheduler_.work_started();
post_submit_sqes_op(lock);
}
else
{
lock.unlock();
io_obj->queues_[op_type].set_result(-ENOBUFS);
post_immediate_completion(&io_obj->queues_[op_type], is_continuation);
}
}
}
else
{
io_obj->queues_[op_type].op_queue_.push(op);
scheduler_.work_started();
}
}
void io_uring_service::cancel_ops(io_uring_service::per_io_object_data& io_obj)
{
if (!io_obj)
return;
mutex::scoped_lock io_object_lock(io_obj->mutex_);
op_queue<operation> ops;
do_cancel_ops(io_obj, ops);
io_object_lock.unlock();
scheduler_.post_deferred_completions(ops);
}
void io_uring_service::cancel_ops_by_key(
io_uring_service::per_io_object_data& io_obj,
int op_type, void* cancellation_key)
{
if (!io_obj)
return;
mutex::scoped_lock io_object_lock(io_obj->mutex_);
bool first = true;
op_queue<operation> ops;
op_queue<io_uring_operation> other_ops;
while (io_uring_operation* op = io_obj->queues_[op_type].op_queue_.front())
{
io_obj->queues_[op_type].op_queue_.pop();
if (op->cancellation_key_ == cancellation_key)
{
if (first)
{
other_ops.push(op);
if (!io_obj->queues_[op_type].cancel_requested_)
{
io_obj->queues_[op_type].cancel_requested_ = true;
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
::io_uring_prep_cancel(sqe, &io_obj->queues_[op_type], 0);
submit_sqes();
}
}
}
else
{
op->ec_ = boost::asio::error::operation_aborted;
ops.push(op);
}
}
else
other_ops.push(op);
first = false;
}
io_obj->queues_[op_type].op_queue_.push(other_ops);
io_object_lock.unlock();
scheduler_.post_deferred_completions(ops);
}
void io_uring_service::deregister_io_object(
io_uring_service::per_io_object_data& io_obj)
{
if (!io_obj)
return;
mutex::scoped_lock io_object_lock(io_obj->mutex_);
if (!io_obj->shutdown_)
{
op_queue<operation> ops;
bool pending_cancelled_ops = do_cancel_ops(io_obj, ops);
io_obj->shutdown_ = true;
io_object_lock.unlock();
scheduler_.post_deferred_completions(ops);
if (pending_cancelled_ops)
{
// There are still pending operations. Prevent cleanup_io_object from
// freeing the I/O object and let the last operation to complete free it.
io_obj = 0;
}
else
{
// Leave io_obj set so that it will be freed by the subsequent call to
// cleanup_io_object.
}
}
else
{
// We are shutting down, so prevent cleanup_io_object from freeing
// the I/O object and let the destructor free it instead.
io_obj = 0;
}
}
void io_uring_service::cleanup_io_object(
io_uring_service::per_io_object_data& io_obj)
{
if (io_obj)
{
free_io_object(io_obj);
io_obj = 0;
}
}
void io_uring_service::run(long usec, op_queue<operation>& ops)
{
__kernel_timespec ts;
int local_ops = 0;
if (usec > 0)
{
ts.tv_sec = usec / 1000000;
ts.tv_nsec = (usec % 1000000) * 1000;
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
++local_ops;
::io_uring_prep_timeout(sqe, &ts, 0, 0);
::io_uring_sqe_set_data(sqe, &ts);
submit_sqes();
}
}
::io_uring_cqe* cqe = 0;
int result = (usec == 0)
? ::io_uring_peek_cqe(&ring_, &cqe)
: ::io_uring_wait_cqe(&ring_, &cqe);
if (local_ops > 0)
{
if (result != 0 || ::io_uring_cqe_get_data(cqe) != &ts)
{
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
++local_ops;
::io_uring_prep_timeout_remove(sqe, reinterpret_cast<__u64>(&ts), 0);
::io_uring_sqe_set_data(sqe, &ts);
submit_sqes();
}
}
}
bool check_timers = false;
int count = 0;
while (result == 0 || local_ops > 0)
{
if (result == 0)
{
if (void* ptr = ::io_uring_cqe_get_data(cqe))
{
if (ptr == this)
{
// The io_uring service was interrupted.
}
else if (ptr == &timer_queues_)
{
check_timers = true;
}
else if (ptr == &timeout_)
{
check_timers = true;
timeout_.tv_sec = 0;
timeout_.tv_nsec = 0;
}
else if (ptr == &ts)
{
--local_ops;
}
else
{
io_queue* io_q = static_cast<io_queue*>(ptr);
io_q->set_result(cqe->res);
ops.push(io_q);
}
}
::io_uring_cqe_seen(&ring_, cqe);
++count;
}
result = (count < complete_batch_size || local_ops > 0)
? ::io_uring_peek_cqe(&ring_, &cqe) : -EAGAIN;
}
decrement(outstanding_work_, count);
if (check_timers)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.get_ready_timers(ops);
if (timeout_.tv_sec == 0 && timeout_.tv_nsec == 0)
{
timeout_ = get_timeout();
if (::io_uring_sqe* sqe = get_sqe())
{
::io_uring_prep_timeout(sqe, &timeout_, 0, 0);
::io_uring_sqe_set_data(sqe, &timeout_);
push_submit_sqes_op(ops);
}
}
}
}
void io_uring_service::interrupt()
{
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
::io_uring_prep_nop(sqe);
::io_uring_sqe_set_data(sqe, this);
}
submit_sqes();
}
void io_uring_service::init_ring()
{
int result = ::io_uring_queue_init(ring_size, &ring_, 0);
if (result < 0)
{
ring_.ring_fd = -1;
boost::system::error_code ec(-result,
boost::asio::error::get_system_category());
boost::asio::detail::throw_error(ec, "io_uring_queue_init");
}
#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
event_fd_ = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
if (event_fd_ < 0)
{
boost::system::error_code ec(-result,
boost::asio::error::get_system_category());
::io_uring_queue_exit(&ring_);
boost::asio::detail::throw_error(ec, "eventfd");
}
result = ::io_uring_register_eventfd(&ring_, event_fd_);
if (result < 0)
{
::close(event_fd_);
::io_uring_queue_exit(&ring_);
boost::system::error_code ec(-result,
boost::asio::error::get_system_category());
boost::asio::detail::throw_error(ec, "io_uring_queue_init");
}
#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
class io_uring_service::event_fd_read_op :
public reactor_op
{
public:
event_fd_read_op(io_uring_service* s)
: reactor_op(boost::system::error_code(),
&event_fd_read_op::do_perform, event_fd_read_op::do_complete),
service_(s)
{
}
static status do_perform(reactor_op* base)
{
event_fd_read_op* o(static_cast<event_fd_read_op*>(base));
for (;;)
{
// Only perform one read. The kernel maintains an atomic counter.
uint64_t counter(0);
errno = 0;
int bytes_read = ::read(o->service_->event_fd_,
&counter, sizeof(uint64_t));
if (bytes_read < 0 && errno == EINTR)
continue;
break;
}
op_queue<operation> ops;
o->service_->run(0, ops);
o->service_->scheduler_.post_deferred_completions(ops);
return not_done;
}
static void do_complete(void* /*owner*/, operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
event_fd_read_op* o(static_cast<event_fd_read_op*>(base));
delete o;
}
private:
io_uring_service* service_;
};
#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
void io_uring_service::register_with_reactor()
{
#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_.register_internal_descriptor(reactor::read_op,
event_fd_, reactor_data_, new event_fd_read_op(this));
#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
io_uring_service::io_object* io_uring_service::allocate_io_object()
{
mutex::scoped_lock registration_lock(registration_mutex_);
return registered_io_objects_.alloc(
BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_IO, scheduler_.concurrency_hint()));
}
void io_uring_service::free_io_object(io_uring_service::io_object* io_obj)
{
mutex::scoped_lock registration_lock(registration_mutex_);
registered_io_objects_.free(io_obj);
}
bool io_uring_service::do_cancel_ops(
per_io_object_data& io_obj, op_queue<operation>& ops)
{
bool cancel_op = false;
for (int i = 0; i < max_ops; ++i)
{
if (io_uring_operation* first_op = io_obj->queues_[i].op_queue_.front())
{
cancel_op = true;
io_obj->queues_[i].op_queue_.pop();
while (io_uring_operation* op = io_obj->queues_[i].op_queue_.front())
{
op->ec_ = boost::asio::error::operation_aborted;
io_obj->queues_[i].op_queue_.pop();
ops.push(op);
}
io_obj->queues_[i].op_queue_.push(first_op);
}
}
if (cancel_op)
{
mutex::scoped_lock lock(mutex_);
for (int i = 0; i < max_ops; ++i)
{
if (!io_obj->queues_[i].op_queue_.empty()
&& !io_obj->queues_[i].cancel_requested_)
{
io_obj->queues_[i].cancel_requested_ = true;
if (::io_uring_sqe* sqe = get_sqe())
::io_uring_prep_cancel(sqe, &io_obj->queues_[i], 0);
}
}
submit_sqes();
}
return cancel_op;
}
void io_uring_service::do_add_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.insert(&queue);
}
void io_uring_service::do_remove_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.erase(&queue);
}
void io_uring_service::update_timeout()
{
if (::io_uring_sqe* sqe = get_sqe())
{
::io_uring_prep_timeout_remove(sqe, reinterpret_cast<__u64>(&timeout_), 0);
::io_uring_sqe_set_data(sqe, &timer_queues_);
}
}
__kernel_timespec io_uring_service::get_timeout() const
{
__kernel_timespec ts;
long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
ts.tv_sec = usec / 1000000;
ts.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
return ts;
}
::io_uring_sqe* io_uring_service::get_sqe()
{
::io_uring_sqe* sqe = ::io_uring_get_sqe(&ring_);
if (!sqe)
{
submit_sqes();
sqe = ::io_uring_get_sqe(&ring_);
}
if (sqe)
{
::io_uring_sqe_set_data(sqe, 0);
++pending_sqes_;
}
return sqe;
}
void io_uring_service::submit_sqes()
{
if (pending_sqes_ != 0)
{
int result = ::io_uring_submit(&ring_);
if (result > 0)
{
pending_sqes_ -= result;
increment(outstanding_work_, result);
}
}
}
void io_uring_service::post_submit_sqes_op(mutex::scoped_lock& lock)
{
if (pending_sqes_ >= submit_batch_size)
{
submit_sqes();
}
else if (pending_sqes_ != 0 && !pending_submit_sqes_op_)
{
pending_submit_sqes_op_ = true;
lock.unlock();
scheduler_.post_immediate_completion(&submit_sqes_op_, false);
}
}
void io_uring_service::push_submit_sqes_op(op_queue<operation>& ops)
{
if (pending_sqes_ != 0 && !pending_submit_sqes_op_)
{
pending_submit_sqes_op_ = true;
ops.push(&submit_sqes_op_);
scheduler_.compensating_work_started();
}
}
io_uring_service::submit_sqes_op::submit_sqes_op(io_uring_service* s)
: operation(&io_uring_service::submit_sqes_op::do_complete),
service_(s)
{
}
void io_uring_service::submit_sqes_op::do_complete(void* owner, operation* base,
const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/)
{
if (owner)
{
submit_sqes_op* o = static_cast<submit_sqes_op*>(base);
mutex::scoped_lock lock(o->service_->mutex_);
o->service_->submit_sqes();
if (o->service_->pending_sqes_ != 0)
o->service_->scheduler_.post_immediate_completion(o, true);
else
o->service_->pending_submit_sqes_op_ = false;
}
}
io_uring_service::io_queue::io_queue()
: operation(&io_uring_service::io_queue::do_complete)
{
}
struct io_uring_service::perform_io_cleanup_on_block_exit
{
explicit perform_io_cleanup_on_block_exit(io_uring_service* s)
: service_(s), io_object_to_free_(0), first_op_(0)
{
}
~perform_io_cleanup_on_block_exit()
{
if (io_object_to_free_)
{
mutex::scoped_lock lock(service_->mutex_);
service_->free_io_object(io_object_to_free_);
}
if (first_op_)
{
// Post the remaining completed operations for invocation.
if (!ops_.empty())
service_->scheduler_.post_deferred_completions(ops_);
// A user-initiated operation has completed, but there's no need to
// explicitly call work_finished() here. Instead, we'll take advantage of
// the fact that the scheduler will call work_finished() once we return.
}
else
{
// No user-initiated operations have completed, so we need to compensate
// for the work_finished() call that the scheduler will make once this
// operation returns.
service_->scheduler_.compensating_work_started();
}
}
io_uring_service* service_;
io_object* io_object_to_free_;
op_queue<operation> ops_;
operation* first_op_;
};
operation* io_uring_service::io_queue::perform_io(int result)
{
perform_io_cleanup_on_block_exit io_cleanup(io_object_->service_);
mutex::scoped_lock io_object_lock(io_object_->mutex_);
if (result != -ECANCELED || cancel_requested_)
{
if (io_uring_operation* op = op_queue_.front())
{
if (result < 0)
{
op->ec_.assign(-result, boost::asio::error::get_system_category());
op->bytes_transferred_ = 0;
}
else
{
op->ec_.assign(0, op->ec_.category());
op->bytes_transferred_ = static_cast<std::size_t>(result);
}
}
while (io_uring_operation* op = op_queue_.front())
{
if (op->perform(io_cleanup.ops_.empty()))
{
op_queue_.pop();
io_cleanup.ops_.push(op);
}
else
break;
}
}
cancel_requested_ = false;
if (!op_queue_.empty())
{
io_uring_service* service = io_object_->service_;
mutex::scoped_lock lock(service->mutex_);
if (::io_uring_sqe* sqe = service->get_sqe())
{
op_queue_.front()->prepare(sqe);
::io_uring_sqe_set_data(sqe, this);
service->post_submit_sqes_op(lock);
}
else
{
lock.unlock();
while (io_uring_operation* op = op_queue_.front())
{
op->ec_ = boost::asio::error::no_buffer_space;
op_queue_.pop();
io_cleanup.ops_.push(op);
}
}
}
// The last operation to complete on a shut down object must free it.
if (io_object_->shutdown_)
{
io_cleanup.io_object_to_free_ = io_object_;
for (int i = 0; i < max_ops; ++i)
if (!io_object_->queues_[i].op_queue_.empty())
io_cleanup.io_object_to_free_ = 0;
}
// The first operation will be returned for completion now. The others will
// be posted for later by the io_cleanup object's destructor.
io_cleanup.first_op_ = io_cleanup.ops_.front();
io_cleanup.ops_.pop();
return io_cleanup.first_op_;
}
void io_uring_service::io_queue::do_complete(void* owner, operation* base,
const boost::system::error_code& ec, std::size_t bytes_transferred)
{
if (owner)
{
io_queue* io_q = static_cast<io_queue*>(base);
int result = static_cast<int>(bytes_transferred);
if (operation* op = io_q->perform_io(result))
{
op->complete(owner, ec, 0);
}
}
}
io_uring_service::io_object::io_object(bool locking)
: mutex_(locking)
{
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING)
#endif // BOOST_ASIO_DETAIL_IMPL_IO_URING_SERVICE_IPP

View File

@@ -0,0 +1,251 @@
//
// detail/io_uring_socket_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_IO_URING_SOCKET_SERVICE_BASE_IPP
#define BOOST_ASIO_DETAIL_IMPL_IO_URING_SOCKET_SERVICE_BASE_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_HAS_IO_URING)
#include <boost/asio/detail/io_uring_socket_service_base.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
io_uring_socket_service_base::io_uring_socket_service_base(
execution_context& context)
: io_uring_service_(boost::asio::use_service<io_uring_service>(context))
{
io_uring_service_.init_task();
}
void io_uring_socket_service_base::base_shutdown()
{
}
void io_uring_socket_service_base::construct(
io_uring_socket_service_base::base_implementation_type& impl)
{
impl.socket_ = invalid_socket;
impl.state_ = 0;
impl.io_object_data_ = 0;
}
void io_uring_socket_service_base::base_move_construct(
io_uring_socket_service_base::base_implementation_type& impl,
io_uring_socket_service_base::base_implementation_type& other_impl)
BOOST_ASIO_NOEXCEPT
{
impl.socket_ = other_impl.socket_;
other_impl.socket_ = invalid_socket;
impl.state_ = other_impl.state_;
other_impl.state_ = 0;
impl.io_object_data_ = other_impl.io_object_data_;
other_impl.io_object_data_ = 0;
}
void io_uring_socket_service_base::base_move_assign(
io_uring_socket_service_base::base_implementation_type& impl,
io_uring_socket_service_base& /*other_service*/,
io_uring_socket_service_base::base_implementation_type& other_impl)
{
destroy(impl);
impl.socket_ = other_impl.socket_;
other_impl.socket_ = invalid_socket;
impl.state_ = other_impl.state_;
other_impl.state_ = 0;
impl.io_object_data_ = other_impl.io_object_data_;
other_impl.io_object_data_ = 0;
}
void io_uring_socket_service_base::destroy(
io_uring_socket_service_base::base_implementation_type& impl)
{
if (impl.socket_ != invalid_socket)
{
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"socket", &impl, impl.socket_, "close"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
boost::system::error_code ignored_ec;
socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
}
}
boost::system::error_code io_uring_socket_service_base::close(
io_uring_socket_service_base::base_implementation_type& impl,
boost::system::error_code& ec)
{
if (is_open(impl))
{
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"socket", &impl, impl.socket_, "close"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
socket_ops::close(impl.socket_, impl.state_, false, ec);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
}
else
{
ec = success_ec_;
}
// The descriptor is closed by the OS even if close() returns an error.
//
// (Actually, POSIX says the state of the descriptor is unspecified. On
// Linux the descriptor is apparently closed anyway; e.g. see
// http://lkml.org/lkml/2005/9/10/129
construct(impl);
return ec;
}
socket_type io_uring_socket_service_base::release(
io_uring_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((io_uring_service_.context(),
"socket", &impl, impl.socket_, "release"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
socket_type sock = impl.socket_;
construct(impl);
ec = success_ec_;
return sock;
}
boost::system::error_code io_uring_socket_service_base::cancel(
io_uring_socket_service_base::base_implementation_type& impl,
boost::system::error_code& ec)
{
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
return ec;
}
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"socket", &impl, impl.socket_, "cancel"));
io_uring_service_.cancel_ops(impl.io_object_data_);
ec = success_ec_;
return ec;
}
boost::system::error_code io_uring_socket_service_base::do_open(
io_uring_socket_service_base::base_implementation_type& impl,
int af, int type, int protocol, boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
return ec;
}
socket_holder sock(socket_ops::socket(af, type, protocol, ec));
if (sock.get() == invalid_socket)
return ec;
io_uring_service_.register_io_object(impl.io_object_data_);
impl.socket_ = sock.release();
switch (type)
{
case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
default: impl.state_ = 0; break;
}
ec = success_ec_;
return ec;
}
boost::system::error_code io_uring_socket_service_base::do_assign(
io_uring_socket_service_base::base_implementation_type& impl, int type,
const io_uring_socket_service_base::native_handle_type& native_socket,
boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
return ec;
}
io_uring_service_.register_io_object(impl.io_object_data_);
impl.socket_ = native_socket;
switch (type)
{
case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
default: impl.state_ = 0; break;
}
impl.state_ |= socket_ops::possible_dup;
ec = success_ec_;
return ec;
}
void io_uring_socket_service_base::start_op(
io_uring_socket_service_base::base_implementation_type& impl,
int op_type, io_uring_operation* op, bool is_continuation, bool noop)
{
if (!noop)
{
io_uring_service_.start_op(op_type,
impl.io_object_data_, op, is_continuation);
}
else
{
io_uring_service_.post_immediate_completion(op, is_continuation);
}
}
void io_uring_socket_service_base::start_accept_op(
io_uring_socket_service_base::base_implementation_type& impl,
io_uring_operation* op, bool is_continuation, bool peer_is_open)
{
if (!peer_is_open)
start_op(impl, io_uring_service::read_op, op, is_continuation, false);
else
{
op->ec_ = boost::asio::error::already_open;
io_uring_service_.post_immediate_completion(op, is_continuation);
}
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING)
#endif // BOOST_ASIO_DETAIL_IMPL_IO_URING_SOCKET_SERVICE_BASE_IPP

View File

@@ -2,7 +2,7 @@
// detail/impl/kqueue_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -20,12 +20,20 @@
#if defined(BOOST_ASIO_HAS_KQUEUE)
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
inline void kqueue_reactor::post_immediate_completion(
operation* op, bool is_continuation) const
{
scheduler_.post_immediate_completion(op, is_continuation);
}
template <typename Time_Traits>
void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
@@ -71,6 +79,18 @@ std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
return n;
}
template <typename Time_Traits>
void kqueue_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
template <typename Time_Traits>
void kqueue_reactor::move_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& target,

View File

@@ -2,7 +2,7 @@
// detail/impl/kqueue_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -25,9 +25,13 @@
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
#if defined(__NetBSD__)
# include <sys/param.h>
#endif
#include <boost/asio/detail/push_options.hpp>
#if defined(__NetBSD__)
#if defined(__NetBSD__) && __NetBSD_Version__ < 999001500
# define BOOST_ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
EV_SET(ev, ident, filt, flags, fflags, data, \
reinterpret_cast<intptr_t>(static_cast<void*>(udata)))
@@ -187,14 +191,23 @@ void kqueue_reactor::move_descriptor(socket_type,
source_descriptor_data = 0;
}
void kqueue_reactor::call_post_immediate_completion(
operation* op, bool is_continuation, const void* self)
{
static_cast<const kqueue_reactor*>(self)->post_immediate_completion(
op, is_continuation);
}
void kqueue_reactor::start_op(int op_type, socket_type descriptor,
kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op,
bool is_continuation, bool allow_speculative)
bool is_continuation, bool allow_speculative,
void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg)
{
if (!descriptor_data)
{
op->ec_ = boost::asio::error::bad_descriptor;
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -202,7 +215,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor,
if (descriptor_data->shutdown_)
{
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -217,7 +230,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor,
if (op->perform())
{
descriptor_lock.unlock();
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -236,7 +249,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());
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
}
@@ -283,6 +296,35 @@ void kqueue_reactor::cancel_ops(socket_type,
scheduler_.post_deferred_completions(ops);
}
void kqueue_reactor::cancel_ops_by_key(socket_type,
kqueue_reactor::per_descriptor_data& descriptor_data,
int op_type, void* cancellation_key)
{
if (!descriptor_data)
return;
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
op_queue<operation> ops;
op_queue<reactor_op> other_ops;
while (reactor_op* op = descriptor_data->op_queue_[op_type].front())
{
descriptor_data->op_queue_[op_type].pop();
if (op->cancellation_key_ == cancellation_key)
{
op->ec_ = boost::asio::error::operation_aborted;
ops.push(op);
}
else
other_ops.push(op);
}
descriptor_data->op_queue_[op_type].push(other_ops);
descriptor_lock.unlock();
scheduler_.post_deferred_completions(ops);
}
void kqueue_reactor::deregister_descriptor(socket_type descriptor,
kqueue_reactor::per_descriptor_data& descriptor_data, bool closing)
{

View File

@@ -2,7 +2,7 @@
// detail/impl/null_event.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/impl/pipe_select_interrupter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -102,12 +102,17 @@ bool pipe_select_interrupter::reset()
{
char data[1024];
signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data));
if (bytes_read < 0 && errno == EINTR)
if (bytes_read == sizeof(data))
continue;
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = ::read(read_descriptor_, data, sizeof(data));
return was_interrupted;
if (bytes_read > 0)
return true;
if (bytes_read == 0)
return false;
if (errno == EINTR)
continue;
if (errno == EWOULDBLOCK || errno == EAGAIN)
return true;
return false;
}
}

View File

@@ -2,7 +2,7 @@
// detail/impl/posix_event.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -38,10 +38,14 @@ posix_event::posix_event()
#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);
int error = ::pthread_condattr_init(&attr);
if (error == 0)
error = ::pthread_cond_init(&cond_, &attr);
{
error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
if (error == 0)
error = ::pthread_cond_init(&cond_, &attr);
::pthread_condattr_destroy(&attr);
}
#endif // (defined(__MACH__) && defined(__APPLE__))
// || (defined(__ANDROID__) && (__ANDROID_API__ < 21))

View File

@@ -2,7 +2,7 @@
// detail/impl/posix_mutex.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -1,16 +1,16 @@
//
// detail/impl/reactive_serial_port_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// detail/impl/posix_serial_port_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
#ifndef BOOST_ASIO_DETAIL_IMPL_POSIX_SERIAL_PORT_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_POSIX_SERIAL_PORT_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -22,7 +22,7 @@
#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
#include <cstring>
#include <boost/asio/detail/reactive_serial_port_service.hpp>
#include <boost/asio/detail/posix_serial_port_service.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -30,25 +30,26 @@ namespace boost {
namespace asio {
namespace detail {
reactive_serial_port_service::reactive_serial_port_service(
posix_serial_port_service::posix_serial_port_service(
execution_context& context)
: execution_context_service_base<reactive_serial_port_service>(context),
: execution_context_service_base<posix_serial_port_service>(context),
descriptor_service_(context)
{
}
void reactive_serial_port_service::shutdown()
void posix_serial_port_service::shutdown()
{
descriptor_service_.shutdown();
}
boost::system::error_code reactive_serial_port_service::open(
reactive_serial_port_service::implementation_type& impl,
boost::system::error_code posix_serial_port_service::open(
posix_serial_port_service::implementation_type& impl,
const std::string& device, boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -56,7 +57,10 @@ boost::system::error_code reactive_serial_port_service::open(
int fd = descriptor_ops::open(device.c_str(),
O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
if (fd < 0)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
if (s >= 0)
@@ -65,13 +69,14 @@ boost::system::error_code reactive_serial_port_service::open(
{
boost::system::error_code ignored_ec;
descriptor_ops::close(fd, state, ignored_ec);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
// Set up default serial port options.
termios ios;
errno = 0;
s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
s = ::tcgetattr(fd, &ios);
descriptor_ops::get_last_error(ec, s < 0);
if (s >= 0)
{
#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
@@ -86,13 +91,14 @@ boost::system::error_code reactive_serial_port_service::open(
#endif
ios.c_iflag |= IGNPAR;
ios.c_cflag |= CREAD | CLOCAL;
errno = 0;
s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
s = ::tcsetattr(fd, TCSANOW, &ios);
descriptor_ops::get_last_error(ec, s < 0);
}
if (s < 0)
{
boost::system::error_code ignored_ec;
descriptor_ops::close(fd, state, ignored_ec);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -103,43 +109,53 @@ boost::system::error_code reactive_serial_port_service::open(
descriptor_ops::close(fd, state, ignored_ec);
}
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
boost::system::error_code reactive_serial_port_service::do_set_option(
reactive_serial_port_service::implementation_type& impl,
reactive_serial_port_service::store_function_type store,
boost::system::error_code posix_serial_port_service::do_set_option(
posix_serial_port_service::implementation_type& impl,
posix_serial_port_service::store_function_type store,
const void* option, boost::system::error_code& ec)
{
termios ios;
errno = 0;
descriptor_ops::error_wrapper(::tcgetattr(
descriptor_service_.native_handle(impl), &ios), ec);
if (ec)
int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios);
descriptor_ops::get_last_error(ec, s < 0);
if (s < 0)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
if (store(option, ios, ec))
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
errno = 0;
descriptor_ops::error_wrapper(::tcsetattr(
descriptor_service_.native_handle(impl), TCSANOW, &ios), ec);
s = ::tcsetattr(descriptor_service_.native_handle(impl), TCSANOW, &ios);
descriptor_ops::get_last_error(ec, s < 0);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
boost::system::error_code reactive_serial_port_service::do_get_option(
const reactive_serial_port_service::implementation_type& impl,
reactive_serial_port_service::load_function_type load,
boost::system::error_code posix_serial_port_service::do_get_option(
const posix_serial_port_service::implementation_type& impl,
posix_serial_port_service::load_function_type load,
void* option, boost::system::error_code& ec) const
{
termios ios;
errno = 0;
descriptor_ops::error_wrapper(::tcgetattr(
descriptor_service_.native_handle(impl), &ios), ec);
if (ec)
int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios);
descriptor_ops::get_last_error(ec, s < 0);
if (s < 0)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
return load(option, ios, ec);
load(option, ios, ec);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
} // namespace detail
@@ -151,4 +167,4 @@ boost::system::error_code reactive_serial_port_service::do_get_option(
#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT)
#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_SERIAL_PORT_SERVICE_IPP

View File

@@ -2,7 +2,7 @@
// detail/impl/posix_thread.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/impl/posix_tss_ptr.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/impl/reactive_descriptor_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -19,7 +19,8 @@
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(__CYGWIN__)
&& !defined(__CYGWIN__) \
&& !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#include <boost/asio/error.hpp>
#include <boost/asio/detail/reactive_descriptor_service.hpp>
@@ -47,11 +48,13 @@ void reactive_descriptor_service::construct(
{
impl.descriptor_ = -1;
impl.state_ = 0;
impl.reactor_data_ = reactor::per_descriptor_data();
}
void reactive_descriptor_service::move_construct(
reactive_descriptor_service::implementation_type& impl,
reactive_descriptor_service::implementation_type& other_impl)
BOOST_ASIO_NOEXCEPT
{
impl.descriptor_ = other_impl.descriptor_;
other_impl.descriptor_ = -1;
@@ -105,6 +108,7 @@ boost::system::error_code reactive_descriptor_service::assign(
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -113,6 +117,7 @@ boost::system::error_code reactive_descriptor_service::assign(
{
ec = boost::system::error_code(err,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -151,6 +156,7 @@ boost::system::error_code reactive_descriptor_service::close(
// We'll just have to assume that other OSes follow the same behaviour.)
construct(impl);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -180,6 +186,7 @@ boost::system::error_code reactive_descriptor_service::cancel(
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -191,10 +198,10 @@ boost::system::error_code reactive_descriptor_service::cancel(
return ec;
}
void reactive_descriptor_service::start_op(
reactive_descriptor_service::implementation_type& impl,
int op_type, reactor_op* op, bool is_continuation,
bool is_non_blocking, bool noop)
void reactive_descriptor_service::do_start_op(implementation_type& impl,
int op_type, reactor_op* op, bool is_continuation, bool is_non_blocking,
bool noop, void (*on_immediate)(operation* op, bool, const void*),
const void* immediate_arg)
{
if (!noop)
{
@@ -202,13 +209,13 @@ void reactive_descriptor_service::start_op(
descriptor_ops::set_internal_non_blocking(
impl.descriptor_, impl.state_, true, op->ec_))
{
reactor_.start_op(op_type, impl.descriptor_,
impl.reactor_data_, op, is_continuation, is_non_blocking);
reactor_.start_op(op_type, impl.descriptor_, impl.reactor_data_, op,
is_continuation, is_non_blocking, on_immediate, immediate_arg);
return;
}
}
reactor_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
}
} // namespace detail
@@ -220,5 +227,6 @@ void reactive_descriptor_service::start_op(
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
// && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP

View File

@@ -2,7 +2,7 @@
// detail/reactive_socket_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -18,7 +18,8 @@
#include <boost/asio/detail/config.hpp>
#if !defined(BOOST_ASIO_HAS_IOCP) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME)
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#include <boost/asio/detail/reactive_socket_service_base.hpp>
@@ -44,11 +45,13 @@ void reactive_socket_service_base::construct(
{
impl.socket_ = invalid_socket;
impl.state_ = 0;
impl.reactor_data_ = reactor::per_descriptor_data();
}
void reactive_socket_service_base::base_move_construct(
reactive_socket_service_base::base_implementation_type& impl,
reactive_socket_service_base::base_implementation_type& other_impl)
BOOST_ASIO_NOEXCEPT
{
impl.socket_ = other_impl.socket_;
other_impl.socket_ = invalid_socket;
@@ -231,10 +234,11 @@ boost::system::error_code reactive_socket_service_base::do_assign(
return ec;
}
void reactive_socket_service_base::start_op(
reactive_socket_service_base::base_implementation_type& impl,
int op_type, reactor_op* op, bool is_continuation,
bool is_non_blocking, bool noop)
void reactive_socket_service_base::do_start_op(
reactive_socket_service_base::base_implementation_type& impl, int op_type,
reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop,
void (*on_immediate)(operation* op, bool, const void*),
const void* immediate_arg)
{
if (!noop)
{
@@ -242,32 +246,38 @@ void reactive_socket_service_base::start_op(
|| socket_ops::set_internal_non_blocking(
impl.socket_, impl.state_, true, op->ec_))
{
reactor_.start_op(op_type, impl.socket_,
impl.reactor_data_, op, is_continuation, is_non_blocking);
reactor_.start_op(op_type, impl.socket_, impl.reactor_data_, op,
is_continuation, is_non_blocking, on_immediate, immediate_arg);
return;
}
}
reactor_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
}
void reactive_socket_service_base::start_accept_op(
void reactive_socket_service_base::do_start_accept_op(
reactive_socket_service_base::base_implementation_type& impl,
reactor_op* op, bool is_continuation, bool peer_is_open)
reactor_op* op, bool is_continuation, bool peer_is_open,
void (*on_immediate)(operation* op, bool, const void*),
const void* immediate_arg)
{
if (!peer_is_open)
start_op(impl, reactor::read_op, op, is_continuation, true, false);
{
do_start_op(impl, reactor::read_op, op, is_continuation,
true, false, on_immediate, immediate_arg);
}
else
{
op->ec_ = boost::asio::error::already_open;
reactor_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
}
}
void reactive_socket_service_base::start_connect_op(
void reactive_socket_service_base::do_start_connect_op(
reactive_socket_service_base::base_implementation_type& impl,
reactor_op* op, bool is_continuation,
const socket_addr_type* addr, size_t addrlen)
reactor_op* op, bool is_continuation, const void* addr, size_t addrlen,
void (*on_immediate)(operation* op, bool, const void*),
const void* immediate_arg)
{
if ((impl.state_ & socket_ops::non_blocking)
|| socket_ops::set_internal_non_blocking(
@@ -279,14 +289,14 @@ void reactive_socket_service_base::start_connect_op(
|| op->ec_ == boost::asio::error::would_block)
{
op->ec_ = boost::system::error_code();
reactor_.start_op(reactor::connect_op, impl.socket_,
impl.reactor_data_, op, is_continuation, false);
reactor_.start_op(reactor::connect_op, impl.socket_, impl.reactor_data_,
op, is_continuation, false, on_immediate, immediate_arg);
return;
}
}
}
reactor_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
}
} // namespace detail
@@ -297,5 +307,6 @@ void reactive_socket_service_base::start_connect_op(
#endif // !defined(BOOST_ASIO_HAS_IOCP)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP

View File

@@ -2,7 +2,7 @@
// detail/impl/resolver_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -81,12 +81,10 @@ void resolver_service_base::base_notify_fork(
work_thread_->join();
work_thread_.reset();
}
else
{
work_scheduler_->restart();
work_thread_.reset(new boost::asio::detail::thread(
work_scheduler_runner(*work_scheduler_)));
}
}
else if (fork_ev != execution_context::fork_prepare)
{
work_scheduler_->restart();
}
}

View File

@@ -2,7 +2,7 @@
// detail/impl/scheduler.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -20,11 +20,16 @@
#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/scheduler.hpp>
#include <boost/asio/detail/scheduler_thread_info.hpp>
#include <boost/asio/detail/signal_blocker.hpp>
#if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
# include <boost/asio/detail/io_uring_service.hpp>
#else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
# include <boost/asio/detail/reactor.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
@@ -105,7 +110,7 @@ struct scheduler::work_cleanup
};
scheduler::scheduler(boost::asio::execution_context& ctx,
int concurrency_hint, bool own_thread)
int concurrency_hint, bool own_thread, get_task_func_type get_task)
: boost::asio::detail::execution_context_service_base<scheduler>(ctx),
one_thread_(concurrency_hint == 1
|| !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
@@ -115,6 +120,7 @@ scheduler::scheduler(boost::asio::execution_context& ctx,
mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
SCHEDULER, concurrency_hint)),
task_(0),
get_task_(get_task),
task_interrupted_(true),
outstanding_work_(0),
stopped_(false),
@@ -136,6 +142,10 @@ scheduler::~scheduler()
{
if (thread_)
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
stop_all_threads(lock);
lock.unlock();
thread_->join();
delete thread_;
}
@@ -175,7 +185,7 @@ void scheduler::init_task()
mutex::scoped_lock lock(mutex_);
if (!shutdown_ && !task_)
{
task_ = &use_service<reactor>(this->context());
task_ = get_task_(this->context());
op_queue_.push(&task_operation_);
wake_one_thread_and_unlock(lock);
}
@@ -318,9 +328,21 @@ void scheduler::restart()
void scheduler::compensating_work_started()
{
thread_info_base* this_thread = thread_call_stack::contains(this);
BOOST_ASIO_ASSUME(this_thread != 0); // Only called from inside scheduler.
++static_cast<thread_info*>(this_thread)->private_outstanding_work;
}
bool scheduler::can_dispatch()
{
return thread_call_stack::contains(this) != 0;
}
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)
{
@@ -344,6 +366,30 @@ void scheduler::post_immediate_completion(
wake_one_thread_and_unlock(lock);
}
void scheduler::post_immediate_completions(std::size_t n,
op_queue<scheduler::operation>& ops, bool is_continuation)
{
#if defined(BOOST_ASIO_HAS_THREADS)
if (one_thread_ || is_continuation)
{
if (thread_info_base* this_thread = thread_call_stack::contains(this))
{
static_cast<thread_info*>(this_thread)->private_outstanding_work
+= static_cast<long>(n);
static_cast<thread_info*>(this_thread)->private_op_queue.push(ops);
return;
}
}
#else // defined(BOOST_ASIO_HAS_THREADS)
(void)is_continuation;
#endif // defined(BOOST_ASIO_HAS_THREADS)
increment(outstanding_work_, static_cast<long>(n));
mutex::scoped_lock lock(mutex_);
op_queue_.push(ops);
wake_one_thread_and_unlock(lock);
}
void scheduler::post_deferred_completion(scheduler::operation* op)
{
#if defined(BOOST_ASIO_HAS_THREADS)
@@ -445,6 +491,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;
}
@@ -525,6 +572,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;
}
@@ -579,6 +627,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;
}
@@ -610,6 +659,15 @@ void scheduler::wake_one_thread_and_unlock(
}
}
scheduler_task* scheduler::get_default_task(boost::asio::execution_context& ctx)
{
#if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
return &use_service<io_uring_service>(ctx);
#else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
return &use_service<reactor>(ctx);
#endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
} // namespace detail
} // namespace asio
} // namespace boost

View File

@@ -2,7 +2,7 @@
// detail/impl/select_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -23,12 +23,24 @@
&& !defined(BOOST_ASIO_HAS_KQUEUE) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME))
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/win_iocp_io_context.hpp>
#else // defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/scheduler.hpp>
#endif // defined(BOOST_ASIO_HAS_IOCP)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
inline void select_reactor::post_immediate_completion(
operation* op, bool is_continuation) const
{
scheduler_.post_immediate_completion(op, is_continuation);
}
template <typename Time_Traits>
void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
@@ -74,6 +86,18 @@ std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
return n;
}
template <typename Time_Traits>
void select_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
template <typename Time_Traits>
void select_reactor::move_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& target,

View File

@@ -2,7 +2,7 @@
// detail/impl/select_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -28,6 +28,12 @@
#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/win_iocp_io_context.hpp>
#else // defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/scheduler.hpp>
#endif // defined(BOOST_ASIO_HAS_IOCP)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
@@ -61,6 +67,7 @@ select_reactor::select_reactor(boost::asio::execution_context& ctx)
#if defined(BOOST_ASIO_HAS_IOCP)
stop_thread_(false),
thread_(0),
restart_reactor_(this),
#endif // defined(BOOST_ASIO_HAS_IOCP)
shutdown_(false)
{
@@ -81,13 +88,14 @@ void select_reactor::shutdown()
shutdown_ = true;
#if defined(BOOST_ASIO_HAS_IOCP)
stop_thread_ = true;
if (thread_)
interrupter_.interrupt();
#endif // defined(BOOST_ASIO_HAS_IOCP)
lock.unlock();
#if defined(BOOST_ASIO_HAS_IOCP)
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
@@ -107,8 +115,12 @@ void select_reactor::shutdown()
void select_reactor::notify_fork(
boost::asio::execution_context::fork_event fork_ev)
{
#if defined(BOOST_ASIO_HAS_IOCP)
(void)fork_ev;
#else // defined(BOOST_ASIO_HAS_IOCP)
if (fork_ev == boost::asio::execution_context::fork_child)
interrupter_.recreate();
#endif // defined(BOOST_ASIO_HAS_IOCP)
}
void select_reactor::init_task()
@@ -140,15 +152,23 @@ void select_reactor::move_descriptor(socket_type,
{
}
void select_reactor::call_post_immediate_completion(
operation* op, bool is_continuation, const void* self)
{
static_cast<const select_reactor*>(self)->post_immediate_completion(
op, is_continuation);
}
void select_reactor::start_op(int op_type, socket_type descriptor,
select_reactor::per_descriptor_data&, reactor_op* op,
bool is_continuation, bool)
select_reactor::per_descriptor_data&, reactor_op* op, bool is_continuation,
bool, void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -165,6 +185,19 @@ void select_reactor::cancel_ops(socket_type descriptor,
cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted);
}
void select_reactor::cancel_ops_by_key(socket_type descriptor,
select_reactor::per_descriptor_data&,
int op_type, void* cancellation_key)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
bool need_interrupt = op_queue_[op_type].cancel_operations_by_key(
descriptor, ops, cancellation_key, boost::asio::error::operation_aborted);
scheduler_.post_deferred_completions(ops);
if (need_interrupt)
interrupter_.interrupt();
}
void select_reactor::deregister_descriptor(socket_type descriptor,
select_reactor::per_descriptor_data&, bool)
{
@@ -240,7 +273,16 @@ void select_reactor::run(long usec, op_queue<operation>& ops)
// Reset the interrupter.
if (retval > 0 && fd_sets_[read_op].is_set(interrupter_.read_descriptor()))
{
interrupter_.reset();
if (!interrupter_.reset())
{
lock.lock();
#if defined(BOOST_ASIO_HAS_IOCP)
stop_thread_ = true;
scheduler_.post_immediate_completion(&restart_reactor_, false);
#else // defined(BOOST_ASIO_HAS_IOCP)
interrupter_.recreate();
#endif // defined(BOOST_ASIO_HAS_IOCP)
}
--retval;
}
@@ -276,11 +318,36 @@ void select_reactor::run_thread()
{
lock.unlock();
op_queue<operation> ops;
run(true, ops);
run(-1, ops);
scheduler_.post_deferred_completions(ops);
lock.lock();
}
}
void select_reactor::restart_reactor::do_complete(void* owner, operation* base,
const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/)
{
if (owner)
{
select_reactor* reactor = static_cast<restart_reactor*>(base)->reactor_;
if (reactor->thread_)
{
reactor->thread_->join();
delete reactor->thread_;
reactor->thread_ = 0;
}
boost::asio::detail::mutex::scoped_lock lock(reactor->mutex_);
reactor->interrupter_.recreate();
reactor->stop_thread_ = false;
lock.unlock();
boost::asio::detail::signal_blocker sb;
reactor->thread_ =
new boost::asio::detail::thread(thread_function(reactor));
}
}
#endif // defined(BOOST_ASIO_HAS_IOCP)
void select_reactor::do_add_timer_queue(timer_queue_base& queue)

View File

@@ -2,7 +2,7 @@
// detail/impl/service_registry.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/impl/service_registry.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/impl/signal_set_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -19,12 +19,17 @@
#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>
#if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
# include <boost/asio/detail/io_uring_service.hpp>
#else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
# include <boost/asio/detail/reactor.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
@@ -50,12 +55,16 @@ struct signal_state
// A count of the number of objects that are registered for each signal.
std::size_t registration_count_[max_signal_number];
// The flags used for each registered signal.
signal_set_base::flags_t flags_[max_signal_number];
};
signal_state* get_signal_state()
{
static signal_state state = {
BOOST_ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } };
BOOST_ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0,
{ 0 }, { signal_set_base::flags_t() } };
return &state;
}
@@ -86,11 +95,45 @@ void boost_asio_signal_handler(int signal_number)
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(__CYGWIN__)
class signal_set_service::pipe_read_op : public reactor_op
class signal_set_service::pipe_read_op :
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
public io_uring_operation
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
public reactor_op
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
{
public:
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
pipe_read_op()
: reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete)
: io_uring_operation(boost::system::error_code(), &pipe_read_op::do_prepare,
&pipe_read_op::do_perform, pipe_read_op::do_complete)
{
}
static void do_prepare(io_uring_operation*, ::io_uring_sqe* sqe)
{
signal_state* state = get_signal_state();
int fd = state->read_descriptor_;
::io_uring_prep_poll_add(sqe, fd, POLLIN);
}
static bool do_perform(io_uring_operation*, bool)
{
signal_state* state = get_signal_state();
int fd = state->read_descriptor_;
int signal_number = 0;
while (::read(fd, &signal_number, sizeof(int)) == sizeof(int))
if (signal_number >= 0 && signal_number < max_signal_number)
signal_set_service::deliver_signal(signal_number);
return false;
}
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
pipe_read_op()
: reactor_op(boost::system::error_code(),
&pipe_read_op::do_perform, pipe_read_op::do_complete)
{
}
@@ -106,6 +149,7 @@ public:
return not_done;
}
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
static void do_complete(void* /*owner*/, operation* base,
const boost::system::error_code& /*ec*/,
@@ -125,7 +169,11 @@ signal_set_service::signal_set_service(execution_context& context)
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(__CYGWIN__)
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
io_uring_service_(boost::asio::use_service<io_uring_service>(context)),
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_(boost::asio::use_service<reactor>(context)),
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
@@ -137,7 +185,11 @@ signal_set_service::signal_set_service(execution_context& context)
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(__CYGWIN__)
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
io_uring_service_.init_task();
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_.init_task();
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
@@ -187,8 +239,14 @@ void signal_set_service::notify_fork(execution_context::fork_event fork_ev)
int read_descriptor = state->read_descriptor_;
state->fork_prepared_ = true;
lock.unlock();
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
(void)read_descriptor;
io_uring_service_.deregister_io_object(io_object_data_);
io_uring_service_.cleanup_io_object(io_object_data_);
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_);
reactor_.cleanup_descriptor_data(reactor_data_);
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
break;
case execution_context::fork_parent:
@@ -197,8 +255,14 @@ void signal_set_service::notify_fork(execution_context::fork_event fork_ev)
int read_descriptor = state->read_descriptor_;
state->fork_prepared_ = false;
lock.unlock();
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
(void)read_descriptor;
io_uring_service_.register_internal_io_object(io_object_data_,
io_uring_service::read_op, new pipe_read_op);
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_.register_internal_descriptor(reactor::read_op,
read_descriptor, reactor_data_, new pipe_read_op);
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
break;
case execution_context::fork_child:
@@ -210,8 +274,14 @@ void signal_set_service::notify_fork(execution_context::fork_event fork_ev)
int read_descriptor = state->read_descriptor_;
state->fork_prepared_ = false;
lock.unlock();
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
(void)read_descriptor;
io_uring_service_.register_internal_io_object(io_object_data_,
io_uring_service::read_op, new pipe_read_op);
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_.register_internal_descriptor(reactor::read_op,
read_descriptor, reactor_data_, new pipe_read_op);
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
break;
default:
@@ -241,8 +311,8 @@ void signal_set_service::destroy(
}
boost::system::error_code signal_set_service::add(
signal_set_service::implementation_type& impl,
int signal_number, boost::system::error_code& ec)
signal_set_service::implementation_type& impl, int signal_number,
signal_set_base::flags_t f, boost::system::error_code& ec)
{
// Check that the signal number is valid.
if (signal_number < 0 || signal_number >= max_signal_number)
@@ -251,6 +321,15 @@ boost::system::error_code signal_set_service::add(
return ec;
}
// Check that the specified flags are supported.
#if !defined(BOOST_ASIO_HAS_SIGACTION)
if (f != signal_set_base::flags::dont_care)
{
ec = boost::asio::error::operation_not_supported;
return ec;
}
#endif // !defined(BOOST_ASIO_HAS_SIGACTION)
signal_state* state = get_signal_state();
static_mutex::scoped_lock lock(state->mutex_);
@@ -278,6 +357,8 @@ boost::system::error_code signal_set_service::add(
memset(&sa, 0, sizeof(sa));
sa.sa_handler = boost_asio_signal_handler;
sigfillset(&sa.sa_mask);
if (f != signal_set_base::flags::dont_care)
sa.sa_flags = static_cast<int>(f);
if (::sigaction(signal_number, &sa, 0) == -1)
# else // defined(BOOST_ASIO_HAS_SIGACTION)
if (::signal(signal_number, boost_asio_signal_handler) == SIG_ERR)
@@ -292,7 +373,39 @@ boost::system::error_code signal_set_service::add(
delete new_registration;
return ec;
}
# if defined(BOOST_ASIO_HAS_SIGACTION)
state->flags_[signal_number] = f;
# endif // defined(BOOST_ASIO_HAS_SIGACTION)
}
# if defined(BOOST_ASIO_HAS_SIGACTION)
// Otherwise check to see if the flags have changed.
else if (f != signal_set_base::flags::dont_care)
{
if (f != state->flags_[signal_number])
{
using namespace std; // For memset.
if (state->flags_[signal_number] != signal_set_base::flags::dont_care)
{
ec = boost::asio::error::invalid_argument;
delete new_registration;
return ec;
}
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = boost_asio_signal_handler;
sigfillset(&sa.sa_mask);
sa.sa_flags = static_cast<int>(f);
if (::sigaction(signal_number, &sa, 0) == -1)
{
ec = boost::system::error_code(errno,
boost::asio::error::get_system_category());
delete new_registration;
return ec;
}
state->flags_[signal_number] = f;
}
}
# endif // defined(BOOST_ASIO_HAS_SIGACTION)
#endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
// Record the new registration in the set.
@@ -361,6 +474,9 @@ boost::system::error_code signal_set_service::remove(
# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
return ec;
}
# if defined(BOOST_ASIO_HAS_SIGACTION)
state->flags_[signal_number] = signal_set_base::flags_t();
# endif // defined(BOOST_ASIO_HAS_SIGACTION)
}
#endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
@@ -415,6 +531,9 @@ boost::system::error_code signal_set_service::clear(
# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
return ec;
}
# if defined(BOOST_ASIO_HAS_SIGACTION)
state->flags_[reg->signal_number_] = signal_set_base::flags_t();
# endif // defined(BOOST_ASIO_HAS_SIGACTION)
}
#endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
@@ -462,6 +581,33 @@ boost::system::error_code signal_set_service::cancel(
return ec;
}
void signal_set_service::cancel_ops_by_key(
signal_set_service::implementation_type& impl, void* cancellation_key)
{
op_queue<operation> ops;
{
op_queue<signal_op> other_ops;
signal_state* state = get_signal_state();
static_mutex::scoped_lock lock(state->mutex_);
while (signal_op* op = impl.queue_.front())
{
impl.queue_.pop();
if (op->cancellation_key_ == cancellation_key)
{
op->ec_ = boost::asio::error::operation_aborted;
ops.push(op);
}
else
other_ops.push(op);
}
impl.queue_.push(other_ops);
}
scheduler_.post_deferred_completions(ops);
}
void signal_set_service::deliver_signal(int signal_number)
{
signal_state* state = get_signal_state();
@@ -538,8 +684,14 @@ void signal_set_service::add_service(signal_set_service* service)
// Register for pipe readiness notifications.
int read_descriptor = state->read_descriptor_;
lock.unlock();
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
(void)read_descriptor;
service->io_uring_service_.register_internal_io_object(
service->io_object_data_, io_uring_service::read_op, new pipe_read_op);
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
service->reactor_.register_internal_descriptor(reactor::read_op,
read_descriptor, service->reactor_data_, new pipe_read_op);
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
@@ -558,10 +710,17 @@ void signal_set_service::remove_service(signal_set_service* service)
// Disable the pipe readiness notifications.
int read_descriptor = state->read_descriptor_;
lock.unlock();
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
(void)read_descriptor;
service->io_uring_service_.deregister_io_object(service->io_object_data_);
service->io_uring_service_.cleanup_io_object(service->io_object_data_);
lock.lock();
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
service->reactor_.deregister_internal_descriptor(
read_descriptor, service->reactor_data_);
service->reactor_.cleanup_descriptor_data(service->reactor_data_);
lock.lock();
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// detail/impl/socket_select_interrupter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -61,11 +61,11 @@ void socket_select_interrupter::open_descriptors()
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);
addr.sin_port = 0;
if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
if (socket_ops::bind(acceptor.get(), &addr,
addr_len, ec) == socket_error_retval)
boost::asio::detail::throw_error(ec, "socket_select_interrupter");
if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
if (socket_ops::getsockname(acceptor.get(), &addr,
&addr_len, ec) == socket_error_retval)
boost::asio::detail::throw_error(ec, "socket_select_interrupter");
@@ -84,7 +84,7 @@ void socket_select_interrupter::open_descriptors()
if (client.get() == invalid_socket)
boost::asio::detail::throw_error(ec, "socket_select_interrupter");
if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
if (socket_ops::connect(client.get(), &addr,
addr_len, ec) == socket_error_retval)
boost::asio::detail::throw_error(ec, "socket_select_interrupter");
@@ -156,11 +156,20 @@ bool socket_select_interrupter::reset()
socket_ops::buf b;
socket_ops::init_buf(b, data, sizeof(data));
boost::system::error_code ec;
int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
return was_interrupted;
for (;;)
{
int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
if (bytes_read == sizeof(data))
continue;
if (bytes_read > 0)
return true;
if (bytes_read == 0)
return false;
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return true;
return false;
}
}
} // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/impl/strand_executor_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,11 +15,13 @@
# 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/defer.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -27,8 +29,132 @@ namespace boost {
namespace asio {
namespace detail {
template <typename F, typename Allocator>
class strand_executor_service::allocator_binder
{
public:
typedef Allocator allocator_type;
allocator_binder(BOOST_ASIO_MOVE_ARG(F) f, const Allocator& a)
: f_(BOOST_ASIO_MOVE_CAST(F)(f)),
allocator_(a)
{
}
allocator_binder(const allocator_binder& other)
: f_(other.f_),
allocator_(other.allocator_)
{
}
#if defined(BOOST_ASIO_HAS_MOVE)
allocator_binder(allocator_binder&& other)
: f_(BOOST_ASIO_MOVE_CAST(F)(other.f_)),
allocator_(BOOST_ASIO_MOVE_CAST(allocator_type)(other.allocator_))
{
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT
{
return allocator_;
}
void operator()()
{
f_();
}
private:
F f_;
allocator_type allocator_;
};
template <typename Executor>
class strand_executor_service::invoker
class strand_executor_service::invoker<Executor,
typename enable_if<
execution::is_executor<Executor>::value
>::type>
{
public:
invoker(const implementation_type& impl, Executor& ex)
: impl_(impl),
executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
invoker(const invoker& other)
: impl_(other.impl_),
executor_(other.executor_)
{
}
#if defined(BOOST_ASIO_HAS_MOVE)
invoker(invoker&& other)
: impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)),
executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
{
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
struct on_invoker_exit
{
invoker* this_;
~on_invoker_exit()
{
if (push_waiting_to_ready(this_->impl_))
{
recycling_allocator<void> allocator;
executor_type ex = this_->executor_;
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost::asio::prefer(
boost::asio::require(
BOOST_ASIO_MOVE_CAST(executor_type)(ex),
execution::blocking.never),
execution::allocator(allocator)
).execute(BOOST_ASIO_MOVE_CAST(invoker)(*this_));
#else // defined(BOOST_ASIO_NO_DEPRECATED)
execution::execute(
boost::asio::prefer(
boost::asio::require(
BOOST_ASIO_MOVE_CAST(executor_type)(ex),
execution::blocking.never),
execution::allocator(allocator)),
BOOST_ASIO_MOVE_CAST(invoker)(*this_));
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
}
};
void operator()()
{
// Ensure the next handler, if any, is scheduled on block exit.
on_invoker_exit on_exit = { this };
(void)on_exit;
run_ready_handlers(impl_);
}
private:
typedef typename decay<
typename prefer_result<
Executor,
execution::outstanding_work_t::tracked_t
>::type
>::type executor_type;
implementation_type impl_;
executor_type executor_;
};
#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
template <typename Executor>
class strand_executor_service::invoker<Executor,
typename enable_if<
!execution::is_executor<Executor>::value
>::type>
{
public:
invoker(const implementation_type& impl, Executor& ex)
@@ -57,13 +183,7 @@ public:
~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)
if (push_waiting_to_ready(this_->impl_))
{
Executor ex(this_->work_.get_executor());
recycling_allocator<void> allocator;
@@ -74,21 +194,11 @@ public:
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);
}
run_ready_handlers(impl_);
}
private:
@@ -96,6 +206,72 @@ private:
executor_work_guard<Executor> work_;
};
#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
template <typename Executor, typename Function>
inline void strand_executor_service::execute(const implementation_type& impl,
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function,
typename enable_if<
can_query<Executor, execution::allocator_t<void> >::value
>::type*)
{
return strand_executor_service::do_execute(impl, ex,
BOOST_ASIO_MOVE_CAST(Function)(function),
boost::asio::query(ex, execution::allocator));
}
template <typename Executor, typename Function>
inline void strand_executor_service::execute(const implementation_type& impl,
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function,
typename enable_if<
!can_query<Executor, execution::allocator_t<void> >::value
>::type*)
{
return strand_executor_service::do_execute(impl, ex,
BOOST_ASIO_MOVE_CAST(Function)(function),
std::allocator<void>());
}
template <typename Executor, typename Function, typename Allocator>
void strand_executor_service::do_execute(const implementation_type& impl,
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
{
typedef typename decay<Function>::type function_type;
// If the executor is not never-blocking, and we are already in the strand,
// then the function can run immediately.
if (boost::asio::query(ex, execution::blocking) != execution::blocking.never
&& running_in_this_thread(impl))
{
// 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, "execute"));
// 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)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
ex.execute(invoker<Executor>(impl, ex));
#else // defined(BOOST_ASIO_NO_DEPRECATED)
execution::execute(ex, invoker<Executor>(impl, ex));
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
}
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)
@@ -103,7 +279,7 @@ void strand_executor_service::dispatch(const implementation_type& impl,
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()))
if (running_in_this_thread(impl))
{
// Make a local, non-const copy of the function.
function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(function));
@@ -125,7 +301,11 @@ void strand_executor_service::dispatch(const implementation_type& impl,
bool first = enqueue(impl, p.p);
p.v = p.p = 0;
if (first)
ex.dispatch(invoker<Executor>(impl, ex), a);
{
boost::asio::dispatch(ex,
allocator_binder<invoker<Executor>, Allocator>(
invoker<Executor>(impl, ex), a));
}
}
// Request invocation of the given function and return immediately.
@@ -147,7 +327,11 @@ void strand_executor_service::post(const implementation_type& impl,
bool first = enqueue(impl, p.p);
p.v = p.p = 0;
if (first)
ex.post(invoker<Executor>(impl, ex), a);
{
boost::asio::post(ex,
allocator_binder<invoker<Executor>, Allocator>(
invoker<Executor>(impl, ex), a));
}
}
// Request invocation of the given function and return immediately.
@@ -169,7 +353,11 @@ void strand_executor_service::defer(const implementation_type& impl,
bool first = enqueue(impl, p.p);
p.v = p.p = 0;
if (first)
ex.defer(invoker<Executor>(impl, ex), a);
{
boost::asio::defer(ex,
allocator_binder<invoker<Executor>, Allocator>(
invoker<Executor>(impl, ex), a));
}
}
} // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/impl/strand_executor_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -127,6 +127,30 @@ bool strand_executor_service::running_in_this_thread(
return !!call_stack<strand_impl>::contains(impl.get());
}
bool strand_executor_service::push_waiting_to_ready(implementation_type& impl)
{
impl->mutex_->lock();
impl->ready_queue_.push(impl->waiting_queue_);
bool more_handlers = impl->locked_ = !impl->ready_queue_.empty();
impl->mutex_->unlock();
return more_handlers;
}
void strand_executor_service::run_ready_handlers(implementation_type& impl)
{
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl.get());
// 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);
}
}
} // namespace detail
} // namespace asio
} // namespace boost

View File

@@ -2,7 +2,7 @@
// detail/impl/strand_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,7 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#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>
@@ -34,29 +33,12 @@ inline strand_service::strand_impl::strand_impl()
{
}
struct strand_service::on_dispatch_exit
{
io_context_impl* io_context_;
strand_impl* impl_;
~on_dispatch_exit()
{
impl_->mutex_.lock();
impl_->ready_queue_.push(impl_->waiting_queue_);
bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();
impl_->mutex_.unlock();
if (more_handlers)
io_context_->post_immediate_completion(impl_, false);
}
};
template <typename Handler>
void strand_service::dispatch(strand_service::implementation_type& impl,
Handler& handler)
{
// If we are already in the strand then the handler can run immediately.
if (call_stack<strand_impl>::contains(impl))
if (running_in_this_thread(impl))
{
fenced_block b(fenced_block::full);
boost_asio_handler_invoke_helpers::invoke(handler, handler);
@@ -64,30 +46,17 @@ void strand_service::dispatch(strand_service::implementation_type& impl,
}
// Allocate and construct an operation to wrap the handler.
typedef completion_handler<Handler> op;
typedef completion_handler<Handler, io_context::executor_type> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_context_.get_executor());
BOOST_ASIO_HANDLER_CREATION((this->context(),
*p.p, "strand", impl, 0, "dispatch"));
bool dispatch_immediately = do_dispatch(impl, p.p);
operation* o = p.p;
p.v = p.p = 0;
if (dispatch_immediately)
{
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl);
// Ensure the next handler, if any, is scheduled on block exit.
on_dispatch_exit on_exit = { &io_context_, impl };
(void)on_exit;
completion_handler<Handler>::do_complete(
&io_context_, o, boost::system::error_code(), 0);
}
do_dispatch(impl, o);
}
// Request the io_context to invoke the given handler and return immediately.
@@ -99,10 +68,10 @@ void strand_service::post(strand_service::implementation_type& impl,
boost_asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef completion_handler<Handler> op;
typedef completion_handler<Handler, io_context::executor_type> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_context_.get_executor());
BOOST_ASIO_HANDLER_CREATION((this->context(),
*p.p, "strand", impl, 0, "post"));

View File

@@ -2,7 +2,7 @@
// detail/impl/strand_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -44,7 +44,8 @@ struct strand_service::on_do_complete_exit
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)),
io_context_(io_context),
io_context_impl_(boost::asio::use_service<io_context_impl>(io_context)),
mutex_(),
salt_(0)
{
@@ -91,18 +92,44 @@ bool strand_service::running_in_this_thread(
return call_stack<strand_impl>::contains(impl) != 0;
}
bool strand_service::do_dispatch(implementation_type& impl, operation* op)
struct strand_service::on_dispatch_exit
{
io_context_impl* io_context_impl_;
strand_impl* impl_;
~on_dispatch_exit()
{
impl_->mutex_.lock();
impl_->ready_queue_.push(impl_->waiting_queue_);
bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();
impl_->mutex_.unlock();
if (more_handlers)
io_context_impl_->post_immediate_completion(impl_, false);
}
};
void strand_service::do_dispatch(implementation_type& impl, operation* op)
{
// If we are running inside the io_context, and no other handler already
// holds the strand lock, then the handler can run immediately.
bool can_dispatch = io_context_.can_dispatch();
bool can_dispatch = io_context_impl_.can_dispatch();
impl->mutex_.lock();
if (can_dispatch && !impl->locked_)
{
// Immediate invocation is allowed.
impl->locked_ = true;
impl->mutex_.unlock();
return true;
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl);
// Ensure the next handler, if any, is scheduled on block exit.
on_dispatch_exit on_exit = { &io_context_impl_, impl };
(void)on_exit;
op->complete(&io_context_impl_, boost::system::error_code(), 0);
return;
}
if (impl->locked_)
@@ -118,10 +145,8 @@ bool strand_service::do_dispatch(implementation_type& impl, operation* op)
impl->locked_ = true;
impl->mutex_.unlock();
impl->ready_queue_.push(op);
io_context_.post_immediate_completion(impl, false);
io_context_impl_.post_immediate_completion(impl, false);
}
return false;
}
void strand_service::do_post(implementation_type& impl,
@@ -141,7 +166,7 @@ void strand_service::do_post(implementation_type& impl,
impl->locked_ = true;
impl->mutex_.unlock();
impl->ready_queue_.push(op);
io_context_.post_immediate_completion(impl, is_continuation);
io_context_impl_.post_immediate_completion(impl, is_continuation);
}
}

View File

@@ -0,0 +1,37 @@
//
// detail/impl/thread_context.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_THREAD_CONTEXT_IPP
#define BOOST_ASIO_DETAIL_IMPL_THREAD_CONTEXT_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/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
thread_info_base* thread_context::top_of_thread_call_stack()
{
return thread_call_stack::top();
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_IMPL_THREAD_CONTEXT_IPP

View File

@@ -2,7 +2,7 @@
// detail/impl/throw_error.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,7 +17,6 @@
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/detail/throw_exception.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -26,16 +25,21 @@ namespace boost {
namespace asio {
namespace detail {
void do_throw_error(const boost::system::error_code& err)
void do_throw_error(
const boost::system::error_code& err
BOOST_ASIO_SOURCE_LOCATION_PARAM)
{
boost::system::system_error e(err);
boost::asio::detail::throw_exception(e);
boost::asio::detail::throw_exception(e BOOST_ASIO_SOURCE_LOCATION_ARG);
}
void do_throw_error(const boost::system::error_code& err, const char* location)
void do_throw_error(
const boost::system::error_code& err,
const char* location
BOOST_ASIO_SOURCE_LOCATION_PARAM)
{
boost::system::system_error e(err, location);
boost::asio::detail::throw_exception(e);
boost::asio::detail::throw_exception(e BOOST_ASIO_SOURCE_LOCATION_ARG);
}
} // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/impl/timer_queue_ptime.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -76,6 +76,12 @@ 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> >::cancel_timer_by_key(
per_timer_data* timer, op_queue<operation>& ops, void* cancellation_key)
{
impl_.cancel_timer_by_key(timer, ops, cancellation_key);
}
void timer_queue<time_traits<boost::posix_time::ptime> >::move_timer(
per_timer_data& target, per_timer_data& source)
{

View File

@@ -2,7 +2,7 @@
// detail/impl/timer_queue_set.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/win_event.ipp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -0,0 +1,267 @@
//
// detail/impl/win_iocp_file_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost 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_WIN_IOCP_FILE_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_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_HAS_FILE) \
&& defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
#include <cstring>
#include <sys/stat.h>
#include <boost/asio/detail/win_iocp_file_service.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
win_iocp_file_service::win_iocp_file_service(
execution_context& context)
: execution_context_service_base<win_iocp_file_service>(context),
handle_service_(context),
nt_flush_buffers_file_ex_(0)
{
if (FARPROC nt_flush_buffers_file_ex_ptr = ::GetProcAddress(
::GetModuleHandleA("NTDLL"), "NtFlushBuffersFileEx"))
{
nt_flush_buffers_file_ex_ = reinterpret_cast<nt_flush_buffers_file_ex_fn>(
reinterpret_cast<void*>(nt_flush_buffers_file_ex_ptr));
}
}
void win_iocp_file_service::shutdown()
{
handle_service_.shutdown();
}
boost::system::error_code win_iocp_file_service::open(
win_iocp_file_service::implementation_type& impl,
const char* path, file_base::flags open_flags,
boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
DWORD access = 0;
if ((open_flags & file_base::read_only) != 0)
access = GENERIC_READ;
else if ((open_flags & file_base::write_only) != 0)
access = GENERIC_WRITE;
else if ((open_flags & file_base::read_write) != 0)
access = GENERIC_READ | GENERIC_WRITE;
DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
DWORD disposition = 0;
if ((open_flags & file_base::create) != 0)
{
if ((open_flags & file_base::exclusive) != 0)
disposition = CREATE_NEW;
else
disposition = OPEN_ALWAYS;
}
else
{
if ((open_flags & file_base::truncate) != 0)
disposition = TRUNCATE_EXISTING;
else
disposition = OPEN_EXISTING;
}
DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
if (impl.is_stream_)
flags |= FILE_FLAG_SEQUENTIAL_SCAN;
else
flags |= FILE_FLAG_RANDOM_ACCESS;
if ((open_flags & file_base::sync_all_on_write) != 0)
flags |= FILE_FLAG_WRITE_THROUGH;
HANDLE handle = ::CreateFileA(path, access, share, 0, disposition, flags, 0);
if (handle != INVALID_HANDLE_VALUE)
{
if (disposition == OPEN_ALWAYS && (open_flags & file_base::truncate) != 0)
{
if (!::SetEndOfFile(handle))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
}
handle_service_.assign(impl, handle, ec);
if (ec)
::CloseHandle(handle);
impl.offset_ = 0;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
else
{
DWORD last_error = ::GetLastError();
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
}
uint64_t win_iocp_file_service::size(
const win_iocp_file_service::implementation_type& impl,
boost::system::error_code& ec) const
{
LARGE_INTEGER result;
if (::GetFileSizeEx(native_handle(impl), &result))
{
boost::asio::error::clear(ec);
return static_cast<uint64_t>(result.QuadPart);
}
else
{
DWORD last_error = ::GetLastError();
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
}
boost::system::error_code win_iocp_file_service::resize(
win_iocp_file_service::implementation_type& impl,
uint64_t n, boost::system::error_code& ec)
{
LARGE_INTEGER distance;
distance.QuadPart = n;
if (::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN))
{
BOOL result = ::SetEndOfFile(native_handle(impl));
DWORD last_error = ::GetLastError();
distance.QuadPart = static_cast<LONGLONG>(impl.offset_);
if (!::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN))
{
result = FALSE;
last_error = ::GetLastError();
}
if (result)
boost::asio::error::clear(ec);
else
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
else
{
DWORD last_error = ::GetLastError();
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
}
boost::system::error_code win_iocp_file_service::sync_all(
win_iocp_file_service::implementation_type& impl,
boost::system::error_code& ec)
{
BOOL result = ::FlushFileBuffers(native_handle(impl));
if (result)
{
boost::asio::error::clear(ec);
return ec;
}
else
{
DWORD last_error = ::GetLastError();
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
}
boost::system::error_code win_iocp_file_service::sync_data(
win_iocp_file_service::implementation_type& impl,
boost::system::error_code& ec)
{
if (nt_flush_buffers_file_ex_)
{
io_status_block status = {};
if (!nt_flush_buffers_file_ex_(native_handle(impl),
flush_flags_file_data_sync_only, 0, 0, &status))
{
boost::asio::error::clear(ec);
return ec;
}
}
return sync_all(impl, ec);
}
uint64_t win_iocp_file_service::seek(
win_iocp_file_service::implementation_type& impl, int64_t offset,
file_base::seek_basis whence, boost::system::error_code& ec)
{
DWORD method;
switch (whence)
{
case file_base::seek_set:
method = FILE_BEGIN;
break;
case file_base::seek_cur:
method = FILE_BEGIN;
offset = static_cast<int64_t>(impl.offset_) + offset;
break;
case file_base::seek_end:
method = FILE_END;
break;
default:
ec = boost::asio::error::invalid_argument;
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
LARGE_INTEGER distance, new_offset;
distance.QuadPart = offset;
if (::SetFilePointerEx(native_handle(impl), distance, &new_offset, method))
{
impl.offset_ = new_offset.QuadPart;
boost::asio::error::clear(ec);
return impl.offset_;
}
else
{
DWORD last_error = ::GetLastError();
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_FILE)
// && defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP

View File

@@ -2,7 +2,7 @@
// detail/impl/win_iocp_handle_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -69,6 +69,7 @@ public:
win_iocp_handle_service::win_iocp_handle_service(execution_context& context)
: execution_context_service_base<win_iocp_handle_service>(context),
iocp_service_(boost::asio::use_service<win_iocp_io_context>(context)),
nt_set_info_(0),
mutex_(),
impl_list_(0)
{
@@ -183,11 +184,15 @@ boost::system::error_code win_iocp_handle_service::assign(
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
if (iocp_service_.register_handle(handle, ec))
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
impl.handle_ = handle;
ec = boost::system::error_code();
@@ -222,9 +227,47 @@ boost::system::error_code win_iocp_handle_service::close(
ec = boost::system::error_code();
}
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
win_iocp_handle_service::native_handle_type win_iocp_handle_service::release(
win_iocp_handle_service::implementation_type& impl,
boost::system::error_code& ec)
{
if (!is_open(impl))
return INVALID_HANDLE_VALUE;
cancel(impl, ec);
if (ec)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return INVALID_HANDLE_VALUE;
}
nt_set_info_fn fn = get_nt_set_info();
if (fn == 0)
{
ec = boost::asio::error::operation_not_supported;
BOOST_ASIO_ERROR_LOCATION(ec);
return INVALID_HANDLE_VALUE;
}
ULONG_PTR iosb[2] = { 0, 0 };
void* info[2] = { 0, 0 };
if (fn(impl.handle_, iosb, &info, sizeof(info),
61 /* FileReplaceCompletionInformation */))
{
ec = boost::asio::error::operation_not_supported;
BOOST_ASIO_ERROR_LOCATION(ec);
return INVALID_HANDLE_VALUE;
}
native_handle_type tmp = impl.handle_;
impl.handle_ = INVALID_HANDLE_VALUE;
return tmp;
}
boost::system::error_code win_iocp_handle_service::cancel(
win_iocp_handle_service::implementation_type& impl,
boost::system::error_code& ec)
@@ -232,6 +275,7 @@ boost::system::error_code win_iocp_handle_service::cancel(
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -243,7 +287,8 @@ boost::system::error_code win_iocp_handle_service::cancel(
{
// The version of Windows supports cancellation from any thread.
typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>(
reinterpret_cast<void*>(cancel_io_ex_ptr));
if (!cancel_io_ex(impl.handle_, 0))
{
DWORD last_error = ::GetLastError();
@@ -292,6 +337,7 @@ boost::system::error_code win_iocp_handle_service::cancel(
ec = boost::asio::error::operation_not_supported;
}
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -302,6 +348,7 @@ size_t win_iocp_handle_service::do_write(
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
@@ -315,6 +362,7 @@ size_t win_iocp_handle_service::do_write(
overlapped_wrapper overlapped(ec);
if (ec)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
@@ -330,6 +378,7 @@ size_t win_iocp_handle_service::do_write(
{
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
}
@@ -343,6 +392,7 @@ size_t win_iocp_handle_service::do_write(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
@@ -394,6 +444,7 @@ size_t win_iocp_handle_service::do_read(
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
@@ -407,6 +458,7 @@ size_t win_iocp_handle_service::do_read(
overlapped_wrapper overlapped(ec);
if (ec)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
@@ -429,6 +481,7 @@ size_t win_iocp_handle_service::do_read(
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
}
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
}
@@ -449,6 +502,7 @@ size_t win_iocp_handle_service::do_read(
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
}
BOOST_ASIO_ERROR_LOCATION(ec);
return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0;
}
@@ -515,6 +569,47 @@ void win_iocp_handle_service::close_for_destruction(implementation_type& impl)
}
}
win_iocp_handle_service::nt_set_info_fn
win_iocp_handle_service::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_handle_service::interlocked_compare_exchange_pointer(
void** dest, void* exch, void* cmp)
{
#if defined(_M_IX86)
return reinterpret_cast<void*>(InterlockedCompareExchange(
reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
reinterpret_cast<LONG>(cmp)));
#else
return InterlockedCompareExchangePointer(dest, exch, cmp);
#endif
}
void* win_iocp_handle_service::interlocked_exchange_pointer(
void** dest, void* val)
{
#if defined(_M_IX86)
return reinterpret_cast<void*>(InterlockedExchange(
reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
#else
return InterlockedExchangePointer(dest, val);
#endif
}
} // namespace detail
} // namespace asio
} // namespace boost

View File

@@ -2,7 +2,7 @@
// detail/impl/win_iocp_io_context.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -77,10 +77,27 @@ std::size_t win_iocp_io_context::cancel_timer(timer_queue<Time_Traits>& queue,
mutex::scoped_lock lock(dispatch_mutex_);
op_queue<win_iocp_operation> ops;
std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
lock.unlock();
post_deferred_completions(ops);
return n;
}
template <typename Time_Traits>
void win_iocp_io_context::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
// If the service has been shut down we silently ignore the cancellation.
if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
return;
mutex::scoped_lock lock(dispatch_mutex_);
op_queue<win_iocp_operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
post_deferred_completions(ops);
}
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,

View File

@@ -2,7 +2,7 @@
// detail/impl/win_iocp_io_context.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -52,7 +52,7 @@ struct win_iocp_io_context::thread_function
struct win_iocp_io_context::work_finished_on_block_exit
{
~work_finished_on_block_exit()
~work_finished_on_block_exit() BOOST_ASIO_NOEXCEPT_IF(false)
{
io_context_->work_finished();
}
@@ -114,6 +114,7 @@ win_iocp_io_context::~win_iocp_io_context()
{
if (thread_.get())
{
stop();
thread_->join();
thread_.reset();
}
@@ -132,6 +133,7 @@ void win_iocp_io_context::shutdown()
if (thread_.get())
{
stop();
thread_->join();
thread_.reset();
::InterlockedDecrement(&outstanding_work_);
@@ -167,7 +169,10 @@ void win_iocp_io_context::shutdown()
}
if (timer_thread_.get())
{
timer_thread_->join();
timer_thread_.reset();
}
}
boost::system::error_code win_iocp_io_context::register_handle(
@@ -199,7 +204,7 @@ size_t win_iocp_io_context::run(boost::system::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;
@@ -217,7 +222,7 @@ size_t win_iocp_io_context::run_one(boost::system::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, boost::system::error_code& ec)
@@ -232,7 +237,7 @@ size_t win_iocp_io_context::wait_one(long usec, boost::system::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(boost::system::error_code& ec)
@@ -248,7 +253,7 @@ size_t win_iocp_io_context::poll(boost::system::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;
@@ -266,7 +271,7 @@ size_t win_iocp_io_context::poll_one(boost::system::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()
@@ -286,6 +291,17 @@ void win_iocp_io_context::stop()
}
}
bool win_iocp_io_context::can_dispatch()
{
return thread_call_stack::contains(this) != 0;
}
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.
@@ -395,7 +411,8 @@ void win_iocp_io_context::on_completion(win_iocp_operation* op,
}
}
size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec)
size_t win_iocp_io_context::do_one(DWORD msec,
win_iocp_thread_info& this_thread, boost::system::error_code& ec)
{
for (;;)
{
@@ -457,6 +474,7 @@ size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec)
(void)on_exit;
op->complete(this, result_ec, bytes_transferred);
this_thread.rethrow_pending_exception();
ec = boost::system::error_code();
return 1;
}
@@ -513,6 +531,7 @@ size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec)
DWORD win_iocp_io_context::get_gqcs_timeout()
{
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600)
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
@@ -525,6 +544,9 @@ DWORD win_iocp_io_context::get_gqcs_timeout()
return INFINITE;
return default_gqcs_timeout;
#else // !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600)
return INFINITE;
#endif // !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600)
}
void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue)

View File

@@ -2,7 +2,7 @@
// detail/impl/win_iocp_serial_port_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -47,6 +47,7 @@ boost::system::error_code win_iocp_serial_port_service::open(
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -62,6 +63,7 @@ boost::system::error_code win_iocp_serial_port_service::open(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -76,21 +78,34 @@ boost::system::error_code win_iocp_serial_port_service::open(
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
// Set some default serial port parameters. This implementation does not
// support changing these, so they might as well be in a known state.
// support changing all of these, so they might as well be in a known state.
dcb.fBinary = TRUE; // Win32 only supports binary mode.
dcb.fDsrSensitivity = FALSE;
dcb.fNull = FALSE; // Do not ignore NULL characters.
dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
dcb.BaudRate = CBR_9600; // 9600 baud by default
dcb.ByteSize = 8; // 8 bit bytes
dcb.fOutxCtsFlow = FALSE; // No flow control
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fParity = FALSE; // No parity
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT; // One stop bit
if (!::SetCommState(handle, &dcb))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -109,6 +124,7 @@ boost::system::error_code win_iocp_serial_port_service::open(
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -133,6 +149,7 @@ boost::system::error_code win_iocp_serial_port_service::do_set_option(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -144,6 +161,7 @@ boost::system::error_code win_iocp_serial_port_service::do_set_option(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -166,6 +184,7 @@ boost::system::error_code win_iocp_serial_port_service::do_get_option(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}

Some files were not shown because too many files have changed in this diff Show More