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