Imported existing code
This commit is contained in:
@@ -0,0 +1,465 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-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_ADAPTIVE_POOL_HPP
|
||||
#define BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP
|
||||
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#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/assert.hpp>
|
||||
#include <boost/utility/addressof.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
|
||||
#include <boost/interprocess/detail/mpl.hpp>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes adaptive_pool pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
/// @cond
|
||||
|
||||
namespace detail{
|
||||
|
||||
template < unsigned int Version
|
||||
, class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock
|
||||
, std::size_t MaxFreeBlocks
|
||||
, unsigned char OverheadPercent
|
||||
>
|
||||
class adaptive_pool_base
|
||||
: public node_pool_allocation_impl
|
||||
< adaptive_pool_base
|
||||
< Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
|
||||
, Version
|
||||
, T
|
||||
, SegmentManager
|
||||
>
|
||||
{
|
||||
public:
|
||||
typedef typename SegmentManager::void_pointer void_pointer;
|
||||
typedef SegmentManager segment_manager;
|
||||
typedef adaptive_pool_base
|
||||
<Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> self_t;
|
||||
|
||||
/// @cond
|
||||
|
||||
template <int dummy>
|
||||
struct node_pool
|
||||
{
|
||||
typedef detail::shared_adaptive_node_pool
|
||||
< SegmentManager, sizeof_value<T>::value, NodesPerBlock, MaxFreeBlocks, OverheadPercent> type;
|
||||
|
||||
static type *get(void *p)
|
||||
{ return static_cast<type*>(p); }
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
BOOST_STATIC_ASSERT((Version <=2));
|
||||
|
||||
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::interprocess::version_type<adaptive_pool_base, Version> version;
|
||||
typedef detail::transform_multiallocation_chain
|
||||
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
|
||||
|
||||
//!Obtains adaptive_pool_base from
|
||||
//!adaptive_pool_base
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef adaptive_pool_base<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
/// @cond
|
||||
private:
|
||||
//!Not assignable from related adaptive_pool_base
|
||||
template<unsigned int Version2, class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char O2>
|
||||
adaptive_pool_base& operator=
|
||||
(const adaptive_pool_base<Version2, T2, SegmentManager2, N2, F2, O2>&);
|
||||
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
//!Constructor from a segment manager. If not present, constructs a node
|
||||
//!pool. Increments the reference count of the associated node pool.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
adaptive_pool_base(segment_manager *segment_mngr)
|
||||
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { }
|
||||
|
||||
//!Copy constructor from other adaptive_pool_base. Increments the reference
|
||||
//!count of the associated node pool. Never throws
|
||||
adaptive_pool_base(const adaptive_pool_base &other)
|
||||
: mp_node_pool(other.get_node_pool())
|
||||
{
|
||||
node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count();
|
||||
}
|
||||
|
||||
//!Assignment from other adaptive_pool_base
|
||||
adaptive_pool_base& operator=(const adaptive_pool_base &other)
|
||||
{
|
||||
adaptive_pool_base c(other);
|
||||
swap(*this, c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Copy constructor from related 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>
|
||||
adaptive_pool_base
|
||||
(const adaptive_pool_base<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
|
||||
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(other.get_segment_manager())) { }
|
||||
|
||||
//!Destructor, removes node_pool_t from memory
|
||||
//!if its reference count reaches to zero. Never throws
|
||||
~adaptive_pool_base()
|
||||
{ detail::destroy_node_pool_if_last_link(node_pool<0>::get(detail::get_pointer(mp_node_pool))); }
|
||||
|
||||
//!Returns a pointer to the node pool.
|
||||
//!Never throws
|
||||
void* get_node_pool() const
|
||||
{ return detail::get_pointer(mp_node_pool); }
|
||||
|
||||
//!Returns the segment manager.
|
||||
//!Never throws
|
||||
segment_manager* get_segment_manager()const
|
||||
{ return node_pool<0>::get(detail::get_pointer(mp_node_pool))->get_segment_manager(); }
|
||||
|
||||
//!Swaps allocators. Does not throw. If each allocator is placed in a
|
||||
//!different memory segment, the result is undefined.
|
||||
friend void swap(self_t &alloc1, self_t &alloc2)
|
||||
{ detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); }
|
||||
|
||||
/// @cond
|
||||
private:
|
||||
void_pointer mp_node_pool;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
//!Equality test for same type
|
||||
//!of adaptive_pool_base
|
||||
template<unsigned int V, class T, class S, std::size_t NPC, std::size_t F, unsigned char OP> inline
|
||||
bool operator==(const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc1,
|
||||
const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc2)
|
||||
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
|
||||
|
||||
//!Inequality test for same type
|
||||
//!of adaptive_pool_base
|
||||
template<unsigned int V, class T, class S, std::size_t NPC, std::size_t F, unsigned char OP> inline
|
||||
bool operator!=(const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc1,
|
||||
const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc2)
|
||||
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
|
||||
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock = 64
|
||||
, std::size_t MaxFreeBlocks = 2
|
||||
, unsigned char OverheadPercent = 5
|
||||
>
|
||||
class adaptive_pool_v1
|
||||
: public adaptive_pool_base
|
||||
< 1
|
||||
, T
|
||||
, SegmentManager
|
||||
, NodesPerBlock
|
||||
, MaxFreeBlocks
|
||||
, OverheadPercent
|
||||
>
|
||||
{
|
||||
public:
|
||||
typedef detail::adaptive_pool_base
|
||||
< 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
adaptive_pool_v1(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
adaptive_pool_v1
|
||||
(const adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
};
|
||||
|
||||
} //namespace detail{
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!An STL node allocator that uses a segment manager as memory
|
||||
//!source. The internal pointer type will of the same type (raw, smart) as
|
||||
//!"typename SegmentManager::void_pointer" type. This allows
|
||||
//!placing the allocator in shared memory, memory mapped-files, etc...
|
||||
//!
|
||||
//!This node allocator shares a segregated storage between all instances
|
||||
//!of adaptive_pool with equal sizeof(T) placed in the same segment
|
||||
//!group. NodesPerBlock is the number of nodes allocated at once when the allocator
|
||||
//!needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
|
||||
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
|
||||
//!deallocated with the segment manager.
|
||||
//!
|
||||
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
|
||||
//!(memory usable for nodes / total memory allocated from the segment manager)
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock
|
||||
, std::size_t MaxFreeBlocks
|
||||
, unsigned char OverheadPercent
|
||||
>
|
||||
class adaptive_pool
|
||||
/// @cond
|
||||
: public detail::adaptive_pool_base
|
||||
< 2
|
||||
, T
|
||||
, SegmentManager
|
||||
, NodesPerBlock
|
||||
, MaxFreeBlocks
|
||||
, OverheadPercent
|
||||
>
|
||||
/// @endcond
|
||||
{
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
typedef detail::adaptive_pool_base
|
||||
< 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
|
||||
public:
|
||||
typedef boost::interprocess::version_type<adaptive_pool, 2> version;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
adaptive_pool(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
adaptive_pool
|
||||
(const adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
|
||||
#else //BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
public:
|
||||
typedef implementation_defined::segment_manager segment_manager;
|
||||
typedef segment_manager::void_pointer void_pointer;
|
||||
typedef implementation_defined::pointer pointer;
|
||||
typedef implementation_defined::const_pointer 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;
|
||||
|
||||
//!Obtains adaptive_pool from
|
||||
//!adaptive_pool
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
private:
|
||||
//!Not assignable from
|
||||
//!related adaptive_pool
|
||||
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
|
||||
adaptive_pool& operator=
|
||||
(const adaptive_pool<T2, SegmentManager2, N2, F2, OP2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!other adaptive_pool
|
||||
//adaptive_pool& operator=(const adaptive_pool&);
|
||||
|
||||
public:
|
||||
//!Constructor from a segment manager. If not present, constructs a node
|
||||
//!pool. Increments the reference count of the associated node pool.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
adaptive_pool(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other adaptive_pool. Increments the reference
|
||||
//!count of the associated node pool. Never throws
|
||||
adaptive_pool(const adaptive_pool &other);
|
||||
|
||||
//!Copy constructor from related adaptive_pool. 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>
|
||||
adaptive_pool
|
||||
(const adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
|
||||
|
||||
//!Destructor, removes node_pool_t from memory
|
||||
//!if its reference count reaches to zero. Never throws
|
||||
~adaptive_pool();
|
||||
|
||||
//!Returns a pointer to the node pool.
|
||||
//!Never throws
|
||||
void* get_node_pool() const;
|
||||
|
||||
//!Returns the segment manager.
|
||||
//!Never throws
|
||||
segment_manager* get_segment_manager()const;
|
||||
|
||||
//!Returns the number of elements that could be allocated.
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!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);
|
||||
|
||||
//!Deallocate allocated memory.
|
||||
//!Never throws
|
||||
void deallocate(const pointer &ptr, size_type count);
|
||||
|
||||
//!Deallocates all free blocks
|
||||
//!of the pool
|
||||
void deallocate_free_blocks();
|
||||
|
||||
//!Swaps allocators. Does not throw. If each allocator is placed in a
|
||||
//!different memory segment, the result is undefined.
|
||||
friend void swap(self_t &alloc1, self_t &alloc2);
|
||||
|
||||
//!Returns address of mutable object.
|
||||
//!Never throws
|
||||
pointer address(reference value) const;
|
||||
|
||||
//!Returns address of non mutable object.
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Copy construct an object.
|
||||
//!Throws if T's copy constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
//!Destroys object. Throws if object's
|
||||
//!destructor throws
|
||||
void destroy(const pointer &ptr);
|
||||
|
||||
//!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;
|
||||
|
||||
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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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();
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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 it);
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!Equality test for same type
|
||||
//!of adaptive_pool
|
||||
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
|
||||
bool operator==(const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
//!Inequality test for same type
|
||||
//!of adaptive_pool
|
||||
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
|
||||
bool operator!=(const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP
|
||||
|
||||
304
libraries/include/boost/interprocess/allocators/allocator.hpp
Normal file
304
libraries/include/boost/interprocess/allocators/allocator.hpp
Normal file
@@ -0,0 +1,304 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-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_HPP
|
||||
#define BOOST_INTERPROCESS_ALLOCATOR_HPP
|
||||
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#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/containers/allocation_type.hpp>
|
||||
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/containers/version_type.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/utility/addressof.hpp>
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
|
||||
//!\file
|
||||
//!Describes an allocator that allocates portions of fixed size
|
||||
//!memory buffer (shared memory, mapped file...)
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
|
||||
//!An STL compatible allocator that uses a segment manager as
|
||||
//!memory source. The internal pointer type will of the same type (raw, smart) as
|
||||
//!"typename SegmentManager::void_pointer" type. This allows
|
||||
//!placing the allocator in shared memory, memory mapped-files, etc...
|
||||
template<class T, class SegmentManager>
|
||||
class allocator
|
||||
{
|
||||
public:
|
||||
//Segment manager
|
||||
typedef SegmentManager segment_manager;
|
||||
typedef typename SegmentManager::void_pointer void_pointer;
|
||||
|
||||
/// @cond
|
||||
private:
|
||||
|
||||
//Self type
|
||||
typedef allocator<T, SegmentManager> self_t;
|
||||
|
||||
//Pointer to void
|
||||
typedef typename segment_manager::void_pointer aux_pointer_t;
|
||||
|
||||
//Typedef to const void pointer
|
||||
typedef typename
|
||||
boost::pointer_to_other
|
||||
<aux_pointer_t, const void>::type cvoid_ptr;
|
||||
|
||||
//Pointer to the allocator
|
||||
typedef typename boost::pointer_to_other
|
||||
<cvoid_ptr, segment_manager>::type alloc_ptr_t;
|
||||
|
||||
//Not assignable from related allocator
|
||||
template<class T2, class SegmentManager2>
|
||||
allocator& operator=(const allocator<T2, SegmentManager2>&);
|
||||
|
||||
//Not assignable from other allocator
|
||||
allocator& operator=(const allocator&);
|
||||
|
||||
//Pointer to the allocator
|
||||
alloc_ptr_t mp_mngr;
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef typename boost::pointer_to_other
|
||||
<cvoid_ptr, T>::type pointer;
|
||||
typedef typename boost::
|
||||
pointer_to_other<pointer, const T>::type const_pointer;
|
||||
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::interprocess::version_type<allocator, 2> version;
|
||||
|
||||
/// @cond
|
||||
|
||||
//Experimental. Don't use.
|
||||
typedef boost::interprocess::detail::transform_multiallocation_chain
|
||||
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
|
||||
/// @endcond
|
||||
|
||||
//!Obtains an allocator that allocates
|
||||
//!objects of type T2
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef allocator<T2, SegmentManager> other;
|
||||
};
|
||||
|
||||
//!Returns the segment manager.
|
||||
//!Never throws
|
||||
segment_manager* get_segment_manager()const
|
||||
{ return detail::get_pointer(mp_mngr); }
|
||||
|
||||
//!Constructor from the segment manager.
|
||||
//!Never throws
|
||||
allocator(segment_manager *segment_mngr)
|
||||
: mp_mngr(segment_mngr) { }
|
||||
|
||||
//!Constructor from other allocator.
|
||||
//!Never throws
|
||||
allocator(const allocator &other)
|
||||
: mp_mngr(other.get_segment_manager()){ }
|
||||
|
||||
//!Constructor from related allocator.
|
||||
//!Never throws
|
||||
template<class T2>
|
||||
allocator(const allocator<T2, SegmentManager> &other)
|
||||
: mp_mngr(other.get_segment_manager()){}
|
||||
|
||||
//!Allocates memory for an array of count elements.
|
||||
//!Throws boost::interprocess::bad_alloc if there is no enough memory
|
||||
pointer allocate(size_type count, cvoid_ptr hint = 0)
|
||||
{
|
||||
(void)hint;
|
||||
if(count > this->max_size())
|
||||
throw bad_alloc();
|
||||
return pointer(static_cast<value_type*>(mp_mngr->allocate(count*sizeof(T))));
|
||||
}
|
||||
|
||||
//!Deallocates memory previously allocated.
|
||||
//!Never throws
|
||||
void deallocate(const pointer &ptr, size_type)
|
||||
{ mp_mngr->deallocate((void*)detail::get_pointer(ptr)); }
|
||||
|
||||
//!Returns the number of elements that could be allocated.
|
||||
//!Never throws
|
||||
size_type max_size() const
|
||||
{ return mp_mngr->get_size()/sizeof(T); }
|
||||
|
||||
//!Swap segment manager. Does not throw. If each allocator is placed in
|
||||
//!different memory segments, the result is undefined.
|
||||
friend void swap(self_t &alloc1, self_t &alloc2)
|
||||
{ detail::do_swap(alloc1.mp_mngr, alloc2.mp_mngr); }
|
||||
|
||||
//!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)mp_mngr->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 mp_mngr->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 multiallocation_chain(mp_mngr->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)
|
||||
{
|
||||
multiallocation_chain(mp_mngr->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 mp_mngr->deallocate_many(chain.extract_multiallocation_chain());
|
||||
}
|
||||
|
||||
//!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 this->allocate(1); }
|
||||
|
||||
//!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 this->allocate_many(1, 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)
|
||||
{ return this->deallocate(p, 1); }
|
||||
|
||||
//!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)
|
||||
{ return this->deallocate_many(boost::interprocess::move(chain)); }
|
||||
|
||||
//!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)); }
|
||||
|
||||
//!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); }
|
||||
|
||||
//!Default construct an object.
|
||||
//!Throws if T's default constructor throws
|
||||
void construct(const pointer &ptr)
|
||||
{ new((void*)detail::get_pointer(ptr)) value_type; }
|
||||
|
||||
//!Destroys object. Throws if object's
|
||||
//!destructor throws
|
||||
void destroy(const pointer &ptr)
|
||||
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
|
||||
};
|
||||
|
||||
//!Equality test for same type
|
||||
//!of allocator
|
||||
template<class T, class SegmentManager> inline
|
||||
bool operator==(const allocator<T , SegmentManager> &alloc1,
|
||||
const allocator<T, SegmentManager> &alloc2)
|
||||
{ return alloc1.get_segment_manager() == alloc2.get_segment_manager(); }
|
||||
|
||||
//!Inequality test for same type
|
||||
//!of allocator
|
||||
template<class T, class SegmentManager> inline
|
||||
bool operator!=(const allocator<T, SegmentManager> &alloc1,
|
||||
const allocator<T, SegmentManager> &alloc2)
|
||||
{ return alloc1.get_segment_manager() != alloc2.get_segment_manager(); }
|
||||
|
||||
} //namespace interprocess {
|
||||
|
||||
/// @cond
|
||||
|
||||
template<class T>
|
||||
struct has_trivial_destructor;
|
||||
|
||||
template<class T, class SegmentManager>
|
||||
struct has_trivial_destructor
|
||||
<boost::interprocess::allocator <T, SegmentManager> >
|
||||
{
|
||||
enum { value = true };
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-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_CACHED_ADAPTIVE_POOL_HPP
|
||||
#define BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP
|
||||
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <boost/interprocess/interprocess_fwd.hpp>
|
||||
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
|
||||
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
#include <boost/interprocess/containers/version_type.hpp>
|
||||
#include <boost/interprocess/allocators/detail/node_tools.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes cached_adaptive_pool pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
/// @cond
|
||||
|
||||
namespace detail {
|
||||
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock = 64
|
||||
, std::size_t MaxFreeBlocks = 2
|
||||
, unsigned char OverheadPercent = 5
|
||||
>
|
||||
class cached_adaptive_pool_v1
|
||||
: public detail::cached_allocator_impl
|
||||
< T
|
||||
, detail::shared_adaptive_node_pool
|
||||
< SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
, MaxFreeBlocks
|
||||
, OverheadPercent
|
||||
>
|
||||
, 1>
|
||||
{
|
||||
public:
|
||||
typedef detail::cached_allocator_impl
|
||||
< T
|
||||
, detail::shared_adaptive_node_pool
|
||||
< SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
, MaxFreeBlocks
|
||||
, OverheadPercent
|
||||
>
|
||||
, 1> base_t;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef cached_adaptive_pool_v1
|
||||
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
cached_adaptive_pool_v1(SegmentManager *segment_mngr,
|
||||
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
: base_t(segment_mngr, max_cached_nodes)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
cached_adaptive_pool_v1
|
||||
(const cached_adaptive_pool_v1
|
||||
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
};
|
||||
|
||||
} //namespace detail{
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!An STL node allocator that uses a segment manager as memory
|
||||
//!source. The internal pointer type will of the same type (raw, smart) as
|
||||
//!"typename SegmentManager::void_pointer" type. This allows
|
||||
//!placing the allocator in shared memory, memory mapped-files, etc...
|
||||
//!
|
||||
//!This node allocator shares a segregated storage between all instances of
|
||||
//!cached_adaptive_pool with equal sizeof(T) placed in the same
|
||||
//!memory segment. But also caches some nodes privately to
|
||||
//!avoid some synchronization overhead.
|
||||
//!
|
||||
//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when
|
||||
//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
|
||||
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
|
||||
//!deallocated with the segment manager.
|
||||
//!
|
||||
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
|
||||
//!(memory usable for nodes / total memory allocated from the segment manager)
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock
|
||||
, std::size_t MaxFreeBlocks
|
||||
, unsigned char OverheadPercent
|
||||
>
|
||||
class cached_adaptive_pool
|
||||
/// @cond
|
||||
: public detail::cached_allocator_impl
|
||||
< T
|
||||
, detail::shared_adaptive_node_pool
|
||||
< SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
, MaxFreeBlocks
|
||||
, OverheadPercent
|
||||
>
|
||||
, 2>
|
||||
/// @endcond
|
||||
{
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
public:
|
||||
typedef detail::cached_allocator_impl
|
||||
< T
|
||||
, detail::shared_adaptive_node_pool
|
||||
< SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
, MaxFreeBlocks
|
||||
, OverheadPercent
|
||||
>
|
||||
, 2> base_t;
|
||||
|
||||
public:
|
||||
typedef boost::interprocess::version_type<cached_adaptive_pool, 2> version;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef cached_adaptive_pool
|
||||
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
cached_adaptive_pool(SegmentManager *segment_mngr,
|
||||
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
: base_t(segment_mngr, max_cached_nodes)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
cached_adaptive_pool
|
||||
(const cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
|
||||
#else
|
||||
public:
|
||||
typedef implementation_defined::segment_manager segment_manager;
|
||||
typedef segment_manager::void_pointer void_pointer;
|
||||
typedef implementation_defined::pointer pointer;
|
||||
typedef implementation_defined::const_pointer 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;
|
||||
|
||||
//!Obtains cached_adaptive_pool from
|
||||
//!cached_adaptive_pool
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
private:
|
||||
//!Not assignable from
|
||||
//!related cached_adaptive_pool
|
||||
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
|
||||
cached_adaptive_pool& operator=
|
||||
(const cached_adaptive_pool<T2, SegmentManager2, N2, F2, OP2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!other cached_adaptive_pool
|
||||
cached_adaptive_pool& operator=(const cached_adaptive_pool&);
|
||||
|
||||
public:
|
||||
//!Constructor from a segment manager. If not present, constructs a node
|
||||
//!pool. Increments the reference count of the associated node pool.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
cached_adaptive_pool(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other cached_adaptive_pool. Increments the reference
|
||||
//!count of the associated node pool. Never throws
|
||||
cached_adaptive_pool(const cached_adaptive_pool &other);
|
||||
|
||||
//!Copy constructor from related cached_adaptive_pool. 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>
|
||||
cached_adaptive_pool
|
||||
(const cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
|
||||
|
||||
//!Destructor, removes node_pool_t from memory
|
||||
//!if its reference count reaches to zero. Never throws
|
||||
~cached_adaptive_pool();
|
||||
|
||||
//!Returns a pointer to the node pool.
|
||||
//!Never throws
|
||||
node_pool_t* get_node_pool() const;
|
||||
|
||||
//!Returns the segment manager.
|
||||
//!Never throws
|
||||
segment_manager* get_segment_manager()const;
|
||||
|
||||
//!Returns the number of elements that could be allocated.
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!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);
|
||||
|
||||
//!Deallocate allocated memory.
|
||||
//!Never throws
|
||||
void deallocate(const pointer &ptr, size_type count);
|
||||
|
||||
//!Deallocates all free blocks
|
||||
//!of the pool
|
||||
void deallocate_free_blocks();
|
||||
|
||||
//!Swaps allocators. Does not throw. If each allocator is placed in a
|
||||
//!different memory segment, the result is undefined.
|
||||
friend void swap(self_t &alloc1, self_t &alloc2);
|
||||
|
||||
//!Returns address of mutable object.
|
||||
//!Never throws
|
||||
pointer address(reference value) const;
|
||||
|
||||
//!Returns address of non mutable object.
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Copy construct an object.
|
||||
//!Throws if T's copy constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
//!Destroys object. Throws if object's
|
||||
//!destructor throws
|
||||
void destroy(const pointer &ptr);
|
||||
|
||||
//!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;
|
||||
|
||||
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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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();
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
//!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);
|
||||
|
||||
//!Returns the max cached nodes parameter.
|
||||
//!Never throws
|
||||
std::size_t get_max_cached_nodes() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!Equality test for same type
|
||||
//!of cached_adaptive_pool
|
||||
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, std::size_t OP> inline
|
||||
bool operator==(const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
//!Inequality test for same type
|
||||
//!of cached_adaptive_pool
|
||||
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, std::size_t OP> inline
|
||||
bool operator!=(const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP
|
||||
|
||||
@@ -0,0 +1,324 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-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_CACHED_NODE_ALLOCATOR_HPP
|
||||
#define BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP
|
||||
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <boost/interprocess/interprocess_fwd.hpp>
|
||||
#include <boost/interprocess/allocators/detail/node_pool.hpp>
|
||||
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/containers/version_type.hpp>
|
||||
#include <boost/interprocess/allocators/detail/node_tools.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes cached_cached_node_allocator pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
|
||||
/// @cond
|
||||
|
||||
namespace detail {
|
||||
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock = 64
|
||||
>
|
||||
class cached_node_allocator_v1
|
||||
: public detail::cached_allocator_impl
|
||||
< T
|
||||
, detail::shared_node_pool
|
||||
< SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
>
|
||||
, 1>
|
||||
{
|
||||
public:
|
||||
typedef detail::cached_allocator_impl
|
||||
< T
|
||||
, detail::shared_node_pool
|
||||
< SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
>
|
||||
, 1> base_t;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef cached_node_allocator_v1
|
||||
<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
cached_node_allocator_v1(SegmentManager *segment_mngr,
|
||||
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
: base_t(segment_mngr, max_cached_nodes)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
cached_node_allocator_v1
|
||||
(const cached_node_allocator_v1
|
||||
<T2, SegmentManager, NodesPerBlock> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
};
|
||||
|
||||
} //namespace detail{
|
||||
|
||||
/// @endcond
|
||||
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock
|
||||
>
|
||||
class cached_node_allocator
|
||||
/// @cond
|
||||
: public detail::cached_allocator_impl
|
||||
< T
|
||||
, detail::shared_node_pool
|
||||
< SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
>
|
||||
, 2>
|
||||
/// @endcond
|
||||
{
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
public:
|
||||
typedef detail::cached_allocator_impl
|
||||
< T
|
||||
, detail::shared_node_pool
|
||||
< SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
>
|
||||
, 2> base_t;
|
||||
|
||||
public:
|
||||
typedef boost::interprocess::version_type<cached_node_allocator, 2> version;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef cached_node_allocator<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
cached_node_allocator(SegmentManager *segment_mngr,
|
||||
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
: base_t(segment_mngr, max_cached_nodes)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
cached_node_allocator
|
||||
(const cached_node_allocator<T2, SegmentManager, NodesPerBlock> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
|
||||
#else
|
||||
public:
|
||||
typedef implementation_defined::segment_manager segment_manager;
|
||||
typedef segment_manager::void_pointer void_pointer;
|
||||
typedef implementation_defined::pointer pointer;
|
||||
typedef implementation_defined::const_pointer 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;
|
||||
|
||||
//!Obtains cached_node_allocator from
|
||||
//!cached_node_allocator
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef cached_node_allocator<T2, SegmentManager> other;
|
||||
};
|
||||
|
||||
private:
|
||||
//!Not assignable from
|
||||
//!related cached_node_allocator
|
||||
template<class T2, class SegmentManager2, std::size_t N2>
|
||||
cached_node_allocator& operator=
|
||||
(const cached_node_allocator<T2, SegmentManager2, N2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!other cached_node_allocator
|
||||
cached_node_allocator& operator=(const cached_node_allocator&);
|
||||
|
||||
public:
|
||||
//!Constructor from a segment manager. If not present, constructs a node
|
||||
//!pool. Increments the reference count of the associated node pool.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
cached_node_allocator(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other cached_node_allocator. Increments the reference
|
||||
//!count of the associated node pool. Never throws
|
||||
cached_node_allocator(const cached_node_allocator &other);
|
||||
|
||||
//!Copy constructor from related cached_node_allocator. 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>
|
||||
cached_node_allocator
|
||||
(const cached_node_allocator<T2, SegmentManager, NodesPerBlock> &other);
|
||||
|
||||
//!Destructor, removes node_pool_t from memory
|
||||
//!if its reference count reaches to zero. Never throws
|
||||
~cached_node_allocator();
|
||||
|
||||
//!Returns a pointer to the node pool.
|
||||
//!Never throws
|
||||
node_pool_t* get_node_pool() const;
|
||||
|
||||
//!Returns the segment manager.
|
||||
//!Never throws
|
||||
segment_manager* get_segment_manager()const;
|
||||
|
||||
//!Returns the number of elements that could be allocated.
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!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);
|
||||
|
||||
//!Deallocate allocated memory.
|
||||
//!Never throws
|
||||
void deallocate(const pointer &ptr, size_type count);
|
||||
|
||||
//!Deallocates all free blocks
|
||||
//!of the pool
|
||||
void deallocate_free_blocks();
|
||||
|
||||
//!Swaps allocators. Does not throw. If each allocator is placed in a
|
||||
//!different memory segment, the result is undefined.
|
||||
friend void swap(self_t &alloc1, self_t &alloc2);
|
||||
|
||||
//!Returns address of mutable object.
|
||||
//!Never throws
|
||||
pointer address(reference value) const;
|
||||
|
||||
//!Returns address of non mutable object.
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Default construct an object.
|
||||
//!Throws if T's default constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
//!Destroys object. Throws if object's
|
||||
//!destructor throws
|
||||
void destroy(const pointer &ptr);
|
||||
|
||||
//!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;
|
||||
|
||||
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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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();
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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 it);
|
||||
//!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);
|
||||
|
||||
//!Returns the max cached nodes parameter.
|
||||
//!Never throws
|
||||
std::size_t get_max_cached_nodes() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!Equality test for same type
|
||||
//!of cached_node_allocator
|
||||
template<class T, class S, std::size_t NPC> inline
|
||||
bool operator==(const cached_node_allocator<T, S, NPC> &alloc1,
|
||||
const cached_node_allocator<T, S, NPC> &alloc2);
|
||||
|
||||
//!Inequality test for same type
|
||||
//!of cached_node_allocator
|
||||
template<class T, class S, std::size_t NPC> inline
|
||||
bool operator!=(const cached_node_allocator<T, S, NPC> &alloc1,
|
||||
const cached_node_allocator<T, S, NPC> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP
|
||||
|
||||
@@ -0,0 +1,639 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-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_DETAIL_ADAPTIVE_NODE_POOL_HPP
|
||||
#define BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP
|
||||
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#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/sync/interprocess_mutex.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/detail/min_max.hpp>
|
||||
#include <boost/interprocess/detail/math_functions.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
#include <boost/intrusive/slist.hpp>
|
||||
#include <boost/math/common_factor_ct.hpp>
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
|
||||
#include <boost/interprocess/allocators/detail/node_tools.hpp>
|
||||
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
|
||||
#include <cstddef>
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
#include <cassert>
|
||||
|
||||
//!\file
|
||||
//!Describes the real adaptive pool shared by many Interprocess pool allocators
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace detail {
|
||||
|
||||
template<class SegmentManagerBase>
|
||||
class private_adaptive_node_pool_impl
|
||||
{
|
||||
//Non-copyable
|
||||
private_adaptive_node_pool_impl();
|
||||
private_adaptive_node_pool_impl(const private_adaptive_node_pool_impl &);
|
||||
private_adaptive_node_pool_impl &operator=(const private_adaptive_node_pool_impl &);
|
||||
|
||||
typedef typename SegmentManagerBase::void_pointer void_pointer;
|
||||
static const std::size_t PayloadPerAllocation = SegmentManagerBase::PayloadPerAllocation;
|
||||
public:
|
||||
typedef typename node_slist<void_pointer>::node_t node_t;
|
||||
typedef typename node_slist<void_pointer>::node_slist_t free_nodes_t;
|
||||
typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain;
|
||||
|
||||
private:
|
||||
typedef typename bi::make_set_base_hook
|
||||
< bi::void_pointer<void_pointer>
|
||||
, bi::optimize_size<true>
|
||||
, bi::constant_time_size<false>
|
||||
, bi::link_mode<bi::normal_link> >::type multiset_hook_t;
|
||||
|
||||
struct hdr_offset_holder
|
||||
{
|
||||
hdr_offset_holder(std::size_t offset = 0)
|
||||
: hdr_offset(offset)
|
||||
{}
|
||||
std::size_t hdr_offset;
|
||||
};
|
||||
|
||||
struct block_info_t
|
||||
:
|
||||
public hdr_offset_holder,
|
||||
public multiset_hook_t
|
||||
{
|
||||
//An intrusive list of free node from this block
|
||||
free_nodes_t free_nodes;
|
||||
friend bool operator <(const block_info_t &l, const block_info_t &r)
|
||||
{
|
||||
// { return l.free_nodes.size() < r.free_nodes.size(); }
|
||||
//Let's order blocks first by free nodes and then by address
|
||||
//so that highest address fully free blocks are deallocated.
|
||||
//This improves returning memory to the OS (trimming).
|
||||
const bool is_less = l.free_nodes.size() < r.free_nodes.size();
|
||||
const bool is_equal = l.free_nodes.size() == r.free_nodes.size();
|
||||
return is_less || (is_equal && (&l < &r));
|
||||
}
|
||||
};
|
||||
typedef typename bi::make_multiset
|
||||
<block_info_t, bi::base_hook<multiset_hook_t> >::type block_multiset_t;
|
||||
typedef typename block_multiset_t::iterator block_iterator;
|
||||
|
||||
static const std::size_t MaxAlign = alignment_of<node_t>::value;
|
||||
static const std::size_t HdrSize = ((sizeof(block_info_t)-1)/MaxAlign+1)*MaxAlign;
|
||||
static const std::size_t HdrOffsetSize = ((sizeof(hdr_offset_holder)-1)/MaxAlign+1)*MaxAlign;
|
||||
static std::size_t calculate_alignment
|
||||
(std::size_t overhead_percent, std::size_t real_node_size)
|
||||
{
|
||||
//to-do: handle real_node_size != node_size
|
||||
const std::size_t divisor = overhead_percent*real_node_size;
|
||||
const std::size_t dividend = HdrOffsetSize*100;
|
||||
std::size_t elements_per_subblock = (dividend - 1)/divisor + 1;
|
||||
std::size_t candidate_power_of_2 =
|
||||
upper_power_of_2(elements_per_subblock*real_node_size + HdrOffsetSize);
|
||||
bool overhead_satisfied = false;
|
||||
//Now calculate the wors-case overhead for a subblock
|
||||
const std::size_t max_subblock_overhead = HdrSize + PayloadPerAllocation;
|
||||
while(!overhead_satisfied){
|
||||
elements_per_subblock = (candidate_power_of_2 - max_subblock_overhead)/real_node_size;
|
||||
const std::size_t overhead_size = candidate_power_of_2 - elements_per_subblock*real_node_size;
|
||||
if(overhead_size*100/candidate_power_of_2 < overhead_percent){
|
||||
overhead_satisfied = true;
|
||||
}
|
||||
else{
|
||||
candidate_power_of_2 <<= 1;
|
||||
}
|
||||
}
|
||||
return candidate_power_of_2;
|
||||
}
|
||||
|
||||
static void calculate_num_subblocks
|
||||
(std::size_t alignment, std::size_t real_node_size, std::size_t elements_per_block
|
||||
,std::size_t &num_subblocks, std::size_t &real_num_node, std::size_t overhead_percent)
|
||||
{
|
||||
std::size_t elements_per_subblock = (alignment - HdrOffsetSize)/real_node_size;
|
||||
std::size_t possible_num_subblock = (elements_per_block - 1)/elements_per_subblock + 1;
|
||||
std::size_t hdr_subblock_elements = (alignment - HdrSize - PayloadPerAllocation)/real_node_size;
|
||||
while(((possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements) < elements_per_block){
|
||||
++possible_num_subblock;
|
||||
}
|
||||
elements_per_subblock = (alignment - HdrOffsetSize)/real_node_size;
|
||||
bool overhead_satisfied = false;
|
||||
while(!overhead_satisfied){
|
||||
const std::size_t total_data = (elements_per_subblock*(possible_num_subblock-1) + hdr_subblock_elements)*real_node_size;
|
||||
const std::size_t total_size = alignment*possible_num_subblock;
|
||||
if((total_size - total_data)*100/total_size < overhead_percent){
|
||||
overhead_satisfied = true;
|
||||
}
|
||||
else{
|
||||
++possible_num_subblock;
|
||||
}
|
||||
}
|
||||
num_subblocks = possible_num_subblock;
|
||||
real_num_node = (possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements;
|
||||
}
|
||||
|
||||
public:
|
||||
//!Segment manager typedef
|
||||
typedef SegmentManagerBase segment_manager_base_type;
|
||||
|
||||
//!Constructor from a segment manager. Never throws
|
||||
private_adaptive_node_pool_impl
|
||||
( segment_manager_base_type *segment_mngr_base, std::size_t node_size
|
||||
, std::size_t nodes_per_block, std::size_t max_free_blocks
|
||||
, unsigned char overhead_percent
|
||||
)
|
||||
: m_max_free_blocks(max_free_blocks)
|
||||
, m_real_node_size(lcm(node_size, std::size_t(alignment_of<node_t>::value)))
|
||||
//Round the size to a power of two value.
|
||||
//This is the total memory size (including payload) that we want to
|
||||
//allocate from the general-purpose allocator
|
||||
, m_real_block_alignment(calculate_alignment(overhead_percent, m_real_node_size))
|
||||
//This is the real number of nodes per block
|
||||
, m_num_subblocks(0)
|
||||
, m_real_num_node(0)
|
||||
//General purpose allocator
|
||||
, mp_segment_mngr_base(segment_mngr_base)
|
||||
, m_block_multiset()
|
||||
, m_totally_free_blocks(0)
|
||||
{
|
||||
calculate_num_subblocks(m_real_block_alignment, m_real_node_size, nodes_per_block, m_num_subblocks, m_real_num_node, overhead_percent);
|
||||
}
|
||||
|
||||
//!Destructor. Deallocates all allocated blocks. Never throws
|
||||
~private_adaptive_node_pool_impl()
|
||||
{ priv_clear(); }
|
||||
|
||||
std::size_t get_real_num_node() const
|
||||
{ return m_real_num_node; }
|
||||
|
||||
//!Returns the segment manager. Never throws
|
||||
segment_manager_base_type* get_segment_manager_base()const
|
||||
{ return detail::get_pointer(mp_segment_mngr_base); }
|
||||
|
||||
//!Allocates array of count elements. Can throw boost::interprocess::bad_alloc
|
||||
void *allocate_node()
|
||||
{
|
||||
priv_invariants();
|
||||
//If there are no free nodes we allocate a new block
|
||||
if (m_block_multiset.empty()){
|
||||
priv_alloc_block(1);
|
||||
}
|
||||
//We take the first free node the multiset can't be empty
|
||||
return priv_take_first_node();
|
||||
}
|
||||
|
||||
//!Deallocates an array pointed by ptr. Never throws
|
||||
void deallocate_node(void *pElem)
|
||||
{
|
||||
multiallocation_chain chain;
|
||||
chain.push_front(void_pointer(pElem));
|
||||
this->priv_reinsert_nodes_in_block(chain, 1);
|
||||
//Update free block count
|
||||
if(m_totally_free_blocks > m_max_free_blocks){
|
||||
this->priv_deallocate_free_blocks(m_max_free_blocks);
|
||||
}
|
||||
priv_invariants();
|
||||
}
|
||||
|
||||
//!Allocates n nodes.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
multiallocation_chain allocate_nodes(const std::size_t n)
|
||||
{
|
||||
multiallocation_chain chain;
|
||||
std::size_t i = 0;
|
||||
try{
|
||||
priv_invariants();
|
||||
while(i != n){
|
||||
//If there are no free nodes we allocate all needed blocks
|
||||
if (m_block_multiset.empty()){
|
||||
priv_alloc_block(((n - i) - 1)/m_real_num_node + 1);
|
||||
}
|
||||
free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes;
|
||||
const std::size_t free_nodes_count_before = free_nodes.size();
|
||||
if(free_nodes_count_before == m_real_num_node){
|
||||
--m_totally_free_blocks;
|
||||
}
|
||||
const std::size_t num_elems = ((n-i) < free_nodes_count_before) ? (n-i) : free_nodes_count_before;
|
||||
for(std::size_t j = 0; j != num_elems; ++j){
|
||||
void *new_node = &free_nodes.front();
|
||||
free_nodes.pop_front();
|
||||
chain.push_back(new_node);
|
||||
}
|
||||
|
||||
if(free_nodes.empty()){
|
||||
m_block_multiset.erase(m_block_multiset.begin());
|
||||
}
|
||||
i += num_elems;
|
||||
}
|
||||
}
|
||||
catch(...){
|
||||
this->deallocate_nodes(chain, i);
|
||||
throw;
|
||||
}
|
||||
priv_invariants();
|
||||
return boost::interprocess::move(chain);
|
||||
}
|
||||
|
||||
//!Deallocates a linked list of nodes. Never throws
|
||||
void deallocate_nodes(multiallocation_chain nodes)
|
||||
{
|
||||
return deallocate_nodes(nodes, nodes.size());
|
||||
}
|
||||
|
||||
//!Deallocates the first n nodes of a linked list of nodes. Never throws
|
||||
void deallocate_nodes(multiallocation_chain &nodes, std::size_t n)
|
||||
{
|
||||
this->priv_reinsert_nodes_in_block(nodes, n);
|
||||
if(m_totally_free_blocks > m_max_free_blocks){
|
||||
this->priv_deallocate_free_blocks(m_max_free_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate_free_blocks()
|
||||
{ this->priv_deallocate_free_blocks(0); }
|
||||
|
||||
std::size_t num_free_nodes()
|
||||
{
|
||||
typedef typename block_multiset_t::const_iterator citerator;
|
||||
std::size_t count = 0;
|
||||
citerator it (m_block_multiset.begin()), itend(m_block_multiset.end());
|
||||
for(; it != itend; ++it){
|
||||
count += it->free_nodes.size();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void swap(private_adaptive_node_pool_impl &other)
|
||||
{
|
||||
assert(m_max_free_blocks == other.m_max_free_blocks);
|
||||
assert(m_real_node_size == other.m_real_node_size);
|
||||
assert(m_real_block_alignment == other.m_real_block_alignment);
|
||||
assert(m_real_num_node == other.m_real_num_node);
|
||||
std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base);
|
||||
std::swap(m_totally_free_blocks, other.m_totally_free_blocks);
|
||||
m_block_multiset.swap(other.m_block_multiset);
|
||||
}
|
||||
|
||||
//Deprecated, use deallocate_free_blocks
|
||||
void deallocate_free_chunks()
|
||||
{ this->priv_deallocate_free_blocks(0); }
|
||||
|
||||
private:
|
||||
void priv_deallocate_free_blocks(std::size_t max_free_blocks)
|
||||
{
|
||||
priv_invariants();
|
||||
//Now check if we've reached the free nodes limit
|
||||
//and check if we have free blocks. If so, deallocate as much
|
||||
//as we can to stay below the limit
|
||||
for( block_iterator itend = m_block_multiset.end()
|
||||
; m_totally_free_blocks > max_free_blocks
|
||||
; --m_totally_free_blocks
|
||||
){
|
||||
assert(!m_block_multiset.empty());
|
||||
block_iterator it = itend;
|
||||
--it;
|
||||
std::size_t num_nodes = it->free_nodes.size();
|
||||
assert(num_nodes == m_real_num_node);
|
||||
(void)num_nodes;
|
||||
m_block_multiset.erase_and_dispose
|
||||
(it, block_destroyer(this));
|
||||
}
|
||||
}
|
||||
|
||||
void priv_reinsert_nodes_in_block(multiallocation_chain &chain, std::size_t n)
|
||||
{
|
||||
block_iterator block_it(m_block_multiset.end());
|
||||
while(n--){
|
||||
void *pElem = detail::get_pointer(chain.front());
|
||||
chain.pop_front();
|
||||
priv_invariants();
|
||||
block_info_t *block_info = this->priv_block_from_node(pElem);
|
||||
assert(block_info->free_nodes.size() < m_real_num_node);
|
||||
//We put the node at the beginning of the free node list
|
||||
node_t * to_deallocate = static_cast<node_t*>(pElem);
|
||||
block_info->free_nodes.push_front(*to_deallocate);
|
||||
|
||||
block_iterator this_block(block_multiset_t::s_iterator_to(*block_info));
|
||||
block_iterator next_block(this_block);
|
||||
++next_block;
|
||||
|
||||
//Cache the free nodes from the block
|
||||
std::size_t this_block_free_nodes = this_block->free_nodes.size();
|
||||
|
||||
if(this_block_free_nodes == 1){
|
||||
m_block_multiset.insert(m_block_multiset.begin(), *block_info);
|
||||
}
|
||||
else{
|
||||
block_iterator next_block(this_block);
|
||||
++next_block;
|
||||
if(next_block != block_it){
|
||||
std::size_t next_free_nodes = next_block->free_nodes.size();
|
||||
if(this_block_free_nodes > next_free_nodes){
|
||||
//Now move the block to the new position
|
||||
m_block_multiset.erase(this_block);
|
||||
m_block_multiset.insert(*block_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Update free block count
|
||||
if(this_block_free_nodes == m_real_num_node){
|
||||
++m_totally_free_blocks;
|
||||
}
|
||||
priv_invariants();
|
||||
}
|
||||
}
|
||||
|
||||
node_t *priv_take_first_node()
|
||||
{
|
||||
assert(m_block_multiset.begin() != m_block_multiset.end());
|
||||
//We take the first free node the multiset can't be empty
|
||||
free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes;
|
||||
node_t *first_node = &free_nodes.front();
|
||||
const std::size_t free_nodes_count = free_nodes.size();
|
||||
assert(0 != free_nodes_count);
|
||||
free_nodes.pop_front();
|
||||
if(free_nodes_count == 1){
|
||||
m_block_multiset.erase(m_block_multiset.begin());
|
||||
}
|
||||
else if(free_nodes_count == m_real_num_node){
|
||||
--m_totally_free_blocks;
|
||||
}
|
||||
priv_invariants();
|
||||
return first_node;
|
||||
}
|
||||
|
||||
class block_destroyer;
|
||||
friend class block_destroyer;
|
||||
|
||||
class block_destroyer
|
||||
{
|
||||
public:
|
||||
block_destroyer(const private_adaptive_node_pool_impl *impl)
|
||||
: mp_impl(impl)
|
||||
{}
|
||||
|
||||
void operator()(typename block_multiset_t::pointer to_deallocate)
|
||||
{
|
||||
std::size_t free_nodes = to_deallocate->free_nodes.size();
|
||||
(void)free_nodes;
|
||||
assert(free_nodes == mp_impl->m_real_num_node);
|
||||
assert(0 == to_deallocate->hdr_offset);
|
||||
hdr_offset_holder *hdr_off_holder = mp_impl->priv_first_subblock_from_block(detail::get_pointer(to_deallocate));
|
||||
mp_impl->mp_segment_mngr_base->deallocate(hdr_off_holder);
|
||||
}
|
||||
const private_adaptive_node_pool_impl *mp_impl;
|
||||
};
|
||||
|
||||
//This macro will activate invariant checking. Slow, but helpful for debugging the code.
|
||||
//#define BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
|
||||
void priv_invariants()
|
||||
#ifdef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
|
||||
#undef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
|
||||
{
|
||||
//We iterate through the block list to free the memory
|
||||
block_iterator it(m_block_multiset.begin()),
|
||||
itend(m_block_multiset.end()), to_deallocate;
|
||||
if(it != itend){
|
||||
for(++it; it != itend; ++it){
|
||||
block_iterator prev(it);
|
||||
--prev;
|
||||
std::size_t sp = prev->free_nodes.size(),
|
||||
si = it->free_nodes.size();
|
||||
assert(sp <= si);
|
||||
(void)sp; (void)si;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
//Check that the total free nodes are correct
|
||||
it = m_block_multiset.begin();
|
||||
itend = m_block_multiset.end();
|
||||
std::size_t total_free_nodes = 0;
|
||||
for(; it != itend; ++it){
|
||||
total_free_nodes += it->free_nodes.size();
|
||||
}
|
||||
assert(total_free_nodes >= m_totally_free_blocks*m_real_num_node);
|
||||
}
|
||||
|
||||
{
|
||||
//Check that the total totally free blocks are correct
|
||||
it = m_block_multiset.begin();
|
||||
itend = m_block_multiset.end();
|
||||
std::size_t total_free_blocks = 0;
|
||||
for(; it != itend; ++it){
|
||||
total_free_blocks += (it->free_nodes.size() == m_real_num_node);
|
||||
}
|
||||
assert(total_free_blocks == m_totally_free_blocks);
|
||||
}
|
||||
{
|
||||
//Check that header offsets are correct
|
||||
it = m_block_multiset.begin();
|
||||
for(; it != itend; ++it){
|
||||
hdr_offset_holder *hdr_off_holder = priv_first_subblock_from_block(&*it);
|
||||
for(std::size_t i = 0, max = m_num_subblocks; i < max; ++i){
|
||||
assert(hdr_off_holder->hdr_offset == std::size_t(reinterpret_cast<char*>(&*it)- reinterpret_cast<char*>(hdr_off_holder)));
|
||||
assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));
|
||||
assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));
|
||||
hdr_off_holder = reinterpret_cast<hdr_offset_holder *>(reinterpret_cast<char*>(hdr_off_holder) + m_real_block_alignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
{} //empty
|
||||
#endif
|
||||
|
||||
//!Deallocates all used memory. Never throws
|
||||
void priv_clear()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
block_iterator it = m_block_multiset.begin();
|
||||
block_iterator itend = m_block_multiset.end();
|
||||
std::size_t num_free_nodes = 0;
|
||||
for(; it != itend; ++it){
|
||||
//Check for memory leak
|
||||
std::size_t n = (std::size_t)it->free_nodes.size(); (void)n;
|
||||
assert(it->free_nodes.size() == m_real_num_node);
|
||||
++num_free_nodes;
|
||||
}
|
||||
assert(num_free_nodes == m_totally_free_blocks);
|
||||
#endif
|
||||
priv_invariants();
|
||||
m_block_multiset.clear_and_dispose
|
||||
(block_destroyer(this));
|
||||
m_totally_free_blocks = 0;
|
||||
}
|
||||
|
||||
block_info_t *priv_block_from_node(void *node) const
|
||||
{
|
||||
hdr_offset_holder *hdr_off_holder =
|
||||
reinterpret_cast<hdr_offset_holder*>((std::size_t)node & std::size_t(~(m_real_block_alignment - 1)));
|
||||
assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));
|
||||
assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));
|
||||
block_info_t *block = reinterpret_cast<block_info_t *>
|
||||
(reinterpret_cast<char*>(hdr_off_holder) + hdr_off_holder->hdr_offset);
|
||||
assert(block->hdr_offset == 0);
|
||||
return block;
|
||||
}
|
||||
|
||||
hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block) const
|
||||
{
|
||||
hdr_offset_holder *hdr_off_holder = reinterpret_cast<hdr_offset_holder*>
|
||||
(reinterpret_cast<char*>(block) - (m_num_subblocks-1)*m_real_block_alignment);
|
||||
assert(hdr_off_holder->hdr_offset == std::size_t(reinterpret_cast<char*>(block) - reinterpret_cast<char*>(hdr_off_holder)));
|
||||
assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));
|
||||
assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));
|
||||
return hdr_off_holder;
|
||||
}
|
||||
|
||||
//!Allocates a several blocks of nodes. Can throw boost::interprocess::bad_alloc
|
||||
void priv_alloc_block(std::size_t n)
|
||||
{
|
||||
std::size_t real_block_size = m_real_block_alignment*m_num_subblocks - SegmentManagerBase::PayloadPerAllocation;
|
||||
std::size_t elements_per_subblock = (m_real_block_alignment - HdrOffsetSize)/m_real_node_size;
|
||||
std::size_t hdr_subblock_elements = (m_real_block_alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/m_real_node_size;
|
||||
|
||||
for(std::size_t i = 0; i != n; ++i){
|
||||
//We allocate a new NodeBlock and put it the last
|
||||
//element of the tree
|
||||
char *mem_address = static_cast<char*>
|
||||
(mp_segment_mngr_base->allocate_aligned(real_block_size, m_real_block_alignment));
|
||||
if(!mem_address) throw std::bad_alloc();
|
||||
++m_totally_free_blocks;
|
||||
|
||||
//First initialize header information on the last subblock
|
||||
char *hdr_addr = mem_address + m_real_block_alignment*(m_num_subblocks-1);
|
||||
block_info_t *c_info = new(hdr_addr)block_info_t;
|
||||
//Some structural checks
|
||||
assert(static_cast<void*>(&static_cast<hdr_offset_holder*>(c_info)->hdr_offset) ==
|
||||
static_cast<void*>(c_info));
|
||||
typename free_nodes_t::iterator prev_insert_pos = c_info->free_nodes.before_begin();
|
||||
for( std::size_t subblock = 0, maxsubblock = m_num_subblocks - 1
|
||||
; subblock < maxsubblock
|
||||
; ++subblock, mem_address += m_real_block_alignment){
|
||||
//Initialize header offset mark
|
||||
new(mem_address) hdr_offset_holder(std::size_t(hdr_addr - mem_address));
|
||||
char *pNode = mem_address + HdrOffsetSize;
|
||||
for(std::size_t i = 0; i < elements_per_subblock; ++i){
|
||||
prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t);
|
||||
pNode += m_real_node_size;
|
||||
}
|
||||
}
|
||||
{
|
||||
char *pNode = hdr_addr + HdrSize;
|
||||
//We initialize all Nodes in Node Block to insert
|
||||
//them in the free Node list
|
||||
for(std::size_t i = 0; i < hdr_subblock_elements; ++i){
|
||||
prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t);
|
||||
pNode += m_real_node_size;
|
||||
}
|
||||
}
|
||||
//Insert the block after the free node list is full
|
||||
m_block_multiset.insert(m_block_multiset.end(), *c_info);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef typename boost::pointer_to_other
|
||||
<void_pointer, segment_manager_base_type>::type segment_mngr_base_ptr_t;
|
||||
|
||||
const std::size_t m_max_free_blocks;
|
||||
const std::size_t m_real_node_size;
|
||||
//Round the size to a power of two value.
|
||||
//This is the total memory size (including payload) that we want to
|
||||
//allocate from the general-purpose allocator
|
||||
const std::size_t m_real_block_alignment;
|
||||
std::size_t m_num_subblocks;
|
||||
//This is the real number of nodes per block
|
||||
//const
|
||||
std::size_t m_real_num_node;
|
||||
segment_mngr_base_ptr_t mp_segment_mngr_base;//Segment manager
|
||||
block_multiset_t m_block_multiset; //Intrusive block list
|
||||
std::size_t m_totally_free_blocks; //Free blocks
|
||||
};
|
||||
|
||||
template< class SegmentManager
|
||||
, std::size_t NodeSize
|
||||
, std::size_t NodesPerBlock
|
||||
, std::size_t MaxFreeBlocks
|
||||
, unsigned char OverheadPercent
|
||||
>
|
||||
class private_adaptive_node_pool
|
||||
: public private_adaptive_node_pool_impl
|
||||
<typename SegmentManager::segment_manager_base_type>
|
||||
{
|
||||
typedef private_adaptive_node_pool_impl
|
||||
<typename SegmentManager::segment_manager_base_type> base_t;
|
||||
//Non-copyable
|
||||
private_adaptive_node_pool();
|
||||
private_adaptive_node_pool(const private_adaptive_node_pool &);
|
||||
private_adaptive_node_pool &operator=(const private_adaptive_node_pool &);
|
||||
|
||||
public:
|
||||
typedef SegmentManager segment_manager;
|
||||
|
||||
static const std::size_t nodes_per_block = NodesPerBlock;
|
||||
|
||||
//Deprecated, use node_per_block
|
||||
static const std::size_t nodes_per_chunk = NodesPerBlock;
|
||||
|
||||
//!Constructor from a segment manager. Never throws
|
||||
private_adaptive_node_pool(segment_manager *segment_mngr)
|
||||
: base_t(segment_mngr, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent)
|
||||
{}
|
||||
|
||||
//!Returns the segment manager. Never throws
|
||||
segment_manager* get_segment_manager() const
|
||||
{ return static_cast<segment_manager*>(base_t::get_segment_manager_base()); }
|
||||
};
|
||||
|
||||
//!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 SegmentManager
|
||||
, std::size_t NodeSize
|
||||
, std::size_t NodesPerBlock
|
||||
, std::size_t MaxFreeBlocks
|
||||
, unsigned char OverheadPercent
|
||||
>
|
||||
class shared_adaptive_node_pool
|
||||
: public detail::shared_pool_impl
|
||||
< private_adaptive_node_pool
|
||||
<SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
|
||||
>
|
||||
{
|
||||
typedef detail::shared_pool_impl
|
||||
< private_adaptive_node_pool
|
||||
<SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
|
||||
> base_t;
|
||||
public:
|
||||
shared_adaptive_node_pool(SegmentManager *segment_mgnr)
|
||||
: base_t(segment_mgnr)
|
||||
{}
|
||||
};
|
||||
|
||||
} //namespace detail {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP
|
||||
|
||||
@@ -0,0 +1,839 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (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/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/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)
|
||||
{
|
||||
//Deallocate all new linked list at once
|
||||
mp_node_pool->deallocate_nodes(m_cached_nodes, n);
|
||||
}
|
||||
};
|
||||
|
||||
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 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 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)
|
||||
{
|
||||
detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool);
|
||||
alloc1.m_cached_nodes.swap(alloc2.m_cached_nodes);
|
||||
detail::do_swap(alloc1.m_max_cached_nodes, alloc2.m_max_cached_nodes);
|
||||
}
|
||||
|
||||
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);
|
||||
//-----------------------
|
||||
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
|
||||
//!interprocess_mutex 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
|
||||
@@ -0,0 +1,409 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-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_DETAIL_NODE_POOL_HPP
|
||||
#define BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP
|
||||
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <boost/intrusive/slist.hpp>
|
||||
#include <boost/math/common_factor_ct.hpp>
|
||||
#include <boost/pointer_to_other.hpp>
|
||||
|
||||
#include <boost/interprocess/sync/interprocess_mutex.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/interprocess/detail/math_functions.hpp>
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
#include <boost/interprocess/allocators/detail/node_tools.hpp>
|
||||
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
|
||||
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
//!\file
|
||||
//!Describes the real adaptive pool shared by many Interprocess adaptive pool allocators
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace detail {
|
||||
|
||||
template<class SegmentManagerBase>
|
||||
class private_node_pool_impl
|
||||
{
|
||||
//Non-copyable
|
||||
private_node_pool_impl();
|
||||
private_node_pool_impl(const private_node_pool_impl &);
|
||||
private_node_pool_impl &operator=(const private_node_pool_impl &);
|
||||
|
||||
//A node object will hold node_t when it's not allocated
|
||||
public:
|
||||
typedef typename SegmentManagerBase::void_pointer void_pointer;
|
||||
typedef typename node_slist<void_pointer>::slist_hook_t slist_hook_t;
|
||||
typedef typename node_slist<void_pointer>::node_t node_t;
|
||||
typedef typename node_slist<void_pointer>::node_slist_t free_nodes_t;
|
||||
typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain;
|
||||
|
||||
private:
|
||||
typedef typename bi::make_slist
|
||||
< node_t, bi::base_hook<slist_hook_t>
|
||||
, bi::linear<true>
|
||||
, bi::constant_time_size<false> >::type blockslist_t;
|
||||
public:
|
||||
|
||||
//!Segment manager typedef
|
||||
typedef SegmentManagerBase segment_manager_base_type;
|
||||
|
||||
//!Constructor from a segment manager. Never throws
|
||||
private_node_pool_impl(segment_manager_base_type *segment_mngr_base, std::size_t node_size, std::size_t nodes_per_block)
|
||||
: m_nodes_per_block(nodes_per_block)
|
||||
, m_real_node_size(detail::lcm(node_size, std::size_t(alignment_of<node_t>::value)))
|
||||
//General purpose allocator
|
||||
, mp_segment_mngr_base(segment_mngr_base)
|
||||
, m_blocklist()
|
||||
, m_freelist()
|
||||
//Debug node count
|
||||
, m_allocated(0)
|
||||
{}
|
||||
|
||||
//!Destructor. Deallocates all allocated blocks. Never throws
|
||||
~private_node_pool_impl()
|
||||
{ this->purge_blocks(); }
|
||||
|
||||
std::size_t get_real_num_node() const
|
||||
{ return m_nodes_per_block; }
|
||||
|
||||
//!Returns the segment manager. Never throws
|
||||
segment_manager_base_type* get_segment_manager_base()const
|
||||
{ return detail::get_pointer(mp_segment_mngr_base); }
|
||||
|
||||
//!Allocates array of count elements. Can throw boost::interprocess::bad_alloc
|
||||
void *allocate_node()
|
||||
{
|
||||
//If there are no free nodes we allocate a new block
|
||||
if (m_freelist.empty())
|
||||
priv_alloc_block();
|
||||
//We take the first free node
|
||||
node_t *n = &m_freelist.front();
|
||||
m_freelist.pop_front();
|
||||
++m_allocated;
|
||||
return n;
|
||||
}
|
||||
|
||||
//!Deallocates an array pointed by ptr. Never throws
|
||||
void deallocate_node(void *ptr)
|
||||
{
|
||||
//We put the node at the beginning of the free node list
|
||||
node_t * to_deallocate = static_cast<node_t*>(ptr);
|
||||
m_freelist.push_front(*to_deallocate);
|
||||
assert(m_allocated>0);
|
||||
--m_allocated;
|
||||
}
|
||||
|
||||
//!Allocates a singly linked list of n nodes ending in null pointer
|
||||
//!can throw boost::interprocess::bad_alloc
|
||||
multiallocation_chain allocate_nodes(const std::size_t n)
|
||||
{
|
||||
multiallocation_chain nodes;
|
||||
std::size_t i = 0;
|
||||
try{
|
||||
for(; i < n; ++i){
|
||||
nodes.push_front(this->allocate_node());
|
||||
}
|
||||
}
|
||||
catch(...){
|
||||
this->deallocate_nodes(nodes, i);
|
||||
throw;
|
||||
}
|
||||
return boost::interprocess::move(nodes);
|
||||
}
|
||||
|
||||
//!Deallocates the first n nodes of a linked list of nodes. Never throws
|
||||
void deallocate_nodes(multiallocation_chain &nodes, std::size_t n)
|
||||
{
|
||||
for(std::size_t i = 0; i < n; ++i){
|
||||
void *p = detail::get_pointer(nodes.front());
|
||||
assert(p);
|
||||
nodes.pop_front();
|
||||
this->deallocate_node(p);
|
||||
}
|
||||
}
|
||||
|
||||
//!Deallocates the nodes pointed by the multiallocation iterator. Never throws
|
||||
void deallocate_nodes(multiallocation_chain chain)
|
||||
{
|
||||
while(!chain.empty()){
|
||||
void *addr = detail::get_pointer(chain.front());
|
||||
chain.pop_front();
|
||||
deallocate_node(addr);
|
||||
}
|
||||
}
|
||||
|
||||
//!Deallocates all the free blocks of memory. Never throws
|
||||
void deallocate_free_blocks()
|
||||
{
|
||||
typedef typename free_nodes_t::iterator nodelist_iterator;
|
||||
typename blockslist_t::iterator bit(m_blocklist.before_begin()),
|
||||
it(m_blocklist.begin()),
|
||||
itend(m_blocklist.end());
|
||||
free_nodes_t backup_list;
|
||||
nodelist_iterator backup_list_last = backup_list.before_begin();
|
||||
|
||||
//Execute the algorithm and get an iterator to the last value
|
||||
std::size_t blocksize = detail::get_rounded_size
|
||||
(m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
|
||||
|
||||
while(it != itend){
|
||||
//Collect all the nodes from the block pointed by it
|
||||
//and push them in the list
|
||||
free_nodes_t free_nodes;
|
||||
nodelist_iterator last_it = free_nodes.before_begin();
|
||||
const void *addr = get_block_from_hook(&*it, blocksize);
|
||||
|
||||
m_freelist.remove_and_dispose_if
|
||||
(is_between(addr, blocksize), push_in_list(free_nodes, last_it));
|
||||
|
||||
//If the number of nodes is equal to m_nodes_per_block
|
||||
//this means that the block can be deallocated
|
||||
if(free_nodes.size() == m_nodes_per_block){
|
||||
//Unlink the nodes
|
||||
free_nodes.clear();
|
||||
it = m_blocklist.erase_after(bit);
|
||||
mp_segment_mngr_base->deallocate((void*)addr);
|
||||
}
|
||||
//Otherwise, insert them in the backup list, since the
|
||||
//next "remove_if" does not need to check them again.
|
||||
else{
|
||||
//Assign the iterator to the last value if necessary
|
||||
if(backup_list.empty() && !m_freelist.empty()){
|
||||
backup_list_last = last_it;
|
||||
}
|
||||
//Transfer nodes. This is constant time.
|
||||
backup_list.splice_after
|
||||
( backup_list.before_begin()
|
||||
, free_nodes
|
||||
, free_nodes.before_begin()
|
||||
, last_it
|
||||
, free_nodes.size());
|
||||
bit = it;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
//We should have removed all the nodes from the free list
|
||||
assert(m_freelist.empty());
|
||||
|
||||
//Now pass all the node to the free list again
|
||||
m_freelist.splice_after
|
||||
( m_freelist.before_begin()
|
||||
, backup_list
|
||||
, backup_list.before_begin()
|
||||
, backup_list_last
|
||||
, backup_list.size());
|
||||
}
|
||||
|
||||
std::size_t num_free_nodes()
|
||||
{ return m_freelist.size(); }
|
||||
|
||||
//!Deallocates all used memory. Precondition: all nodes allocated from this pool should
|
||||
//!already be deallocated. Otherwise, undefined behaviour. Never throws
|
||||
void purge_blocks()
|
||||
{
|
||||
//check for memory leaks
|
||||
assert(m_allocated==0);
|
||||
std::size_t blocksize = detail::get_rounded_size
|
||||
(m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
|
||||
typename blockslist_t::iterator
|
||||
it(m_blocklist.begin()), itend(m_blocklist.end()), aux;
|
||||
|
||||
//We iterate though the NodeBlock list to free the memory
|
||||
while(!m_blocklist.empty()){
|
||||
void *addr = get_block_from_hook(&m_blocklist.front(), blocksize);
|
||||
m_blocklist.pop_front();
|
||||
mp_segment_mngr_base->deallocate((void*)addr);
|
||||
}
|
||||
//Just clear free node list
|
||||
m_freelist.clear();
|
||||
}
|
||||
|
||||
void swap(private_node_pool_impl &other)
|
||||
{
|
||||
std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base);
|
||||
m_blocklist.swap(other.m_blocklist);
|
||||
m_freelist.swap(other.m_freelist);
|
||||
std::swap(m_allocated, other.m_allocated);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct push_in_list
|
||||
{
|
||||
push_in_list(free_nodes_t &l, typename free_nodes_t::iterator &it)
|
||||
: slist_(l), last_it_(it)
|
||||
{}
|
||||
|
||||
void operator()(typename free_nodes_t::pointer p) const
|
||||
{
|
||||
slist_.push_front(*p);
|
||||
if(slist_.size() == 1){ //Cache last element
|
||||
++last_it_ = slist_.begin();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
free_nodes_t &slist_;
|
||||
typename free_nodes_t::iterator &last_it_;
|
||||
};
|
||||
|
||||
struct is_between
|
||||
: std::unary_function<typename free_nodes_t::value_type, bool>
|
||||
{
|
||||
is_between(const void *addr, std::size_t size)
|
||||
: beg_(static_cast<const char *>(addr)), end_(beg_+size)
|
||||
{}
|
||||
|
||||
bool operator()(typename free_nodes_t::const_reference v) const
|
||||
{
|
||||
return (beg_ <= reinterpret_cast<const char *>(&v) &&
|
||||
end_ > reinterpret_cast<const char *>(&v));
|
||||
}
|
||||
private:
|
||||
const char * beg_;
|
||||
const char * end_;
|
||||
};
|
||||
|
||||
//!Allocates a block of nodes. Can throw boost::interprocess::bad_alloc
|
||||
void priv_alloc_block()
|
||||
{
|
||||
//We allocate a new NodeBlock and put it as first
|
||||
//element in the free Node list
|
||||
std::size_t blocksize =
|
||||
detail::get_rounded_size(m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
|
||||
char *pNode = reinterpret_cast<char*>
|
||||
(mp_segment_mngr_base->allocate(blocksize + sizeof(node_t)));
|
||||
if(!pNode) throw bad_alloc();
|
||||
char *pBlock = pNode;
|
||||
m_blocklist.push_front(get_block_hook(pBlock, blocksize));
|
||||
|
||||
//We initialize all Nodes in Node Block to insert
|
||||
//them in the free Node list
|
||||
for(std::size_t i = 0; i < m_nodes_per_block; ++i, pNode += m_real_node_size){
|
||||
m_freelist.push_front(*new (pNode) node_t);
|
||||
}
|
||||
}
|
||||
|
||||
//!Deprecated, use deallocate_free_blocks
|
||||
void deallocate_free_chunks()
|
||||
{ this->deallocate_free_blocks(); }
|
||||
|
||||
//!Deprecated, use purge_blocks
|
||||
void purge_chunks()
|
||||
{ this->purge_blocks(); }
|
||||
|
||||
private:
|
||||
//!Returns a reference to the block hook placed in the end of the block
|
||||
static inline node_t & get_block_hook (void *block, std::size_t blocksize)
|
||||
{
|
||||
return *reinterpret_cast<node_t*>(reinterpret_cast<char*>(block) + blocksize);
|
||||
}
|
||||
|
||||
//!Returns the starting address of the block reference to the block hook placed in the end of the block
|
||||
inline void *get_block_from_hook (node_t *hook, std::size_t blocksize)
|
||||
{
|
||||
return (reinterpret_cast<char*>(hook) - blocksize);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef typename boost::pointer_to_other
|
||||
<void_pointer, segment_manager_base_type>::type segment_mngr_base_ptr_t;
|
||||
|
||||
const std::size_t m_nodes_per_block;
|
||||
const std::size_t m_real_node_size;
|
||||
segment_mngr_base_ptr_t mp_segment_mngr_base; //Segment manager
|
||||
blockslist_t m_blocklist; //Intrusive container of blocks
|
||||
free_nodes_t m_freelist; //Intrusive container of free nods
|
||||
std::size_t m_allocated; //Used nodes for debugging
|
||||
};
|
||||
|
||||
|
||||
//!Pooled shared memory allocator using single segregated storage. 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 SegmentManager, std::size_t NodeSize, std::size_t NodesPerBlock >
|
||||
class private_node_pool
|
||||
//Inherit from the implementation to avoid template bloat
|
||||
: public private_node_pool_impl<typename SegmentManager::segment_manager_base_type>
|
||||
{
|
||||
typedef private_node_pool_impl<typename SegmentManager::segment_manager_base_type> base_t;
|
||||
//Non-copyable
|
||||
private_node_pool();
|
||||
private_node_pool(const private_node_pool &);
|
||||
private_node_pool &operator=(const private_node_pool &);
|
||||
|
||||
public:
|
||||
typedef SegmentManager segment_manager;
|
||||
|
||||
static const std::size_t nodes_per_block = NodesPerBlock;
|
||||
//Deprecated, use nodes_per_block
|
||||
static const std::size_t nodes_per_chunk = NodesPerBlock;
|
||||
|
||||
//!Constructor from a segment manager. Never throws
|
||||
private_node_pool(segment_manager *segment_mngr)
|
||||
: base_t(segment_mngr, NodeSize, NodesPerBlock)
|
||||
{}
|
||||
|
||||
//!Returns the segment manager. Never throws
|
||||
segment_manager* get_segment_manager() const
|
||||
{ return static_cast<segment_manager*>(base_t::get_segment_manager_base()); }
|
||||
};
|
||||
|
||||
|
||||
//!Pooled shared memory allocator using single segregated storage. 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
|
||||
//!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 SegmentManager
|
||||
, std::size_t NodeSize
|
||||
, std::size_t NodesPerBlock
|
||||
>
|
||||
class shared_node_pool
|
||||
: public detail::shared_pool_impl
|
||||
< private_node_pool
|
||||
<SegmentManager, NodeSize, NodesPerBlock>
|
||||
>
|
||||
{
|
||||
typedef detail::shared_pool_impl
|
||||
< private_node_pool
|
||||
<SegmentManager, NodeSize, NodesPerBlock>
|
||||
> base_t;
|
||||
public:
|
||||
shared_node_pool(SegmentManager *segment_mgnr)
|
||||
: base_t(segment_mgnr)
|
||||
{}
|
||||
};
|
||||
|
||||
} //namespace detail {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP
|
||||
@@ -0,0 +1,50 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2007-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_DETAIL_NODE_TOOLS_HPP
|
||||
#define BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP
|
||||
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <boost/intrusive/slist.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace detail {
|
||||
|
||||
|
||||
template<class VoidPointer>
|
||||
struct node_slist
|
||||
{
|
||||
//This hook will be used to chain the individual nodes
|
||||
typedef typename bi::make_slist_base_hook
|
||||
<bi::void_pointer<VoidPointer>, bi::link_mode<bi::normal_link> >::type slist_hook_t;
|
||||
|
||||
//A node object will hold node_t when it's not allocated
|
||||
struct node_t
|
||||
: public slist_hook_t
|
||||
{};
|
||||
|
||||
typedef typename bi::make_slist
|
||||
<node_t, bi::linear<true>, bi::base_hook<slist_hook_t> >::type node_slist_t;
|
||||
};
|
||||
|
||||
} //namespace detail {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP
|
||||
@@ -0,0 +1,449 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-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_NODE_ALLOCATOR_HPP
|
||||
#define BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP
|
||||
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#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/assert.hpp>
|
||||
#include <boost/utility/addressof.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
#include <boost/interprocess/allocators/detail/node_pool.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes node_allocator pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
/// @cond
|
||||
|
||||
namespace detail{
|
||||
|
||||
template < unsigned int Version
|
||||
, class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock
|
||||
>
|
||||
class node_allocator_base
|
||||
: public node_pool_allocation_impl
|
||||
< node_allocator_base
|
||||
< Version, T, SegmentManager, NodesPerBlock>
|
||||
, Version
|
||||
, T
|
||||
, SegmentManager
|
||||
>
|
||||
{
|
||||
public:
|
||||
typedef typename SegmentManager::void_pointer void_pointer;
|
||||
typedef SegmentManager segment_manager;
|
||||
typedef node_allocator_base
|
||||
<Version, T, SegmentManager, NodesPerBlock> self_t;
|
||||
|
||||
/// @cond
|
||||
|
||||
template <int dummy>
|
||||
struct node_pool
|
||||
{
|
||||
typedef detail::shared_node_pool
|
||||
< SegmentManager, sizeof_value<T>::value, NodesPerBlock> type;
|
||||
|
||||
static type *get(void *p)
|
||||
{ return static_cast<type*>(p); }
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
BOOST_STATIC_ASSERT((Version <=2));
|
||||
|
||||
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::interprocess::version_type<node_allocator_base, Version> version;
|
||||
typedef detail::transform_multiallocation_chain
|
||||
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
|
||||
|
||||
//!Obtains node_allocator_base from
|
||||
//!node_allocator_base
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
/// @cond
|
||||
private:
|
||||
//!Not assignable from related node_allocator_base
|
||||
template<unsigned int Version2, class T2, class SegmentManager2, std::size_t N2>
|
||||
node_allocator_base& operator=
|
||||
(const node_allocator_base<Version2, T2, SegmentManager2, N2>&);
|
||||
|
||||
//!Not assignable from other node_allocator_base
|
||||
//node_allocator_base& operator=(const node_allocator_base&);
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
//!Constructor from a segment manager. If not present, constructs a node
|
||||
//!pool. Increments the reference count of the associated node pool.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
node_allocator_base(segment_manager *segment_mngr)
|
||||
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { }
|
||||
|
||||
//!Copy constructor from other node_allocator_base. Increments the reference
|
||||
//!count of the associated node pool. Never throws
|
||||
node_allocator_base(const node_allocator_base &other)
|
||||
: mp_node_pool(other.get_node_pool())
|
||||
{
|
||||
node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count();
|
||||
}
|
||||
|
||||
//!Copy constructor from related node_allocator_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>
|
||||
node_allocator_base
|
||||
(const node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> &other)
|
||||
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(other.get_segment_manager())) { }
|
||||
|
||||
//!Assignment from other node_allocator_base
|
||||
node_allocator_base& operator=(const node_allocator_base &other)
|
||||
{
|
||||
node_allocator_base c(other);
|
||||
swap(*this, c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Destructor, removes node_pool_t from memory
|
||||
//!if its reference count reaches to zero. Never throws
|
||||
~node_allocator_base()
|
||||
{ detail::destroy_node_pool_if_last_link(node_pool<0>::get(detail::get_pointer(mp_node_pool))); }
|
||||
|
||||
//!Returns a pointer to the node pool.
|
||||
//!Never throws
|
||||
void* get_node_pool() const
|
||||
{ return detail::get_pointer(mp_node_pool); }
|
||||
|
||||
//!Returns the segment manager.
|
||||
//!Never throws
|
||||
segment_manager* get_segment_manager()const
|
||||
{ return node_pool<0>::get(detail::get_pointer(mp_node_pool))->get_segment_manager(); }
|
||||
|
||||
//!Swaps allocators. Does not throw. If each allocator is placed in a
|
||||
//!different memory segment, the result is undefined.
|
||||
friend void swap(self_t &alloc1, self_t &alloc2)
|
||||
{ detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); }
|
||||
|
||||
/// @cond
|
||||
private:
|
||||
void_pointer mp_node_pool;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
//!Equality test for same type
|
||||
//!of node_allocator_base
|
||||
template<unsigned int V, class T, class S, std::size_t NPC> inline
|
||||
bool operator==(const node_allocator_base<V, T, S, NPC> &alloc1,
|
||||
const node_allocator_base<V, T, S, NPC> &alloc2)
|
||||
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
|
||||
|
||||
//!Inequality test for same type
|
||||
//!of node_allocator_base
|
||||
template<unsigned int V, class T, class S, std::size_t NPC> inline
|
||||
bool operator!=(const node_allocator_base<V, T, S, NPC> &alloc1,
|
||||
const node_allocator_base<V, T, S, NPC> &alloc2)
|
||||
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
|
||||
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock = 64
|
||||
>
|
||||
class node_allocator_v1
|
||||
: public node_allocator_base
|
||||
< 1
|
||||
, T
|
||||
, SegmentManager
|
||||
, NodesPerBlock
|
||||
>
|
||||
{
|
||||
public:
|
||||
typedef detail::node_allocator_base
|
||||
< 1, T, SegmentManager, NodesPerBlock> base_t;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef node_allocator_v1<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
node_allocator_v1(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
node_allocator_v1
|
||||
(const node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
};
|
||||
|
||||
} //namespace detail{
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!An STL node allocator that uses a segment manager as memory
|
||||
//!source. The internal pointer type will of the same type (raw, smart) as
|
||||
//!"typename SegmentManager::void_pointer" type. This allows
|
||||
//!placing the allocator in shared memory, memory mapped-files, etc...
|
||||
//!This node allocator shares a segregated storage between all instances
|
||||
//!of node_allocator with equal sizeof(T) placed in the same segment
|
||||
//!group. NodesPerBlock is the number of nodes allocated at once when the allocator
|
||||
//!needs runs out of nodes
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock
|
||||
>
|
||||
class node_allocator
|
||||
/// @cond
|
||||
: public detail::node_allocator_base
|
||||
< 2
|
||||
, T
|
||||
, SegmentManager
|
||||
, NodesPerBlock
|
||||
>
|
||||
/// @endcond
|
||||
{
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
typedef detail::node_allocator_base
|
||||
< 2, T, SegmentManager, NodesPerBlock> base_t;
|
||||
public:
|
||||
typedef boost::interprocess::version_type<node_allocator, 2> version;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef node_allocator<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
node_allocator(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
node_allocator
|
||||
(const node_allocator<T2, SegmentManager, NodesPerBlock> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
|
||||
#else //BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
public:
|
||||
typedef implementation_defined::segment_manager segment_manager;
|
||||
typedef segment_manager::void_pointer void_pointer;
|
||||
typedef implementation_defined::pointer pointer;
|
||||
typedef implementation_defined::const_pointer 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;
|
||||
|
||||
//!Obtains node_allocator from
|
||||
//!node_allocator
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef node_allocator<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
private:
|
||||
//!Not assignable from
|
||||
//!related node_allocator
|
||||
template<class T2, class SegmentManager2, std::size_t N2>
|
||||
node_allocator& operator=
|
||||
(const node_allocator<T2, SegmentManager2, N2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!other node_allocator
|
||||
//node_allocator& operator=(const node_allocator&);
|
||||
|
||||
public:
|
||||
//!Constructor from a segment manager. If not present, constructs a node
|
||||
//!pool. Increments the reference count of the associated node pool.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
node_allocator(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other node_allocator. Increments the reference
|
||||
//!count of the associated node pool. Never throws
|
||||
node_allocator(const node_allocator &other);
|
||||
|
||||
//!Copy constructor from related node_allocator. 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>
|
||||
node_allocator
|
||||
(const node_allocator<T2, SegmentManager, NodesPerBlock> &other);
|
||||
|
||||
//!Destructor, removes node_pool_t from memory
|
||||
//!if its reference count reaches to zero. Never throws
|
||||
~node_allocator();
|
||||
|
||||
//!Returns a pointer to the node pool.
|
||||
//!Never throws
|
||||
void* get_node_pool() const;
|
||||
|
||||
//!Returns the segment manager.
|
||||
//!Never throws
|
||||
segment_manager* get_segment_manager()const;
|
||||
|
||||
//!Returns the number of elements that could be allocated.
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!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);
|
||||
|
||||
//!Deallocate allocated memory.
|
||||
//!Never throws
|
||||
void deallocate(const pointer &ptr, size_type count);
|
||||
|
||||
//!Deallocates all free blocks
|
||||
//!of the pool
|
||||
void deallocate_free_blocks();
|
||||
|
||||
//!Swaps allocators. Does not throw. If each allocator is placed in a
|
||||
//!different memory segment, the result is undefined.
|
||||
friend void swap(self_t &alloc1, self_t &alloc2);
|
||||
|
||||
//!Returns address of mutable object.
|
||||
//!Never throws
|
||||
pointer address(reference value) const;
|
||||
|
||||
//!Returns address of non mutable object.
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Copy construct an object.
|
||||
//!Throws if T's copy constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
//!Destroys object. Throws if object's
|
||||
//!destructor throws
|
||||
void destroy(const pointer &ptr);
|
||||
|
||||
//!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;
|
||||
|
||||
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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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();
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!Equality test for same type
|
||||
//!of node_allocator
|
||||
template<class T, class S, std::size_t NPC> inline
|
||||
bool operator==(const node_allocator<T, S, NPC> &alloc1,
|
||||
const node_allocator<T, S, NPC> &alloc2);
|
||||
|
||||
//!Inequality test for same type
|
||||
//!of node_allocator
|
||||
template<class T, class S, std::size_t NPC> inline
|
||||
bool operator!=(const node_allocator<T, S, NPC> &alloc1,
|
||||
const node_allocator<T, S, NPC> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP
|
||||
@@ -0,0 +1,465 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-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_PRIVATE_ADAPTIVE_POOL_HPP
|
||||
#define BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP
|
||||
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#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/assert.hpp>
|
||||
#include <boost/utility/addressof.hpp>
|
||||
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes private_adaptive_pool_base pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
/// @cond
|
||||
|
||||
namespace detail {
|
||||
|
||||
template < unsigned int Version
|
||||
, class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock
|
||||
, std::size_t MaxFreeBlocks
|
||||
, unsigned char OverheadPercent
|
||||
>
|
||||
class private_adaptive_pool_base
|
||||
: public node_pool_allocation_impl
|
||||
< private_adaptive_pool_base < Version, T, SegmentManager, NodesPerBlock
|
||||
, MaxFreeBlocks, OverheadPercent>
|
||||
, Version
|
||||
, T
|
||||
, SegmentManager
|
||||
>
|
||||
{
|
||||
public:
|
||||
//Segment manager
|
||||
typedef SegmentManager segment_manager;
|
||||
typedef typename SegmentManager::void_pointer void_pointer;
|
||||
|
||||
/// @cond
|
||||
private:
|
||||
typedef private_adaptive_pool_base
|
||||
< Version, T, SegmentManager, NodesPerBlock
|
||||
, MaxFreeBlocks, OverheadPercent> self_t;
|
||||
typedef detail::private_adaptive_node_pool
|
||||
<SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
, MaxFreeBlocks
|
||||
, OverheadPercent
|
||||
> node_pool_t;
|
||||
|
||||
BOOST_STATIC_ASSERT((Version <=2));
|
||||
|
||||
/// @endcond
|
||||
|
||||
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::interprocess::version_type
|
||||
<private_adaptive_pool_base, Version> version;
|
||||
typedef detail::transform_multiallocation_chain
|
||||
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
|
||||
|
||||
//!Obtains node_allocator from other node_allocator
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef private_adaptive_pool_base
|
||||
<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
/// @cond
|
||||
|
||||
template <int dummy>
|
||||
struct node_pool
|
||||
{
|
||||
typedef detail::private_adaptive_node_pool
|
||||
<SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
, MaxFreeBlocks
|
||||
, OverheadPercent
|
||||
> type;
|
||||
|
||||
static type *get(void *p)
|
||||
{ return static_cast<type*>(p); }
|
||||
};
|
||||
|
||||
private:
|
||||
//!Not assignable from related private_adaptive_pool_base
|
||||
template<unsigned int Version2, class T2, class MemoryAlgorithm2, std::size_t N2, std::size_t F2, unsigned char OP2>
|
||||
private_adaptive_pool_base& operator=
|
||||
(const private_adaptive_pool_base<Version2, T2, MemoryAlgorithm2, N2, F2, OP2>&);
|
||||
|
||||
//!Not assignable from other private_adaptive_pool_base
|
||||
private_adaptive_pool_base& operator=(const private_adaptive_pool_base&);
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
//!Constructor from a segment manager
|
||||
private_adaptive_pool_base(segment_manager *segment_mngr)
|
||||
: m_node_pool(segment_mngr)
|
||||
{}
|
||||
|
||||
//!Copy constructor from other private_adaptive_pool_base. Never throws
|
||||
private_adaptive_pool_base(const private_adaptive_pool_base &other)
|
||||
: m_node_pool(other.get_segment_manager())
|
||||
{}
|
||||
|
||||
//!Copy constructor from related private_adaptive_pool_base. Never throws.
|
||||
template<class T2>
|
||||
private_adaptive_pool_base
|
||||
(const private_adaptive_pool_base
|
||||
<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
|
||||
: m_node_pool(other.get_segment_manager())
|
||||
{}
|
||||
|
||||
//!Destructor, frees all used memory. Never throws
|
||||
~private_adaptive_pool_base()
|
||||
{}
|
||||
|
||||
//!Returns the segment manager. Never throws
|
||||
segment_manager* get_segment_manager()const
|
||||
{ return m_node_pool.get_segment_manager(); }
|
||||
|
||||
//!Returns the internal node pool. Never throws
|
||||
node_pool_t* get_node_pool() const
|
||||
{ return const_cast<node_pool_t*>(&m_node_pool); }
|
||||
|
||||
//!Swaps allocators. Does not throw. If each allocator is placed in a
|
||||
//!different shared memory segments, the result is undefined.
|
||||
friend void swap(self_t &alloc1,self_t &alloc2)
|
||||
{ alloc1.m_node_pool.swap(alloc2.m_node_pool); }
|
||||
|
||||
/// @cond
|
||||
private:
|
||||
node_pool_t m_node_pool;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
//!Equality test for same type of private_adaptive_pool_base
|
||||
template<unsigned int V, class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
|
||||
bool operator==(const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc2)
|
||||
{ return &alloc1 == &alloc2; }
|
||||
|
||||
//!Inequality test for same type of private_adaptive_pool_base
|
||||
template<unsigned int V, class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
|
||||
bool operator!=(const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc2)
|
||||
{ return &alloc1 != &alloc2; }
|
||||
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock = 64
|
||||
, std::size_t MaxFreeBlocks = 2
|
||||
, unsigned char OverheadPercent = 5
|
||||
>
|
||||
class private_adaptive_pool_v1
|
||||
: public private_adaptive_pool_base
|
||||
< 1
|
||||
, T
|
||||
, SegmentManager
|
||||
, NodesPerBlock
|
||||
, MaxFreeBlocks
|
||||
, OverheadPercent
|
||||
>
|
||||
{
|
||||
public:
|
||||
typedef detail::private_adaptive_pool_base
|
||||
< 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
private_adaptive_pool_v1(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
private_adaptive_pool_v1
|
||||
(const private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
};
|
||||
|
||||
} //namespace detail {
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!An STL node allocator that uses a segment manager as memory
|
||||
//!source. The internal pointer type will of the same type (raw, smart) as
|
||||
//!"typename SegmentManager::void_pointer" type. This allows
|
||||
//!placing the allocator in shared memory, memory mapped-files, etc...
|
||||
//!This allocator has its own node pool.
|
||||
//!
|
||||
//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when
|
||||
//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
|
||||
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
|
||||
//!deallocated with the segment manager.
|
||||
//!
|
||||
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
|
||||
//!(memory usable for nodes / total memory allocated from the segment manager)
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock
|
||||
, std::size_t MaxFreeBlocks
|
||||
, unsigned char OverheadPercent
|
||||
>
|
||||
class private_adaptive_pool
|
||||
/// @cond
|
||||
: public detail::private_adaptive_pool_base
|
||||
< 2
|
||||
, T
|
||||
, SegmentManager
|
||||
, NodesPerBlock
|
||||
, MaxFreeBlocks
|
||||
, OverheadPercent
|
||||
>
|
||||
/// @endcond
|
||||
{
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
typedef detail::private_adaptive_pool_base
|
||||
< 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
|
||||
public:
|
||||
typedef boost::interprocess::version_type<private_adaptive_pool, 2> version;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef private_adaptive_pool
|
||||
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
private_adaptive_pool(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
private_adaptive_pool
|
||||
(const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
|
||||
#else
|
||||
public:
|
||||
typedef implementation_defined::segment_manager segment_manager;
|
||||
typedef segment_manager::void_pointer void_pointer;
|
||||
typedef implementation_defined::pointer pointer;
|
||||
typedef implementation_defined::const_pointer 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;
|
||||
|
||||
//!Obtains private_adaptive_pool from
|
||||
//!private_adaptive_pool
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef private_adaptive_pool
|
||||
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
private:
|
||||
//!Not assignable from
|
||||
//!related private_adaptive_pool
|
||||
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
|
||||
private_adaptive_pool& operator=
|
||||
(const private_adaptive_pool<T2, SegmentManager2, N2, F2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!other private_adaptive_pool
|
||||
private_adaptive_pool& operator=(const private_adaptive_pool&);
|
||||
|
||||
public:
|
||||
//!Constructor from a segment manager. If not present, constructs a node
|
||||
//!pool. Increments the reference count of the associated node pool.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
private_adaptive_pool(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other private_adaptive_pool. Increments the reference
|
||||
//!count of the associated node pool. Never throws
|
||||
private_adaptive_pool(const private_adaptive_pool &other);
|
||||
|
||||
//!Copy constructor from related private_adaptive_pool. 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>
|
||||
private_adaptive_pool
|
||||
(const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
|
||||
|
||||
//!Destructor, removes node_pool_t from memory
|
||||
//!if its reference count reaches to zero. Never throws
|
||||
~private_adaptive_pool();
|
||||
|
||||
//!Returns a pointer to the node pool.
|
||||
//!Never throws
|
||||
node_pool_t* get_node_pool() const;
|
||||
|
||||
//!Returns the segment manager.
|
||||
//!Never throws
|
||||
segment_manager* get_segment_manager()const;
|
||||
|
||||
//!Returns the number of elements that could be allocated.
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!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);
|
||||
|
||||
//!Deallocate allocated memory.
|
||||
//!Never throws
|
||||
void deallocate(const pointer &ptr, size_type count);
|
||||
|
||||
//!Deallocates all free blocks
|
||||
//!of the pool
|
||||
void deallocate_free_blocks();
|
||||
|
||||
//!Swaps allocators. Does not throw. If each allocator is placed in a
|
||||
//!different memory segment, the result is undefined.
|
||||
friend void swap(self_t &alloc1, self_t &alloc2);
|
||||
|
||||
//!Returns address of mutable object.
|
||||
//!Never throws
|
||||
pointer address(reference value) const;
|
||||
|
||||
//!Returns address of non mutable object.
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Copy construct an object.
|
||||
//!Throws if T's copy constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
//!Destroys object. Throws if object's
|
||||
//!destructor throws
|
||||
void destroy(const pointer &ptr);
|
||||
|
||||
//!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;
|
||||
|
||||
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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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();
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!Equality test for same type
|
||||
//!of private_adaptive_pool
|
||||
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
|
||||
bool operator==(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
//!Inequality test for same type
|
||||
//!of private_adaptive_pool
|
||||
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
|
||||
bool operator!=(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP
|
||||
|
||||
@@ -0,0 +1,441 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-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_PRIVATE_NODE_ALLOCATOR_HPP
|
||||
#define BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP
|
||||
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#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/assert.hpp>
|
||||
#include <boost/utility/addressof.hpp>
|
||||
#include <boost/interprocess/allocators/detail/node_pool.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes private_node_allocator_base pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
/// @cond
|
||||
|
||||
namespace detail {
|
||||
|
||||
template < unsigned int Version
|
||||
, class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock
|
||||
>
|
||||
class private_node_allocator_base
|
||||
: public node_pool_allocation_impl
|
||||
< private_node_allocator_base < Version, T, SegmentManager, NodesPerBlock>
|
||||
, Version
|
||||
, T
|
||||
, SegmentManager
|
||||
>
|
||||
{
|
||||
public:
|
||||
//Segment manager
|
||||
typedef SegmentManager segment_manager;
|
||||
typedef typename SegmentManager::void_pointer void_pointer;
|
||||
|
||||
/// @cond
|
||||
private:
|
||||
typedef private_node_allocator_base
|
||||
< Version, T, SegmentManager, NodesPerBlock> self_t;
|
||||
typedef detail::private_node_pool
|
||||
<SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
> node_pool_t;
|
||||
|
||||
BOOST_STATIC_ASSERT((Version <=2));
|
||||
|
||||
/// @endcond
|
||||
|
||||
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::interprocess::version_type
|
||||
<private_node_allocator_base, Version> version;
|
||||
typedef detail::transform_multiallocation_chain
|
||||
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
|
||||
|
||||
//!Obtains node_allocator from other node_allocator
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef private_node_allocator_base
|
||||
<Version, T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <int dummy>
|
||||
struct node_pool
|
||||
{
|
||||
typedef detail::private_node_pool
|
||||
<SegmentManager
|
||||
, sizeof_value<T>::value
|
||||
, NodesPerBlock
|
||||
> type;
|
||||
|
||||
static type *get(void *p)
|
||||
{ return static_cast<type*>(p); }
|
||||
};
|
||||
|
||||
private:
|
||||
//!Not assignable from related private_node_allocator_base
|
||||
template<unsigned int Version2, class T2, class MemoryAlgorithm2, std::size_t N2>
|
||||
private_node_allocator_base& operator=
|
||||
(const private_node_allocator_base<Version2, T2, MemoryAlgorithm2, N2>&);
|
||||
|
||||
//!Not assignable from other private_node_allocator_base
|
||||
private_node_allocator_base& operator=(const private_node_allocator_base&);
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
//!Constructor from a segment manager
|
||||
private_node_allocator_base(segment_manager *segment_mngr)
|
||||
: m_node_pool(segment_mngr)
|
||||
{}
|
||||
|
||||
//!Copy constructor from other private_node_allocator_base. Never throws
|
||||
private_node_allocator_base(const private_node_allocator_base &other)
|
||||
: m_node_pool(other.get_segment_manager())
|
||||
{}
|
||||
|
||||
//!Copy constructor from related private_node_allocator_base. Never throws.
|
||||
template<class T2>
|
||||
private_node_allocator_base
|
||||
(const private_node_allocator_base
|
||||
<Version, T2, SegmentManager, NodesPerBlock> &other)
|
||||
: m_node_pool(other.get_segment_manager())
|
||||
{}
|
||||
|
||||
//!Destructor, frees all used memory. Never throws
|
||||
~private_node_allocator_base()
|
||||
{}
|
||||
|
||||
//!Returns the segment manager. Never throws
|
||||
segment_manager* get_segment_manager()const
|
||||
{ return m_node_pool.get_segment_manager(); }
|
||||
|
||||
//!Returns the internal node pool. Never throws
|
||||
node_pool_t* get_node_pool() const
|
||||
{ return const_cast<node_pool_t*>(&m_node_pool); }
|
||||
|
||||
//!Swaps allocators. Does not throw. If each allocator is placed in a
|
||||
//!different shared memory segments, the result is undefined.
|
||||
friend void swap(self_t &alloc1,self_t &alloc2)
|
||||
{ alloc1.m_node_pool.swap(alloc2.m_node_pool); }
|
||||
|
||||
/// @cond
|
||||
private:
|
||||
node_pool_t m_node_pool;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
//!Equality test for same type of private_node_allocator_base
|
||||
template<unsigned int V, class T, class S, std::size_t NPC> inline
|
||||
bool operator==(const private_node_allocator_base<V, T, S, NPC> &alloc1,
|
||||
const private_node_allocator_base<V, T, S, NPC> &alloc2)
|
||||
{ return &alloc1 == &alloc2; }
|
||||
|
||||
//!Inequality test for same type of private_node_allocator_base
|
||||
template<unsigned int V, class T, class S, std::size_t NPC> inline
|
||||
bool operator!=(const private_node_allocator_base<V, T, S, NPC> &alloc1,
|
||||
const private_node_allocator_base<V, T, S, NPC> &alloc2)
|
||||
{ return &alloc1 != &alloc2; }
|
||||
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock = 64
|
||||
>
|
||||
class private_node_allocator_v1
|
||||
: public private_node_allocator_base
|
||||
< 1
|
||||
, T
|
||||
, SegmentManager
|
||||
, NodesPerBlock
|
||||
>
|
||||
{
|
||||
public:
|
||||
typedef detail::private_node_allocator_base
|
||||
< 1, T, SegmentManager, NodesPerBlock> base_t;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
private_node_allocator_v1(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
private_node_allocator_v1
|
||||
(const private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
};
|
||||
|
||||
} //namespace detail {
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!An STL node allocator that uses a segment manager as memory
|
||||
//!source. The internal pointer type will of the same type (raw, smart) as
|
||||
//!"typename SegmentManager::void_pointer" type. This allows
|
||||
//!placing the allocator in shared memory, memory mapped-files, etc...
|
||||
//!This allocator has its own node pool. NodesPerBlock is the number of nodes allocated
|
||||
//!at once when the allocator needs runs out of nodes
|
||||
template < class T
|
||||
, class SegmentManager
|
||||
, std::size_t NodesPerBlock
|
||||
>
|
||||
class private_node_allocator
|
||||
/// @cond
|
||||
: public detail::private_node_allocator_base
|
||||
< 2
|
||||
, T
|
||||
, SegmentManager
|
||||
, NodesPerBlock
|
||||
>
|
||||
/// @endcond
|
||||
{
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
typedef detail::private_node_allocator_base
|
||||
< 2, T, SegmentManager, NodesPerBlock> base_t;
|
||||
public:
|
||||
typedef boost::interprocess::version_type<private_node_allocator, 2> version;
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef private_node_allocator
|
||||
<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
private_node_allocator(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
template<class T2>
|
||||
private_node_allocator
|
||||
(const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other)
|
||||
: base_t(other)
|
||||
{}
|
||||
|
||||
#else
|
||||
public:
|
||||
typedef implementation_defined::segment_manager segment_manager;
|
||||
typedef segment_manager::void_pointer void_pointer;
|
||||
typedef implementation_defined::pointer pointer;
|
||||
typedef implementation_defined::const_pointer 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;
|
||||
|
||||
//!Obtains private_node_allocator from
|
||||
//!private_node_allocator
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef private_node_allocator
|
||||
<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
private:
|
||||
//!Not assignable from
|
||||
//!related private_node_allocator
|
||||
template<class T2, class SegmentManager2, std::size_t N2>
|
||||
private_node_allocator& operator=
|
||||
(const private_node_allocator<T2, SegmentManager2, N2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!other private_node_allocator
|
||||
private_node_allocator& operator=(const private_node_allocator&);
|
||||
|
||||
public:
|
||||
//!Constructor from a segment manager. If not present, constructs a node
|
||||
//!pool. Increments the reference count of the associated node pool.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
private_node_allocator(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other private_node_allocator. Increments the reference
|
||||
//!count of the associated node pool. Never throws
|
||||
private_node_allocator(const private_node_allocator &other);
|
||||
|
||||
//!Copy constructor from related private_node_allocator. 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>
|
||||
private_node_allocator
|
||||
(const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other);
|
||||
|
||||
//!Destructor, removes node_pool_t from memory
|
||||
//!if its reference count reaches to zero. Never throws
|
||||
~private_node_allocator();
|
||||
|
||||
//!Returns a pointer to the node pool.
|
||||
//!Never throws
|
||||
node_pool_t* get_node_pool() const;
|
||||
|
||||
//!Returns the segment manager.
|
||||
//!Never throws
|
||||
segment_manager* get_segment_manager()const;
|
||||
|
||||
//!Returns the number of elements that could be allocated.
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!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);
|
||||
|
||||
//!Deallocate allocated memory.
|
||||
//!Never throws
|
||||
void deallocate(const pointer &ptr, size_type count);
|
||||
|
||||
//!Deallocates all free blocks
|
||||
//!of the pool
|
||||
void deallocate_free_blocks();
|
||||
|
||||
//!Swaps allocators. Does not throw. If each allocator is placed in a
|
||||
//!different memory segment, the result is undefined.
|
||||
friend void swap(self_t &alloc1, self_t &alloc2);
|
||||
|
||||
//!Returns address of mutable object.
|
||||
//!Never throws
|
||||
pointer address(reference value) const;
|
||||
|
||||
//!Returns address of non mutable object.
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Copy construct an object.
|
||||
//!Throws if T's copy constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
//!Destroys object. Throws if object's
|
||||
//!destructor throws
|
||||
void destroy(const pointer &ptr);
|
||||
|
||||
//!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;
|
||||
|
||||
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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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();
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
|
||||
//!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);
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!Equality test for same type
|
||||
//!of private_node_allocator
|
||||
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
|
||||
bool operator==(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
//!Inequality test for same type
|
||||
//!of private_node_allocator
|
||||
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
|
||||
bool operator!=(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP
|
||||
|
||||
Reference in New Issue
Block a user