////////////////////////////////////////////////////////////////////////////// | |
// | |
// (C) Copyright Ion Gaztanaga 2008. 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) | |
// | |
// See http://www.boost.org/libs/interprocess for documentation. | |
// | |
////////////////////////////////////////////////////////////////////////////// | |
#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP | |
#define BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP | |
#include <boost/interprocess/detail/config_begin.hpp> | |
#include <boost/interprocess/detail/workaround.hpp> | |
#include <boost/pointer_to_other.hpp> | |
#include <boost/interprocess/interprocess_fwd.hpp> | |
#include <boost/interprocess/detail/utilities.hpp> //get_pointer | |
#include <utility> //std::pair | |
#include <boost/utility/addressof.hpp> //boost::addressof | |
#include <boost/assert.hpp> //BOOST_ASSERT | |
#include <boost/assert.hpp> | |
#include <boost/interprocess/exceptions.hpp> //bad_alloc | |
#include <boost/interprocess/sync/scoped_lock.hpp> //scoped_lock | |
#include <boost/interprocess/containers/allocation_type.hpp> //boost::interprocess::allocation_type | |
#include <boost/interprocess/containers/container/detail/multiallocation_chain.hpp> | |
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp> | |
#include <boost/interprocess/detail/segment_manager_helper.hpp> | |
#include <algorithm> //std::swap | |
#include <boost/interprocess/detail/move.hpp> | |
#include <boost/interprocess/detail/type_traits.hpp> | |
#include <boost/interprocess/detail/utilities.hpp> | |
namespace boost { | |
namespace interprocess { | |
template <class T> | |
struct sizeof_value | |
{ | |
static const std::size_t value = sizeof(T); | |
}; | |
template <> | |
struct sizeof_value<void> | |
{ | |
static const std::size_t value = sizeof(void*); | |
}; | |
template <> | |
struct sizeof_value<const void> | |
{ | |
static const std::size_t value = sizeof(void*); | |
}; | |
template <> | |
struct sizeof_value<volatile void> | |
{ | |
static const std::size_t value = sizeof(void*); | |
}; | |
template <> | |
struct sizeof_value<const volatile void> | |
{ | |
static const std::size_t value = sizeof(void*); | |
}; | |
namespace detail { | |
//!Object function that creates the node allocator if it is not created and | |
//!increments reference count if it is already created | |
template<class NodePool> | |
struct get_or_create_node_pool_func | |
{ | |
//!This connects or constructs the unique instance of node_pool_t | |
//!Can throw boost::interprocess::bad_alloc | |
void operator()() | |
{ | |
//Find or create the node_pool_t | |
mp_node_pool = mp_segment_manager->template find_or_construct | |
<NodePool>(boost::interprocess::unique_instance)(mp_segment_manager); | |
//If valid, increment link count | |
if(mp_node_pool != 0) | |
mp_node_pool->inc_ref_count(); | |
} | |
//!Constructor. Initializes function | |
//!object parameters | |
get_or_create_node_pool_func(typename NodePool::segment_manager *mngr) | |
: mp_segment_manager(mngr){} | |
NodePool *mp_node_pool; | |
typename NodePool::segment_manager *mp_segment_manager; | |
}; | |
template<class NodePool> | |
inline NodePool *get_or_create_node_pool(typename NodePool::segment_manager *mgnr) | |
{ | |
detail::get_or_create_node_pool_func<NodePool> func(mgnr); | |
mgnr->atomic_func(func); | |
return func.mp_node_pool; | |
} | |
//!Object function that decrements the reference count. If the count | |
//!reaches to zero destroys the node allocator from memory. | |
//!Never throws | |
template<class NodePool> | |
struct destroy_if_last_link_func | |
{ | |
//!Decrements reference count and destroys the object if there is no | |
//!more attached allocators. Never throws | |
void operator()() | |
{ | |
//If not the last link return | |
if(mp_node_pool->dec_ref_count() != 0) return; | |
//Last link, let's destroy the segment_manager | |
mp_node_pool->get_segment_manager()->template destroy<NodePool>(boost::interprocess::unique_instance); | |
} | |
//!Constructor. Initializes function | |
//!object parameters | |
destroy_if_last_link_func(NodePool *pool) | |
: mp_node_pool(pool) | |
{} | |
NodePool *mp_node_pool; | |
}; | |
//!Destruction function, initializes and executes destruction function | |
//!object. Never throws | |
template<class NodePool> | |
inline void destroy_node_pool_if_last_link(NodePool *pool) | |
{ | |
//Get segment manager | |
typename NodePool::segment_manager *mngr = pool->get_segment_manager(); | |
//Execute destruction functor atomically | |
destroy_if_last_link_func<NodePool>func(pool); | |
mngr->atomic_func(func); | |
} | |
template<class NodePool> | |
class cache_impl | |
{ | |
typedef typename NodePool::segment_manager:: | |
void_pointer void_pointer; | |
typedef typename pointer_to_other | |
<void_pointer, NodePool>::type node_pool_ptr; | |
typedef typename NodePool::multiallocation_chain multiallocation_chain; | |
node_pool_ptr mp_node_pool; | |
multiallocation_chain m_cached_nodes; | |
std::size_t m_max_cached_nodes; | |
public: | |
typedef typename NodePool::segment_manager segment_manager; | |
cache_impl(segment_manager *segment_mngr, std::size_t max_cached_nodes) | |
: mp_node_pool(get_or_create_node_pool<NodePool>(segment_mngr)) | |
, m_max_cached_nodes(max_cached_nodes) | |
{} | |
cache_impl(const cache_impl &other) | |
: mp_node_pool(other.get_node_pool()) | |
, m_max_cached_nodes(other.get_max_cached_nodes()) | |
{ | |
mp_node_pool->inc_ref_count(); | |
} | |
~cache_impl() | |
{ | |
this->deallocate_all_cached_nodes(); | |
detail::destroy_node_pool_if_last_link(detail::get_pointer(mp_node_pool)); | |
} | |
NodePool *get_node_pool() const | |
{ return detail::get_pointer(mp_node_pool); } | |
segment_manager *get_segment_manager() const | |
{ return mp_node_pool->get_segment_manager(); } | |
std::size_t get_max_cached_nodes() const | |
{ return m_max_cached_nodes; } | |
void *cached_allocation() | |
{ | |
//If don't have any cached node, we have to get a new list of free nodes from the pool | |
if(m_cached_nodes.empty()){ | |
m_cached_nodes = mp_node_pool->allocate_nodes(m_max_cached_nodes/2); | |
} | |
void *ret = detail::get_pointer(m_cached_nodes.front()); | |
m_cached_nodes.pop_front(); | |
return ret; | |
} | |
multiallocation_chain cached_allocation(std::size_t n) | |
{ | |
multiallocation_chain chain; | |
std::size_t count = n, allocated(0); | |
BOOST_TRY{ | |
//If don't have any cached node, we have to get a new list of free nodes from the pool | |
while(!m_cached_nodes.empty() && count--){ | |
void *ret = detail::get_pointer(m_cached_nodes.front()); | |
m_cached_nodes.pop_front(); | |
chain.push_back(ret); | |
++allocated; | |
} | |
if(allocated != n){ | |
multiallocation_chain chain2(mp_node_pool->allocate_nodes(n - allocated)); | |
chain.splice_after(chain.last(), chain2, chain2.before_begin(), chain2.last(), n - allocated); | |
} | |
return boost::interprocess::move(chain); | |
} | |
BOOST_CATCH(...){ | |
this->cached_deallocation(boost::interprocess::move(chain)); | |
BOOST_RETHROW | |
} | |
BOOST_CATCH_END | |
} | |
void cached_deallocation(void *ptr) | |
{ | |
//Check if cache is full | |
if(m_cached_nodes.size() >= m_max_cached_nodes){ | |
//This only occurs if this allocator deallocate memory allocated | |
//with other equal allocator. Since the cache is full, and more | |
//deallocations are probably coming, we'll make some room in cache | |
//in a single, efficient multi node deallocation. | |
this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2); | |
} | |
m_cached_nodes.push_front(ptr); | |
} | |
void cached_deallocation(multiallocation_chain chain) | |
{ | |
m_cached_nodes.splice_after(m_cached_nodes.before_begin(), chain); | |
//Check if cache is full | |
if(m_cached_nodes.size() >= m_max_cached_nodes){ | |
//This only occurs if this allocator deallocate memory allocated | |
//with other equal allocator. Since the cache is full, and more | |
//deallocations are probably coming, we'll make some room in cache | |
//in a single, efficient multi node deallocation. | |
this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2); | |
} | |
} | |
//!Sets the new max cached nodes value. This can provoke deallocations | |
//!if "newmax" is less than current cached nodes. Never throws | |
void set_max_cached_nodes(std::size_t newmax) | |
{ | |
m_max_cached_nodes = newmax; | |
this->priv_deallocate_remaining_nodes(); | |
} | |
//!Frees all cached nodes. | |
//!Never throws | |
void deallocate_all_cached_nodes() | |
{ | |
if(m_cached_nodes.empty()) return; | |
mp_node_pool->deallocate_nodes(boost::interprocess::move(m_cached_nodes)); | |
} | |
private: | |
//!Frees all cached nodes at once. | |
//!Never throws | |
void priv_deallocate_remaining_nodes() | |
{ | |
if(m_cached_nodes.size() > m_max_cached_nodes){ | |
priv_deallocate_n_nodes(m_cached_nodes.size()-m_max_cached_nodes); | |
} | |
} | |
//!Frees n cached nodes at once. Never throws | |
void priv_deallocate_n_nodes(std::size_t n) | |
{ | |
//This only occurs if this allocator deallocate memory allocated | |
//with other equal allocator. Since the cache is full, and more | |
//deallocations are probably coming, we'll make some room in cache | |
//in a single, efficient multi node deallocation. | |
std::size_t count(n); | |
typename multiallocation_chain::iterator it(m_cached_nodes.before_begin()); | |
while(count--){ | |
++it; | |
} | |
multiallocation_chain chain; | |
chain.splice_after(chain.before_begin(), m_cached_nodes, m_cached_nodes.before_begin(), it, n); | |
//Deallocate all new linked list at once | |
mp_node_pool->deallocate_nodes(boost::interprocess::move(chain)); | |
} | |
public: | |
void swap(cache_impl &other) | |
{ | |
detail::do_swap(mp_node_pool, other.mp_node_pool); | |
m_cached_nodes.swap(other.m_cached_nodes); | |
detail::do_swap(m_max_cached_nodes, other.m_max_cached_nodes); | |
} | |
}; | |
template<class Derived, class T, class SegmentManager> | |
class array_allocation_impl | |
{ | |
const Derived *derived() const | |
{ return static_cast<const Derived*>(this); } | |
Derived *derived() | |
{ return static_cast<Derived*>(this); } | |
typedef typename SegmentManager::void_pointer void_pointer; | |
public: | |
typedef typename boost:: | |
pointer_to_other<void_pointer, T>::type pointer; | |
typedef typename boost:: | |
pointer_to_other<void_pointer, const T>::type const_pointer; | |
typedef T value_type; | |
typedef typename detail::add_reference | |
<value_type>::type reference; | |
typedef typename detail::add_reference | |
<const value_type>::type const_reference; | |
typedef std::size_t size_type; | |
typedef std::ptrdiff_t difference_type; | |
typedef boost::container::containers_detail::transform_multiallocation_chain | |
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain; | |
public: | |
//!Returns maximum the number of objects the previously allocated memory | |
//!pointed by p can hold. This size only works for memory allocated with | |
//!allocate, allocation_command and allocate_many. | |
size_type size(const pointer &p) const | |
{ | |
return (size_type)this->derived()->get_segment_manager()->size(detail::get_pointer(p))/sizeof(T); | |
} | |
std::pair<pointer, bool> | |
allocation_command(boost::interprocess::allocation_type command, | |
size_type limit_size, | |
size_type preferred_size, | |
size_type &received_size, const pointer &reuse = 0) | |
{ | |
return this->derived()->get_segment_manager()->allocation_command | |
(command, limit_size, preferred_size, received_size, detail::get_pointer(reuse)); | |
} | |
//!Allocates many elements of size elem_size in a contiguous block | |
//!of memory. The minimum number to be allocated is min_elements, | |
//!the preferred and maximum number is | |
//!preferred_elements. The number of actually allocated elements is | |
//!will be assigned to received_size. The elements must be deallocated | |
//!with deallocate(...) | |
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements) | |
{ | |
return this->derived()->get_segment_manager()->allocate_many(sizeof(T)*elem_size, num_elements); | |
} | |
//!Allocates n_elements elements, each one of size elem_sizes[i]in a | |
//!contiguous block | |
//!of memory. The elements must be deallocated | |
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements) | |
{ | |
return this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T)); | |
} | |
//!Allocates many elements of size elem_size in a contiguous block | |
//!of memory. The minimum number to be allocated is min_elements, | |
//!the preferred and maximum number is | |
//!preferred_elements. The number of actually allocated elements is | |
//!will be assigned to received_size. The elements must be deallocated | |
//!with deallocate(...) | |
void deallocate_many(multiallocation_chain chain) | |
{ return this->derived()->get_segment_manager()->deallocate_many(boost::interprocess::move(chain)); } | |
//!Returns the number of elements that could be | |
//!allocated. Never throws | |
size_type max_size() const | |
{ return this->derived()->get_segment_manager()->get_size()/sizeof(T); } | |
//!Returns address of mutable object. | |
//!Never throws | |
pointer address(reference value) const | |
{ return pointer(boost::addressof(value)); } | |
//!Returns address of non mutable object. | |
//!Never throws | |
const_pointer address(const_reference value) const | |
{ return const_pointer(boost::addressof(value)); } | |
//!Default construct an object. | |
//!Throws if T's default constructor throws | |
void construct(const pointer &ptr) | |
{ new((void*)detail::get_pointer(ptr)) value_type; } | |
//!Copy construct an object | |
//!Throws if T's copy constructor throws | |
void construct(const pointer &ptr, const_reference v) | |
{ new((void*)detail::get_pointer(ptr)) value_type(v); } | |
//!Destroys object. Throws if object's | |
//!destructor throws | |
void destroy(const pointer &ptr) | |
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } | |
}; | |
template<class Derived, unsigned int Version, class T, class SegmentManager> | |
class node_pool_allocation_impl | |
: public array_allocation_impl | |
< Derived | |
, T | |
, SegmentManager> | |
{ | |
const Derived *derived() const | |
{ return static_cast<const Derived*>(this); } | |
Derived *derived() | |
{ return static_cast<Derived*>(this); } | |
typedef typename SegmentManager::void_pointer void_pointer; | |
typedef typename boost:: | |
pointer_to_other<void_pointer, const void>::type cvoid_pointer; | |
public: | |
typedef typename boost:: | |
pointer_to_other<void_pointer, T>::type pointer; | |
typedef typename boost:: | |
pointer_to_other<void_pointer, const T>::type const_pointer; | |
typedef T value_type; | |
typedef typename detail::add_reference | |
<value_type>::type reference; | |
typedef typename detail::add_reference | |
<const value_type>::type const_reference; | |
typedef std::size_t size_type; | |
typedef std::ptrdiff_t difference_type; | |
typedef boost::container::containers_detail::transform_multiallocation_chain | |
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain; | |
template <int Dummy> | |
struct node_pool | |
{ | |
typedef typename Derived::template node_pool<0>::type type; | |
static type *get(void *p) | |
{ return static_cast<type*>(p); } | |
}; | |
public: | |
//!Allocate memory for an array of count elements. | |
//!Throws boost::interprocess::bad_alloc if there is no enough memory | |
pointer allocate(size_type count, cvoid_pointer hint = 0) | |
{ | |
(void)hint; | |
typedef typename node_pool<0>::type node_pool_t; | |
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); | |
if(count > this->max_size()) | |
throw bad_alloc(); | |
else if(Version == 1 && count == 1) | |
return pointer(static_cast<value_type*> | |
(pool->allocate_node())); | |
else | |
return pointer(static_cast<value_type*> | |
(pool->get_segment_manager()->allocate(sizeof(T)*count))); | |
} | |
//!Deallocate allocated memory. Never throws | |
void deallocate(const pointer &ptr, size_type count) | |
{ | |
(void)count; | |
typedef typename node_pool<0>::type node_pool_t; | |
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); | |
if(Version == 1 && count == 1) | |
pool->deallocate_node(detail::get_pointer(ptr)); | |
else | |
pool->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr)); | |
} | |
//!Allocates just one object. Memory allocated with this function | |
//!must be deallocated only with deallocate_one(). | |
//!Throws boost::interprocess::bad_alloc if there is no enough memory | |
pointer allocate_one() | |
{ | |
typedef typename node_pool<0>::type node_pool_t; | |
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); | |
return pointer(static_cast<value_type*>(pool->allocate_node())); | |
} | |
//!Allocates many elements of size == 1 in a contiguous block | |
//!of memory. The minimum number to be allocated is min_elements, | |
//!the preferred and maximum number is | |
//!preferred_elements. The number of actually allocated elements is | |
//!will be assigned to received_size. Memory allocated with this function | |
//!must be deallocated only with deallocate_one(). | |
multiallocation_chain allocate_individual(std::size_t num_elements) | |
{ | |
typedef typename node_pool<0>::type node_pool_t; | |
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); | |
return multiallocation_chain(pool->allocate_nodes(num_elements)); | |
} | |
//!Deallocates memory previously allocated with allocate_one(). | |
//!You should never use deallocate_one to deallocate memory allocated | |
//!with other functions different from allocate_one(). Never throws | |
void deallocate_one(const pointer &p) | |
{ | |
typedef typename node_pool<0>::type node_pool_t; | |
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); | |
pool->deallocate_node(detail::get_pointer(p)); | |
} | |
//!Allocates many elements of size == 1 in a contiguous block | |
//!of memory. The minimum number to be allocated is min_elements, | |
//!the preferred and maximum number is | |
//!preferred_elements. The number of actually allocated elements is | |
//!will be assigned to received_size. Memory allocated with this function | |
//!must be deallocated only with deallocate_one(). | |
void deallocate_individual(multiallocation_chain chain) | |
{ | |
node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes | |
(chain.extract_multiallocation_chain()); | |
} | |
//!Deallocates all free blocks of the pool | |
void deallocate_free_blocks() | |
{ node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); } | |
//!Deprecated, use deallocate_free_blocks. | |
//!Deallocates all free chunks of the pool. | |
void deallocate_free_chunks() | |
{ node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); } | |
}; | |
template<class T, class NodePool, unsigned int Version> | |
class cached_allocator_impl | |
: public array_allocation_impl | |
<cached_allocator_impl<T, NodePool, Version>, T, typename NodePool::segment_manager> | |
{ | |
cached_allocator_impl & operator=(const cached_allocator_impl& other); | |
typedef array_allocation_impl | |
< cached_allocator_impl | |
<T, NodePool, Version> | |
, T | |
, typename NodePool::segment_manager> base_t; | |
public: | |
typedef NodePool node_pool_t; | |
typedef typename NodePool::segment_manager segment_manager; | |
typedef typename segment_manager::void_pointer void_pointer; | |
typedef typename boost:: | |
pointer_to_other<void_pointer, const void>::type cvoid_pointer; | |
typedef typename base_t::pointer pointer; | |
typedef typename base_t::size_type size_type; | |
typedef typename base_t::multiallocation_chain multiallocation_chain; | |
typedef typename base_t::value_type value_type; | |
public: | |
enum { DEFAULT_MAX_CACHED_NODES = 64 }; | |
cached_allocator_impl(segment_manager *segment_mngr, std::size_t max_cached_nodes) | |
: m_cache(segment_mngr, max_cached_nodes) | |
{} | |
cached_allocator_impl(const cached_allocator_impl &other) | |
: m_cache(other.m_cache) | |
{} | |
//!Copy constructor from related cached_adaptive_pool_base. If not present, constructs | |
//!a node pool. Increments the reference count of the associated node pool. | |
//!Can throw boost::interprocess::bad_alloc | |
template<class T2, class NodePool2> | |
cached_allocator_impl | |
(const cached_allocator_impl | |
<T2, NodePool2, Version> &other) | |
: m_cache(other.get_segment_manager(), other.get_max_cached_nodes()) | |
{} | |
//!Returns a pointer to the node pool. | |
//!Never throws | |
node_pool_t* get_node_pool() const | |
{ return m_cache.get_node_pool(); } | |
//!Returns the segment manager. | |
//!Never throws | |
segment_manager* get_segment_manager()const | |
{ return m_cache.get_segment_manager(); } | |
//!Sets the new max cached nodes value. This can provoke deallocations | |
//!if "newmax" is less than current cached nodes. Never throws | |
void set_max_cached_nodes(std::size_t newmax) | |
{ m_cache.set_max_cached_nodes(newmax); } | |
//!Returns the max cached nodes parameter. | |
//!Never throws | |
std::size_t get_max_cached_nodes() const | |
{ return m_cache.get_max_cached_nodes(); } | |
//!Allocate memory for an array of count elements. | |
//!Throws boost::interprocess::bad_alloc if there is no enough memory | |
pointer allocate(size_type count, cvoid_pointer hint = 0) | |
{ | |
(void)hint; | |
void * ret; | |
if(count > this->max_size()) | |
throw bad_alloc(); | |
else if(Version == 1 && count == 1){ | |
ret = m_cache.cached_allocation(); | |
} | |
else{ | |
ret = this->get_segment_manager()->allocate(sizeof(T)*count); | |
} | |
return pointer(static_cast<T*>(ret)); | |
} | |
//!Deallocate allocated memory. Never throws | |
void deallocate(const pointer &ptr, size_type count) | |
{ | |
(void)count; | |
if(Version == 1 && count == 1){ | |
m_cache.cached_deallocation(detail::get_pointer(ptr)); | |
} | |
else{ | |
this->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr)); | |
} | |
} | |
//!Allocates just one object. Memory allocated with this function | |
//!must be deallocated only with deallocate_one(). | |
//!Throws boost::interprocess::bad_alloc if there is no enough memory | |
pointer allocate_one() | |
{ return pointer(static_cast<value_type*>(this->m_cache.cached_allocation())); } | |
//!Allocates many elements of size == 1 in a contiguous block | |
//!of memory. The minimum number to be allocated is min_elements, | |
//!the preferred and maximum number is | |
//!preferred_elements. The number of actually allocated elements is | |
//!will be assigned to received_size. Memory allocated with this function | |
//!must be deallocated only with deallocate_one(). | |
multiallocation_chain allocate_individual(std::size_t num_elements) | |
{ return multiallocation_chain(this->m_cache.cached_allocation(num_elements)); } | |
//!Deallocates memory previously allocated with allocate_one(). | |
//!You should never use deallocate_one to deallocate memory allocated | |
//!with other functions different from allocate_one(). Never throws | |
void deallocate_one(const pointer &p) | |
{ this->m_cache.cached_deallocation(detail::get_pointer(p)); } | |
//!Allocates many elements of size == 1 in a contiguous block | |
//!of memory. The minimum number to be allocated is min_elements, | |
//!the preferred and maximum number is | |
//!preferred_elements. The number of actually allocated elements is | |
//!will be assigned to received_size. Memory allocated with this function | |
//!must be deallocated only with deallocate_one(). | |
void deallocate_individual(multiallocation_chain chain) | |
{ | |
typename node_pool_t::multiallocation_chain mem | |
(chain.extract_multiallocation_chain()); | |
m_cache.cached_deallocation(boost::interprocess::move(mem)); | |
} | |
//!Deallocates all free blocks of the pool | |
void deallocate_free_blocks() | |
{ m_cache.get_node_pool()->deallocate_free_blocks(); } | |
//!Swaps allocators. Does not throw. If each allocator is placed in a | |
//!different shared memory segments, the result is undefined. | |
friend void swap(cached_allocator_impl &alloc1, cached_allocator_impl &alloc2) | |
{ alloc1.m_cache.swap(alloc2.m_cache); } | |
void deallocate_cache() | |
{ m_cache.deallocate_all_cached_nodes(); } | |
//!Deprecated use deallocate_free_blocks. | |
void deallocate_free_chunks() | |
{ m_cache.get_node_pool()->deallocate_free_blocks(); } | |
/// @cond | |
private: | |
cache_impl<node_pool_t> m_cache; | |
}; | |
//!Equality test for same type of | |
//!cached_allocator_impl | |
template<class T, class N, unsigned int V> inline | |
bool operator==(const cached_allocator_impl<T, N, V> &alloc1, | |
const cached_allocator_impl<T, N, V> &alloc2) | |
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); } | |
//!Inequality test for same type of | |
//!cached_allocator_impl | |
template<class T, class N, unsigned int V> inline | |
bool operator!=(const cached_allocator_impl<T, N, V> &alloc1, | |
const cached_allocator_impl<T, N, V> &alloc2) | |
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); } | |
//!Pooled shared memory allocator using adaptive pool. Includes | |
//!a reference count but the class does not delete itself, this is | |
//!responsibility of user classes. Node size (NodeSize) and the number of | |
//!nodes allocated per block (NodesPerBlock) are known at compile time | |
template<class private_node_allocator_t> | |
class shared_pool_impl | |
: public private_node_allocator_t | |
{ | |
public: | |
//!Segment manager typedef | |
typedef typename private_node_allocator_t:: | |
segment_manager segment_manager; | |
typedef typename private_node_allocator_t:: | |
multiallocation_chain multiallocation_chain; | |
private: | |
typedef typename segment_manager::mutex_family::mutex_type mutex_type; | |
public: | |
//!Constructor from a segment manager. Never throws | |
shared_pool_impl(segment_manager *segment_mngr) | |
: private_node_allocator_t(segment_mngr) | |
{} | |
//!Destructor. Deallocates all allocated blocks. Never throws | |
~shared_pool_impl() | |
{} | |
//!Allocates array of count elements. Can throw boost::interprocess::bad_alloc | |
void *allocate_node() | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
return private_node_allocator_t::allocate_node(); | |
} | |
//!Deallocates an array pointed by ptr. Never throws | |
void deallocate_node(void *ptr) | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
private_node_allocator_t::deallocate_node(ptr); | |
} | |
/* | |
//!Allocates a singly linked list of n nodes ending in null pointer. | |
//!can throw boost::interprocess::bad_alloc | |
void allocate_nodes(multiallocation_chain &nodes, std::size_t n) | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
return private_node_allocator_t::allocate_nodes(nodes, n); | |
} | |
*/ | |
//!Allocates n nodes. | |
//!Can throw boost::interprocess::bad_alloc | |
multiallocation_chain allocate_nodes(const std::size_t n) | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
return private_node_allocator_t::allocate_nodes(n); | |
} | |
//!Deallocates a linked list of nodes ending in null pointer. Never throws | |
void deallocate_nodes(multiallocation_chain &nodes, std::size_t num) | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
private_node_allocator_t::deallocate_nodes(nodes, num); | |
} | |
//!Deallocates the nodes pointed by the multiallocation iterator. Never throws | |
void deallocate_nodes(multiallocation_chain chain) | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
private_node_allocator_t::deallocate_nodes(boost::interprocess::move(chain)); | |
} | |
//!Deallocates all the free blocks of memory. Never throws | |
void deallocate_free_blocks() | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
private_node_allocator_t::deallocate_free_blocks(); | |
} | |
//!Deallocates all used memory from the common pool. | |
//!Precondition: all nodes allocated from this pool should | |
//!already be deallocated. Otherwise, undefined behavior. Never throws | |
void purge_blocks() | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
private_node_allocator_t::purge_blocks(); | |
} | |
//!Increments internal reference count and returns new count. Never throws | |
std::size_t inc_ref_count() | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
return ++m_header.m_usecount; | |
} | |
//!Decrements internal reference count and returns new count. Never throws | |
std::size_t dec_ref_count() | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
BOOST_ASSERT(m_header.m_usecount > 0); | |
return --m_header.m_usecount; | |
} | |
//!Deprecated, use deallocate_free_blocks. | |
void deallocate_free_chunks() | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
private_node_allocator_t::deallocate_free_blocks(); | |
} | |
//!Deprecated, use purge_blocks. | |
void purge_chunks() | |
{ | |
//----------------------- | |
boost::interprocess::scoped_lock<mutex_type> guard(m_header); | |
//----------------------- | |
private_node_allocator_t::purge_blocks(); | |
} | |
private: | |
//!This struct includes needed data and derives from | |
//!the mutex type to allow EBO when using null_mutex | |
struct header_t : mutex_type | |
{ | |
std::size_t m_usecount; //Number of attached allocators | |
header_t() | |
: m_usecount(0) {} | |
} m_header; | |
}; | |
} //namespace detail { | |
} //namespace interprocess { | |
} //namespace boost { | |
#include <boost/interprocess/detail/config_end.hpp> | |
#endif //#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP |