From 4e405c20182e5e3d3ff3175b6c672a14148f2cd3 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 25 Oct 2021 11:57:14 +1100 Subject: [PATCH] Reduce size of io_context executors to a single pointer. --- include/boost/asio/detail/cstdint.hpp | 2 + include/boost/asio/impl/io_context.hpp | 88 +++++++------- include/boost/asio/io_context.hpp | 151 +++++++++++++------------ 3 files changed, 122 insertions(+), 119 deletions(-) diff --git a/include/boost/asio/detail/cstdint.hpp b/include/boost/asio/detail/cstdint.hpp index f309bf8b..5e827958 100644 --- a/include/boost/asio/detail/cstdint.hpp +++ b/include/boost/asio/detail/cstdint.hpp @@ -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) diff --git a/include/boost/asio/impl/io_context.hpp b/include/boost/asio/impl/io_context.hpp index 0b414891..2f0f0e6d 100644 --- a/include/boost/asio/impl/io_context.hpp +++ b/include/boost/asio/impl/io_context.hpp @@ -214,21 +214,20 @@ io_context::wrap(Handler handler) #endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template +template io_context::basic_executor_type& io_context::basic_executor_type::operator=( const basic_executor_type& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { - io_context* old_io_context = io_context_; - io_context_ = other.io_context_; - allocator_ = other.allocator_; - bits_ = other.bits_; + static_cast(*this) = static_cast(other); + io_context* old_io_context = context_ptr(); + target_ = other.target_; if (Bits & outstanding_work_tracked) { - if (io_context_) - io_context_->impl_.work_started(); + if (context_ptr()) + context_ptr()->impl_.work_started(); if (old_io_context) old_io_context->impl_.work_finished(); } @@ -237,20 +236,19 @@ io_context::basic_executor_type::operator=( } #if defined(BOOST_ASIO_HAS_MOVE) -template +template io_context::basic_executor_type& io_context::basic_executor_type::operator=( basic_executor_type&& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { - io_context* old_io_context = io_context_; - io_context_ = other.io_context_; - allocator_ = std::move(other.allocator_); - bits_ = other.bits_; + static_cast(*this) = static_cast(other); + io_context* old_io_context = context_ptr(); + target_ = other.target_; if (Bits & outstanding_work_tracked) { - other.io_context_ = 0; + other.target_ = 0; if (old_io_context) old_io_context->impl_.work_finished(); } @@ -259,14 +257,14 @@ io_context::basic_executor_type::operator=( } #endif // defined(BOOST_ASIO_HAS_MOVE) -template +template inline bool io_context::basic_executor_type::running_in_this_thread() const BOOST_ASIO_NOEXCEPT { - return io_context_->impl_.can_dispatch(); + return context_ptr()->impl_.can_dispatch(); } -template +template template void io_context::basic_executor_type::execute( BOOST_ASIO_MOVE_ARG(Function) f) const @@ -275,7 +273,7 @@ void io_context::basic_executor_type::execute( // Invoke immediately if the blocking.possibly property is enabled and we are // already inside the thread pool. - if ((bits_ & blocking_never) == 0 && io_context_->impl_.can_dispatch()) + if ((bits() & blocking_never) == 0 && context_ptr()->impl_.can_dispatch()) { // Make a local, non-const copy of the function. function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); @@ -294,7 +292,7 @@ void io_context::basic_executor_type::execute( } catch (...) { - io_context_->impl_.capture_current_exception(); + context_ptr()->impl_.capture_current_exception(); return; } #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) @@ -303,41 +301,43 @@ void io_context::basic_executor_type::execute( // Allocate and construct an operation to wrap the function. typedef detail::executor_op op; - typename op::ptr p = { detail::addressof(allocator_), - op::ptr::allocate(allocator_), 0 }; - p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); + typename op::ptr p = { + detail::addressof(static_cast(*this)), + op::ptr::allocate(static_cast(*this)), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), + static_cast(*this)); - BOOST_ASIO_HANDLER_CREATION((*io_context_, *p.p, - "io_context", io_context_, 0, "execute")); + BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p, + "io_context", context_ptr(), 0, "execute")); - io_context_->impl_.post_immediate_completion(p.p, - (bits_ & relationship_continuation) != 0); + context_ptr()->impl_.post_immediate_completion(p.p, + (bits() & relationship_continuation) != 0); p.v = p.p = 0; } #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) -template +template inline io_context& io_context::basic_executor_type< Allocator, Bits>::context() const BOOST_ASIO_NOEXCEPT { - return *io_context_; + return *context_ptr(); } -template +template inline void io_context::basic_executor_type::on_work_started() const BOOST_ASIO_NOEXCEPT { - io_context_->impl_.work_started(); + context_ptr()->impl_.work_started(); } -template +template inline void io_context::basic_executor_type::on_work_finished() const BOOST_ASIO_NOEXCEPT { - io_context_->impl_.work_finished(); + context_ptr()->impl_.work_finished(); } -template +template template void io_context::basic_executor_type::dispatch( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const @@ -345,7 +345,7 @@ void io_context::basic_executor_type::dispatch( typedef typename decay::type function_type; // Invoke immediately if we are already inside the thread pool. - if (io_context_->impl_.can_dispatch()) + if (context_ptr()->impl_.can_dispatch()) { // Make a local, non-const copy of the function. function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); @@ -361,14 +361,14 @@ void io_context::basic_executor_type::dispatch( typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); - BOOST_ASIO_HANDLER_CREATION((*io_context_, *p.p, - "io_context", io_context_, 0, "dispatch")); + BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p, + "io_context", context_ptr(), 0, "dispatch")); - io_context_->impl_.post_immediate_completion(p.p, false); + context_ptr()->impl_.post_immediate_completion(p.p, false); p.v = p.p = 0; } -template +template template void io_context::basic_executor_type::post( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const @@ -381,14 +381,14 @@ void io_context::basic_executor_type::post( typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); - BOOST_ASIO_HANDLER_CREATION((*io_context_, *p.p, - "io_context", io_context_, 0, "post")); + BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p, + "io_context", context_ptr(), 0, "post")); - io_context_->impl_.post_immediate_completion(p.p, false); + context_ptr()->impl_.post_immediate_completion(p.p, false); p.v = p.p = 0; } -template +template template void io_context::basic_executor_type::defer( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const @@ -401,10 +401,10 @@ void io_context::basic_executor_type::defer( typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); - BOOST_ASIO_HANDLER_CREATION((*io_context_, *p.p, - "io_context", io_context_, 0, "defer")); + BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p, + "io_context", context_ptr(), 0, "defer")); - io_context_->impl_.post_immediate_completion(p.p, true); + context_ptr()->impl_.post_immediate_completion(p.p, true); p.v = p.p = 0; } #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) diff --git a/include/boost/asio/io_context.hpp b/include/boost/asio/io_context.hpp index 791a5f7d..3ece6f16 100644 --- a/include/boost/asio/io_context.hpp +++ b/include/boost/asio/io_context.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -57,9 +58,10 @@ namespace detail { struct io_context_bits { - BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1); - BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 2); - BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 4); + BOOST_ASIO_STATIC_CONSTEXPR(uintptr_t, blocking_never = 1); + BOOST_ASIO_STATIC_CONSTEXPR(uintptr_t, relationship_continuation = 2); + BOOST_ASIO_STATIC_CONSTEXPR(uintptr_t, outstanding_work_tracked = 4); + BOOST_ASIO_STATIC_CONSTEXPR(uintptr_t, runtime_bits = 3); }; } // namespace detail @@ -219,10 +221,10 @@ private: #endif public: - template + template class basic_executor_type; - template + template friend class basic_executor_type; /// Executor used to submit functions to an io_context. @@ -668,31 +670,30 @@ namespace detail { } // namespace detail /// Executor implementation type used to submit functions to an io_context. -template -class io_context::basic_executor_type : detail::io_context_bits +template +class io_context::basic_executor_type : + detail::io_context_bits, Allocator { public: /// Copy constructor. basic_executor_type( const basic_executor_type& other) BOOST_ASIO_NOEXCEPT - : io_context_(other.io_context_), - allocator_(other.allocator_), - bits_(other.bits_) + : Allocator(static_cast(other)), + target_(other.target_) { if (Bits & outstanding_work_tracked) - if (io_context_) - io_context_->impl_.work_started(); + if (context_ptr()) + context_ptr()->impl_.work_started(); } #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move constructor. basic_executor_type(basic_executor_type&& other) BOOST_ASIO_NOEXCEPT - : io_context_(other.io_context_), - allocator_(BOOST_ASIO_MOVE_CAST(Allocator)(other.allocator_)), - bits_(other.bits_) + : Allocator(BOOST_ASIO_MOVE_CAST(Allocator)(other)), + target_(other.target_) { if (Bits & outstanding_work_tracked) - other.io_context_ = 0; + other.target_ = 0; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) @@ -700,8 +701,8 @@ public: ~basic_executor_type() BOOST_ASIO_NOEXCEPT { if (Bits & outstanding_work_tracked) - if (io_context_) - io_context_->impl_.work_finished(); + if (context_ptr()) + context_ptr()->impl_.work_finished(); } /// Assignment operator. @@ -733,8 +734,8 @@ private: BOOST_ASIO_CONSTEXPR basic_executor_type require( execution::blocking_t::possibly_t) const { - return basic_executor_type(io_context_, - allocator_, bits_ & ~blocking_never); + return basic_executor_type(context_ptr(), + *this, bits() & ~blocking_never); } /// Obtain an executor with the @c blocking.never property. @@ -750,8 +751,8 @@ private: BOOST_ASIO_CONSTEXPR basic_executor_type require( execution::blocking_t::never_t) const { - return basic_executor_type(io_context_, - allocator_, bits_ | blocking_never); + return basic_executor_type(context_ptr(), + *this, bits() | blocking_never); } /// Obtain an executor with the @c relationship.fork property. @@ -767,8 +768,8 @@ private: BOOST_ASIO_CONSTEXPR basic_executor_type require( execution::relationship_t::fork_t) const { - return basic_executor_type(io_context_, - allocator_, bits_ & ~relationship_continuation); + return basic_executor_type(context_ptr(), + *this, bits() & ~relationship_continuation); } /// Obtain an executor with the @c relationship.continuation property. @@ -784,8 +785,8 @@ private: BOOST_ASIO_CONSTEXPR basic_executor_type require( execution::relationship_t::continuation_t) const { - return basic_executor_type(io_context_, - allocator_, bits_ | relationship_continuation); + return basic_executor_type(context_ptr(), + *this, bits() | relationship_continuation); } /// Obtain an executor with the @c outstanding_work.tracked property. @@ -803,7 +804,7 @@ private: require(execution::outstanding_work_t::tracked_t) const { return basic_executor_type( - io_context_, allocator_, bits_); + context_ptr(), *this, bits()); } /// Obtain an executor with the @c outstanding_work.untracked property. @@ -821,7 +822,7 @@ private: require(execution::outstanding_work_t::untracked_t) const { return basic_executor_type( - io_context_, allocator_, bits_); + context_ptr(), *this, bits()); } /// Obtain an executor with the specified @c allocator property. @@ -839,7 +840,7 @@ private: require(execution::allocator_t a) const { return basic_executor_type( - io_context_, a.value(), bits_); + context_ptr(), a.value(), bits()); } /// Obtain an executor with the default @c allocator property. @@ -856,7 +857,7 @@ private: require(execution::allocator_t) const { return basic_executor_type, Bits>( - io_context_, std::allocator(), bits_); + context_ptr(), std::allocator(), bits()); } #if !defined(GENERATING_DOCUMENTATION) @@ -895,7 +896,7 @@ private: */ io_context& query(execution::context_t) const BOOST_ASIO_NOEXCEPT { - return *io_context_; + return *context_ptr(); } /// Query the current value of the @c blocking property. @@ -912,7 +913,7 @@ private: BOOST_ASIO_CONSTEXPR execution::blocking_t query( execution::blocking_t) const BOOST_ASIO_NOEXCEPT { - return (bits_ & blocking_never) + return (bits() & blocking_never) ? execution::blocking_t(execution::blocking.never) : execution::blocking_t(execution::blocking.possibly); } @@ -931,7 +932,7 @@ private: BOOST_ASIO_CONSTEXPR execution::relationship_t query( execution::relationship_t) const BOOST_ASIO_NOEXCEPT { - return (bits_ & relationship_continuation) + return (bits() & relationship_continuation) ? execution::relationship_t(execution::relationship.continuation) : execution::relationship_t(execution::relationship.fork); } @@ -969,7 +970,7 @@ private: BOOST_ASIO_CONSTEXPR Allocator query( execution::allocator_t) const BOOST_ASIO_NOEXCEPT { - return allocator_; + return static_cast(*this); } /// Query the current value of the @c allocator property. @@ -985,7 +986,7 @@ private: BOOST_ASIO_CONSTEXPR Allocator query( execution::allocator_t) const BOOST_ASIO_NOEXCEPT { - return allocator_; + return static_cast(*this); } public: @@ -1003,9 +1004,8 @@ public: friend bool operator==(const basic_executor_type& a, const basic_executor_type& b) BOOST_ASIO_NOEXCEPT { - return a.io_context_ == b.io_context_ - && a.allocator_ == b.allocator_ - && a.bits_ == b.bits_; + return a.target_ == b.target_ + && static_cast(a) == static_cast(b); } /// Compare two executors for inequality. @@ -1015,9 +1015,8 @@ public: friend bool operator!=(const basic_executor_type& a, const basic_executor_type& b) BOOST_ASIO_NOEXCEPT { - return a.io_context_ != b.io_context_ - || a.allocator_ != b.allocator_ - || a.bits_ != b.bits_; + return a.target_ != b.target_ + || static_cast(a) != static_cast(b); } #if !defined(GENERATING_DOCUMENTATION) @@ -1117,38 +1116,40 @@ public: private: friend class io_context; - template friend class basic_executor_type; + template friend class basic_executor_type; // Constructor used by io_context::get_executor(). explicit basic_executor_type(io_context& i) BOOST_ASIO_NOEXCEPT - : io_context_(&i), - allocator_(), - bits_(0) + : Allocator(), + target_(reinterpret_cast(&i)) { if (Bits & outstanding_work_tracked) - io_context_->impl_.work_started(); + context_ptr()->impl_.work_started(); } // Constructor used by require(). basic_executor_type(io_context* i, - const Allocator& a, unsigned int bits) BOOST_ASIO_NOEXCEPT - : io_context_(i), - allocator_(a), - bits_(bits) + const Allocator& a, uintptr_t bits) BOOST_ASIO_NOEXCEPT + : Allocator(a), + target_(reinterpret_cast(i) | bits) { if (Bits & outstanding_work_tracked) - if (io_context_) - io_context_->impl_.work_started(); + if (context_ptr()) + context_ptr()->impl_.work_started(); } - // The underlying io_context. - io_context* io_context_; + io_context* context_ptr() const BOOST_ASIO_NOEXCEPT + { + return reinterpret_cast(target_ & ~runtime_bits); + } - // The allocator used for execution functions. - Allocator allocator_; + uintptr_t bits() const BOOST_ASIO_NOEXCEPT + { + return target_ & runtime_bits; + } - // The runtime-switched properties of the io_context executor. - unsigned int bits_; + // The underlying io_context and runtime bits. + uintptr_t target_; }; #if !defined(BOOST_ASIO_NO_DEPRECATED) @@ -1279,7 +1280,7 @@ namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) -template +template struct equality_comparable< boost::asio::io_context::basic_executor_type > @@ -1292,7 +1293,7 @@ struct equality_comparable< #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) -template +template struct execute_member< boost::asio::io_context::basic_executor_type, Function @@ -1307,7 +1308,7 @@ struct execute_member< #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) -template +template struct require_member< boost::asio::io_context::basic_executor_type, boost::asio::execution::blocking_t::possibly_t @@ -1319,7 +1320,7 @@ struct require_member< Allocator, Bits> result_type; }; -template +template struct require_member< boost::asio::io_context::basic_executor_type, boost::asio::execution::blocking_t::never_t @@ -1331,7 +1332,7 @@ struct require_member< Allocator, Bits> result_type; }; -template +template struct require_member< boost::asio::io_context::basic_executor_type, boost::asio::execution::relationship_t::fork_t @@ -1343,7 +1344,7 @@ struct require_member< Allocator, Bits> result_type; }; -template +template struct require_member< boost::asio::io_context::basic_executor_type, boost::asio::execution::relationship_t::continuation_t @@ -1355,7 +1356,7 @@ struct require_member< Allocator, Bits> result_type; }; -template +template struct require_member< boost::asio::io_context::basic_executor_type, boost::asio::execution::outstanding_work_t::tracked_t @@ -1367,7 +1368,7 @@ struct require_member< Allocator, Bits | outstanding_work_tracked> result_type; }; -template +template struct require_member< boost::asio::io_context::basic_executor_type, boost::asio::execution::outstanding_work_t::untracked_t @@ -1379,7 +1380,7 @@ struct require_member< Allocator, Bits & ~outstanding_work_tracked> result_type; }; -template +template struct require_member< boost::asio::io_context::basic_executor_type, boost::asio::execution::allocator_t @@ -1391,7 +1392,7 @@ struct require_member< std::allocator, Bits> result_type; }; -template struct require_member< boost::asio::io_context::basic_executor_type, @@ -1408,7 +1409,7 @@ struct require_member< #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) -template +template struct query_static_constexpr_member< boost::asio::io_context::basic_executor_type, Property, @@ -1432,7 +1433,7 @@ struct query_static_constexpr_member< } }; -template +template struct query_static_constexpr_member< boost::asio::io_context::basic_executor_type, Property, @@ -1458,7 +1459,7 @@ struct query_static_constexpr_member< #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) -template +template struct query_member< boost::asio::io_context::basic_executor_type, Property, @@ -1475,7 +1476,7 @@ struct query_member< typedef boost::asio::execution::blocking_t result_type; }; -template +template struct query_member< boost::asio::io_context::basic_executor_type, Property, @@ -1492,7 +1493,7 @@ struct query_member< typedef boost::asio::execution::relationship_t result_type; }; -template +template struct query_member< boost::asio::io_context::basic_executor_type, boost::asio::execution::context_t @@ -1503,7 +1504,7 @@ struct query_member< typedef boost::asio::io_context& result_type; }; -template +template struct query_member< boost::asio::io_context::basic_executor_type, boost::asio::execution::allocator_t @@ -1514,7 +1515,7 @@ struct query_member< typedef Allocator result_type; }; -template +template struct query_member< boost::asio::io_context::basic_executor_type, boost::asio::execution::allocator_t