executor.hpp 10 KB

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