service_registry.ipp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. //
  2. // detail/impl/service_registry.ipp
  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_DETAIL_IMPL_SERVICE_REGISTRY_IPP
  11. #define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
  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 <vector>
  17. #include <boost/asio/detail/service_registry.hpp>
  18. #include <boost/asio/detail/throw_exception.hpp>
  19. #include <boost/asio/detail/push_options.hpp>
  20. namespace boost {
  21. namespace asio {
  22. namespace detail {
  23. service_registry::service_registry(execution_context& owner)
  24. : owner_(owner),
  25. first_service_(0)
  26. {
  27. }
  28. service_registry::~service_registry()
  29. {
  30. }
  31. void service_registry::shutdown_services()
  32. {
  33. execution_context::service* service = first_service_;
  34. while (service)
  35. {
  36. service->shutdown();
  37. service = service->next_;
  38. }
  39. }
  40. void service_registry::destroy_services()
  41. {
  42. while (first_service_)
  43. {
  44. execution_context::service* next_service = first_service_->next_;
  45. first_service_->destroy_(first_service_);
  46. first_service_ = next_service;
  47. }
  48. }
  49. void service_registry::notify_fork(execution_context::fork_event fork_ev)
  50. {
  51. // Make a copy of all of the services while holding the lock. We don't want
  52. // to hold the lock while calling into each service, as it may try to call
  53. // back into this class.
  54. std::vector<execution_context::service*> services;
  55. {
  56. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  57. execution_context::service* service = first_service_;
  58. while (service)
  59. {
  60. services.push_back(service);
  61. service = service->next_;
  62. }
  63. }
  64. // If processing the fork_prepare event, we want to go in reverse order of
  65. // service registration, which happens to be the existing order of the
  66. // services in the vector. For the other events we want to go in the other
  67. // direction.
  68. std::size_t num_services = services.size();
  69. if (fork_ev == execution_context::fork_prepare)
  70. for (std::size_t i = 0; i < num_services; ++i)
  71. services[i]->notify_fork(fork_ev);
  72. else
  73. for (std::size_t i = num_services; i > 0; --i)
  74. services[i - 1]->notify_fork(fork_ev);
  75. }
  76. void service_registry::init_key_from_id(execution_context::service::key& key,
  77. const execution_context::id& id)
  78. {
  79. key.type_info_ = 0;
  80. key.id_ = &id;
  81. }
  82. bool service_registry::keys_match(
  83. const execution_context::service::key& key1,
  84. const execution_context::service::key& key2)
  85. {
  86. if (key1.id_ && key2.id_)
  87. if (key1.id_ == key2.id_)
  88. return true;
  89. if (key1.type_info_ && key2.type_info_)
  90. if (*key1.type_info_ == *key2.type_info_)
  91. return true;
  92. return false;
  93. }
  94. void service_registry::destroy_added(execution_context::service* service)
  95. {
  96. delete service;
  97. }
  98. service_registry::auto_service_ptr::~auto_service_ptr()
  99. {
  100. if (ptr_)
  101. ptr_->destroy_(ptr_);
  102. }
  103. execution_context::service* service_registry::do_use_service(
  104. const execution_context::service::key& key,
  105. factory_type factory, void* owner)
  106. {
  107. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  108. // First see if there is an existing service object with the given key.
  109. execution_context::service* service = first_service_;
  110. while (service)
  111. {
  112. if (keys_match(service->key_, key))
  113. return service;
  114. service = service->next_;
  115. }
  116. // Create a new service object. The service registry's mutex is not locked
  117. // at this time to allow for nested calls into this function from the new
  118. // service's constructor.
  119. lock.unlock();
  120. auto_service_ptr new_service = { factory(owner_, owner) };
  121. new_service.ptr_->key_ = key;
  122. lock.lock();
  123. // Check that nobody else created another service object of the same type
  124. // while the lock was released.
  125. service = first_service_;
  126. while (service)
  127. {
  128. if (keys_match(service->key_, key))
  129. return service;
  130. service = service->next_;
  131. }
  132. // Service was successfully initialised, pass ownership to registry.
  133. new_service.ptr_->next_ = first_service_;
  134. first_service_ = new_service.ptr_;
  135. new_service.ptr_ = 0;
  136. return first_service_;
  137. }
  138. void service_registry::do_add_service(
  139. const execution_context::service::key& key,
  140. execution_context::service* new_service)
  141. {
  142. if (&owner_ != &new_service->context())
  143. boost::asio::detail::throw_exception(invalid_service_owner());
  144. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  145. // Check if there is an existing service object with the given key.
  146. execution_context::service* service = first_service_;
  147. while (service)
  148. {
  149. if (keys_match(service->key_, key))
  150. boost::asio::detail::throw_exception(service_already_exists());
  151. service = service->next_;
  152. }
  153. // Take ownership of the service object.
  154. if (!new_service->destroy_)
  155. new_service->destroy_ = &service_registry::destroy_added;
  156. new_service->key_ = key;
  157. new_service->next_ = first_service_;
  158. first_service_ = new_service;
  159. }
  160. bool service_registry::do_has_service(
  161. const execution_context::service::key& key) const
  162. {
  163. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  164. execution_context::service* service = first_service_;
  165. while (service)
  166. {
  167. if (keys_match(service->key_, key))
  168. return true;
  169. service = service->next_;
  170. }
  171. return false;
  172. }
  173. } // namespace detail
  174. } // namespace asio
  175. } // namespace boost
  176. #include <boost/asio/detail/pop_options.hpp>
  177. #endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP