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