fix doc example typo
[boost.git] / boost / asio / detail / service_registry.hpp
blob6b25663f7d84025450ff0035b6a31445a46cf5b5
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 //
11 #ifndef BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP
12 #define BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/push_options.hpp>
20 #include <boost/asio/detail/push_options.hpp>
21 #include <memory>
22 #include <typeinfo>
23 #include <boost/asio/detail/pop_options.hpp>
25 #include <boost/asio/io_service.hpp>
26 #include <boost/asio/detail/mutex.hpp>
27 #include <boost/asio/detail/noncopyable.hpp>
28 #include <boost/asio/detail/service_id.hpp>
30 #if defined(BOOST_NO_TYPEID)
31 # if !defined(BOOST_ASIO_NO_TYPEID)
32 # define BOOST_ASIO_NO_TYPEID
33 # endif // !defined(BOOST_ASIO_NO_TYPEID)
34 #endif // defined(BOOST_NO_TYPEID)
36 namespace boost {
37 namespace asio {
38 namespace detail {
40 #if defined(__GNUC__)
41 # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
42 # pragma GCC visibility push (default)
43 # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
44 #endif // defined(__GNUC__)
46 template <typename T>
47 class typeid_wrapper {};
49 #if defined(__GNUC__)
50 # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
51 # pragma GCC visibility pop
52 # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
53 #endif // defined(__GNUC__)
55 class service_registry
56 : private noncopyable
58 public:
59 // Constructor.
60 service_registry(boost::asio::io_service& o)
61 : owner_(o),
62 first_service_(0)
66 // Destructor.
67 ~service_registry()
69 // Shutdown all services. This must be done in a separate loop before the
70 // services are destroyed since the destructors of user-defined handler
71 // objects may try to access other service objects.
72 boost::asio::io_service::service* service = first_service_;
73 while (service)
75 service->shutdown_service();
76 service = service->next_;
79 // Destroy all services.
80 while (first_service_)
82 boost::asio::io_service::service* next_service = first_service_->next_;
83 delete first_service_;
84 first_service_ = next_service;
88 // Get the service object corresponding to the specified service type. Will
89 // create a new service object automatically if no such object already
90 // exists. Ownership of the service object is not transferred to the caller.
91 template <typename Service>
92 Service& use_service()
94 boost::asio::detail::mutex::scoped_lock lock(mutex_);
96 // First see if there is an existing service object for the given type.
97 boost::asio::io_service::service* service = first_service_;
98 while (service)
100 if (service_id_matches(*service, Service::id))
101 return *static_cast<Service*>(service);
102 service = service->next_;
105 // Create a new service object. The service registry's mutex is not locked
106 // at this time to allow for nested calls into this function from the new
107 // service's constructor.
108 lock.unlock();
109 std::auto_ptr<Service> new_service(new Service(owner_));
110 init_service_id(*new_service, Service::id);
111 Service& new_service_ref = *new_service;
112 lock.lock();
114 // Check that nobody else created another service object of the same type
115 // while the lock was released.
116 service = first_service_;
117 while (service)
119 if (service_id_matches(*service, Service::id))
120 return *static_cast<Service*>(service);
121 service = service->next_;
124 // Service was successfully initialised, pass ownership to registry.
125 new_service->next_ = first_service_;
126 first_service_ = new_service.release();
128 return new_service_ref;
131 // Add a service object. Returns false on error, in which case ownership of
132 // the object is retained by the caller.
133 template <typename Service>
134 bool add_service(Service* new_service)
136 boost::asio::detail::mutex::scoped_lock lock(mutex_);
138 // Check if there is an existing service object for the given type.
139 boost::asio::io_service::service* service = first_service_;
140 while (service)
142 if (service_id_matches(*service, Service::id))
143 return false;
144 service = service->next_;
147 // Take ownership of the service object.
148 init_service_id(*new_service, Service::id);
149 new_service->next_ = first_service_;
150 first_service_ = new_service;
152 return true;
155 // Check whether a service object of the specified type already exists.
156 template <typename Service>
157 bool has_service() const
159 boost::asio::detail::mutex::scoped_lock lock(mutex_);
161 boost::asio::io_service::service* service = first_service_;
162 while (service)
164 if (service_id_matches(*service, Service::id))
165 return true;
166 service = service->next_;
169 return false;
172 private:
173 // Set a service's id.
174 void init_service_id(boost::asio::io_service::service& service,
175 const boost::asio::io_service::id& id)
177 service.type_info_ = 0;
178 service.id_ = &id;
181 #if !defined(BOOST_ASIO_NO_TYPEID)
182 // Set a service's id.
183 template <typename Service>
184 void init_service_id(boost::asio::io_service::service& service,
185 const boost::asio::detail::service_id<Service>& /*id*/)
187 service.type_info_ = &typeid(typeid_wrapper<Service>);
188 service.id_ = 0;
190 #endif // !defined(BOOST_ASIO_NO_TYPEID)
192 // Check if a service matches the given id.
193 static bool service_id_matches(
194 const boost::asio::io_service::service& service,
195 const boost::asio::io_service::id& id)
197 return service.id_ == &id;
200 #if !defined(BOOST_ASIO_NO_TYPEID)
201 // Check if a service matches the given id.
202 template <typename Service>
203 static bool service_id_matches(
204 const boost::asio::io_service::service& service,
205 const boost::asio::detail::service_id<Service>& /*id*/)
207 return service.type_info_ != 0
208 && *service.type_info_ == typeid(typeid_wrapper<Service>);
210 #endif // !defined(BOOST_ASIO_NO_TYPEID)
212 // Mutex to protect access to internal data.
213 mutable boost::asio::detail::mutex mutex_;
215 // The owner of this service registry and the services it contains.
216 boost::asio::io_service& owner_;
218 // The first service in the list of contained services.
219 boost::asio::io_service::service* first_service_;
222 } // namespace detail
223 } // namespace asio
224 } // namespace boost
226 #include <boost/asio/detail/pop_options.hpp>
228 #endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP