You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
190 lines
5.4 KiB
190 lines
5.4 KiB
// |
|
// detail/impl/service_registry.ipp |
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
// |
|
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
|
// |
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying |
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
|
// |
|
|
|
#ifndef BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP |
|
#define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP |
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200) |
|
# pragma once |
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
|
|
|
#include <boost/asio/detail/config.hpp> |
|
#include <boost/throw_exception.hpp> |
|
#include <vector> |
|
#include <boost/asio/detail/service_registry.hpp> |
|
|
|
#include <boost/asio/detail/push_options.hpp> |
|
|
|
namespace boost { |
|
namespace asio { |
|
namespace detail { |
|
|
|
service_registry::~service_registry() |
|
{ |
|
// Shutdown all services. This must be done in a separate loop before the |
|
// services are destroyed since the destructors of user-defined handler |
|
// objects may try to access other service objects. |
|
boost::asio::io_service::service* service = first_service_; |
|
while (service) |
|
{ |
|
service->shutdown_service(); |
|
service = service->next_; |
|
} |
|
|
|
// Destroy all services. |
|
while (first_service_) |
|
{ |
|
boost::asio::io_service::service* next_service = first_service_->next_; |
|
destroy(first_service_); |
|
first_service_ = next_service; |
|
} |
|
} |
|
|
|
void service_registry::notify_fork(boost::asio::io_service::fork_event fork_ev) |
|
{ |
|
// Make a copy of all of the services while holding the lock. We don't want |
|
// to hold the lock while calling into each service, as it may try to call |
|
// back into this class. |
|
std::vector<boost::asio::io_service::service*> services; |
|
{ |
|
boost::asio::detail::mutex::scoped_lock lock(mutex_); |
|
boost::asio::io_service::service* service = first_service_; |
|
while (service) |
|
{ |
|
services.push_back(service); |
|
service = service->next_; |
|
} |
|
} |
|
|
|
// If processing the fork_prepare event, we want to go in reverse order of |
|
// service registration, which happens to be the existing order of the |
|
// services in the vector. For the other events we want to go in the other |
|
// direction. |
|
std::size_t num_services = services.size(); |
|
if (fork_ev == boost::asio::io_service::fork_prepare) |
|
for (std::size_t i = 0; i < num_services; ++i) |
|
services[i]->fork_service(fork_ev); |
|
else |
|
for (std::size_t i = num_services; i > 0; --i) |
|
services[i - 1]->fork_service(fork_ev); |
|
} |
|
|
|
void service_registry::init_key(boost::asio::io_service::service::key& key, |
|
const boost::asio::io_service::id& id) |
|
{ |
|
key.type_info_ = 0; |
|
key.id_ = &id; |
|
} |
|
|
|
bool service_registry::keys_match( |
|
const boost::asio::io_service::service::key& key1, |
|
const boost::asio::io_service::service::key& key2) |
|
{ |
|
if (key1.id_ && key2.id_) |
|
if (key1.id_ == key2.id_) |
|
return true; |
|
if (key1.type_info_ && key2.type_info_) |
|
if (*key1.type_info_ == *key2.type_info_) |
|
return true; |
|
return false; |
|
} |
|
|
|
void service_registry::destroy(boost::asio::io_service::service* service) |
|
{ |
|
delete service; |
|
} |
|
|
|
boost::asio::io_service::service* service_registry::do_use_service( |
|
const boost::asio::io_service::service::key& key, |
|
factory_type factory) |
|
{ |
|
boost::asio::detail::mutex::scoped_lock lock(mutex_); |
|
|
|
// First see if there is an existing service object with the given key. |
|
boost::asio::io_service::service* service = first_service_; |
|
while (service) |
|
{ |
|
if (keys_match(service->key_, key)) |
|
return service; |
|
service = service->next_; |
|
} |
|
|
|
// Create a new service object. The service registry's mutex is not locked |
|
// at this time to allow for nested calls into this function from the new |
|
// service's constructor. |
|
lock.unlock(); |
|
auto_service_ptr new_service = { factory(owner_) }; |
|
new_service.ptr_->key_ = key; |
|
lock.lock(); |
|
|
|
// Check that nobody else created another service object of the same type |
|
// while the lock was released. |
|
service = first_service_; |
|
while (service) |
|
{ |
|
if (keys_match(service->key_, key)) |
|
return service; |
|
service = service->next_; |
|
} |
|
|
|
// Service was successfully initialised, pass ownership to registry. |
|
new_service.ptr_->next_ = first_service_; |
|
first_service_ = new_service.ptr_; |
|
new_service.ptr_ = 0; |
|
return first_service_; |
|
} |
|
|
|
void service_registry::do_add_service( |
|
const boost::asio::io_service::service::key& key, |
|
boost::asio::io_service::service* new_service) |
|
{ |
|
if (&owner_ != &new_service->get_io_service()) |
|
boost::throw_exception(invalid_service_owner()); |
|
|
|
boost::asio::detail::mutex::scoped_lock lock(mutex_); |
|
|
|
// Check if there is an existing service object with the given key. |
|
boost::asio::io_service::service* service = first_service_; |
|
while (service) |
|
{ |
|
if (keys_match(service->key_, key)) |
|
boost::throw_exception(service_already_exists()); |
|
service = service->next_; |
|
} |
|
|
|
// Take ownership of the service object. |
|
new_service->key_ = key; |
|
new_service->next_ = first_service_; |
|
first_service_ = new_service; |
|
} |
|
|
|
bool service_registry::do_has_service( |
|
const boost::asio::io_service::service::key& key) const |
|
{ |
|
boost::asio::detail::mutex::scoped_lock lock(mutex_); |
|
|
|
boost::asio::io_service::service* service = first_service_; |
|
while (service) |
|
{ |
|
if (keys_match(service->key_, key)) |
|
return true; |
|
service = service->next_; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
} // namespace detail |
|
} // namespace asio |
|
} // namespace boost |
|
|
|
#include <boost/asio/detail/pop_options.hpp> |
|
|
|
#endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
|
|
|