Back to home page

EIC code displayed by LXR

 
 

    


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