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

source code of boost/boost/asio/detail/impl/service_registry.ipp