service_registry.ipp 5.2 KB

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