executor.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. //
  2. // executor.hpp
  3. // ~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_EXECUTOR_HPP
  11. #define BOOST_ASIO_EXECUTOR_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  17. #include <new>
  18. #include <typeinfo>
  19. #include <boost/asio/detail/cstddef.hpp>
  20. #include <boost/asio/detail/executor_function.hpp>
  21. #include <boost/asio/detail/memory.hpp>
  22. #include <boost/asio/detail/throw_exception.hpp>
  23. #include <boost/asio/execution_context.hpp>
  24. #include <boost/asio/detail/push_options.hpp>
  25. namespace boost {
  26. namespace asio {
  27. /// Exception thrown when trying to access an empty polymorphic executor.
  28. class bad_executor
  29. : public std::exception
  30. {
  31. public:
  32. /// Constructor.
  33. BOOST_ASIO_DECL bad_executor() noexcept;
  34. /// Obtain message associated with exception.
  35. BOOST_ASIO_DECL virtual const char* what() const
  36. noexcept;
  37. };
  38. /// Polymorphic wrapper for executors.
  39. class executor
  40. {
  41. public:
  42. /// Default constructor.
  43. executor() noexcept
  44. : impl_(0)
  45. {
  46. }
  47. /// Construct from nullptr.
  48. executor(nullptr_t) noexcept
  49. : impl_(0)
  50. {
  51. }
  52. /// Copy constructor.
  53. executor(const executor& other) noexcept
  54. : impl_(other.clone())
  55. {
  56. }
  57. /// Move constructor.
  58. executor(executor&& other) noexcept
  59. : impl_(other.impl_)
  60. {
  61. other.impl_ = 0;
  62. }
  63. /// Construct a polymorphic wrapper for the specified executor.
  64. template <typename Executor>
  65. executor(Executor e);
  66. /// Construct a polymorphic executor that points to the same target as
  67. /// another polymorphic executor.
  68. executor(std::nothrow_t, const executor& other) noexcept
  69. : impl_(other.clone())
  70. {
  71. }
  72. /// Construct a polymorphic executor that moves the target from another
  73. /// polymorphic executor.
  74. executor(std::nothrow_t, executor&& other) noexcept
  75. : impl_(other.impl_)
  76. {
  77. other.impl_ = 0;
  78. }
  79. /// Construct a polymorphic wrapper for the specified executor.
  80. template <typename Executor>
  81. executor(std::nothrow_t, Executor e) noexcept;
  82. /// Allocator-aware constructor to create a polymorphic wrapper for the
  83. /// specified executor.
  84. template <typename Executor, typename Allocator>
  85. executor(allocator_arg_t, const Allocator& a, Executor e);
  86. /// Destructor.
  87. ~executor()
  88. {
  89. destroy();
  90. }
  91. /// Assignment operator.
  92. executor& operator=(const executor& other) noexcept
  93. {
  94. destroy();
  95. impl_ = other.clone();
  96. return *this;
  97. }
  98. // Move assignment operator.
  99. executor& operator=(executor&& other) noexcept
  100. {
  101. destroy();
  102. impl_ = other.impl_;
  103. other.impl_ = 0;
  104. return *this;
  105. }
  106. /// Assignment operator for nullptr_t.
  107. executor& operator=(nullptr_t) noexcept
  108. {
  109. destroy();
  110. impl_ = 0;
  111. return *this;
  112. }
  113. /// Assignment operator to create a polymorphic wrapper for the specified
  114. /// executor.
  115. template <typename Executor>
  116. executor& operator=(Executor&& e) noexcept
  117. {
  118. executor tmp(static_cast<Executor&&>(e));
  119. destroy();
  120. impl_ = tmp.impl_;
  121. tmp.impl_ = 0;
  122. return *this;
  123. }
  124. /// Obtain the underlying execution context.
  125. execution_context& context() const noexcept
  126. {
  127. return get_impl()->context();
  128. }
  129. /// Inform the executor that it has some outstanding work to do.
  130. void on_work_started() const noexcept
  131. {
  132. get_impl()->on_work_started();
  133. }
  134. /// Inform the executor that some work is no longer outstanding.
  135. void on_work_finished() const noexcept
  136. {
  137. get_impl()->on_work_finished();
  138. }
  139. /// Request the executor to invoke the given function object.
  140. /**
  141. * This function is used to ask the executor to execute the given function
  142. * object. The function object is executed according to the rules of the
  143. * target executor object.
  144. *
  145. * @param f The function object to be called. The executor will make a copy
  146. * of the handler object as required. The function signature of the function
  147. * object must be: @code void function(); @endcode
  148. *
  149. * @param a An allocator that may be used by the executor to allocate the
  150. * internal storage needed for function invocation.
  151. */
  152. template <typename Function, typename Allocator>
  153. void dispatch(Function&& f, const Allocator& a) const;
  154. /// Request the executor to invoke the given function object.
  155. /**
  156. * This function is used to ask the executor to execute the given function
  157. * object. The function object is executed according to the rules of the
  158. * target executor object.
  159. *
  160. * @param f The function object to be called. The executor will make
  161. * a copy of the handler object as required. The function signature of the
  162. * function object must be: @code void function(); @endcode
  163. *
  164. * @param a An allocator that may be used by the executor to allocate the
  165. * internal storage needed for function invocation.
  166. */
  167. template <typename Function, typename Allocator>
  168. void post(Function&& f, const Allocator& a) const;
  169. /// Request the executor to invoke the given function object.
  170. /**
  171. * This function is used to ask the executor to execute the given function
  172. * object. The function object is executed according to the rules of the
  173. * target executor object.
  174. *
  175. * @param f The function object to be called. The executor will make
  176. * a copy of the handler object as required. The function signature of the
  177. * function object must be: @code void function(); @endcode
  178. *
  179. * @param a An allocator that may be used by the executor to allocate the
  180. * internal storage needed for function invocation.
  181. */
  182. template <typename Function, typename Allocator>
  183. void defer(Function&& f, const Allocator& a) const;
  184. struct unspecified_bool_type_t {};
  185. typedef void (*unspecified_bool_type)(unspecified_bool_type_t);
  186. static void unspecified_bool_true(unspecified_bool_type_t) {}
  187. /// Operator to test if the executor contains a valid target.
  188. operator unspecified_bool_type() const noexcept
  189. {
  190. return impl_ ? &executor::unspecified_bool_true : 0;
  191. }
  192. /// Obtain type information for the target executor object.
  193. /**
  194. * @returns If @c *this has a target type of type @c T, <tt>typeid(T)</tt>;
  195. * otherwise, <tt>typeid(void)</tt>.
  196. */
  197. #if !defined(BOOST_ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)
  198. const std::type_info& target_type() const noexcept
  199. {
  200. return impl_ ? impl_->target_type() : typeid(void);
  201. }
  202. #else // !defined(BOOST_ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)
  203. const void* target_type() const noexcept
  204. {
  205. return impl_ ? impl_->target_type() : 0;
  206. }
  207. #endif // !defined(BOOST_ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)
  208. /// Obtain a pointer to the target executor object.
  209. /**
  210. * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored
  211. * executor target; otherwise, a null pointer.
  212. */
  213. template <typename Executor>
  214. Executor* target() noexcept;
  215. /// Obtain a pointer to the target executor object.
  216. /**
  217. * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored
  218. * executor target; otherwise, a null pointer.
  219. */
  220. template <typename Executor>
  221. const Executor* target() const noexcept;
  222. /// Compare two executors for equality.
  223. friend bool operator==(const executor& a,
  224. const executor& b) noexcept
  225. {
  226. if (a.impl_ == b.impl_)
  227. return true;
  228. if (!a.impl_ || !b.impl_)
  229. return false;
  230. return a.impl_->equals(b.impl_);
  231. }
  232. /// Compare two executors for inequality.
  233. friend bool operator!=(const executor& a,
  234. const executor& b) noexcept
  235. {
  236. return !(a == b);
  237. }
  238. private:
  239. #if !defined(GENERATING_DOCUMENTATION)
  240. typedef detail::executor_function function;
  241. template <typename, typename> class impl;
  242. #if !defined(BOOST_ASIO_NO_TYPEID)
  243. typedef const std::type_info& type_id_result_type;
  244. #else // !defined(BOOST_ASIO_NO_TYPEID)
  245. typedef const void* type_id_result_type;
  246. #endif // !defined(BOOST_ASIO_NO_TYPEID)
  247. template <typename T>
  248. static type_id_result_type type_id()
  249. {
  250. #if !defined(BOOST_ASIO_NO_TYPEID)
  251. return typeid(T);
  252. #else // !defined(BOOST_ASIO_NO_TYPEID)
  253. static int unique_id;
  254. return &unique_id;
  255. #endif // !defined(BOOST_ASIO_NO_TYPEID)
  256. }
  257. // Base class for all polymorphic executor implementations.
  258. class impl_base
  259. {
  260. public:
  261. virtual impl_base* clone() const noexcept = 0;
  262. virtual void destroy() noexcept = 0;
  263. virtual execution_context& context() noexcept = 0;
  264. virtual void on_work_started() noexcept = 0;
  265. virtual void on_work_finished() noexcept = 0;
  266. virtual void dispatch(function&&) = 0;
  267. virtual void post(function&&) = 0;
  268. virtual void defer(function&&) = 0;
  269. virtual type_id_result_type target_type() const noexcept = 0;
  270. virtual void* target() noexcept = 0;
  271. virtual const void* target() const noexcept = 0;
  272. virtual bool equals(const impl_base* e) const noexcept = 0;
  273. protected:
  274. impl_base(bool fast_dispatch) : fast_dispatch_(fast_dispatch) {}
  275. virtual ~impl_base() {}
  276. private:
  277. friend class executor;
  278. const bool fast_dispatch_;
  279. };
  280. // Helper function to check and return the implementation pointer.
  281. impl_base* get_impl() const
  282. {
  283. if (!impl_)
  284. {
  285. bad_executor ex;
  286. boost::asio::detail::throw_exception(ex);
  287. }
  288. return impl_;
  289. }
  290. // Helper function to clone another implementation.
  291. impl_base* clone() const noexcept
  292. {
  293. return impl_ ? impl_->clone() : 0;
  294. }
  295. // Helper function to destroy an implementation.
  296. void destroy() noexcept
  297. {
  298. if (impl_)
  299. impl_->destroy();
  300. }
  301. impl_base* impl_;
  302. #endif // !defined(GENERATING_DOCUMENTATION)
  303. };
  304. } // namespace asio
  305. } // namespace boost
  306. BOOST_ASIO_USES_ALLOCATOR(boost::asio::executor)
  307. #include <boost/asio/detail/pop_options.hpp>
  308. #include <boost/asio/impl/executor.hpp>
  309. #if defined(BOOST_ASIO_HEADER_ONLY)
  310. # include <boost/asio/impl/executor.ipp>
  311. #endif // defined(BOOST_ASIO_HEADER_ONLY)
  312. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  313. #endif // BOOST_ASIO_EXECUTOR_HPP