Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:33

0001 //
0002 // detail/impl/service_registry.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 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_DETAIL_IMPL_SERVICE_REGISTRY_IPP
0012 #define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
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 <vector>
0020 #include <boost/asio/detail/service_registry.hpp>
0021 #include <boost/asio/detail/throw_exception.hpp>
0022 
0023 #include <boost/asio/detail/push_options.hpp>
0024 
0025 namespace boost {
0026 namespace asio {
0027 namespace detail {
0028 
0029 service_registry::service_registry(execution_context& owner)
0030   : owner_(owner),
0031     first_service_(0)
0032 {
0033 }
0034 
0035 service_registry::~service_registry()
0036 {
0037 }
0038 
0039 void service_registry::shutdown_services()
0040 {
0041   execution_context::service* service = first_service_;
0042   while (service)
0043   {
0044     service->shutdown();
0045     service = service->next_;
0046   }
0047 }
0048 
0049 void service_registry::destroy_services()
0050 {
0051   while (first_service_)
0052   {
0053     execution_context::service* next_service = first_service_->next_;
0054     destroy(first_service_);
0055     first_service_ = next_service;
0056   }
0057 }
0058 
0059 void service_registry::notify_fork(execution_context::fork_event fork_ev)
0060 {
0061   // Make a copy of all of the services while holding the lock. We don't want
0062   // to hold the lock while calling into each service, as it may try to call
0063   // back into this class.
0064   std::vector<execution_context::service*> services;
0065   {
0066     boost::asio::detail::mutex::scoped_lock lock(mutex_);
0067     execution_context::service* service = first_service_;
0068     while (service)
0069     {
0070       services.push_back(service);
0071       service = service->next_;
0072     }
0073   }
0074 
0075   // If processing the fork_prepare event, we want to go in reverse order of
0076   // service registration, which happens to be the existing order of the
0077   // services in the vector. For the other events we want to go in the other
0078   // direction.
0079   std::size_t num_services = services.size();
0080   if (fork_ev == execution_context::fork_prepare)
0081     for (std::size_t i = 0; i < num_services; ++i)
0082       services[i]->notify_fork(fork_ev);
0083   else
0084     for (std::size_t i = num_services; i > 0; --i)
0085       services[i - 1]->notify_fork(fork_ev);
0086 }
0087 
0088 void service_registry::init_key_from_id(execution_context::service::key& key,
0089     const execution_context::id& id)
0090 {
0091   key.type_info_ = 0;
0092   key.id_ = &id;
0093 }
0094 
0095 bool service_registry::keys_match(
0096     const execution_context::service::key& key1,
0097     const execution_context::service::key& key2)
0098 {
0099   if (key1.id_ && key2.id_)
0100     if (key1.id_ == key2.id_)
0101       return true;
0102   if (key1.type_info_ && key2.type_info_)
0103     if (*key1.type_info_ == *key2.type_info_)
0104       return true;
0105   return false;
0106 }
0107 
0108 void service_registry::destroy(execution_context::service* service)
0109 {
0110   delete service;
0111 }
0112 
0113 execution_context::service* service_registry::do_use_service(
0114     const execution_context::service::key& key,
0115     factory_type factory, void* owner)
0116 {
0117   boost::asio::detail::mutex::scoped_lock lock(mutex_);
0118 
0119   // First see if there is an existing service object with the given key.
0120   execution_context::service* service = first_service_;
0121   while (service)
0122   {
0123     if (keys_match(service->key_, key))
0124       return service;
0125     service = service->next_;
0126   }
0127 
0128   // Create a new service object. The service registry's mutex is not locked
0129   // at this time to allow for nested calls into this function from the new
0130   // service's constructor.
0131   lock.unlock();
0132   auto_service_ptr new_service = { factory(owner) };
0133   new_service.ptr_->key_ = key;
0134   lock.lock();
0135 
0136   // Check that nobody else created another service object of the same type
0137   // while the lock was released.
0138   service = first_service_;
0139   while (service)
0140   {
0141     if (keys_match(service->key_, key))
0142       return service;
0143     service = service->next_;
0144   }
0145 
0146   // Service was successfully initialised, pass ownership to registry.
0147   new_service.ptr_->next_ = first_service_;
0148   first_service_ = new_service.ptr_;
0149   new_service.ptr_ = 0;
0150   return first_service_;
0151 }
0152 
0153 void service_registry::do_add_service(
0154     const execution_context::service::key& key,
0155     execution_context::service* new_service)
0156 {
0157   if (&owner_ != &new_service->context())
0158     boost::asio::detail::throw_exception(invalid_service_owner());
0159 
0160   boost::asio::detail::mutex::scoped_lock lock(mutex_);
0161 
0162   // Check if there is an existing service object with the given key.
0163   execution_context::service* service = first_service_;
0164   while (service)
0165   {
0166     if (keys_match(service->key_, key))
0167       boost::asio::detail::throw_exception(service_already_exists());
0168     service = service->next_;
0169   }
0170 
0171   // Take ownership of the service object.
0172   new_service->key_ = key;
0173   new_service->next_ = first_service_;
0174   first_service_ = new_service;
0175 }
0176 
0177 bool service_registry::do_has_service(
0178     const execution_context::service::key& key) const
0179 {
0180   boost::asio::detail::mutex::scoped_lock lock(mutex_);
0181 
0182   execution_context::service* service = first_service_;
0183   while (service)
0184   {
0185     if (keys_match(service->key_, key))
0186       return true;
0187     service = service->next_;
0188   }
0189 
0190   return false;
0191 }
0192 
0193 } // namespace detail
0194 } // namespace asio
0195 } // namespace boost
0196 
0197 #include <boost/asio/detail/pop_options.hpp>
0198 
0199 #endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP