2 // service_registry.hpp
3 // ~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP
12 #define BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/push_options.hpp>
20 #include <boost/asio/detail/push_options.hpp>
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)
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__)
47 class typeid_wrapper
{};
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
60 service_registry(boost::asio::io_service
& o
)
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_
;
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_
;
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.
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
;
114 // Check that nobody else created another service object of the same type
115 // while the lock was released.
116 service
= first_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_
;
142 if (service_id_matches(*service
, Service::id
))
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
;
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_
;
164 if (service_id_matches(*service
, Service::id
))
166 service
= service
->next_
;
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;
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
>);
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
226 #include <boost/asio/detail/pop_options.hpp>
228 #endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP