Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
5.2KB

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