service_registry.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. //
  2. // service_registry.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2008 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_SERVICE_REGISTRY_HPP
  11. #define BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/push_options.hpp>
  16. #include <boost/asio/detail/push_options.hpp>
  17. #include <memory>
  18. #include <typeinfo>
  19. #include <boost/asio/detail/pop_options.hpp>
  20. #include <boost/asio/io_service.hpp>
  21. #include <boost/asio/detail/mutex.hpp>
  22. #include <boost/asio/detail/noncopyable.hpp>
  23. #include <boost/asio/detail/service_id.hpp>
  24. #if defined(BOOST_NO_TYPEID)
  25. # if !defined(BOOST_ASIO_NO_TYPEID)
  26. # define BOOST_ASIO_NO_TYPEID
  27. # endif // !defined(BOOST_ASIO_NO_TYPEID)
  28. #endif // defined(BOOST_NO_TYPEID)
  29. namespace boost {
  30. namespace asio {
  31. namespace detail {
  32. #if defined(__GNUC__)
  33. # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
  34. # pragma GCC visibility push (default)
  35. # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
  36. #endif // defined(__GNUC__)
  37. template <typename T>
  38. class typeid_wrapper {};
  39. #if defined(__GNUC__)
  40. # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
  41. # pragma GCC visibility pop
  42. # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
  43. #endif // defined(__GNUC__)
  44. class service_registry
  45. : private noncopyable
  46. {
  47. public:
  48. // Constructor.
  49. service_registry(boost::asio::io_service& o)
  50. : owner_(o),
  51. first_service_(0)
  52. {
  53. }
  54. // Destructor.
  55. ~service_registry()
  56. {
  57. // Shutdown all services. This must be done in a separate loop before the
  58. // services are destroyed since the destructors of user-defined handler
  59. // objects may try to access other service objects.
  60. boost::asio::io_service::service* service = first_service_;
  61. while (service)
  62. {
  63. service->shutdown_service();
  64. service = service->next_;
  65. }
  66. // Destroy all services.
  67. while (first_service_)
  68. {
  69. boost::asio::io_service::service* next_service = first_service_->next_;
  70. delete first_service_;
  71. first_service_ = next_service;
  72. }
  73. }
  74. // Get the service object corresponding to the specified service type. Will
  75. // create a new service object automatically if no such object already
  76. // exists. Ownership of the service object is not transferred to the caller.
  77. template <typename Service>
  78. Service& use_service()
  79. {
  80. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  81. // First see if there is an existing service object for the given type.
  82. boost::asio::io_service::service* service = first_service_;
  83. while (service)
  84. {
  85. if (service_id_matches(*service, Service::id))
  86. return *static_cast<Service*>(service);
  87. service = service->next_;
  88. }
  89. // Create a new service object. The service registry's mutex is not locked
  90. // at this time to allow for nested calls into this function from the new
  91. // service's constructor.
  92. lock.unlock();
  93. std::auto_ptr<Service> new_service(new Service(owner_));
  94. init_service_id(*new_service, Service::id);
  95. Service& new_service_ref = *new_service;
  96. lock.lock();
  97. // Check that nobody else created another service object of the same type
  98. // while the lock was released.
  99. service = first_service_;
  100. while (service)
  101. {
  102. if (service_id_matches(*service, Service::id))
  103. return *static_cast<Service*>(service);
  104. service = service->next_;
  105. }
  106. // Service was successfully initialised, pass ownership to registry.
  107. new_service->next_ = first_service_;
  108. first_service_ = new_service.release();
  109. return new_service_ref;
  110. }
  111. // Add a service object. Returns false on error, in which case ownership of
  112. // the object is retained by the caller.
  113. template <typename Service>
  114. bool add_service(Service* new_service)
  115. {
  116. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  117. // Check if there is an existing service object for the given type.
  118. boost::asio::io_service::service* service = first_service_;
  119. while (service)
  120. {
  121. if (service_id_matches(*service, Service::id))
  122. return false;
  123. service = service->next_;
  124. }
  125. // Take ownership of the service object.
  126. init_service_id(*new_service, Service::id);
  127. new_service->next_ = first_service_;
  128. first_service_ = new_service;
  129. return true;
  130. }
  131. // Check whether a service object of the specified type already exists.
  132. template <typename Service>
  133. bool has_service() const
  134. {
  135. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  136. boost::asio::io_service::service* service = first_service_;
  137. while (service)
  138. {
  139. if (service_id_matches(*service, Service::id))
  140. return true;
  141. service = service->next_;
  142. }
  143. return false;
  144. }
  145. private:
  146. // Set a service's id.
  147. void init_service_id(boost::asio::io_service::service& service,
  148. const boost::asio::io_service::id& id)
  149. {
  150. service.type_info_ = 0;
  151. service.id_ = &id;
  152. }
  153. #if !defined(BOOST_ASIO_NO_TYPEID)
  154. // Set a service's id.
  155. template <typename Service>
  156. void init_service_id(boost::asio::io_service::service& service,
  157. const boost::asio::detail::service_id<Service>& /*id*/)
  158. {
  159. service.type_info_ = &typeid(typeid_wrapper<Service>);
  160. service.id_ = 0;
  161. }
  162. #endif // !defined(BOOST_ASIO_NO_TYPEID)
  163. // Check if a service matches the given id.
  164. static bool service_id_matches(
  165. const boost::asio::io_service::service& service,
  166. const boost::asio::io_service::id& id)
  167. {
  168. return service.id_ == &id;
  169. }
  170. #if !defined(BOOST_ASIO_NO_TYPEID)
  171. // Check if a service matches the given id.
  172. template <typename Service>
  173. static bool service_id_matches(
  174. const boost::asio::io_service::service& service,
  175. const boost::asio::detail::service_id<Service>& /*id*/)
  176. {
  177. return service.type_info_ != 0
  178. && *service.type_info_ == typeid(typeid_wrapper<Service>);
  179. }
  180. #endif // !defined(BOOST_ASIO_NO_TYPEID)
  181. // Mutex to protect access to internal data.
  182. mutable boost::asio::detail::mutex mutex_;
  183. // The owner of this service registry and the services it contains.
  184. boost::asio::io_service& owner_;
  185. // The first service in the list of contained services.
  186. boost::asio::io_service::service* first_service_;
  187. };
  188. } // namespace detail
  189. } // namespace asio
  190. } // namespace boost
  191. #include <boost/asio/detail/pop_options.hpp>
  192. #endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP