service_registry.ipp 5.5 KB

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