diff options
Diffstat (limited to '3rdparty/asio/include/asio/io_context.hpp')
-rw-r--r-- | 3rdparty/asio/include/asio/io_context.hpp | 894 |
1 files changed, 805 insertions, 89 deletions
diff --git a/3rdparty/asio/include/asio/io_context.hpp b/3rdparty/asio/include/asio/io_context.hpp index 44fe432c76c..7b69418c1b7 100644 --- a/3rdparty/asio/include/asio/io_context.hpp +++ b/3rdparty/asio/include/asio/io_context.hpp @@ -2,7 +2,7 @@ // io_context.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the 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,9 +20,9 @@ #include <stdexcept> #include <typeinfo> #include "asio/async_result.hpp" -#include "asio/detail/noncopyable.hpp" #include "asio/detail/wrapped_handler.hpp" #include "asio/error_code.hpp" +#include "asio/execution.hpp" #include "asio/execution_context.hpp" #if defined(ASIO_HAS_CHRONO) @@ -36,17 +36,30 @@ # include "asio/detail/signal_init.hpp" #endif +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else +# include "asio/detail/scheduler.hpp" +#endif + #include "asio/detail/push_options.hpp" namespace asio { namespace detail { #if defined(ASIO_HAS_IOCP) - typedef class win_iocp_io_context io_context_impl; + typedef win_iocp_io_context io_context_impl; class win_iocp_overlapped_ptr; #else - typedef class scheduler io_context_impl; + typedef scheduler io_context_impl; #endif + + struct io_context_bits + { + ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1); + ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 2); + ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 4); + }; } // namespace detail /// Provides core I/O functionality. @@ -64,12 +77,12 @@ namespace detail { * * @par Thread Safety * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Safe, with the specific exceptions of the restart() and - * notify_fork() functions. Calling restart() while there are unfinished run(), - * run_one(), poll() or poll_one() calls results in undefined behaviour. The - * notify_fork() function should not be called while any io_context function, - * or any function on an I/O object that is associated with the io_context, is - * being called in another thread. + * @e Shared @e objects: Safe, with the specific exceptions of the restart() + * and notify_fork() functions. Calling restart() while there are unfinished + * run(), run_one(), run_for(), run_until(), poll() or poll_one() calls results + * in undefined behaviour. The notify_fork() function should not be called + * while any io_context function, or any function on an I/O object that is + * associated with the io_context, is being called in another thread. * * @par Concepts: * Dispatcher. @@ -78,25 +91,26 @@ namespace detail { * * Synchronous operations on I/O objects implicitly run the io_context object * for an individual operation. The io_context functions run(), run_one(), - * poll() or poll_one() must be called for the io_context to perform - * asynchronous operations on behalf of a C++ program. Notification that an - * asynchronous operation has completed is delivered by invocation of the - * associated handler. Handlers are invoked only by a thread that is currently - * calling any overload of run(), run_one(), poll() or poll_one() for the - * io_context. + * run_for(), run_until(), poll() or poll_one() must be called for the + * io_context to perform asynchronous operations on behalf of a C++ program. + * Notification that an asynchronous operation has completed is delivered by + * invocation of the associated handler. Handlers are invoked only by a thread + * that is currently calling any overload of run(), run_one(), run_for(), + * run_until(), poll() or poll_one() for the io_context. * * @par Effect of exceptions thrown from handlers * * If an exception is thrown from a handler, the exception is allowed to * propagate through the throwing thread's invocation of run(), run_one(), - * poll() or poll_one(). No other threads that are calling any of these - * functions are affected. It is then the responsibility of the application to - * catch the exception. + * run_for(), run_until(), poll() or poll_one(). No other threads that are + * calling any of these functions are affected. It is then the responsibility + * of the application to catch the exception. * - * After the exception has been caught, the run(), run_one(), poll() or - * poll_one() call may be restarted @em without the need for an intervening - * call to restart(). This allows the thread to rejoin the io_context object's - * thread pool without impacting any other threads in the pool. + * After the exception has been caught, the run(), run_one(), run_for(), + * run_until(), poll() or poll_one() call may be restarted @em without the need + * for an intervening call to restart(). This allows the thread to rejoin the + * io_context object's thread pool without impacting any other threads in the + * pool. * * For example: * @@ -117,18 +131,65 @@ namespace detail { * } * @endcode * + * @par Submitting arbitrary tasks to the io_context + * + * To submit functions to the io_context, use the @ref asio::dispatch, + * @ref asio::post or @ref asio::defer free functions. + * + * For example: + * + * @code void my_task() + * { + * ... + * } + * + * ... + * + * asio::io_context io_context; + * + * // Submit a function to the io_context. + * asio::post(io_context, my_task); + * + * // Submit a lambda object to the io_context. + * asio::post(io_context, + * []() + * { + * ... + * }); + * + * // Run the io_context until it runs out of work. + * io_context.run(); @endcode + * * @par Stopping the io_context from running out of work * * Some applications may need to prevent an io_context object's run() call from * returning when there is no more work to do. For example, the io_context may * be being run in a background thread that is launched prior to the * application's asynchronous operations. The run() call may be kept running by - * creating an object of type - * asio::executor_work_guard<io_context::executor_type>: + * creating an executor that tracks work against the io_context: * * @code asio::io_context io_context; - * asio::executor_work_guard<asio::io_context::executor_type> - * = asio::make_work_guard(io_context); + * auto work = asio::require(io_context.get_executor(), + * asio::execution::outstanding_work.tracked); + * ... @endcode + * + * If using C++03, which lacks automatic variable type deduction, you may + * compute the return type of the require call: + * + * @code asio::io_context io_context; + * typename asio::require_result< + * asio::io_context::executor_type, + * asio::exeution::outstanding_work_t::tracked_t> + * work = asio::require(io_context.get_executor(), + * asio::execution::outstanding_work.tracked); + * ... @endcode + * + * or store the result in the type-erasing executor wrapper, any_io_executor: + * + * @code asio::io_context io_context; + * asio::any_io_executor work + * = asio::require(io_context.get_executor(), + * asio::execution::outstanding_work.tracked); * ... @endcode * * To effect a shutdown, the application will then need to call the io_context @@ -137,13 +198,15 @@ namespace detail { * permitting ready handlers to be dispatched. * * Alternatively, if the application requires that all operations and handlers - * be allowed to finish normally, the work object may be explicitly reset. + * be allowed to finish normally, store the work-tracking executor in an + * any_io_executor object, so that it may be explicitly reset. * * @code asio::io_context io_context; - * asio::executor_work_guard<asio::io_context::executor_type> - * = asio::make_work_guard(io_context); + * asio::any_io_executor work + * = asio::require(io_context.get_executor(), + * asio::execution::outstanding_work.tracked); * ... - * work.reset(); // Allow run() to exit. @endcode + * work = asio::any_io_executor(); // Allow run() to exit. @endcode */ class io_context : public execution_context @@ -155,8 +218,14 @@ private: #endif public: - class executor_type; - friend class executor_type; + template <typename Allocator, unsigned int Bits> + class basic_executor_type; + + template <typename Allocator, unsigned int Bits> + friend class basic_executor_type; + + /// Executor used to submit functions to an io_context. + typedef basic_executor_type<std::allocator<void>, 0> executor_type; #if !defined(ASIO_NO_DEPRECATED) class work; @@ -165,9 +234,11 @@ public: class service; -#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_EXTENSIONS) \ + && !defined(ASIO_NO_TS_EXECUTORS) class strand; #endif // !defined(ASIO_NO_EXTENSIONS) + // && !defined(ASIO_NO_TS_EXECUTORS) /// The type used to count the number of handlers executed by the context. typedef std::size_t count_type; @@ -238,9 +309,10 @@ public: * * @return The number of handlers that were executed. * - * @note The run() function must not be called from a thread that is currently - * calling one of run(), run_one(), poll() or poll_one() on the same - * io_context object. + * @note Calling the run() function from a thread that is currently calling + * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on + * the same io_context object may introduce the potential for deadlock. It is + * the caller's reponsibility to avoid this. * * The poll() function may also be used to dispatch ready handlers, but * without blocking. @@ -268,9 +340,10 @@ public: * * @return The number of handlers that were executed. * - * @note The run() function must not be called from a thread that is currently - * calling one of run(), run_one(), poll() or poll_one() on the same - * io_context object. + * @note Calling the run() function from a thread that is currently calling + * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on + * the same io_context object may introduce the potential for deadlock. It is + * the caller's reponsibility to avoid this. * * The poll() function may also be used to dispatch ready handlers, but * without blocking. @@ -318,6 +391,11 @@ public: * returns @c true). Subsequent calls to run(), run_one(), poll() or * poll_one() will return immediately unless there is a prior call to * restart(). + * + * @note Calling the run_one() function from a thread that is currently + * calling one of run(), run_one(), run_for(), run_until(), poll() or + * poll_one() on the same io_context object may introduce the potential for + * deadlock. It is the caller's reponsibility to avoid this. */ ASIO_DECL count_type run_one(); @@ -335,6 +413,11 @@ public: * restart(). * * @return The number of handlers that were executed. + * + * @note Calling the run_one() function from a thread that is currently + * calling one of run(), run_one(), run_for(), run_until(), poll() or + * poll_one() on the same io_context object may introduce the potential for + * deadlock. It is the caller's reponsibility to avoid this. */ ASIO_DECL count_type run_one(asio::error_code& ec); #endif // !defined(ASIO_NO_DEPRECATED) @@ -489,9 +572,9 @@ public: * * throws an exception. */ - template <typename CompletionHandler> - ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - dispatch(ASIO_MOVE_ARG(CompletionHandler) handler); + template <typename LegacyCompletionHandler> + ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) + dispatch(ASIO_MOVE_ARG(LegacyCompletionHandler) handler); /// (Deprecated: Use asio::post().) Request the io_context to invoke /// the given handler and return immediately. @@ -516,9 +599,9 @@ public: * * throws an exception. */ - template <typename CompletionHandler> - ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - post(ASIO_MOVE_ARG(CompletionHandler) handler); + template <typename LegacyCompletionHandler> + ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) + post(ASIO_MOVE_ARG(LegacyCompletionHandler) handler); /// (Deprecated: Use asio::bind_executor().) Create a new handler that /// automatically dispatches the wrapped handler on the io_context. @@ -552,6 +635,14 @@ public: #endif // !defined(ASIO_NO_DEPRECATED) private: + io_context(const io_context&) ASIO_DELETED; + io_context& operator=(const io_context&) ASIO_DELETED; + +#if !defined(ASIO_NO_DEPRECATED) + struct initiate_dispatch; + struct initiate_post; +#endif // !defined(ASIO_NO_DEPRECATED) + // Helper function to add the implementation. ASIO_DECL impl_type& add_impl(impl_type* impl); @@ -571,10 +662,382 @@ private: impl_type& impl_; }; -/// Executor used to submit functions to an io_context. -class io_context::executor_type +namespace detail { + +} // namespace detail + +/// Executor implementation type used to submit functions to an io_context. +template <typename Allocator, unsigned int Bits> +class io_context::basic_executor_type : detail::io_context_bits { public: + /// Copy constructor. + basic_executor_type( + const basic_executor_type& other) ASIO_NOEXCEPT + : io_context_(other.io_context_), + allocator_(other.allocator_), + bits_(other.bits_) + { + if (Bits & outstanding_work_tracked) + if (io_context_) + io_context_->impl_.work_started(); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + basic_executor_type(basic_executor_type&& other) ASIO_NOEXCEPT + : io_context_(other.io_context_), + allocator_(ASIO_MOVE_CAST(Allocator)(other.allocator_)), + bits_(other.bits_) + { + if (Bits & outstanding_work_tracked) + other.io_context_ = 0; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + ~basic_executor_type() ASIO_NOEXCEPT + { + if (Bits & outstanding_work_tracked) + if (io_context_) + io_context_->impl_.work_finished(); + } + + /// Assignment operator. + basic_executor_type& operator=( + const basic_executor_type& other) ASIO_NOEXCEPT; + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move assignment operator. + basic_executor_type& operator=( + basic_executor_type&& other) ASIO_NOEXCEPT; +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +#if !defined(GENERATING_DOCUMENTATION) +private: + friend struct asio_require_fn::impl; + friend struct asio_prefer_fn::impl; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Obtain an executor with the @c blocking.possibly property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.possibly); @endcode + */ + ASIO_CONSTEXPR basic_executor_type require( + execution::blocking_t::possibly_t) const + { + return basic_executor_type(io_context_, + allocator_, bits_ & ~blocking_never); + } + + /// Obtain an executor with the @c blocking.never property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.never); @endcode + */ + ASIO_CONSTEXPR basic_executor_type require( + execution::blocking_t::never_t) const + { + return basic_executor_type(io_context_, + allocator_, bits_ | blocking_never); + } + + /// Obtain an executor with the @c relationship.fork property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::relationship.fork); @endcode + */ + ASIO_CONSTEXPR basic_executor_type require( + execution::relationship_t::fork_t) const + { + return basic_executor_type(io_context_, + allocator_, bits_ & ~relationship_continuation); + } + + /// Obtain an executor with the @c relationship.continuation property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::relationship.continuation); @endcode + */ + ASIO_CONSTEXPR basic_executor_type require( + execution::relationship_t::continuation_t) const + { + return basic_executor_type(io_context_, + allocator_, bits_ | relationship_continuation); + } + + /// Obtain an executor with the @c outstanding_work.tracked property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::outstanding_work.tracked); @endcode + */ + ASIO_CONSTEXPR basic_executor_type<Allocator, + ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)> + require(execution::outstanding_work_t::tracked_t) const + { + return basic_executor_type<Allocator, Bits | outstanding_work_tracked>( + io_context_, allocator_, bits_); + } + + /// Obtain an executor with the @c outstanding_work.untracked property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::outstanding_work.untracked); @endcode + */ + ASIO_CONSTEXPR basic_executor_type<Allocator, + ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)> + require(execution::outstanding_work_t::untracked_t) const + { + return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>( + io_context_, allocator_, bits_); + } + + /// Obtain an executor with the specified @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::allocator(my_allocator)); @endcode + */ + template <typename OtherAllocator> + ASIO_CONSTEXPR basic_executor_type<OtherAllocator, Bits> + require(execution::allocator_t<OtherAllocator> a) const + { + return basic_executor_type<OtherAllocator, Bits>( + io_context_, a.value(), bits_); + } + + /// Obtain an executor with the default @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::allocator); @endcode + */ + ASIO_CONSTEXPR basic_executor_type<std::allocator<void>, Bits> + require(execution::allocator_t<void>) const + { + return basic_executor_type<std::allocator<void>, Bits>( + io_context_, std::allocator<void>(), bits_); + } + +#if !defined(GENERATING_DOCUMENTATION) +private: + friend struct asio_query_fn::impl; + friend struct asio::execution::detail::mapping_t<0>; + friend struct asio::execution::detail::outstanding_work_t<0>; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Query the current value of the @c mapping property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * if (asio::query(ex, asio::execution::mapping) + * == asio::execution::mapping.thread) + * ... @endcode + */ + static ASIO_CONSTEXPR execution::mapping_t query( + execution::mapping_t) ASIO_NOEXCEPT + { + return execution::mapping.thread; + } + + /// Query the current value of the @c context property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * asio::io_context& ctx = asio::query( + * ex, asio::execution::context); @endcode + */ + io_context& query(execution::context_t) const ASIO_NOEXCEPT + { + return *io_context_; + } + + /// Query the current value of the @c blocking property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * if (asio::query(ex, asio::execution::blocking) + * == asio::execution::blocking.always) + * ... @endcode + */ + ASIO_CONSTEXPR execution::blocking_t query( + execution::blocking_t) const ASIO_NOEXCEPT + { + return (bits_ & blocking_never) + ? execution::blocking_t(execution::blocking.never) + : execution::blocking_t(execution::blocking.possibly); + } + + /// Query the current value of the @c relationship property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * if (asio::query(ex, asio::execution::relationship) + * == asio::execution::relationship.continuation) + * ... @endcode + */ + ASIO_CONSTEXPR execution::relationship_t query( + execution::relationship_t) const ASIO_NOEXCEPT + { + return (bits_ & relationship_continuation) + ? execution::relationship_t(execution::relationship.continuation) + : execution::relationship_t(execution::relationship.fork); + } + + /// Query the current value of the @c outstanding_work property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * if (asio::query(ex, asio::execution::outstanding_work) + * == asio::execution::outstanding_work.tracked) + * ... @endcode + */ + static ASIO_CONSTEXPR execution::outstanding_work_t query( + execution::outstanding_work_t) ASIO_NOEXCEPT + { + return (Bits & outstanding_work_tracked) + ? execution::outstanding_work_t(execution::outstanding_work.tracked) + : execution::outstanding_work_t(execution::outstanding_work.untracked); + } + + /// Query the current value of the @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * auto alloc = asio::query(ex, + * asio::execution::allocator); @endcode + */ + template <typename OtherAllocator> + ASIO_CONSTEXPR Allocator query( + execution::allocator_t<OtherAllocator>) const ASIO_NOEXCEPT + { + return allocator_; + } + + /// Query the current value of the @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * auto alloc = asio::query(ex, + * asio::execution::allocator); @endcode + */ + ASIO_CONSTEXPR Allocator query( + execution::allocator_t<void>) const ASIO_NOEXCEPT + { + return allocator_; + } + +public: + /// Determine whether the io_context is running in the current thread. + /** + * @return @c true if the current thread is running the io_context. Otherwise + * returns @c false. + */ + bool running_in_this_thread() const ASIO_NOEXCEPT; + + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator==(const basic_executor_type& a, + const basic_executor_type& b) ASIO_NOEXCEPT + { + return a.io_context_ == b.io_context_ + && a.allocator_ == b.allocator_ + && a.bits_ == b.bits_; + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator!=(const basic_executor_type& a, + const basic_executor_type& b) ASIO_NOEXCEPT + { + return a.io_context_ != b.io_context_ + || a.allocator_ != b.allocator_ + || a.bits_ != b.bits_; + } + +#if !defined(GENERATING_DOCUMENTATION) +private: + friend struct asio_execution_execute_fn::impl; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Execution function. + /** + * Do not call this function directly. It is intended for use with the + * execution::execute customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * execution::execute(ex, my_function_object); @endcode + */ + template <typename Function> + void execute(ASIO_MOVE_ARG(Function) f) const; + +#if !defined(ASIO_NO_TS_EXECUTORS) +public: /// Obtain the underlying execution context. io_context& context() const ASIO_NOEXCEPT; @@ -608,8 +1071,9 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void dispatch(ASIO_MOVE_ARG(Function) f, + const OtherAllocator& a) const; /// Request the io_context to invoke the given function object. /** @@ -624,8 +1088,9 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void post(ASIO_MOVE_ARG(Function) f, + const OtherAllocator& a) const; /// Request the io_context to invoke the given function object. /** @@ -644,44 +1109,45 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void defer(ASIO_MOVE_ARG(Function) f, + const OtherAllocator& a) const; +#endif // !defined(ASIO_NO_TS_EXECUTORS) - /// Determine whether the io_context is running in the current thread. - /** - * @return @c true if the current thread is running the io_context. Otherwise - * returns @c false. - */ - bool running_in_this_thread() const ASIO_NOEXCEPT; +private: + friend class io_context; + template <typename, unsigned int> friend class basic_executor_type; - /// Compare two executors for equality. - /** - * Two executors are equal if they refer to the same underlying io_context. - */ - friend bool operator==(const executor_type& a, - const executor_type& b) ASIO_NOEXCEPT + // Constructor used by io_context::get_executor(). + explicit basic_executor_type(io_context& i) ASIO_NOEXCEPT + : io_context_(&i), + allocator_(), + bits_(0) { - return &a.io_context_ == &b.io_context_; + if (Bits & outstanding_work_tracked) + io_context_->impl_.work_started(); } - /// Compare two executors for inequality. - /** - * Two executors are equal if they refer to the same underlying io_context. - */ - friend bool operator!=(const executor_type& a, - const executor_type& b) ASIO_NOEXCEPT + // Constructor used by require(). + basic_executor_type(io_context* i, + const Allocator& a, unsigned int bits) ASIO_NOEXCEPT + : io_context_(i), + allocator_(a), + bits_(bits) { - return &a.io_context_ != &b.io_context_; + if (Bits & outstanding_work_tracked) + if (io_context_) + io_context_->impl_.work_started(); } -private: - friend class io_context; + // The underlying io_context. + io_context* io_context_; - // Constructor. - explicit executor_type(io_context& i) : io_context_(i) {} + // The allocator used for execution functions. + Allocator allocator_; - // The underlying io_context. - io_context& io_context_; + // The runtime-switched properties of the io_context executor. + unsigned int bits_; }; #if !defined(ASIO_NO_DEPRECATED) @@ -726,10 +1192,6 @@ public: /// Get the io_context associated with the work. asio::io_context& get_io_context(); - /// (Deprecated: Use get_io_context().) Get the io_context associated with the - /// work. - asio::io_context& get_io_service(); - private: // Prevent assignment. void operator=(const work& other); @@ -747,11 +1209,6 @@ public: /// Get the io_context object that owns the service. asio::io_context& get_io_context(); -#if !defined(ASIO_NO_DEPRECATED) - /// Get the io_context object that owns the service. - asio::io_context& get_io_service(); -#endif // !defined(ASIO_NO_DEPRECATED) - private: /// Destroy all user-defined handler objects owned by the service. ASIO_DECL virtual void shutdown(); @@ -814,6 +1271,265 @@ template <typename Type> asio::detail::service_id<Type> service_base<Type>::id; } // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <typename Allocator, unsigned int Bits> +struct equality_comparable< + asio::io_context::basic_executor_type<Allocator, Bits> + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename Allocator, unsigned int Bits, typename Function> +struct execute_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + Function + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::blocking_t::possibly_t + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::blocking_t::never_t + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::relationship_t::fork_t + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::relationship_t::continuation_t + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::outstanding_work_t::tracked_t + > : asio::detail::io_context_bits +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef asio::io_context::basic_executor_type< + Allocator, Bits | outstanding_work_tracked> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::outstanding_work_t::untracked_t + > : asio::detail::io_context_bits +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef asio::io_context::basic_executor_type< + Allocator, Bits & ~outstanding_work_tracked> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<void> + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef asio::io_context::basic_executor_type< + std::allocator<void>, Bits> result_type; +}; + +template <unsigned int Bits, + typename Allocator, typename OtherAllocator> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<OtherAllocator> + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef asio::io_context::basic_executor_type< + OtherAllocator, Bits> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template <typename Allocator, unsigned int Bits, typename Property> +struct query_static_constexpr_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::outstanding_work_t + >::value + >::type + > : asio::detail::io_context_bits +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef asio::execution::outstanding_work_t result_type; + + static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT + { + return (Bits & outstanding_work_tracked) + ? execution::outstanding_work_t(execution::outstanding_work.tracked) + : execution::outstanding_work_t(execution::outstanding_work.untracked); + } +}; + +template <typename Allocator, unsigned int Bits, typename Property> +struct query_static_constexpr_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::mapping_t + >::value + >::type + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef asio::execution::mapping_t::thread_t result_type; + + static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT + { + return result_type(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename Allocator, unsigned int Bits, typename Property> +struct query_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::blocking_t + >::value + >::type + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef asio::execution::blocking_t result_type; +}; + +template <typename Allocator, unsigned int Bits, typename Property> +struct query_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::relationship_t + >::value + >::type + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef asio::execution::relationship_t result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct query_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::context_t + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef asio::io_context& result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct query_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<void> + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef Allocator result_type; +}; + +template <typename Allocator, unsigned int Bits, typename OtherAllocator> +struct query_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<OtherAllocator> + > +{ + ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef Allocator result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + } // namespace asio #include "asio/detail/pop_options.hpp" |