|
|
|||
File indexing completed on 2026-09-04 08:42:34
0001 // 0002 // execution_context.hpp 0003 // ~~~~~~~~~~~~~~~~~~~~~ 0004 // 0005 // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com) 0006 // 0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 0009 // 0010 0011 #ifndef BOOST_ASIO_EXECUTION_CONTEXT_HPP 0012 #define BOOST_ASIO_EXECUTION_CONTEXT_HPP 0013 0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 0015 # pragma once 0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 0017 0018 #include <boost/asio/detail/config.hpp> 0019 #include <cstddef> 0020 #include <stdexcept> 0021 #include <typeinfo> 0022 #include <boost/asio/detail/memory.hpp> 0023 #include <boost/asio/detail/noncopyable.hpp> 0024 0025 #include <boost/asio/detail/push_options.hpp> 0026 0027 namespace boost { 0028 namespace asio { 0029 0030 class execution_context; 0031 class io_context; 0032 0033 #if !defined(GENERATING_DOCUMENTATION) 0034 template <typename Service> Service& use_service(execution_context&); 0035 template <typename Service> Service& use_service(io_context&); 0036 template <typename Service> void add_service(execution_context&, Service*); 0037 template <typename Service> bool has_service(execution_context&); 0038 #endif // !defined(GENERATING_DOCUMENTATION) 0039 0040 namespace detail { class service_registry; } 0041 0042 /// A context for function object execution. 0043 /** 0044 * An execution context represents a place where function objects will be 0045 * executed. An @c io_context is an example of an execution context. 0046 * 0047 * @par The execution_context class and services 0048 * 0049 * Class execution_context implements an extensible, type-safe, polymorphic set 0050 * of services, indexed by service type. 0051 * 0052 * Services exist to manage the resources that are shared across an execution 0053 * context. For example, timers may be implemented in terms of a single timer 0054 * queue, and this queue would be stored in a service. 0055 * 0056 * Access to the services of an execution_context is via three function 0057 * templates, use_service(), add_service() and has_service(). 0058 * 0059 * In a call to @c use_service<Service>(), the type argument chooses a service, 0060 * making available all members of the named type. If @c Service is not present 0061 * in an execution_context, an object of type @c Service is created and added 0062 * to the execution_context. A C++ program can check if an execution_context 0063 * implements a particular service with the function template @c 0064 * has_service<Service>(). 0065 * 0066 * Service objects may be explicitly added to an execution_context using the 0067 * function template @c add_service<Service>(). If the @c Service is already 0068 * present, the service_already_exists exception is thrown. If the owner of the 0069 * service is not the same object as the execution_context parameter, the 0070 * invalid_service_owner exception is thrown. 0071 * 0072 * Once a service reference is obtained from an execution_context object by 0073 * calling use_service(), that reference remains usable as long as the owning 0074 * execution_context object exists. 0075 * 0076 * All service implementations have execution_context::service as a public base 0077 * class. Custom services may be implemented by deriving from this class and 0078 * then added to an execution_context using the facilities described above. 0079 * 0080 * @par The execution_context as a base class 0081 * 0082 * Class execution_context may be used only as a base class for concrete 0083 * execution context types. The @c io_context is an example of such a derived 0084 * type. 0085 * 0086 * On destruction, a class that is derived from execution_context must perform 0087 * <tt>execution_context::shutdown()</tt> followed by 0088 * <tt>execution_context::destroy()</tt>. 0089 * 0090 * This destruction sequence permits programs to simplify their resource 0091 * management by using @c shared_ptr<>. Where an object's lifetime is tied to 0092 * the lifetime of a connection (or some other sequence of asynchronous 0093 * operations), a @c shared_ptr to the object would be bound into the handlers 0094 * for all asynchronous operations associated with it. This works as follows: 0095 * 0096 * @li When a single connection ends, all associated asynchronous operations 0097 * complete. The corresponding handler objects are destroyed, and all @c 0098 * shared_ptr references to the objects are destroyed. 0099 * 0100 * @li To shut down the whole program, the io_context function stop() is called 0101 * to terminate any run() calls as soon as possible. The io_context destructor 0102 * calls @c shutdown() and @c destroy() to destroy all pending handlers, 0103 * causing all @c shared_ptr references to all connection objects to be 0104 * destroyed. 0105 */ 0106 class execution_context 0107 : private noncopyable 0108 { 0109 public: 0110 template <typename T> class allocator; 0111 class id; 0112 class service; 0113 class service_maker; 0114 0115 public: 0116 /// Constructor. 0117 BOOST_ASIO_DECL execution_context(); 0118 0119 /// Constructor. 0120 /** 0121 * @param a An allocator that will be used for allocating objects that are 0122 * associated with the context, such as services and internal state for I/O 0123 * objects. 0124 */ 0125 template <typename Allocator> 0126 execution_context(allocator_arg_t, const Allocator& a); 0127 0128 /// Constructor. 0129 /** 0130 * Construct with a service maker, to create an initial set of services that 0131 * will be installed into the execution context at construction time. 0132 * 0133 * @param initial_services Used to create the initial services. The @c make 0134 * function will be called once at the end of execution_context construction. 0135 */ 0136 BOOST_ASIO_DECL explicit execution_context( 0137 const service_maker& initial_services); 0138 0139 /// Constructor. 0140 /** 0141 * Construct with a service maker, to create an initial set of services that 0142 * will be installed into the execution context at construction time. 0143 * 0144 * @param a An allocator that will be used for allocating objects that are 0145 * associated with the context, such as services and internal state for I/O 0146 * objects. 0147 * 0148 * @param initial_services Used to create the initial services. The @c make 0149 * function will be called once at the end of execution_context construction. 0150 */ 0151 template <typename Allocator> 0152 execution_context(allocator_arg_t, const Allocator& a, 0153 const service_maker& initial_services); 0154 0155 /// Destructor. 0156 BOOST_ASIO_DECL ~execution_context(); 0157 0158 protected: 0159 /// Shuts down all services in the context. 0160 /** 0161 * This function is implemented as follows: 0162 * 0163 * @li For each service object @c svc in the execution_context set, in 0164 * reverse order of the beginning of service object lifetime, performs @c 0165 * svc->shutdown(). 0166 */ 0167 BOOST_ASIO_DECL void shutdown(); 0168 0169 /// Destroys all services in the context. 0170 /** 0171 * This function is implemented as follows: 0172 * 0173 * @li For each service object @c svc in the execution_context set, in 0174 * reverse order * of the beginning of service object lifetime, performs 0175 * <tt>delete static_cast<execution_context::service*>(svc)</tt>. 0176 */ 0177 BOOST_ASIO_DECL void destroy(); 0178 0179 public: 0180 /// Fork-related event notifications. 0181 enum fork_event 0182 { 0183 /// Notify the context that the process is about to fork. 0184 fork_prepare, 0185 0186 /// Notify the context that the process has forked and is the parent. 0187 fork_parent, 0188 0189 /// Notify the context that the process has forked and is the child. 0190 fork_child 0191 }; 0192 0193 /// Notify the execution_context of a fork-related event. 0194 /** 0195 * This function is used to inform the execution_context that the process is 0196 * about to fork, or has just forked. This allows the execution_context, and 0197 * the services it contains, to perform any necessary housekeeping to ensure 0198 * correct operation following a fork. 0199 * 0200 * This function must not be called while any other execution_context 0201 * function, or any function associated with the execution_context's derived 0202 * class, is being called in another thread. It is, however, safe to call 0203 * this function from within a completion handler, provided no other thread 0204 * is accessing the execution_context or its derived class. 0205 * 0206 * @param event A fork-related event. 0207 * 0208 * @throws boost::system::system_error Thrown on failure. If the notification 0209 * fails the execution_context object should no longer be used and should be 0210 * destroyed. 0211 * 0212 * @par Example 0213 * The following code illustrates how to incorporate the notify_fork() 0214 * function: 0215 * @code my_execution_context.notify_fork(execution_context::fork_prepare); 0216 * if (fork() == 0) 0217 * { 0218 * // This is the child process. 0219 * my_execution_context.notify_fork(execution_context::fork_child); 0220 * } 0221 * else 0222 * { 0223 * // This is the parent process. 0224 * my_execution_context.notify_fork(execution_context::fork_parent); 0225 * } @endcode 0226 * 0227 * @note For each service object @c svc in the execution_context set, 0228 * performs <tt>svc->notify_fork();</tt>. When processing the fork_prepare 0229 * event, services are visited in reverse order of the beginning of service 0230 * object lifetime. Otherwise, services are visited in order of the beginning 0231 * of service object lifetime. 0232 */ 0233 BOOST_ASIO_DECL void notify_fork(fork_event event); 0234 0235 /// Obtain the service object corresponding to the given type. 0236 /** 0237 * This function is used to locate a service object that corresponds to the 0238 * given service type. If there is no existing implementation of the service, 0239 * then the execution_context will create a new instance of the service. 0240 * 0241 * @param e The execution_context object that owns the service. 0242 * 0243 * @return The service interface implementing the specified service type. 0244 * Ownership of the service interface is not transferred to the caller. 0245 */ 0246 template <typename Service> 0247 friend Service& use_service(execution_context& e); 0248 0249 /// Obtain the service object corresponding to the given type. 0250 /** 0251 * This function is used to locate a service object that corresponds to the 0252 * given service type. If there is no existing implementation of the service, 0253 * then the io_context will create a new instance of the service. 0254 * 0255 * @param ioc The io_context object that owns the service. 0256 * 0257 * @return The service interface implementing the specified service type. 0258 * Ownership of the service interface is not transferred to the caller. 0259 * 0260 * @note This overload is preserved for backwards compatibility with services 0261 * that inherit from io_context::service. 0262 */ 0263 template <typename Service> 0264 friend Service& use_service(io_context& ioc); 0265 0266 /// Creates a service object and adds it to the execution_context. 0267 /** 0268 * This function is used to add a service to the execution_context. 0269 * 0270 * @param e The execution_context object that owns the service. 0271 * 0272 * @param args Zero or more arguments to be passed to the service 0273 * constructor. 0274 * 0275 * @throws boost::asio::service_already_exists Thrown if a service of the 0276 * given type is already present in the execution_context. 0277 */ 0278 template <typename Service, typename... Args> 0279 friend Service& make_service(execution_context& e, Args&&... args); 0280 0281 /// (Deprecated: Use make_service().) Add a service object to the 0282 /// execution_context. 0283 /** 0284 * This function is used to add a service to the execution_context. 0285 * 0286 * @param e The execution_context object that owns the service. 0287 * 0288 * @param svc The service object. On success, ownership of the service object 0289 * is transferred to the execution_context. When the execution_context object 0290 * is destroyed, it will destroy the service object by performing: @code 0291 * delete static_cast<execution_context::service*>(svc) @endcode 0292 * 0293 * @throws boost::asio::service_already_exists Thrown if a service of the 0294 * given type is already present in the execution_context. 0295 * 0296 * @throws boost::asio::invalid_service_owner Thrown if the service's owning 0297 * execution_context is not the execution_context object specified by the 0298 * @c e parameter. 0299 */ 0300 template <typename Service> 0301 friend void add_service(execution_context& e, Service* svc); 0302 0303 /// Determine if an execution_context contains a specified service type. 0304 /** 0305 * This function is used to determine whether the execution_context contains a 0306 * service object corresponding to the given service type. 0307 * 0308 * @param e The execution_context object that owns the service. 0309 * 0310 * @return A boolean indicating whether the execution_context contains the 0311 * service. 0312 */ 0313 template <typename Service> 0314 friend bool has_service(execution_context& e); 0315 0316 private: 0317 class allocator_impl_base; 0318 template <typename Allocator> class allocator_impl; 0319 0320 // Helper constructors to perform non-templated parts of context construction. 0321 BOOST_ASIO_DECL explicit execution_context(allocator_impl_base* alloc); 0322 BOOST_ASIO_DECL execution_context(allocator_impl_base* alloc, 0323 const service_maker& initial_services); 0324 0325 // The allocator used for all services and other context-wide allocations. 0326 struct auto_allocator_ptr 0327 { 0328 allocator_impl_base* ptr_; 0329 ~auto_allocator_ptr(); 0330 } allocator_; 0331 0332 // The service registry. 0333 detail::service_registry* service_registry_; 0334 }; 0335 0336 class execution_context::allocator_impl_base 0337 { 0338 public: 0339 virtual void destroy() = 0; 0340 virtual void* allocate(std::size_t size, std::size_t align) = 0; 0341 virtual void deallocate(void* ptr, std::size_t size, std::size_t align) = 0; 0342 0343 protected: 0344 BOOST_ASIO_DECL virtual ~allocator_impl_base(); 0345 }; 0346 0347 template <typename Allocator> 0348 class execution_context::allocator_impl 0349 : public execution_context::allocator_impl_base 0350 { 0351 public: 0352 allocator_impl(const Allocator& alloc) : allocator_(alloc) {} 0353 void destroy(); 0354 void* allocate(std::size_t size, std::size_t align); 0355 void deallocate(void* ptr, std::size_t size, std::size_t align); 0356 0357 private: 0358 Allocator allocator_; 0359 }; 0360 0361 template <typename T> 0362 class execution_context::allocator 0363 { 0364 public: 0365 /// The type of objects that may be allocated by the allocator. 0366 typedef T value_type; 0367 0368 /// Rebinds an allocator to another value type. 0369 template <typename U> 0370 struct rebind 0371 { 0372 /// Specifies the type of the rebound allocator. 0373 typedef allocator<U> other; 0374 }; 0375 0376 /// Construct an allocator that is associated with an execution context. 0377 explicit constexpr allocator(execution_context& e) noexcept 0378 : impl_(e.allocator_.ptr_) 0379 { 0380 } 0381 0382 /// Construct from another @c allocator for a different value type. 0383 template <typename U> 0384 constexpr allocator(const allocator<U>& a) noexcept 0385 : impl_(a.impl_) 0386 { 0387 } 0388 0389 /// Equality operator. 0390 constexpr bool operator==(const allocator& other) const noexcept 0391 { 0392 return impl_ == other.impl_; 0393 } 0394 0395 /// Inequality operator. 0396 constexpr bool operator!=(const allocator& other) const noexcept 0397 { 0398 return impl_ != other.impl_; 0399 } 0400 0401 /// Allocate space for @c n objects of the allocator's value type. 0402 T* allocate(std::size_t n) const 0403 { 0404 return static_cast<T*>(impl_->allocate(sizeof(T) * n, alignof(T))); 0405 } 0406 0407 /// Deallocate space for @c n objects of the allocator's value type. 0408 void deallocate(T* p, std::size_t n) const 0409 { 0410 impl_->deallocate(p, sizeof(T) * n, alignof(T)); 0411 } 0412 0413 private: 0414 template <typename> friend class execution_context::allocator; 0415 allocator_impl_base* impl_; 0416 }; 0417 0418 template <> 0419 class execution_context::allocator<void> 0420 { 0421 public: 0422 /// @c void as no objects can be allocated through a proto-allocator. 0423 typedef void value_type; 0424 0425 /// Rebinds an allocator to another value type. 0426 template <typename U> 0427 struct rebind 0428 { 0429 /// Specifies the type of the rebound allocator. 0430 typedef allocator<U> other; 0431 }; 0432 0433 /// Construct an allocator that is associated with an execution context. 0434 explicit constexpr allocator(execution_context& e) noexcept 0435 : impl_(e.allocator_.ptr_) 0436 { 0437 } 0438 0439 /// Construct from another @c allocator for a different value type. 0440 template <typename U> 0441 constexpr allocator(const allocator<U>& a) noexcept 0442 : impl_(a.impl_) 0443 { 0444 } 0445 0446 /// Equality operator. 0447 constexpr bool operator==(const allocator& other) const noexcept 0448 { 0449 return impl_ == other.impl_; 0450 } 0451 0452 /// Inequality operator. 0453 constexpr bool operator!=(const allocator& other) const noexcept 0454 { 0455 return impl_ != other.impl_; 0456 } 0457 0458 private: 0459 template <typename> friend class execution_context::allocator; 0460 allocator_impl_base* impl_; 0461 }; 0462 0463 /// Class used to uniquely identify a service. 0464 class execution_context::id 0465 : private noncopyable 0466 { 0467 public: 0468 /// Constructor. 0469 id() {} 0470 }; 0471 0472 /// Base class for all execution context services. 0473 class execution_context::service 0474 : private noncopyable 0475 { 0476 public: 0477 /// Get the context object that owns the service. 0478 execution_context& context(); 0479 0480 protected: 0481 /// Constructor. 0482 /** 0483 * @param owner The execution_context object that owns the service. 0484 */ 0485 BOOST_ASIO_DECL service(execution_context& owner); 0486 0487 /// Destructor. 0488 BOOST_ASIO_DECL virtual ~service(); 0489 0490 private: 0491 /// Destroy all user-defined handler objects owned by the service. 0492 virtual void shutdown() = 0; 0493 0494 /// Handle notification of a fork-related event to perform any necessary 0495 /// housekeeping. 0496 /** 0497 * This function is not a pure virtual so that services only have to 0498 * implement it if necessary. The default implementation does nothing. 0499 */ 0500 BOOST_ASIO_DECL virtual void notify_fork( 0501 execution_context::fork_event event); 0502 0503 friend class detail::service_registry; 0504 struct key 0505 { 0506 key() : type_info_(0), id_(0) {} 0507 const std::type_info* type_info_; 0508 const execution_context::id* id_; 0509 } key_; 0510 0511 execution_context& owner_; 0512 service* next_; 0513 void (*destroy_)(service*); 0514 }; 0515 0516 /// Base class for all execution context service makers. 0517 /** 0518 * A service maker is called by the execution context to create services that 0519 * need to be installed into the execution context at construction time. 0520 */ 0521 class execution_context::service_maker 0522 : private noncopyable 0523 { 0524 public: 0525 /// Make services to be added to the execution context. 0526 virtual void make(execution_context& context) const = 0; 0527 0528 protected: 0529 /// Destructor. 0530 BOOST_ASIO_DECL virtual ~service_maker(); 0531 }; 0532 0533 /// Exception thrown when trying to add a duplicate service to an 0534 /// execution_context. 0535 class service_already_exists 0536 : public std::logic_error 0537 { 0538 public: 0539 BOOST_ASIO_DECL service_already_exists(); 0540 }; 0541 0542 /// Exception thrown when trying to add a service object to an 0543 /// execution_context where the service has a different owner. 0544 class invalid_service_owner 0545 : public std::logic_error 0546 { 0547 public: 0548 BOOST_ASIO_DECL invalid_service_owner(); 0549 }; 0550 0551 namespace detail { 0552 0553 // Special derived service id type to keep classes header-file only. 0554 template <typename Type> 0555 class service_id 0556 : public execution_context::id 0557 { 0558 }; 0559 0560 // Special service base class to keep classes header-file only. 0561 template <typename Type> 0562 class execution_context_service_base 0563 : public execution_context::service 0564 { 0565 public: 0566 static service_id<Type> id; 0567 0568 // Constructor. 0569 execution_context_service_base(execution_context& e) 0570 : execution_context::service(e) 0571 { 0572 } 0573 }; 0574 0575 template <typename Type> 0576 service_id<Type> execution_context_service_base<Type>::id; 0577 0578 } // namespace detail 0579 } // namespace asio 0580 } // namespace boost 0581 0582 #include <boost/asio/detail/pop_options.hpp> 0583 0584 #include <boost/asio/impl/execution_context.hpp> 0585 #if defined(BOOST_ASIO_HEADER_ONLY) 0586 # include <boost/asio/impl/execution_context.ipp> 0587 #endif // defined(BOOST_ASIO_HEADER_ONLY) 0588 0589 #endif // BOOST_ASIO_EXECUTION_CONTEXT_HPP
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|