]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/detail/impl/service_registry.ipp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / asio / detail / impl / service_registry.ipp
CommitLineData
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
25namespace boost {
26namespace asio {
27namespace detail {
28
b32b8144
FG
29service_registry::service_registry(execution_context& owner)
30 : owner_(owner),
31 first_service_(0)
32{
33}
34
7c673cae
FG
35service_registry::~service_registry()
36{
b32b8144
FG
37}
38
39void 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
49void 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 59void 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
88void 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
95bool 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 108void service_registry::destroy(execution_context::service* service)
7c673cae
FG
109{
110 delete service;
111}
112
b32b8144
FG
113execution_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
153void 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
177bool 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