execution_context.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. //
  2. // execution_context.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2025 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_EXECUTION_CONTEXT_HPP
  11. #define BOOST_ASIO_EXECUTION_CONTEXT_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. #include <cstddef>
  17. #include <stdexcept>
  18. #include <typeinfo>
  19. #include <boost/asio/detail/memory.hpp>
  20. #include <boost/asio/detail/noncopyable.hpp>
  21. #include <boost/asio/detail/push_options.hpp>
  22. namespace boost {
  23. namespace asio {
  24. class execution_context;
  25. class io_context;
  26. #if !defined(GENERATING_DOCUMENTATION)
  27. template <typename Service> Service& use_service(execution_context&);
  28. template <typename Service> Service& use_service(io_context&);
  29. template <typename Service> void add_service(execution_context&, Service*);
  30. template <typename Service> bool has_service(execution_context&);
  31. #endif // !defined(GENERATING_DOCUMENTATION)
  32. namespace detail { class service_registry; }
  33. /// A context for function object execution.
  34. /**
  35. * An execution context represents a place where function objects will be
  36. * executed. An @c io_context is an example of an execution context.
  37. *
  38. * @par The execution_context class and services
  39. *
  40. * Class execution_context implements an extensible, type-safe, polymorphic set
  41. * of services, indexed by service type.
  42. *
  43. * Services exist to manage the resources that are shared across an execution
  44. * context. For example, timers may be implemented in terms of a single timer
  45. * queue, and this queue would be stored in a service.
  46. *
  47. * Access to the services of an execution_context is via three function
  48. * templates, use_service(), add_service() and has_service().
  49. *
  50. * In a call to @c use_service<Service>(), the type argument chooses a service,
  51. * making available all members of the named type. If @c Service is not present
  52. * in an execution_context, an object of type @c Service is created and added
  53. * to the execution_context. A C++ program can check if an execution_context
  54. * implements a particular service with the function template @c
  55. * has_service<Service>().
  56. *
  57. * Service objects may be explicitly added to an execution_context using the
  58. * function template @c add_service<Service>(). If the @c Service is already
  59. * present, the service_already_exists exception is thrown. If the owner of the
  60. * service is not the same object as the execution_context parameter, the
  61. * invalid_service_owner exception is thrown.
  62. *
  63. * Once a service reference is obtained from an execution_context object by
  64. * calling use_service(), that reference remains usable as long as the owning
  65. * execution_context object exists.
  66. *
  67. * All service implementations have execution_context::service as a public base
  68. * class. Custom services may be implemented by deriving from this class and
  69. * then added to an execution_context using the facilities described above.
  70. *
  71. * @par The execution_context as a base class
  72. *
  73. * Class execution_context may be used only as a base class for concrete
  74. * execution context types. The @c io_context is an example of such a derived
  75. * type.
  76. *
  77. * On destruction, a class that is derived from execution_context must perform
  78. * <tt>execution_context::shutdown()</tt> followed by
  79. * <tt>execution_context::destroy()</tt>.
  80. *
  81. * This destruction sequence permits programs to simplify their resource
  82. * management by using @c shared_ptr<>. Where an object's lifetime is tied to
  83. * the lifetime of a connection (or some other sequence of asynchronous
  84. * operations), a @c shared_ptr to the object would be bound into the handlers
  85. * for all asynchronous operations associated with it. This works as follows:
  86. *
  87. * @li When a single connection ends, all associated asynchronous operations
  88. * complete. The corresponding handler objects are destroyed, and all @c
  89. * shared_ptr references to the objects are destroyed.
  90. *
  91. * @li To shut down the whole program, the io_context function stop() is called
  92. * to terminate any run() calls as soon as possible. The io_context destructor
  93. * calls @c shutdown() and @c destroy() to destroy all pending handlers,
  94. * causing all @c shared_ptr references to all connection objects to be
  95. * destroyed.
  96. */
  97. class execution_context
  98. : private noncopyable
  99. {
  100. public:
  101. template <typename T> class allocator;
  102. class id;
  103. class service;
  104. class service_maker;
  105. public:
  106. /// Constructor.
  107. BOOST_ASIO_DECL execution_context();
  108. /// Constructor.
  109. /**
  110. * @param a An allocator that will be used for allocating objects that are
  111. * associated with the context, such as services and internal state for I/O
  112. * objects.
  113. */
  114. template <typename Allocator>
  115. execution_context(allocator_arg_t, const Allocator& a);
  116. /// Constructor.
  117. /**
  118. * Construct with a service maker, to create an initial set of services that
  119. * will be installed into the execution context at construction time.
  120. *
  121. * @param initial_services Used to create the initial services. The @c make
  122. * function will be called once at the end of execution_context construction.
  123. */
  124. BOOST_ASIO_DECL explicit execution_context(
  125. const service_maker& initial_services);
  126. /// Constructor.
  127. /**
  128. * Construct with a service maker, to create an initial set of services that
  129. * will be installed into the execution context at construction time.
  130. *
  131. * @param a An allocator that will be used for allocating objects that are
  132. * associated with the context, such as services and internal state for I/O
  133. * objects.
  134. *
  135. * @param initial_services Used to create the initial services. The @c make
  136. * function will be called once at the end of execution_context construction.
  137. */
  138. template <typename Allocator>
  139. execution_context(allocator_arg_t, const Allocator& a,
  140. const service_maker& initial_services);
  141. /// Destructor.
  142. BOOST_ASIO_DECL ~execution_context();
  143. protected:
  144. /// Shuts down all services in the context.
  145. /**
  146. * This function is implemented as follows:
  147. *
  148. * @li For each service object @c svc in the execution_context set, in
  149. * reverse order of the beginning of service object lifetime, performs @c
  150. * svc->shutdown().
  151. */
  152. BOOST_ASIO_DECL void shutdown();
  153. /// Destroys all services in the context.
  154. /**
  155. * This function is implemented as follows:
  156. *
  157. * @li For each service object @c svc in the execution_context set, in
  158. * reverse order * of the beginning of service object lifetime, performs
  159. * <tt>delete static_cast<execution_context::service*>(svc)</tt>.
  160. */
  161. BOOST_ASIO_DECL void destroy();
  162. public:
  163. /// Fork-related event notifications.
  164. enum fork_event
  165. {
  166. /// Notify the context that the process is about to fork.
  167. fork_prepare,
  168. /// Notify the context that the process has forked and is the parent.
  169. fork_parent,
  170. /// Notify the context that the process has forked and is the child.
  171. fork_child
  172. };
  173. /// Notify the execution_context of a fork-related event.
  174. /**
  175. * This function is used to inform the execution_context that the process is
  176. * about to fork, or has just forked. This allows the execution_context, and
  177. * the services it contains, to perform any necessary housekeeping to ensure
  178. * correct operation following a fork.
  179. *
  180. * This function must not be called while any other execution_context
  181. * function, or any function associated with the execution_context's derived
  182. * class, is being called in another thread. It is, however, safe to call
  183. * this function from within a completion handler, provided no other thread
  184. * is accessing the execution_context or its derived class.
  185. *
  186. * @param event A fork-related event.
  187. *
  188. * @throws boost::system::system_error Thrown on failure. If the notification
  189. * fails the execution_context object should no longer be used and should be
  190. * destroyed.
  191. *
  192. * @par Example
  193. * The following code illustrates how to incorporate the notify_fork()
  194. * function:
  195. * @code my_execution_context.notify_fork(execution_context::fork_prepare);
  196. * if (fork() == 0)
  197. * {
  198. * // This is the child process.
  199. * my_execution_context.notify_fork(execution_context::fork_child);
  200. * }
  201. * else
  202. * {
  203. * // This is the parent process.
  204. * my_execution_context.notify_fork(execution_context::fork_parent);
  205. * } @endcode
  206. *
  207. * @note For each service object @c svc in the execution_context set,
  208. * performs <tt>svc->notify_fork();</tt>. When processing the fork_prepare
  209. * event, services are visited in reverse order of the beginning of service
  210. * object lifetime. Otherwise, services are visited in order of the beginning
  211. * of service object lifetime.
  212. */
  213. BOOST_ASIO_DECL void notify_fork(fork_event event);
  214. /// Obtain the service object corresponding to the given type.
  215. /**
  216. * This function is used to locate a service object that corresponds to the
  217. * given service type. If there is no existing implementation of the service,
  218. * then the execution_context will create a new instance of the service.
  219. *
  220. * @param e The execution_context object that owns the service.
  221. *
  222. * @return The service interface implementing the specified service type.
  223. * Ownership of the service interface is not transferred to the caller.
  224. */
  225. template <typename Service>
  226. friend Service& use_service(execution_context& e);
  227. /// Obtain the service object corresponding to the given type.
  228. /**
  229. * This function is used to locate a service object that corresponds to the
  230. * given service type. If there is no existing implementation of the service,
  231. * then the io_context will create a new instance of the service.
  232. *
  233. * @param ioc The io_context object that owns the service.
  234. *
  235. * @return The service interface implementing the specified service type.
  236. * Ownership of the service interface is not transferred to the caller.
  237. *
  238. * @note This overload is preserved for backwards compatibility with services
  239. * that inherit from io_context::service.
  240. */
  241. template <typename Service>
  242. friend Service& use_service(io_context& ioc);
  243. /// Creates a service object and adds it to the execution_context.
  244. /**
  245. * This function is used to add a service to the execution_context.
  246. *
  247. * @param e The execution_context object that owns the service.
  248. *
  249. * @param args Zero or more arguments to be passed to the service
  250. * constructor.
  251. *
  252. * @throws boost::asio::service_already_exists Thrown if a service of the
  253. * given type is already present in the execution_context.
  254. */
  255. template <typename Service, typename... Args>
  256. friend Service& make_service(execution_context& e, Args&&... args);
  257. /// (Deprecated: Use make_service().) Add a service object to the
  258. /// execution_context.
  259. /**
  260. * This function is used to add a service to the execution_context.
  261. *
  262. * @param e The execution_context object that owns the service.
  263. *
  264. * @param svc The service object. On success, ownership of the service object
  265. * is transferred to the execution_context. When the execution_context object
  266. * is destroyed, it will destroy the service object by performing: @code
  267. * delete static_cast<execution_context::service*>(svc) @endcode
  268. *
  269. * @throws boost::asio::service_already_exists Thrown if a service of the
  270. * given type is already present in the execution_context.
  271. *
  272. * @throws boost::asio::invalid_service_owner Thrown if the service's owning
  273. * execution_context is not the execution_context object specified by the
  274. * @c e parameter.
  275. */
  276. template <typename Service>
  277. friend void add_service(execution_context& e, Service* svc);
  278. /// Determine if an execution_context contains a specified service type.
  279. /**
  280. * This function is used to determine whether the execution_context contains a
  281. * service object corresponding to the given service type.
  282. *
  283. * @param e The execution_context object that owns the service.
  284. *
  285. * @return A boolean indicating whether the execution_context contains the
  286. * service.
  287. */
  288. template <typename Service>
  289. friend bool has_service(execution_context& e);
  290. private:
  291. class allocator_impl_base;
  292. template <typename Allocator> class allocator_impl;
  293. // Helper constructors to perform non-templated parts of context construction.
  294. BOOST_ASIO_DECL explicit execution_context(allocator_impl_base* alloc);
  295. BOOST_ASIO_DECL execution_context(allocator_impl_base* alloc,
  296. const service_maker& initial_services);
  297. // The allocator used for all services and other context-wide allocations.
  298. struct auto_allocator_ptr
  299. {
  300. allocator_impl_base* ptr_;
  301. ~auto_allocator_ptr();
  302. } allocator_;
  303. // The service registry.
  304. detail::service_registry* service_registry_;
  305. };
  306. class execution_context::allocator_impl_base
  307. {
  308. public:
  309. virtual void destroy() = 0;
  310. virtual void* allocate(std::size_t size, std::size_t align) = 0;
  311. virtual void deallocate(void* ptr, std::size_t size, std::size_t align) = 0;
  312. protected:
  313. BOOST_ASIO_DECL virtual ~allocator_impl_base();
  314. };
  315. template <typename Allocator>
  316. class execution_context::allocator_impl
  317. : public execution_context::allocator_impl_base
  318. {
  319. public:
  320. allocator_impl(const Allocator& alloc) : allocator_(alloc) {}
  321. void destroy();
  322. void* allocate(std::size_t size, std::size_t align);
  323. void deallocate(void* ptr, std::size_t size, std::size_t align);
  324. private:
  325. Allocator allocator_;
  326. };
  327. template <typename T>
  328. class execution_context::allocator
  329. {
  330. public:
  331. /// The type of objects that may be allocated by the allocator.
  332. typedef T value_type;
  333. /// Rebinds an allocator to another value type.
  334. template <typename U>
  335. struct rebind
  336. {
  337. /// Specifies the type of the rebound allocator.
  338. typedef allocator<U> other;
  339. };
  340. /// Construct an allocator that is associated with an execution context.
  341. explicit constexpr allocator(execution_context& e) noexcept
  342. : impl_(e.allocator_.ptr_)
  343. {
  344. }
  345. /// Construct from another @c allocator for a different value type.
  346. template <typename U>
  347. constexpr allocator(const allocator<U>& a) noexcept
  348. : impl_(a.impl_)
  349. {
  350. }
  351. /// Equality operator.
  352. constexpr bool operator==(const allocator& other) const noexcept
  353. {
  354. return impl_ == other.impl_;
  355. }
  356. /// Inequality operator.
  357. constexpr bool operator!=(const allocator& other) const noexcept
  358. {
  359. return impl_ != other.impl_;
  360. }
  361. /// Allocate space for @c n objects of the allocator's value type.
  362. T* allocate(std::size_t n) const
  363. {
  364. return static_cast<T*>(impl_->allocate(sizeof(T) * n, alignof(T)));
  365. }
  366. /// Deallocate space for @c n objects of the allocator's value type.
  367. void deallocate(T* p, std::size_t n) const
  368. {
  369. impl_->deallocate(p, sizeof(T) * n, alignof(T));
  370. }
  371. private:
  372. template <typename> friend class execution_context::allocator;
  373. allocator_impl_base* impl_;
  374. };
  375. template <>
  376. class execution_context::allocator<void>
  377. {
  378. public:
  379. /// @c void as no objects can be allocated through a proto-allocator.
  380. typedef void value_type;
  381. /// Rebinds an allocator to another value type.
  382. template <typename U>
  383. struct rebind
  384. {
  385. /// Specifies the type of the rebound allocator.
  386. typedef allocator<U> other;
  387. };
  388. /// Construct an allocator that is associated with an execution context.
  389. explicit constexpr allocator(execution_context& e) noexcept
  390. : impl_(e.allocator_.ptr_)
  391. {
  392. }
  393. /// Construct from another @c allocator for a different value type.
  394. template <typename U>
  395. constexpr allocator(const allocator<U>& a) noexcept
  396. : impl_(a.impl_)
  397. {
  398. }
  399. /// Equality operator.
  400. constexpr bool operator==(const allocator& other) const noexcept
  401. {
  402. return impl_ == other.impl_;
  403. }
  404. /// Inequality operator.
  405. constexpr bool operator!=(const allocator& other) const noexcept
  406. {
  407. return impl_ != other.impl_;
  408. }
  409. private:
  410. template <typename> friend class execution_context::allocator;
  411. allocator_impl_base* impl_;
  412. };
  413. /// Class used to uniquely identify a service.
  414. class execution_context::id
  415. : private noncopyable
  416. {
  417. public:
  418. /// Constructor.
  419. id() {}
  420. };
  421. /// Base class for all execution context services.
  422. class execution_context::service
  423. : private noncopyable
  424. {
  425. public:
  426. /// Get the context object that owns the service.
  427. execution_context& context();
  428. protected:
  429. /// Constructor.
  430. /**
  431. * @param owner The execution_context object that owns the service.
  432. */
  433. BOOST_ASIO_DECL service(execution_context& owner);
  434. /// Destructor.
  435. BOOST_ASIO_DECL virtual ~service();
  436. private:
  437. /// Destroy all user-defined handler objects owned by the service.
  438. virtual void shutdown() = 0;
  439. /// Handle notification of a fork-related event to perform any necessary
  440. /// housekeeping.
  441. /**
  442. * This function is not a pure virtual so that services only have to
  443. * implement it if necessary. The default implementation does nothing.
  444. */
  445. BOOST_ASIO_DECL virtual void notify_fork(
  446. execution_context::fork_event event);
  447. friend class detail::service_registry;
  448. struct key
  449. {
  450. key() : type_info_(0), id_(0) {}
  451. const std::type_info* type_info_;
  452. const execution_context::id* id_;
  453. } key_;
  454. execution_context& owner_;
  455. service* next_;
  456. void (*destroy_)(service*);
  457. };
  458. /// Base class for all execution context service makers.
  459. /**
  460. * A service maker is called by the execution context to create services that
  461. * need to be installed into the execution context at construction time.
  462. */
  463. class execution_context::service_maker
  464. : private noncopyable
  465. {
  466. public:
  467. /// Make services to be added to the execution context.
  468. virtual void make(execution_context& context) const = 0;
  469. protected:
  470. /// Destructor.
  471. BOOST_ASIO_DECL virtual ~service_maker();
  472. };
  473. /// Exception thrown when trying to add a duplicate service to an
  474. /// execution_context.
  475. class service_already_exists
  476. : public std::logic_error
  477. {
  478. public:
  479. BOOST_ASIO_DECL service_already_exists();
  480. };
  481. /// Exception thrown when trying to add a service object to an
  482. /// execution_context where the service has a different owner.
  483. class invalid_service_owner
  484. : public std::logic_error
  485. {
  486. public:
  487. BOOST_ASIO_DECL invalid_service_owner();
  488. };
  489. namespace detail {
  490. // Special derived service id type to keep classes header-file only.
  491. template <typename Type>
  492. class service_id
  493. : public execution_context::id
  494. {
  495. };
  496. // Special service base class to keep classes header-file only.
  497. template <typename Type>
  498. class execution_context_service_base
  499. : public execution_context::service
  500. {
  501. public:
  502. static service_id<Type> id;
  503. // Constructor.
  504. execution_context_service_base(execution_context& e)
  505. : execution_context::service(e)
  506. {
  507. }
  508. };
  509. template <typename Type>
  510. service_id<Type> execution_context_service_base<Type>::id;
  511. } // namespace detail
  512. } // namespace asio
  513. } // namespace boost
  514. #include <boost/asio/detail/pop_options.hpp>
  515. #include <boost/asio/impl/execution_context.hpp>
  516. #if defined(BOOST_ASIO_HEADER_ONLY)
  517. # include <boost/asio/impl/execution_context.ipp>
  518. #endif // defined(BOOST_ASIO_HEADER_ONLY)
  519. #endif // BOOST_ASIO_EXECUTION_CONTEXT_HPP