Updated Boost libraries
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -35,7 +35,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes adaptive_pool pooled shared memory STL compatible allocator
|
||||
//!Describes adaptive_pool pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
@@ -101,11 +101,11 @@ class adaptive_pool_base
|
||||
typedef boost::container::container_detail::transform_multiallocation_chain
|
||||
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
|
||||
|
||||
//!Obtains adaptive_pool_base from
|
||||
//!Obtains adaptive_pool_base from
|
||||
//!adaptive_pool_base
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef adaptive_pool_base<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
@@ -122,15 +122,15 @@ class adaptive_pool_base
|
||||
//!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)
|
||||
adaptive_pool_base(segment_manager *segment_mngr)
|
||||
: mp_node_pool(ipcdetail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { }
|
||||
|
||||
//!Copy constructor from other adaptive_pool_base. Increments the reference
|
||||
//!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(ipcdetail::to_raw_pointer(mp_node_pool))->inc_ref_count();
|
||||
adaptive_pool_base(const adaptive_pool_base &other)
|
||||
: mp_node_pool(other.get_node_pool())
|
||||
{
|
||||
node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))->inc_ref_count();
|
||||
}
|
||||
|
||||
//!Assignment from other adaptive_pool_base
|
||||
@@ -151,7 +151,7 @@ class adaptive_pool_base
|
||||
|
||||
//!Destructor, removes node_pool_t from memory
|
||||
//!if its reference count reaches to zero. Never throws
|
||||
~adaptive_pool_base()
|
||||
~adaptive_pool_base()
|
||||
{ ipcdetail::destroy_node_pool_if_last_link(node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))); }
|
||||
|
||||
//!Returns a pointer to the node pool.
|
||||
@@ -178,14 +178,14 @@ class adaptive_pool_base
|
||||
//!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,
|
||||
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,
|
||||
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(); }
|
||||
|
||||
@@ -211,11 +211,11 @@ class adaptive_pool_v1
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
adaptive_pool_v1(SegmentManager *segment_mngr)
|
||||
adaptive_pool_v1(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
@@ -230,13 +230,13 @@ class adaptive_pool_v1
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!An STL node allocator that uses a segment manager as memory
|
||||
//!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
|
||||
//!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
|
||||
@@ -271,11 +271,11 @@ class adaptive_pool
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
adaptive_pool(SegmentManager *segment_mngr)
|
||||
adaptive_pool(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
@@ -299,11 +299,11 @@ class adaptive_pool
|
||||
typedef typename segment_manager::size_type size_type;
|
||||
typedef typename segment_manager::difference_type difference_type;
|
||||
|
||||
//!Obtains adaptive_pool from
|
||||
//!Obtains adaptive_pool from
|
||||
//!adaptive_pool
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
@@ -314,7 +314,7 @@ class adaptive_pool
|
||||
adaptive_pool& operator=
|
||||
(const adaptive_pool<T2, SegmentManager2, N2, F2, OP2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!Not assignable from
|
||||
//!other adaptive_pool
|
||||
//adaptive_pool& operator=(const adaptive_pool&);
|
||||
|
||||
@@ -324,7 +324,7 @@ class adaptive_pool
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
adaptive_pool(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other adaptive_pool. Increments the reference
|
||||
//!Copy constructor from other adaptive_pool. Increments the reference
|
||||
//!count of the associated node pool. Never throws
|
||||
adaptive_pool(const adaptive_pool &other);
|
||||
|
||||
@@ -351,7 +351,7 @@ class adaptive_pool
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!Allocate memory for an array of count elements.
|
||||
//!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);
|
||||
|
||||
@@ -375,7 +375,7 @@ class adaptive_pool
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
/*
|
||||
//!Copy construct an object.
|
||||
//!Copy construct an object.
|
||||
//!Throws if T's copy constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
@@ -390,7 +390,7 @@ class adaptive_pool
|
||||
|
||||
std::pair<pointer, bool>
|
||||
allocation_command(boost::interprocess::allocation_type command,
|
||||
size_type limit_size,
|
||||
size_type limit_size,
|
||||
size_type preferred_size,
|
||||
size_type &received_size, const pointer &reuse = 0);
|
||||
|
||||
@@ -400,12 +400,12 @@ class adaptive_pool
|
||||
//!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, size_type num_elements);
|
||||
void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain);
|
||||
|
||||
//!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);
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain);
|
||||
|
||||
//!Allocates many elements of size elem_size in a contiguous block
|
||||
//!of memory. The minimum number to be allocated is min_elements,
|
||||
@@ -413,7 +413,7 @@ class adaptive_pool
|
||||
//!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);
|
||||
void deallocate_many(multiallocation_chain &chain);
|
||||
|
||||
//!Allocates just one object. Memory allocated with this function
|
||||
//!must be deallocated only with deallocate_one().
|
||||
@@ -426,7 +426,7 @@ class adaptive_pool
|
||||
//!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(size_type num_elements);
|
||||
void allocate_individual(size_type num_elements, multiallocation_chain &chain);
|
||||
|
||||
//!Deallocates memory previously allocated with allocate_one().
|
||||
//!You should never use deallocate_one to deallocate memory allocated
|
||||
@@ -439,7 +439,7 @@ class adaptive_pool
|
||||
//!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);
|
||||
void deallocate_individual(multiallocation_chain &chain);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -448,13 +448,13 @@ class adaptive_pool
|
||||
//!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,
|
||||
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,
|
||||
bool operator!=(const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -45,12 +45,12 @@ namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
|
||||
//!An STL compatible allocator that uses a segment manager as
|
||||
//!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
|
||||
class allocator
|
||||
{
|
||||
public:
|
||||
//Segment manager
|
||||
@@ -115,7 +115,7 @@ class allocator
|
||||
//!objects of type T2
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef allocator<T2, SegmentManager> other;
|
||||
};
|
||||
|
||||
@@ -126,27 +126,28 @@ class allocator
|
||||
|
||||
//!Constructor from the segment manager.
|
||||
//!Never throws
|
||||
allocator(segment_manager *segment_mngr)
|
||||
allocator(segment_manager *segment_mngr)
|
||||
: mp_mngr(segment_mngr) { }
|
||||
|
||||
//!Constructor from other allocator.
|
||||
//!Never throws
|
||||
allocator(const allocator &other)
|
||||
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)
|
||||
allocator(const allocator<T2, SegmentManager> &other)
|
||||
: mp_mngr(other.get_segment_manager()){}
|
||||
|
||||
//!Allocates memory for an array of count elements.
|
||||
//!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())
|
||||
if(size_overflows<sizeof(T)>(count)){
|
||||
throw bad_alloc();
|
||||
}
|
||||
return pointer(static_cast<value_type*>(mp_mngr->allocate(count*sizeof(T))));
|
||||
}
|
||||
|
||||
@@ -169,13 +170,13 @@ class allocator
|
||||
//!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(ipcdetail::to_raw_pointer(p))/sizeof(T);
|
||||
}
|
||||
|
||||
std::pair<pointer, bool>
|
||||
allocation_command(boost::interprocess::allocation_type command,
|
||||
size_type limit_size,
|
||||
size_type limit_size,
|
||||
size_type preferred_size,
|
||||
size_type &received_size, const pointer &reuse = 0)
|
||||
{
|
||||
@@ -189,19 +190,20 @@ class allocator
|
||||
//!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, size_type num_elements)
|
||||
void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain)
|
||||
{
|
||||
return multiallocation_chain(mp_mngr->allocate_many(sizeof(T)*elem_size, num_elements));
|
||||
if(size_overflows<sizeof(T)>(elem_size)){
|
||||
throw bad_alloc();
|
||||
}
|
||||
mp_mngr->allocate_many(elem_size*sizeof(T), num_elements, chain);
|
||||
}
|
||||
|
||||
//!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)
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
|
||||
{
|
||||
multiallocation_chain(mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T)));
|
||||
mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T), chain);
|
||||
}
|
||||
|
||||
//!Allocates many elements of size elem_size in a contiguous block
|
||||
@@ -210,10 +212,8 @@ class allocator
|
||||
//!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());
|
||||
}
|
||||
void deallocate_many(multiallocation_chain &chain)
|
||||
{ mp_mngr->deallocate_many(chain); }
|
||||
|
||||
//!Allocates just one object. Memory allocated with this function
|
||||
//!must be deallocated only with deallocate_one().
|
||||
@@ -227,9 +227,8 @@ class allocator
|
||||
//!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
|
||||
(size_type num_elements)
|
||||
{ return this->allocate_many(1, num_elements); }
|
||||
void allocate_individual(size_type num_elements, multiallocation_chain &chain)
|
||||
{ this->allocate_many(1, num_elements, chain); }
|
||||
|
||||
//!Deallocates memory previously allocated with allocate_one().
|
||||
//!You should never use deallocate_one to deallocate memory allocated
|
||||
@@ -243,8 +242,8 @@ class allocator
|
||||
//!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::move(chain)); }
|
||||
void deallocate_individual(multiallocation_chain &chain)
|
||||
{ this->deallocate_many(chain); }
|
||||
|
||||
//!Returns address of mutable object.
|
||||
//!Never throws
|
||||
@@ -273,14 +272,14 @@ class allocator
|
||||
//!Equality test for same type
|
||||
//!of allocator
|
||||
template<class T, class SegmentManager> inline
|
||||
bool operator==(const allocator<T , SegmentManager> &alloc1,
|
||||
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,
|
||||
bool operator!=(const allocator<T, SegmentManager> &alloc1,
|
||||
const allocator<T, SegmentManager> &alloc2)
|
||||
{ return alloc1.get_segment_manager() != alloc2.get_segment_manager(); }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes cached_adaptive_pool pooled shared memory STL compatible allocator
|
||||
//!Describes cached_adaptive_pool pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
@@ -69,7 +69,7 @@ class cached_adaptive_pool_v1
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef cached_adaptive_pool_v1
|
||||
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
@@ -77,7 +77,7 @@ class cached_adaptive_pool_v1
|
||||
typedef typename base_t::size_type size_type;
|
||||
|
||||
cached_adaptive_pool_v1(SegmentManager *segment_mngr,
|
||||
size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
: base_t(segment_mngr, max_cached_nodes)
|
||||
{}
|
||||
|
||||
@@ -93,12 +93,12 @@ class cached_adaptive_pool_v1
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!An STL node allocator that uses a segment manager as memory
|
||||
//!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
|
||||
//!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.
|
||||
@@ -149,13 +149,13 @@ class cached_adaptive_pool
|
||||
|
||||
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)
|
||||
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
: base_t(segment_mngr, max_cached_nodes)
|
||||
{}
|
||||
|
||||
@@ -179,11 +179,11 @@ class cached_adaptive_pool
|
||||
typedef typename segment_manager::size_type size_type;
|
||||
typedef typename segment_manager::difference_type difference_type;
|
||||
|
||||
//!Obtains cached_adaptive_pool from
|
||||
//!Obtains cached_adaptive_pool from
|
||||
//!cached_adaptive_pool
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
@@ -194,7 +194,7 @@ class cached_adaptive_pool
|
||||
cached_adaptive_pool& operator=
|
||||
(const cached_adaptive_pool<T2, SegmentManager2, N2, F2, OP2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!Not assignable from
|
||||
//!other cached_adaptive_pool
|
||||
cached_adaptive_pool& operator=(const cached_adaptive_pool&);
|
||||
|
||||
@@ -204,7 +204,7 @@ class cached_adaptive_pool
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
cached_adaptive_pool(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other cached_adaptive_pool. Increments the reference
|
||||
//!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);
|
||||
|
||||
@@ -231,7 +231,7 @@ class cached_adaptive_pool
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!Allocate memory for an array of count elements.
|
||||
//!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);
|
||||
|
||||
@@ -255,7 +255,7 @@ class cached_adaptive_pool
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Copy construct an object.
|
||||
//!Copy construct an object.
|
||||
//!Throws if T's copy constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
@@ -270,7 +270,7 @@ class cached_adaptive_pool
|
||||
|
||||
std::pair<pointer, bool>
|
||||
allocation_command(boost::interprocess::allocation_type command,
|
||||
size_type limit_size,
|
||||
size_type limit_size,
|
||||
size_type preferred_size,
|
||||
size_type &received_size, const pointer &reuse = 0);
|
||||
|
||||
@@ -280,12 +280,12 @@ class cached_adaptive_pool
|
||||
//!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, size_type num_elements);
|
||||
void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain);
|
||||
|
||||
//!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);
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain);
|
||||
|
||||
//!Allocates many elements of size elem_size in a contiguous block
|
||||
//!of memory. The minimum number to be allocated is min_elements,
|
||||
@@ -293,7 +293,7 @@ class cached_adaptive_pool
|
||||
//!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);
|
||||
void deallocate_many(multiallocation_chain &chain);
|
||||
|
||||
//!Allocates just one object. Memory allocated with this function
|
||||
//!must be deallocated only with deallocate_one().
|
||||
@@ -319,7 +319,7 @@ class cached_adaptive_pool
|
||||
//!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);
|
||||
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(size_type newmax);
|
||||
@@ -335,13 +335,13 @@ class cached_adaptive_pool
|
||||
//!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,
|
||||
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,
|
||||
bool operator!=(const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes cached_cached_node_allocator pooled shared memory STL compatible allocator
|
||||
//!Describes cached_cached_node_allocator pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
@@ -64,7 +64,7 @@ class cached_node_allocator_v1
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef cached_node_allocator_v1
|
||||
<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
@@ -72,7 +72,7 @@ class cached_node_allocator_v1
|
||||
typedef typename base_t::size_type size_type;
|
||||
|
||||
cached_node_allocator_v1(SegmentManager *segment_mngr,
|
||||
size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
: base_t(segment_mngr, max_cached_nodes)
|
||||
{}
|
||||
|
||||
@@ -122,12 +122,12 @@ class cached_node_allocator
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef cached_node_allocator<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
cached_node_allocator(SegmentManager *segment_mngr,
|
||||
size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
|
||||
: base_t(segment_mngr, max_cached_nodes)
|
||||
{}
|
||||
|
||||
@@ -151,11 +151,11 @@ class cached_node_allocator
|
||||
typedef typename SegmentManager::size_type size_type;
|
||||
typedef typename SegmentManager::difference_type difference_type;
|
||||
|
||||
//!Obtains cached_node_allocator from
|
||||
//!Obtains cached_node_allocator from
|
||||
//!cached_node_allocator
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef cached_node_allocator<T2, SegmentManager> other;
|
||||
};
|
||||
|
||||
@@ -166,7 +166,7 @@ class cached_node_allocator
|
||||
cached_node_allocator& operator=
|
||||
(const cached_node_allocator<T2, SegmentManager2, N2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!Not assignable from
|
||||
//!other cached_node_allocator
|
||||
cached_node_allocator& operator=(const cached_node_allocator&);
|
||||
|
||||
@@ -176,7 +176,7 @@ class cached_node_allocator
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
cached_node_allocator(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other cached_node_allocator. Increments the reference
|
||||
//!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);
|
||||
|
||||
@@ -203,7 +203,7 @@ class cached_node_allocator
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!Allocate memory for an array of count elements.
|
||||
//!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);
|
||||
|
||||
@@ -227,7 +227,7 @@ class cached_node_allocator
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Default construct an object.
|
||||
//!Default construct an object.
|
||||
//!Throws if T's default constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
@@ -242,7 +242,7 @@ class cached_node_allocator
|
||||
|
||||
std::pair<pointer, bool>
|
||||
allocation_command(boost::interprocess::allocation_type command,
|
||||
size_type limit_size,
|
||||
size_type limit_size,
|
||||
size_type preferred_size,
|
||||
size_type &received_size, const pointer &reuse = 0);
|
||||
|
||||
@@ -252,12 +252,12 @@ class cached_node_allocator
|
||||
//!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, size_type num_elements);
|
||||
void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain);
|
||||
|
||||
//!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);
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain);
|
||||
|
||||
//!Allocates many elements of size elem_size in a contiguous block
|
||||
//!of memory. The minimum number to be allocated is min_elements,
|
||||
@@ -265,7 +265,7 @@ class cached_node_allocator
|
||||
//!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);
|
||||
void deallocate_many(multiallocation_chain &chain);
|
||||
|
||||
//!Allocates just one object. Memory allocated with this function
|
||||
//!must be deallocated only with deallocate_one().
|
||||
@@ -307,13 +307,13 @@ class cached_node_allocator
|
||||
//!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,
|
||||
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,
|
||||
bool operator!=(const cached_node_allocator<T, S, NPC> &alloc1,
|
||||
const cached_node_allocator<T, S, NPC> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -45,10 +45,16 @@ template< class SegmentManager
|
||||
>
|
||||
class private_adaptive_node_pool
|
||||
: public boost::container::container_detail::private_adaptive_node_pool_impl
|
||||
<typename SegmentManager::segment_manager_base_type>
|
||||
< typename SegmentManager::segment_manager_base_type
|
||||
, ::boost::container::adaptive_pool_flag::size_ordered |
|
||||
::boost::container::adaptive_pool_flag::address_ordered
|
||||
>
|
||||
{
|
||||
typedef boost::container::container_detail::private_adaptive_node_pool_impl
|
||||
<typename SegmentManager::segment_manager_base_type> base_t;
|
||||
< typename SegmentManager::segment_manager_base_type
|
||||
, ::boost::container::adaptive_pool_flag::size_ordered |
|
||||
::boost::container::adaptive_pool_flag::address_ordered
|
||||
> base_t;
|
||||
//Non-copyable
|
||||
private_adaptive_node_pool();
|
||||
private_adaptive_node_pool(const private_adaptive_node_pool &);
|
||||
@@ -74,7 +80,7 @@ class private_adaptive_node_pool
|
||||
};
|
||||
|
||||
//!Pooled shared memory allocator using adaptive pool. Includes
|
||||
//!a reference count but the class does not delete itself, this is
|
||||
//!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
|
||||
@@ -83,7 +89,7 @@ template< class SegmentManager
|
||||
, std::size_t MaxFreeBlocks
|
||||
, unsigned char OverheadPercent
|
||||
>
|
||||
class shared_adaptive_node_pool
|
||||
class shared_adaptive_node_pool
|
||||
: public ipcdetail::shared_pool_impl
|
||||
< private_adaptive_node_pool
|
||||
<SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
@@ -73,7 +73,7 @@ namespace ipcdetail {
|
||||
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()()
|
||||
@@ -90,7 +90,7 @@ struct get_or_create_node_pool_func
|
||||
//!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;
|
||||
};
|
||||
@@ -103,13 +103,13 @@ inline NodePool *get_or_create_node_pool(typename NodePool::segment_manager *mgn
|
||||
return func.mp_node_pool;
|
||||
}
|
||||
|
||||
//!Object function that decrements the reference count. If the count
|
||||
//!reaches to zero destroys the node allocator from memory.
|
||||
//!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
|
||||
//!Decrements reference count and destroys the object if there is no
|
||||
//!more attached allocators. Never throws
|
||||
void operator()()
|
||||
{
|
||||
@@ -117,19 +117,19 @@ struct destroy_if_last_link_func
|
||||
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);
|
||||
}
|
||||
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)
|
||||
destroy_if_last_link_func(NodePool *pool)
|
||||
: mp_node_pool(pool)
|
||||
{}
|
||||
|
||||
NodePool *mp_node_pool;
|
||||
};
|
||||
|
||||
//!Destruction function, initializes and executes destruction function
|
||||
//!Destruction function, initializes and executes destruction function
|
||||
//!object. Never throws
|
||||
template<class NodePool>
|
||||
inline void destroy_node_pool_if_last_link(NodePool *pool)
|
||||
@@ -173,7 +173,7 @@ class cache_impl
|
||||
~cache_impl()
|
||||
{
|
||||
this->deallocate_all_cached_nodes();
|
||||
ipcdetail::destroy_node_pool_if_last_link(ipcdetail::to_raw_pointer(mp_node_pool));
|
||||
ipcdetail::destroy_node_pool_if_last_link(ipcdetail::to_raw_pointer(mp_node_pool));
|
||||
}
|
||||
|
||||
NodePool *get_node_pool() const
|
||||
@@ -189,34 +189,29 @@ class cache_impl
|
||||
{
|
||||
//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);
|
||||
mp_node_pool->allocate_nodes(m_max_cached_nodes/2, m_cached_nodes);
|
||||
}
|
||||
void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.front());
|
||||
m_cached_nodes.pop_front();
|
||||
void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.pop_front());
|
||||
return ret;
|
||||
}
|
||||
|
||||
multiallocation_chain cached_allocation(size_type n)
|
||||
void cached_allocation(size_type n, multiallocation_chain &chain)
|
||||
{
|
||||
multiallocation_chain chain;
|
||||
size_type 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 = ipcdetail::to_raw_pointer(m_cached_nodes.front());
|
||||
m_cached_nodes.pop_front();
|
||||
void *ret = ipcdetail::to_raw_pointer(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);
|
||||
mp_node_pool->allocate_nodes(n - allocated, chain);
|
||||
}
|
||||
return boost::move(chain);
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
this->cached_deallocation(boost::move(chain));
|
||||
this->cached_deallocation(chain);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
@@ -227,7 +222,7 @@ class cache_impl
|
||||
//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
|
||||
//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);
|
||||
@@ -235,14 +230,14 @@ class cache_impl
|
||||
m_cached_nodes.push_front(ptr);
|
||||
}
|
||||
|
||||
void cached_deallocation(multiallocation_chain chain)
|
||||
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
|
||||
//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);
|
||||
@@ -262,7 +257,7 @@ class cache_impl
|
||||
void deallocate_all_cached_nodes()
|
||||
{
|
||||
if(m_cached_nodes.empty()) return;
|
||||
mp_node_pool->deallocate_nodes(boost::move(m_cached_nodes));
|
||||
mp_node_pool->deallocate_nodes(m_cached_nodes);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -279,7 +274,7 @@ class cache_impl
|
||||
void priv_deallocate_n_nodes(size_type n)
|
||||
{
|
||||
//This only occurs if this allocator deallocate memory allocated
|
||||
//with other equal allocator. Since the cache is full, and more
|
||||
//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.
|
||||
size_type count(n);
|
||||
@@ -290,16 +285,16 @@ class cache_impl
|
||||
multiallocation_chain chain;
|
||||
chain.splice_after(chain.before_begin(), m_cached_nodes, m_cached_nodes.before_begin(), it, n);
|
||||
//Deallocate all new linked list at once
|
||||
mp_node_pool->deallocate_nodes(boost::move(chain));
|
||||
mp_node_pool->deallocate_nodes(chain);
|
||||
}
|
||||
|
||||
public:
|
||||
void swap(cache_impl &other)
|
||||
{
|
||||
ipcdetail::do_swap(mp_node_pool, other.mp_node_pool);
|
||||
m_cached_nodes.swap(other.m_cached_nodes);
|
||||
ipcdetail::do_swap(m_max_cached_nodes, other.m_max_cached_nodes);
|
||||
}
|
||||
ipcdetail::do_swap(mp_node_pool, other.mp_node_pool);
|
||||
m_cached_nodes.swap(other.m_cached_nodes);
|
||||
ipcdetail::do_swap(m_max_cached_nodes, other.m_max_cached_nodes);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Derived, class T, class SegmentManager>
|
||||
@@ -335,13 +330,13 @@ class array_allocation_impl
|
||||
//!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(ipcdetail::to_raw_pointer(p))/sizeof(T);
|
||||
}
|
||||
|
||||
std::pair<pointer, bool>
|
||||
allocation_command(boost::interprocess::allocation_type command,
|
||||
size_type limit_size,
|
||||
size_type limit_size,
|
||||
size_type preferred_size,
|
||||
size_type &received_size, const pointer &reuse = 0)
|
||||
{
|
||||
@@ -355,17 +350,20 @@ class array_allocation_impl
|
||||
//!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, size_type num_elements)
|
||||
void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain)
|
||||
{
|
||||
return this->derived()->get_segment_manager()->allocate_many(sizeof(T)*elem_size, num_elements);
|
||||
if(size_overflows<sizeof(T)>(elem_size)){
|
||||
throw bad_alloc();
|
||||
}
|
||||
this->derived()->get_segment_manager()->allocate_many(elem_size*sizeof(T), num_elements, chain);
|
||||
}
|
||||
|
||||
//!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)
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
|
||||
{
|
||||
return this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T));
|
||||
this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T), chain);
|
||||
}
|
||||
|
||||
//!Allocates many elements of size elem_size in a contiguous block
|
||||
@@ -374,8 +372,8 @@ class array_allocation_impl
|
||||
//!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::move(chain)); }
|
||||
void deallocate_many(multiallocation_chain &chain)
|
||||
{ this->derived()->get_segment_manager()->deallocate_many(chain); }
|
||||
|
||||
//!Returns the number of elements that could be
|
||||
//!allocated. Never throws
|
||||
@@ -450,21 +448,24 @@ class node_pool_allocation_impl
|
||||
};
|
||||
|
||||
public:
|
||||
//!Allocate memory for an array of count elements.
|
||||
//!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())
|
||||
if(size_overflows<sizeof(T)>(count)){
|
||||
throw bad_alloc();
|
||||
else if(Version == 1 && count == 1)
|
||||
}
|
||||
else if(Version == 1 && count == 1){
|
||||
return pointer(static_cast<value_type*>
|
||||
(pool->allocate_node()));
|
||||
else
|
||||
}
|
||||
else{
|
||||
return pointer(static_cast<value_type*>
|
||||
(pool->get_segment_manager()->allocate(sizeof(T)*count)));
|
||||
(pool->get_segment_manager()->allocate(count*sizeof(T))));
|
||||
}
|
||||
}
|
||||
|
||||
//!Deallocate allocated memory. Never throws
|
||||
@@ -495,11 +496,11 @@ class node_pool_allocation_impl
|
||||
//!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(size_type num_elements)
|
||||
void allocate_individual(size_type num_elements, multiallocation_chain &chain)
|
||||
{
|
||||
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));
|
||||
pool->allocate_nodes(num_elements, chain);
|
||||
}
|
||||
|
||||
//!Deallocates memory previously allocated with allocate_one().
|
||||
@@ -518,10 +519,10 @@ class node_pool_allocation_impl
|
||||
//!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)
|
||||
void deallocate_individual(multiallocation_chain &chain)
|
||||
{
|
||||
node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes
|
||||
(chain.extract_multiallocation_chain());
|
||||
(chain);
|
||||
}
|
||||
|
||||
//!Deallocates all free blocks of the pool
|
||||
@@ -599,20 +600,21 @@ class cached_allocator_impl
|
||||
size_type get_max_cached_nodes() const
|
||||
{ return m_cache.get_max_cached_nodes(); }
|
||||
|
||||
//!Allocate memory for an array of count elements.
|
||||
//!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())
|
||||
if(size_overflows<sizeof(T)>(count)){
|
||||
throw bad_alloc();
|
||||
}
|
||||
else if(Version == 1 && count == 1){
|
||||
ret = m_cache.cached_allocation();
|
||||
}
|
||||
else{
|
||||
ret = this->get_segment_manager()->allocate(sizeof(T)*count);
|
||||
}
|
||||
ret = this->get_segment_manager()->allocate(count*sizeof(T));
|
||||
}
|
||||
return pointer(static_cast<T*>(ret));
|
||||
}
|
||||
|
||||
@@ -640,8 +642,8 @@ class cached_allocator_impl
|
||||
//!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(size_type num_elements)
|
||||
{ return multiallocation_chain(this->m_cache.cached_allocation(num_elements)); }
|
||||
void allocate_individual(size_type num_elements, multiallocation_chain &chain)
|
||||
{ this->m_cache.cached_allocation(num_elements, chain); }
|
||||
|
||||
//!Deallocates memory previously allocated with allocate_one().
|
||||
//!You should never use deallocate_one to deallocate memory allocated
|
||||
@@ -655,12 +657,8 @@ class cached_allocator_impl
|
||||
//!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::move(mem));
|
||||
}
|
||||
void deallocate_individual(multiallocation_chain &chain)
|
||||
{ m_cache.cached_deallocation(chain); }
|
||||
|
||||
//!Deallocates all free blocks of the pool
|
||||
void deallocate_free_blocks()
|
||||
@@ -686,20 +684,20 @@ class cached_allocator_impl
|
||||
//!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,
|
||||
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,
|
||||
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
|
||||
//!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>
|
||||
@@ -736,7 +734,7 @@ class shared_pool_impl
|
||||
//-----------------------
|
||||
return private_node_allocator_t::allocate_node();
|
||||
}
|
||||
|
||||
|
||||
//!Deallocates an array pointed by ptr. Never throws
|
||||
void deallocate_node(void *ptr)
|
||||
{
|
||||
@@ -745,25 +743,15 @@ class shared_pool_impl
|
||||
//-----------------------
|
||||
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, size_type n)
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
|
||||
//-----------------------
|
||||
return private_node_allocator_t::allocate_nodes(nodes, n);
|
||||
}
|
||||
*/
|
||||
//!Allocates n nodes.
|
||||
|
||||
//!Allocates n nodes.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
multiallocation_chain allocate_nodes(const size_type n)
|
||||
void allocate_nodes(const size_type n, multiallocation_chain &chain)
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
|
||||
//-----------------------
|
||||
return private_node_allocator_t::allocate_nodes(n);
|
||||
private_node_allocator_t::allocate_nodes(n, chain);
|
||||
}
|
||||
|
||||
//!Deallocates a linked list of nodes ending in null pointer. Never throws
|
||||
@@ -776,12 +764,12 @@ class shared_pool_impl
|
||||
}
|
||||
|
||||
//!Deallocates the nodes pointed by the multiallocation iterator. Never throws
|
||||
void deallocate_nodes(multiallocation_chain chain)
|
||||
void deallocate_nodes(multiallocation_chain &chain)
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
|
||||
//-----------------------
|
||||
private_node_allocator_t::deallocate_nodes(boost::move(chain));
|
||||
private_node_allocator_t::deallocate_nodes(chain);
|
||||
}
|
||||
|
||||
//!Deallocates all the free blocks of memory. Never throws
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -37,7 +37,7 @@ namespace ipcdetail {
|
||||
|
||||
|
||||
//!Pooled shared memory allocator using single segregated storage. Includes
|
||||
//!a reference count but the class does not delete itself, this is
|
||||
//!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 >
|
||||
@@ -73,18 +73,18 @@ class private_node_pool
|
||||
|
||||
|
||||
//!Pooled shared memory allocator using single segregated storage. Includes
|
||||
//!a reference count but the class does not delete itself, this is
|
||||
//!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
|
||||
//!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
|
||||
class shared_node_pool
|
||||
: public ipcdetail::shared_pool_impl
|
||||
< private_node_pool
|
||||
<SegmentManager, NodeSize, NodesPerBlock>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2007-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2007-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes node_allocator pooled shared memory STL compatible allocator
|
||||
//!Describes node_allocator pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
@@ -98,11 +98,11 @@ class node_allocator_base
|
||||
typedef boost::container::container_detail::transform_multiallocation_chain
|
||||
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
|
||||
|
||||
//!Obtains node_allocator_base from
|
||||
//!Obtains node_allocator_base from
|
||||
//!node_allocator_base
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
@@ -121,15 +121,15 @@ class node_allocator_base
|
||||
//!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)
|
||||
node_allocator_base(segment_manager *segment_mngr)
|
||||
: mp_node_pool(ipcdetail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { }
|
||||
|
||||
//!Copy constructor from other node_allocator_base. Increments the reference
|
||||
//!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(ipcdetail::to_raw_pointer(mp_node_pool))->inc_ref_count();
|
||||
node_allocator_base(const node_allocator_base &other)
|
||||
: mp_node_pool(other.get_node_pool())
|
||||
{
|
||||
node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))->inc_ref_count();
|
||||
}
|
||||
|
||||
//!Copy constructor from related node_allocator_base. If not present, constructs
|
||||
@@ -150,7 +150,7 @@ class node_allocator_base
|
||||
|
||||
//!Destructor, removes node_pool_t from memory
|
||||
//!if its reference count reaches to zero. Never throws
|
||||
~node_allocator_base()
|
||||
~node_allocator_base()
|
||||
{ ipcdetail::destroy_node_pool_if_last_link(node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))); }
|
||||
|
||||
//!Returns a pointer to the node pool.
|
||||
@@ -177,14 +177,14 @@ class node_allocator_base
|
||||
//!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,
|
||||
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,
|
||||
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(); }
|
||||
|
||||
@@ -206,11 +206,11 @@ class node_allocator_v1
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef node_allocator_v1<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
node_allocator_v1(SegmentManager *segment_mngr)
|
||||
node_allocator_v1(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
@@ -225,12 +225,12 @@ class node_allocator_v1
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!An STL node allocator that uses a segment manager as memory
|
||||
//!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
|
||||
//!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
|
||||
@@ -256,11 +256,11 @@ class node_allocator
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef node_allocator<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
node_allocator(SegmentManager *segment_mngr)
|
||||
node_allocator(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
@@ -284,11 +284,11 @@ class node_allocator
|
||||
typedef typename segment_manager::size_type size_type;
|
||||
typedef typename segment_manager::difference_type difference_type;
|
||||
|
||||
//!Obtains node_allocator from
|
||||
//!Obtains node_allocator from
|
||||
//!node_allocator
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef node_allocator<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
@@ -299,7 +299,7 @@ class node_allocator
|
||||
node_allocator& operator=
|
||||
(const node_allocator<T2, SegmentManager2, N2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!Not assignable from
|
||||
//!other node_allocator
|
||||
//node_allocator& operator=(const node_allocator&);
|
||||
|
||||
@@ -309,7 +309,7 @@ class node_allocator
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
node_allocator(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other node_allocator. Increments the reference
|
||||
//!Copy constructor from other node_allocator. Increments the reference
|
||||
//!count of the associated node pool. Never throws
|
||||
node_allocator(const node_allocator &other);
|
||||
|
||||
@@ -336,7 +336,7 @@ class node_allocator
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!Allocate memory for an array of count elements.
|
||||
//!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);
|
||||
|
||||
@@ -360,7 +360,7 @@ class node_allocator
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Copy construct an object.
|
||||
//!Copy construct an object.
|
||||
//!Throws if T's copy constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
@@ -375,7 +375,7 @@ class node_allocator
|
||||
|
||||
std::pair<pointer, bool>
|
||||
allocation_command(boost::interprocess::allocation_type command,
|
||||
size_type limit_size,
|
||||
size_type limit_size,
|
||||
size_type preferred_size,
|
||||
size_type &received_size, const pointer &reuse = 0);
|
||||
|
||||
@@ -385,12 +385,12 @@ class node_allocator
|
||||
//!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, size_type num_elements);
|
||||
void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain);
|
||||
|
||||
//!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);
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain);
|
||||
|
||||
//!Allocates many elements of size elem_size in a contiguous block
|
||||
//!of memory. The minimum number to be allocated is min_elements,
|
||||
@@ -398,7 +398,7 @@ class node_allocator
|
||||
//!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);
|
||||
void deallocate_many(multiallocation_chain &chain);
|
||||
|
||||
//!Allocates just one object. Memory allocated with this function
|
||||
//!must be deallocated only with deallocate_one().
|
||||
@@ -411,7 +411,7 @@ class node_allocator
|
||||
//!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(size_type num_elements);
|
||||
void allocate_individual(size_type num_elements, multiallocation_chain &chain);
|
||||
|
||||
//!Deallocates memory previously allocated with allocate_one().
|
||||
//!You should never use deallocate_one to deallocate memory allocated
|
||||
@@ -424,7 +424,7 @@ class node_allocator
|
||||
//!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);
|
||||
void deallocate_individual(multiallocation_chain &chain);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -433,13 +433,13 @@ class node_allocator
|
||||
//!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,
|
||||
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,
|
||||
bool operator!=(const node_allocator<T, S, NPC> &alloc1,
|
||||
const node_allocator<T, S, NPC> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes private_adaptive_pool_base pooled shared memory STL compatible allocator
|
||||
//!Describes private_adaptive_pool_base pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
@@ -102,7 +102,7 @@ class private_adaptive_pool_base
|
||||
//!Obtains node_allocator from other node_allocator
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef private_adaptive_pool_base
|
||||
<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
@@ -154,7 +154,7 @@ class private_adaptive_pool_base
|
||||
{}
|
||||
|
||||
//!Destructor, frees all used memory. Never throws
|
||||
~private_adaptive_pool_base()
|
||||
~private_adaptive_pool_base()
|
||||
{}
|
||||
|
||||
//!Returns the segment manager. Never throws
|
||||
@@ -178,13 +178,13 @@ class private_adaptive_pool_base
|
||||
|
||||
//!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,
|
||||
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,
|
||||
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; }
|
||||
|
||||
@@ -210,11 +210,11 @@ class private_adaptive_pool_v1
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
private_adaptive_pool_v1(SegmentManager *segment_mngr)
|
||||
private_adaptive_pool_v1(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
@@ -229,7 +229,7 @@ class private_adaptive_pool_v1
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!An STL node allocator that uses a segment manager as memory
|
||||
//!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...
|
||||
@@ -269,12 +269,12 @@ class private_adaptive_pool
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef private_adaptive_pool
|
||||
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
|
||||
private_adaptive_pool(SegmentManager *segment_mngr)
|
||||
private_adaptive_pool(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
@@ -298,11 +298,11 @@ class private_adaptive_pool
|
||||
typedef typename segment_manager::size_type size_type;
|
||||
typedef typename segment_manager::difference_type difference_type;
|
||||
|
||||
//!Obtains private_adaptive_pool from
|
||||
//!Obtains private_adaptive_pool from
|
||||
//!private_adaptive_pool
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef private_adaptive_pool
|
||||
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
|
||||
};
|
||||
@@ -314,7 +314,7 @@ class private_adaptive_pool
|
||||
private_adaptive_pool& operator=
|
||||
(const private_adaptive_pool<T2, SegmentManager2, N2, F2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!Not assignable from
|
||||
//!other private_adaptive_pool
|
||||
private_adaptive_pool& operator=(const private_adaptive_pool&);
|
||||
|
||||
@@ -324,7 +324,7 @@ class private_adaptive_pool
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
private_adaptive_pool(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other private_adaptive_pool. Increments the reference
|
||||
//!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);
|
||||
|
||||
@@ -351,7 +351,7 @@ class private_adaptive_pool
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!Allocate memory for an array of count elements.
|
||||
//!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);
|
||||
|
||||
@@ -375,7 +375,7 @@ class private_adaptive_pool
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Copy construct an object.
|
||||
//!Copy construct an object.
|
||||
//!Throws if T's copy constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
@@ -390,7 +390,7 @@ class private_adaptive_pool
|
||||
|
||||
std::pair<pointer, bool>
|
||||
allocation_command(boost::interprocess::allocation_type command,
|
||||
size_type limit_size,
|
||||
size_type limit_size,
|
||||
size_type preferred_size,
|
||||
size_type &received_size, const pointer &reuse = 0);
|
||||
|
||||
@@ -400,12 +400,12 @@ class private_adaptive_pool
|
||||
//!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, size_type num_elements);
|
||||
void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain);
|
||||
|
||||
//!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);
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain);
|
||||
|
||||
//!Allocates many elements of size elem_size in a contiguous block
|
||||
//!of memory. The minimum number to be allocated is min_elements,
|
||||
@@ -413,7 +413,7 @@ class private_adaptive_pool
|
||||
//!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);
|
||||
void deallocate_many(multiallocation_chain &chain);
|
||||
|
||||
//!Allocates just one object. Memory allocated with this function
|
||||
//!must be deallocated only with deallocate_one().
|
||||
@@ -426,7 +426,7 @@ class private_adaptive_pool
|
||||
//!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(size_type num_elements);
|
||||
void allocate_individual(size_type num_elements, multiallocation_chain &chain);
|
||||
|
||||
//!Deallocates memory previously allocated with allocate_one().
|
||||
//!You should never use deallocate_one to deallocate memory allocated
|
||||
@@ -439,7 +439,7 @@ class private_adaptive_pool
|
||||
//!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);
|
||||
void deallocate_individual(multiallocation_chain &chain);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -448,13 +448,13 @@ class private_adaptive_pool
|
||||
//!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,
|
||||
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,
|
||||
bool operator!=(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
//!\file
|
||||
//!Describes private_node_allocator_base pooled shared memory STL compatible allocator
|
||||
//!Describes private_node_allocator_base pooled shared memory STL compatible allocator
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
@@ -97,7 +97,7 @@ class private_node_allocator_base
|
||||
//!Obtains node_allocator from other node_allocator
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef private_node_allocator_base
|
||||
<Version, T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
@@ -146,7 +146,7 @@ class private_node_allocator_base
|
||||
{}
|
||||
|
||||
//!Destructor, frees all used memory. Never throws
|
||||
~private_node_allocator_base()
|
||||
~private_node_allocator_base()
|
||||
{}
|
||||
|
||||
//!Returns the segment manager. Never throws
|
||||
@@ -170,13 +170,13 @@ class private_node_allocator_base
|
||||
|
||||
//!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,
|
||||
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,
|
||||
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; }
|
||||
|
||||
@@ -198,11 +198,11 @@ class private_node_allocator_v1
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
private_node_allocator_v1(SegmentManager *segment_mngr)
|
||||
private_node_allocator_v1(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
@@ -217,11 +217,11 @@ class private_node_allocator_v1
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!An STL node allocator that uses a segment manager as memory
|
||||
//!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
|
||||
//!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
|
||||
@@ -246,12 +246,12 @@ class private_node_allocator
|
||||
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef private_node_allocator
|
||||
<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
|
||||
private_node_allocator(SegmentManager *segment_mngr)
|
||||
private_node_allocator(SegmentManager *segment_mngr)
|
||||
: base_t(segment_mngr)
|
||||
{}
|
||||
|
||||
@@ -275,11 +275,11 @@ class private_node_allocator
|
||||
typedef typename segment_manager::size_type size_type;
|
||||
typedef typename segment_manage::difference_type difference_type;
|
||||
|
||||
//!Obtains private_node_allocator from
|
||||
//!Obtains private_node_allocator from
|
||||
//!private_node_allocator
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
{
|
||||
typedef private_node_allocator
|
||||
<T2, SegmentManager, NodesPerBlock> other;
|
||||
};
|
||||
@@ -291,7 +291,7 @@ class private_node_allocator
|
||||
private_node_allocator& operator=
|
||||
(const private_node_allocator<T2, SegmentManager2, N2>&);
|
||||
|
||||
//!Not assignable from
|
||||
//!Not assignable from
|
||||
//!other private_node_allocator
|
||||
private_node_allocator& operator=(const private_node_allocator&);
|
||||
|
||||
@@ -301,7 +301,7 @@ class private_node_allocator
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
private_node_allocator(segment_manager *segment_mngr);
|
||||
|
||||
//!Copy constructor from other private_node_allocator. Increments the reference
|
||||
//!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);
|
||||
|
||||
@@ -328,7 +328,7 @@ class private_node_allocator
|
||||
//!Never throws
|
||||
size_type max_size() const;
|
||||
|
||||
//!Allocate memory for an array of count elements.
|
||||
//!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);
|
||||
|
||||
@@ -352,7 +352,7 @@ class private_node_allocator
|
||||
//!Never throws
|
||||
const_pointer address(const_reference value) const;
|
||||
|
||||
//!Copy construct an object.
|
||||
//!Copy construct an object.
|
||||
//!Throws if T's copy constructor throws
|
||||
void construct(const pointer &ptr, const_reference v);
|
||||
|
||||
@@ -367,7 +367,7 @@ class private_node_allocator
|
||||
|
||||
std::pair<pointer, bool>
|
||||
allocation_command(boost::interprocess::allocation_type command,
|
||||
size_type limit_size,
|
||||
size_type limit_size,
|
||||
size_type preferred_size,
|
||||
size_type &received_size, const pointer &reuse = 0);
|
||||
|
||||
@@ -377,12 +377,12 @@ class private_node_allocator
|
||||
//!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, size_type num_elements);
|
||||
void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain);
|
||||
|
||||
//!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);
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain);
|
||||
|
||||
//!Allocates many elements of size elem_size in a contiguous block
|
||||
//!of memory. The minimum number to be allocated is min_elements,
|
||||
@@ -390,7 +390,7 @@ class private_node_allocator
|
||||
//!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);
|
||||
void deallocate_many(multiallocation_chain &chain);
|
||||
|
||||
//!Allocates just one object. Memory allocated with this function
|
||||
//!must be deallocated only with deallocate_one().
|
||||
@@ -403,7 +403,7 @@ class private_node_allocator
|
||||
//!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(size_type num_elements);
|
||||
void allocate_individual(size_type num_elements, multiallocation_chain &chain);
|
||||
|
||||
//!Deallocates memory previously allocated with allocate_one().
|
||||
//!You should never use deallocate_one to deallocate memory allocated
|
||||
@@ -416,7 +416,7 @@ class private_node_allocator
|
||||
//!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);
|
||||
void deallocate_individual(multiallocation_chain &chain);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -425,13 +425,13 @@ class private_node_allocator
|
||||
//!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,
|
||||
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,
|
||||
bool operator!=(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1,
|
||||
const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
#if (!defined(BOOST_INTERPROCESS_WINDOWS))
|
||||
# include <fcntl.h> //open, O_CREAT, O_*...
|
||||
# include <fcntl.h> //open, O_CREAT, O_*...
|
||||
# include <sys/mman.h> //mmap
|
||||
# include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
|
||||
#else
|
||||
@@ -43,12 +43,10 @@ namespace ipcdetail{
|
||||
{
|
||||
public:
|
||||
static mapped_region
|
||||
create_posix_mapped_region(void *address, offset_t offset, std::size_t size)
|
||||
create_posix_mapped_region(void *address, std::size_t size)
|
||||
{
|
||||
mapped_region region;
|
||||
region.m_base = address;
|
||||
region.m_offset = offset;
|
||||
region.m_extra_offset = 0;
|
||||
region.m_size = size;
|
||||
return region;
|
||||
}
|
||||
@@ -92,16 +90,16 @@ anonymous_shared_memory(std::size_t size, void *address = 0)
|
||||
, 0);
|
||||
|
||||
if(address == MAP_FAILED){
|
||||
if(fd != -1)
|
||||
if(fd != -1)
|
||||
close(fd);
|
||||
error_info err = system_error_code();
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
|
||||
if(fd != -1)
|
||||
if(fd != -1)
|
||||
close(fd);
|
||||
|
||||
return ipcdetail::raw_mapped_region_creator::create_posix_mapped_region(address, 0, size);
|
||||
return ipcdetail::raw_mapped_region_creator::create_posix_mapped_region(address, size);
|
||||
}
|
||||
#else
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2009. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2009-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2006-2011
|
||||
// (C) Copyright Ion Gaztanaga 2006-2012
|
||||
// (C) Copyright Markus Schoepflin 2007
|
||||
// (C) Copyright Bryce Lelbach 2010
|
||||
//
|
||||
@@ -117,23 +117,6 @@ inline boost::uint32_t atomic_cas32
|
||||
: "cc");
|
||||
|
||||
return prev;
|
||||
/*
|
||||
asm volatile( "lock\n\t"
|
||||
"cmpxchg %3,%1"
|
||||
: "=a" (prev), "=m" (*(mem))
|
||||
: "0" (prev), "r" (with)
|
||||
: "memory", "cc");
|
||||
*/
|
||||
/*
|
||||
boost::uint32_t prev;
|
||||
|
||||
asm volatile ("lock; cmpxchgl %1, %2"
|
||||
: "=a" (prev)
|
||||
: "r" (with), "m" (*(mem)), "0"(cmp));
|
||||
asm volatile("" : : : "memory");
|
||||
|
||||
return prev;
|
||||
*/
|
||||
}
|
||||
|
||||
//! Atomically add 'val' to an boost::uint32_t
|
||||
@@ -158,14 +141,6 @@ inline boost::uint32_t atomic_add32
|
||||
);
|
||||
|
||||
return r;
|
||||
/*
|
||||
asm volatile( "lock\n\t; xaddl %0,%1"
|
||||
: "=r"(val), "=m"(*mem)
|
||||
: "0"(val), "m"(*mem));
|
||||
asm volatile("" : : : "memory");
|
||||
|
||||
return val;
|
||||
*/
|
||||
}
|
||||
|
||||
//! Atomically increment an apr_uint32_t by 1
|
||||
@@ -208,17 +183,14 @@ inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32
|
||||
{
|
||||
boost::uint32_t prev, temp;
|
||||
|
||||
asm volatile ("0:\n\t" // retry local label
|
||||
"lwarx %0,0,%2\n\t" // load prev and reserve
|
||||
"add %1,%0,%3\n\t" // temp = prev + val
|
||||
"stwcx. %1,0,%2\n\t" // conditionally store
|
||||
"bne- 0b" // start over if we lost
|
||||
// the reservation
|
||||
//XXX find a cleaner way to define the temp
|
||||
//it's not an output
|
||||
: "=&r" (prev), "=&r" (temp) // output, temp
|
||||
: "b" (mem), "r" (val) // inputs
|
||||
: "memory", "cc"); // clobbered
|
||||
asm volatile ("1:\n\t"
|
||||
"lwarx %0,0,%2\n\t"
|
||||
"add %1,%0,%3\n\t"
|
||||
"stwcx. %1,0,%2\n\t"
|
||||
"bne- 1b"
|
||||
: "=&r" (prev), "=&r" (temp)
|
||||
: "b" (mem), "r" (val)
|
||||
: "cc", "memory");
|
||||
return prev;
|
||||
}
|
||||
|
||||
@@ -233,19 +205,16 @@ inline boost::uint32_t atomic_cas32
|
||||
{
|
||||
boost::uint32_t prev;
|
||||
|
||||
asm volatile ("0:\n\t" // retry local label
|
||||
"lwarx %0,0,%1\n\t" // load prev and reserve
|
||||
"cmpw %0,%3\n\t" // does it match cmp?
|
||||
"bne- 1f\n\t" // ...no, bail out
|
||||
"stwcx. %2,0,%1\n\t" // ...yes, conditionally
|
||||
// store with
|
||||
"bne- 0b\n\t" // start over if we lost
|
||||
// the reservation
|
||||
"1:" // exit local label
|
||||
|
||||
: "=&r"(prev) // output
|
||||
: "b" (mem), "r" (with), "r"(cmp) // inputs
|
||||
: "memory", "cc"); // clobbered
|
||||
asm volatile ("1:\n\t"
|
||||
"lwarx %0,0,%1\n\t"
|
||||
"cmpw %0,%3\n\t"
|
||||
"bne- 2f\n\t"
|
||||
"stwcx. %2,0,%1\n\t"
|
||||
"bne- 1b\n\t"
|
||||
"2:"
|
||||
: "=&r"(prev)
|
||||
: "b" (mem), "r"(cmp), "r" (with)
|
||||
: "cc", "memory");
|
||||
return prev;
|
||||
}
|
||||
|
||||
@@ -275,56 +244,6 @@ inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
|
||||
} //namespace interprocess{
|
||||
} //namespace boost{
|
||||
|
||||
#elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 )
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail{
|
||||
|
||||
//! Atomically add 'val' to an boost::uint32_t
|
||||
//! "mem": pointer to the object
|
||||
//! "val": amount to add
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_add32
|
||||
(volatile boost::uint32_t *mem, boost::uint32_t val)
|
||||
{ return __sync_fetch_and_add(const_cast<boost::uint32_t *>(mem), val); }
|
||||
|
||||
//! Atomically increment an apr_uint32_t by 1
|
||||
//! "mem": pointer to the object
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
|
||||
{ return atomic_add32(mem, 1); }
|
||||
|
||||
//! Atomically decrement an boost::uint32_t by 1
|
||||
//! "mem": pointer to the atomic value
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
|
||||
{ return atomic_add32(mem, (boost::uint32_t)-1); }
|
||||
|
||||
//! Atomically read an boost::uint32_t from memory
|
||||
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
|
||||
{ return *mem; }
|
||||
|
||||
//! Compare an boost::uint32_t's value with "cmp".
|
||||
//! If they are the same swap the value with "with"
|
||||
//! "mem": pointer to the value
|
||||
//! "with" what to swap it with
|
||||
//! "cmp": the value to compare it to
|
||||
//! Returns the old value of *mem
|
||||
inline boost::uint32_t atomic_cas32
|
||||
(volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
|
||||
{ return __sync_val_compare_and_swap(const_cast<boost::uint32_t *>(mem), cmp, with); }
|
||||
|
||||
//! Atomically set an boost::uint32_t in memory
|
||||
//! "mem": pointer to the object
|
||||
//! "param": val value that the object will assume
|
||||
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
|
||||
{ *mem = val; }
|
||||
|
||||
} //namespace ipcdetail{
|
||||
} //namespace interprocess{
|
||||
} //namespace boost{
|
||||
|
||||
#elif (defined(sun) || defined(__sun))
|
||||
|
||||
#include <atomic.h>
|
||||
@@ -471,97 +390,147 @@ inline boost::uint32_t atomic_cas32(
|
||||
} //namespace interprocess{
|
||||
} //namespace boost{
|
||||
|
||||
#elif defined(__IBMCPP__) && (__IBMCPP__ >= 800) && defined(_AIX)
|
||||
#elif defined(__IBMCPP__) && (__IBMCPP__ >= 800) && defined(_AIX)
|
||||
|
||||
#include <builtins.h>
|
||||
#include <builtins.h>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail{
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail{
|
||||
|
||||
//first define boost::uint32_t versions of __lwarx and __stwcx to avoid poluting
|
||||
//all the functions with casts
|
||||
//first define boost::uint32_t versions of __lwarx and __stwcx to avoid poluting
|
||||
//all the functions with casts
|
||||
|
||||
//! From XLC documenation :
|
||||
//! This function can be used with a subsequent stwcxu call to implement a
|
||||
//! read-modify-write on a specified memory location. The two functions work
|
||||
//! together to ensure that if the store is successfully performed, no other
|
||||
//! processor or mechanism can modify the target doubleword between the time
|
||||
//! lwarxu function is executed and the time the stwcxu functio ncompletes.
|
||||
//! "mem" : pointer to the object
|
||||
//! Returns the value at pointed to by mem
|
||||
inline boost::uint32_t lwarxu(volatile boost::uint32_t *mem)
|
||||
{
|
||||
return static_cast<boost::uint32_t>(__lwarx(reinterpret_cast<volatile int*>(mem)));
|
||||
}
|
||||
//! From XLC documenation :
|
||||
//! This function can be used with a subsequent stwcxu call to implement a
|
||||
//! read-modify-write on a specified memory location. The two functions work
|
||||
//! together to ensure that if the store is successfully performed, no other
|
||||
//! processor or mechanism can modify the target doubleword between the time
|
||||
//! lwarxu function is executed and the time the stwcxu functio ncompletes.
|
||||
//! "mem" : pointer to the object
|
||||
//! Returns the value at pointed to by mem
|
||||
inline boost::uint32_t lwarxu(volatile boost::uint32_t *mem)
|
||||
{
|
||||
return static_cast<boost::uint32_t>(__lwarx(reinterpret_cast<volatile int*>(mem)));
|
||||
}
|
||||
|
||||
//! "mem" : pointer to the object
|
||||
//! "val" : the value to store
|
||||
//! Returns true if the update of mem is successful and false if it is
|
||||
//!unsuccessful
|
||||
inline bool stwcxu(volatile boost::uint32_t* mem, boost::uint32_t val)
|
||||
{
|
||||
return (__stwcx(reinterpret_cast<volatile int*>(mem), static_cast<int>(val)) != 0);
|
||||
}
|
||||
//! "mem" : pointer to the object
|
||||
//! "val" : the value to store
|
||||
//! Returns true if the update of mem is successful and false if it is
|
||||
//!unsuccessful
|
||||
inline bool stwcxu(volatile boost::uint32_t* mem, boost::uint32_t val)
|
||||
{
|
||||
return (__stwcx(reinterpret_cast<volatile int*>(mem), static_cast<int>(val)) != 0);
|
||||
}
|
||||
|
||||
//! "mem": pointer to the object
|
||||
//! "val": amount to add
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_add32
|
||||
(volatile boost::uint32_t *mem, boost::uint32_t val)
|
||||
{
|
||||
boost::uint32_t oldValue;
|
||||
do
|
||||
{
|
||||
oldValue = lwarxu(mem);
|
||||
}while (!stwcxu(mem, oldValue+val));
|
||||
return oldValue;
|
||||
}
|
||||
//! "mem": pointer to the object
|
||||
//! "val": amount to add
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_add32
|
||||
(volatile boost::uint32_t *mem, boost::uint32_t val)
|
||||
{
|
||||
boost::uint32_t oldValue;
|
||||
do
|
||||
{
|
||||
oldValue = lwarxu(mem);
|
||||
}while (!stwcxu(mem, oldValue+val));
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
//! Atomically increment an apr_uint32_t by 1
|
||||
//! "mem": pointer to the object
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
|
||||
{ return atomic_add32(mem, 1); }
|
||||
//! Atomically increment an apr_uint32_t by 1
|
||||
//! "mem": pointer to the object
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
|
||||
{ return atomic_add32(mem, 1); }
|
||||
|
||||
//! Atomically decrement an boost::uint32_t by 1
|
||||
//! "mem": pointer to the atomic value
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
|
||||
{ return atomic_add32(mem, (boost::uint32_t)-1); }
|
||||
//! Atomically decrement an boost::uint32_t by 1
|
||||
//! "mem": pointer to the atomic value
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
|
||||
{ return atomic_add32(mem, (boost::uint32_t)-1); }
|
||||
|
||||
//! Atomically read an boost::uint32_t from memory
|
||||
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
|
||||
{ return *mem; }
|
||||
//! Atomically read an boost::uint32_t from memory
|
||||
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
|
||||
{ return *mem; }
|
||||
|
||||
//! Compare an boost::uint32_t's value with "cmp".
|
||||
//! If they are the same swap the value with "with"
|
||||
//! "mem": pointer to the value
|
||||
//! "with" what to swap it with
|
||||
//! "cmp": the value to compare it to
|
||||
//! Returns the old value of *mem
|
||||
inline boost::uint32_t atomic_cas32
|
||||
(volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
|
||||
{
|
||||
boost::uint32_t oldValue;
|
||||
boost::uint32_t valueToStore;
|
||||
do
|
||||
{
|
||||
oldValue = lwarxu(mem);
|
||||
} while (!stwcxu(mem, (oldValue == with) ? cmp : oldValue));
|
||||
//! Compare an boost::uint32_t's value with "cmp".
|
||||
//! If they are the same swap the value with "with"
|
||||
//! "mem": pointer to the value
|
||||
//! "with" what to swap it with
|
||||
//! "cmp": the value to compare it to
|
||||
//! Returns the old value of *mem
|
||||
inline boost::uint32_t atomic_cas32
|
||||
(volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
|
||||
{
|
||||
boost::uint32_t oldValue;
|
||||
boost::uint32_t valueToStore;
|
||||
do
|
||||
{
|
||||
oldValue = lwarxu(mem);
|
||||
} while (!stwcxu(mem, (oldValue == with) ? cmp : oldValue));
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
//! Atomically set an boost::uint32_t in memory
|
||||
//! "mem": pointer to the object
|
||||
//! "param": val value that the object will assume
|
||||
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
|
||||
{ *mem = val; }
|
||||
//! Atomically set an boost::uint32_t in memory
|
||||
//! "mem": pointer to the object
|
||||
//! "param": val value that the object will assume
|
||||
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
|
||||
{ *mem = val; }
|
||||
|
||||
} //namespace ipcdetail
|
||||
} //namespace interprocess
|
||||
} //namespace boost
|
||||
} //namespace ipcdetail
|
||||
} //namespace interprocess
|
||||
} //namespace boost
|
||||
|
||||
#elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 )
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail{
|
||||
|
||||
//! Atomically add 'val' to an boost::uint32_t
|
||||
//! "mem": pointer to the object
|
||||
//! "val": amount to add
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_add32
|
||||
(volatile boost::uint32_t *mem, boost::uint32_t val)
|
||||
{ return __sync_fetch_and_add(const_cast<boost::uint32_t *>(mem), val); }
|
||||
|
||||
//! Atomically increment an apr_uint32_t by 1
|
||||
//! "mem": pointer to the object
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
|
||||
{ return atomic_add32(mem, 1); }
|
||||
|
||||
//! Atomically decrement an boost::uint32_t by 1
|
||||
//! "mem": pointer to the atomic value
|
||||
//! Returns the old value pointed to by mem
|
||||
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
|
||||
{ return atomic_add32(mem, (boost::uint32_t)-1); }
|
||||
|
||||
//! Atomically read an boost::uint32_t from memory
|
||||
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
|
||||
{ return *mem; }
|
||||
|
||||
//! Compare an boost::uint32_t's value with "cmp".
|
||||
//! If they are the same swap the value with "with"
|
||||
//! "mem": pointer to the value
|
||||
//! "with" what to swap it with
|
||||
//! "cmp": the value to compare it to
|
||||
//! Returns the old value of *mem
|
||||
inline boost::uint32_t atomic_cas32
|
||||
(volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
|
||||
{ return __sync_val_compare_and_swap(const_cast<boost::uint32_t *>(mem), cmp, with); }
|
||||
|
||||
//! Atomically set an boost::uint32_t in memory
|
||||
//! "mem": pointer to the object
|
||||
//! "param": val value that the object will assume
|
||||
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
|
||||
{ *mem = val; }
|
||||
|
||||
} //namespace ipcdetail{
|
||||
} //namespace interprocess{
|
||||
} //namespace boost{
|
||||
|
||||
#else
|
||||
|
||||
@@ -583,9 +552,9 @@ inline bool atomic_add_unless32
|
||||
return c != unless_this;
|
||||
}
|
||||
|
||||
} //namespace ipcdetail
|
||||
} //namespace interprocess
|
||||
} //namespace boost
|
||||
} //namespace ipcdetail
|
||||
} //namespace interprocess
|
||||
} //namespace boost
|
||||
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -44,4 +44,5 @@
|
||||
// with /GR-; unpredictable behavior may result
|
||||
#pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site
|
||||
#pragma warning (disable : 4671) // the copy constructor is inaccessible
|
||||
#pragma warning (disable : 4250) // inherits 'x' via dominance
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2012-2012. 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_EXTERNAL_CONFIG_INCLUDED
|
||||
#define BOOST_INTERPROCESS_EXTERNAL_CONFIG_INCLUDED
|
||||
#include <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2012-2012. 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.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
@@ -0,0 +1,298 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2009-2012. 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_FILE_LOCKING_HELPERS_HPP
|
||||
#define BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_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 <sstream>
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <cstddef>
|
||||
#include <boost/interprocess/detail/os_file_functions.hpp>
|
||||
|
||||
#include <boost/interprocess/detail/tmp_dir_helpers.hpp>
|
||||
|
||||
#if defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <sys/locking.h>
|
||||
|
||||
#else //defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#endif //defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
|
||||
namespace boost{
|
||||
namespace interprocess{
|
||||
namespace ipcdetail{
|
||||
|
||||
#if defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
|
||||
struct locking_file_serial_id
|
||||
{
|
||||
int fd;
|
||||
unsigned long dwVolumeSerialNumber;
|
||||
unsigned long nFileIndexHigh;
|
||||
unsigned long nFileIndexLow;
|
||||
//This reference count counts the number of modules attached
|
||||
//to the shared memory and lock file. This serves to unlink
|
||||
//the locking file and shared memory when all modules are
|
||||
//done with the global memory (shared memory)
|
||||
volatile boost::uint32_t modules_attached_to_gmem_count;
|
||||
};
|
||||
|
||||
inline bool lock_locking_file(int fd)
|
||||
{
|
||||
int ret = 0;
|
||||
while(ret != 0 && errno == EDEADLK){
|
||||
ret = _locking(fd, _LK_LOCK, 1/*lock_file_contents_length()*/);
|
||||
}
|
||||
return 0 == ret;
|
||||
}
|
||||
|
||||
inline bool try_lock_locking_file(int fd)
|
||||
{
|
||||
return 0 == _locking(fd, _LK_NBLCK , 1);
|
||||
}
|
||||
|
||||
inline int open_or_create_and_lock_file(const char *name)
|
||||
{
|
||||
permissions p;
|
||||
p.set_unrestricted();
|
||||
while(1){
|
||||
file_handle_t handle = create_or_open_file(name, read_write, p);
|
||||
int fd = _open_osfhandle((intptr_t)handle, _O_TEXT);
|
||||
if(fd < 0){
|
||||
close_file(handle);
|
||||
return fd;
|
||||
}
|
||||
if(!try_lock_locking_file(fd)){
|
||||
_close(fd);
|
||||
return -1;
|
||||
}
|
||||
struct _stat s;
|
||||
if(0 == _stat(name, &s)){
|
||||
return fd;
|
||||
}
|
||||
else{
|
||||
_close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int try_open_and_lock_file(const char *name)
|
||||
{
|
||||
file_handle_t handle = open_existing_file(name, read_write);
|
||||
int fd = _open_osfhandle((intptr_t)handle, _O_TEXT);
|
||||
if(fd < 0){
|
||||
close_file(handle);
|
||||
return fd;
|
||||
}
|
||||
if(!try_lock_locking_file(fd)){
|
||||
_close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
inline void close_lock_file(int fd)
|
||||
{ _close(fd); }
|
||||
|
||||
inline bool is_valid_fd(int fd)
|
||||
{
|
||||
struct _stat s;
|
||||
return EBADF != _fstat(fd, &s);
|
||||
}
|
||||
|
||||
inline bool is_normal_file(int fd)
|
||||
{
|
||||
if(_isatty(fd))
|
||||
return false;
|
||||
struct _stat s;
|
||||
if(0 != _fstat(fd, &s))
|
||||
return false;
|
||||
return 0 != (s.st_mode & _S_IFREG);
|
||||
}
|
||||
|
||||
inline std::size_t get_size(int fd)
|
||||
{
|
||||
struct _stat s;
|
||||
if(0 != _fstat(fd, &s))
|
||||
return 0u;
|
||||
return (std::size_t)s.st_size;
|
||||
}
|
||||
|
||||
inline bool fill_file_serial_id(int fd, locking_file_serial_id &id)
|
||||
{
|
||||
winapi::interprocess_by_handle_file_information info;
|
||||
if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info))
|
||||
return false;
|
||||
id.fd = fd;
|
||||
id.dwVolumeSerialNumber = info.dwVolumeSerialNumber;
|
||||
id.nFileIndexHigh = info.nFileIndexHigh;
|
||||
id.nFileIndexLow = info.nFileIndexLow;
|
||||
id.modules_attached_to_gmem_count = 1; //Initialize attached count
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool compare_file_serial(int fd, const locking_file_serial_id &id)
|
||||
{
|
||||
winapi::interprocess_by_handle_file_information info;
|
||||
if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info))
|
||||
return false;
|
||||
|
||||
return id.dwVolumeSerialNumber == info.dwVolumeSerialNumber &&
|
||||
id.nFileIndexHigh == info.nFileIndexHigh &&
|
||||
id.nFileIndexLow == info.nFileIndexLow;
|
||||
}
|
||||
|
||||
#else //UNIX
|
||||
|
||||
struct locking_file_serial_id
|
||||
{
|
||||
int fd;
|
||||
dev_t st_dev;
|
||||
ino_t st_ino;
|
||||
//This reference count counts the number of modules attached
|
||||
//to the shared memory and lock file. This serves to unlink
|
||||
//the locking file and shared memory when all modules are
|
||||
//done with the global memory (shared memory)
|
||||
volatile boost::uint32_t modules_attached_to_gmem_count;
|
||||
};
|
||||
|
||||
inline bool lock_locking_file(int fd)
|
||||
{
|
||||
int ret = 0;
|
||||
while(ret != 0 && errno != EINTR){
|
||||
struct flock lock;
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 1;
|
||||
ret = fcntl (fd, F_SETLKW, &lock);
|
||||
}
|
||||
return 0 == ret;
|
||||
}
|
||||
|
||||
inline bool try_lock_locking_file(int fd)
|
||||
{
|
||||
struct flock lock;
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 1;
|
||||
return 0 == fcntl (fd, F_SETLK, &lock);
|
||||
}
|
||||
|
||||
inline int open_or_create_and_lock_file(const char *name)
|
||||
{
|
||||
permissions p;
|
||||
p.set_unrestricted();
|
||||
while(1){
|
||||
int fd = create_or_open_file(name, read_write, p);
|
||||
if(fd < 0){
|
||||
return fd;
|
||||
}
|
||||
if(!try_lock_locking_file(fd)){
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
struct stat s;
|
||||
if(0 == stat(name, &s)){
|
||||
return fd;
|
||||
}
|
||||
else{
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int try_open_and_lock_file(const char *name)
|
||||
{
|
||||
int fd = open_existing_file(name, read_write);
|
||||
if(fd < 0){
|
||||
return fd;
|
||||
}
|
||||
if(!try_lock_locking_file(fd)){
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
inline void close_lock_file(int fd)
|
||||
{ close(fd); }
|
||||
|
||||
inline bool is_valid_fd(int fd)
|
||||
{
|
||||
struct stat s;
|
||||
return EBADF != fstat(fd, &s);
|
||||
}
|
||||
|
||||
inline bool is_normal_file(int fd)
|
||||
{
|
||||
struct stat s;
|
||||
if(0 != fstat(fd, &s))
|
||||
return false;
|
||||
return 0 != (s.st_mode & S_IFREG);
|
||||
}
|
||||
|
||||
inline std::size_t get_size(int fd)
|
||||
{
|
||||
struct stat s;
|
||||
if(0 != fstat(fd, &s))
|
||||
return 0u;
|
||||
return (std::size_t)s.st_size;
|
||||
}
|
||||
|
||||
inline bool fill_file_serial_id(int fd, locking_file_serial_id &id)
|
||||
{
|
||||
struct stat s;
|
||||
if(0 != fstat(fd, &s))
|
||||
return false;
|
||||
id.fd = fd;
|
||||
id.st_dev = s.st_dev;
|
||||
id.st_ino = s.st_ino;
|
||||
id.modules_attached_to_gmem_count = 1; //Initialize attached count
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool compare_file_serial(int fd, const locking_file_serial_id &id)
|
||||
{
|
||||
struct stat info;
|
||||
if(0 != fstat(fd, &info))
|
||||
return false;
|
||||
|
||||
return id.st_dev == info.st_dev &&
|
||||
id.st_ino == info.st_ino;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} //namespace ipcdetail{
|
||||
} //namespace interprocess{
|
||||
} //namespace boost{
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2006-2012. 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)
|
||||
//
|
||||
@@ -44,13 +44,13 @@ class file_wrapper
|
||||
file_wrapper(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions())
|
||||
{ this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm); }
|
||||
|
||||
//!Tries to open a file with name "name", with the access mode "mode".
|
||||
//!Tries to open a file with name "name", with the access mode "mode".
|
||||
//!If the file does not previously exist, it throws an error.
|
||||
file_wrapper(open_only_t, const char *name, mode_t mode)
|
||||
{ this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); }
|
||||
|
||||
//!Moves the ownership of "moved"'s file to *this.
|
||||
//!After the call, "moved" does not represent any file.
|
||||
//!Moves the ownership of "moved"'s file to *this.
|
||||
//!After the call, "moved" does not represent any file.
|
||||
//!Does not throw
|
||||
file_wrapper(BOOST_RV_REF(file_wrapper) moved)
|
||||
: m_handle(file_handle_t(ipcdetail::invalid_file()))
|
||||
@@ -60,10 +60,10 @@ class file_wrapper
|
||||
//!After the call, "moved" does not represent any file.
|
||||
//!Does not throw
|
||||
file_wrapper &operator=(BOOST_RV_REF(file_wrapper) moved)
|
||||
{
|
||||
{
|
||||
file_wrapper tmp(boost::move(moved));
|
||||
this->swap(tmp);
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Swaps to file_wrappers.
|
||||
@@ -73,7 +73,7 @@ class file_wrapper
|
||||
//!Erases a file from the system.
|
||||
//!Returns false on error. Never throws
|
||||
static bool remove(const char *name);
|
||||
|
||||
|
||||
//!Sets the size of the file
|
||||
void truncate(offset_t length);
|
||||
|
||||
@@ -108,11 +108,11 @@ class file_wrapper
|
||||
std::string m_filename;
|
||||
};
|
||||
|
||||
inline file_wrapper::file_wrapper()
|
||||
inline file_wrapper::file_wrapper()
|
||||
: m_handle(file_handle_t(ipcdetail::invalid_file()))
|
||||
{}
|
||||
|
||||
inline file_wrapper::~file_wrapper()
|
||||
inline file_wrapper::~file_wrapper()
|
||||
{ this->priv_close(); }
|
||||
|
||||
inline const char *file_wrapper::get_name() const
|
||||
@@ -122,10 +122,10 @@ inline bool file_wrapper::get_size(offset_t &size) const
|
||||
{ return get_file_size((file_handle_t)m_handle, size); }
|
||||
|
||||
inline void file_wrapper::swap(file_wrapper &other)
|
||||
{
|
||||
{
|
||||
std::swap(m_handle, other.m_handle);
|
||||
std::swap(m_mode, other.m_mode);
|
||||
m_filename.swap(other.m_filename);
|
||||
m_filename.swap(other.m_filename);
|
||||
}
|
||||
|
||||
inline mapping_handle_t file_wrapper::get_mapping_handle() const
|
||||
@@ -135,7 +135,7 @@ inline mode_t file_wrapper::get_mode() const
|
||||
{ return m_mode; }
|
||||
|
||||
inline bool file_wrapper::priv_open_or_create
|
||||
(ipcdetail::create_enum_t type,
|
||||
(ipcdetail::create_enum_t type,
|
||||
const char *filename,
|
||||
mode_t mode,
|
||||
const permissions &perm = permissions())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -25,7 +25,7 @@
|
||||
//!Describes an abstract interface for placement construction and destruction.
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
struct in_place_interface
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,496 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2009-2012. 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_INTERMODULE_SINGLETON_COMMON_HPP
|
||||
#define BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_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/detail/atomic.hpp>
|
||||
#include <boost/interprocess/detail/os_thread_functions.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/type_traits/type_with_alignment.hpp>
|
||||
#include <boost/interprocess/detail/mpl.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace boost{
|
||||
namespace interprocess{
|
||||
namespace ipcdetail{
|
||||
|
||||
namespace intermodule_singleton_helpers {
|
||||
|
||||
inline void get_pid_creation_time_str(std::string &s)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << get_current_process_id() << '_';
|
||||
stream.precision(6);
|
||||
stream << std::fixed << get_current_process_creation_time();
|
||||
s = stream.str();
|
||||
}
|
||||
|
||||
inline const char *get_map_base_name()
|
||||
{ return "bip.gmem.map."; }
|
||||
|
||||
inline void get_map_name(std::string &map_name)
|
||||
{
|
||||
get_pid_creation_time_str(map_name);
|
||||
map_name.insert(0, get_map_base_name());
|
||||
}
|
||||
|
||||
inline std::size_t get_map_size()
|
||||
{ return 65536; }
|
||||
|
||||
template<class ThreadSafeGlobalMap>
|
||||
struct thread_safe_global_map_dependant;
|
||||
|
||||
} //namespace intermodule_singleton_helpers {
|
||||
|
||||
//This class contains common code for all singleton types, so that we instantiate this
|
||||
//code just once per module. This class also holds a thread soafe global map
|
||||
//to be used by all instances protected with a reference count
|
||||
template<class ThreadSafeGlobalMap>
|
||||
class intermodule_singleton_common
|
||||
{
|
||||
public:
|
||||
typedef void*(singleton_constructor_t)(ThreadSafeGlobalMap &);
|
||||
typedef void (singleton_destructor_t)(void *, ThreadSafeGlobalMap &);
|
||||
|
||||
static const ::boost::uint32_t Uninitialized = 0u;
|
||||
static const ::boost::uint32_t Initializing = 1u;
|
||||
static const ::boost::uint32_t Initialized = 2u;
|
||||
static const ::boost::uint32_t Broken = 3u;
|
||||
static const ::boost::uint32_t Destroyed = 4u;
|
||||
|
||||
//Initialize this_module_singleton_ptr, creates the global map if needed and also creates an unique
|
||||
//opaque type in global map through a singleton_constructor_t function call,
|
||||
//initializing the passed pointer to that unique instance.
|
||||
//
|
||||
//We have two concurrency types here. a)the global map/singleton creation must
|
||||
//be safe between threads of this process but in different modules/dlls. b)
|
||||
//the pointer to the singleton is per-module, so we have to protect this
|
||||
//initization between threads of the same module.
|
||||
//
|
||||
//All static variables declared here are shared between inside a module
|
||||
//so atomic operations will synchronize only threads of the same module.
|
||||
static void initialize_singleton_logic
|
||||
(void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_constructor_t constructor, bool phoenix)
|
||||
{
|
||||
//If current module is not initialized enter to lock free logic
|
||||
if(atomic_read32(&this_module_singleton_initialized) != Initialized){
|
||||
//Now a single thread of the module will succeed in this CAS.
|
||||
//trying to pass from Uninitialized to Initializing
|
||||
::boost::uint32_t previous_module_singleton_initialized = atomic_cas32
|
||||
(&this_module_singleton_initialized, Initializing, Uninitialized);
|
||||
//If the thread succeeded the CAS (winner) it will compete with other
|
||||
//winner threads from other modules to create the global map
|
||||
if(previous_module_singleton_initialized == Destroyed){
|
||||
//Trying to resurrect a dead Phoenix singleton. Just try to
|
||||
//mark it as uninitialized and start again
|
||||
if(phoenix){
|
||||
atomic_cas32(&this_module_singleton_initialized, Uninitialized, Destroyed);
|
||||
previous_module_singleton_initialized = atomic_cas32
|
||||
(&this_module_singleton_initialized, Initializing, Uninitialized);
|
||||
}
|
||||
//Trying to resurrect a non-Phoenix dead singleton is an error
|
||||
else{
|
||||
throw interprocess_exception("Boost.Interprocess: Dead reference on non-Phoenix singleton of type");
|
||||
}
|
||||
}
|
||||
if(previous_module_singleton_initialized == Uninitialized){
|
||||
try{
|
||||
//Now initialize the global map, this function must solve concurrency
|
||||
//issues between threads of several modules
|
||||
initialize_global_map_handle();
|
||||
//Now try to create the singleton in global map.
|
||||
//This function solves concurrency issues
|
||||
//between threads of several modules
|
||||
void *tmp = constructor(get_map());
|
||||
//Increment the module reference count that reflects how many
|
||||
//singletons this module holds, so that we can safely destroy
|
||||
//module global map object when no singleton is left
|
||||
atomic_inc32(&this_module_singleton_count);
|
||||
//Insert a barrier before assigning the pointer to
|
||||
//make sure this assignment comes after the initialization
|
||||
atomic_write32(&this_module_singleton_initialized, Initializing);
|
||||
//Assign the singleton address to the module-local pointer
|
||||
ptr = tmp;
|
||||
//Memory barrier inserted, all previous operations should complete
|
||||
//before this one. Now marked as initialized
|
||||
atomic_write32(&this_module_singleton_initialized, Initialized);
|
||||
}
|
||||
catch(...){
|
||||
//Mark singleton failed to initialize
|
||||
atomic_write32(&this_module_singleton_initialized, Broken);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
//If previous state was initializing, this means that another winner thread is
|
||||
//trying to initialize the singleton. Just wait until completes its work.
|
||||
else if(previous_module_singleton_initialized == Initializing){
|
||||
while(1){
|
||||
previous_module_singleton_initialized = atomic_read32(&this_module_singleton_initialized);
|
||||
if(previous_module_singleton_initialized >= Initialized){
|
||||
//Already initialized, or exception thrown by initializer thread
|
||||
break;
|
||||
}
|
||||
else if(previous_module_singleton_initialized == Initializing){
|
||||
thread_yield();
|
||||
}
|
||||
else{
|
||||
//This can't be happening!
|
||||
BOOST_ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(previous_module_singleton_initialized == Initialized){
|
||||
//Nothing to do here, the singleton is ready
|
||||
}
|
||||
//If previous state was greater than initialized, then memory is broken
|
||||
//trying to initialize the singleton.
|
||||
else{//(previous_module_singleton_initialized > Initialized)
|
||||
throw interprocess_exception("boost::interprocess::intermodule_singleton initialization failed");
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(ptr != 0);
|
||||
}
|
||||
|
||||
static void finalize_singleton_logic(void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_destructor_t destructor)
|
||||
{
|
||||
//Protect destruction against lazy singletons not initialized in this execution
|
||||
if(ptr){
|
||||
//Note: this destructor might provoke a Phoenix singleton
|
||||
//resurrection. This means that this_module_singleton_count
|
||||
//might change after this call.
|
||||
destructor(ptr, get_map());
|
||||
ptr = 0;
|
||||
|
||||
//Memory barrier to make sure pointer is nulled.
|
||||
//Mark this singleton as destroyed.
|
||||
atomic_write32(&this_module_singleton_initialized, Destroyed);
|
||||
|
||||
//If this is the last singleton of this module
|
||||
//apply map destruction.
|
||||
//Note: singletons are destroyed when the module is unloaded
|
||||
//so no threads should be executing or holding references
|
||||
//to this module
|
||||
if(1 == atomic_dec32(&this_module_singleton_count)){
|
||||
destroy_global_map_handle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static ThreadSafeGlobalMap &get_map()
|
||||
{
|
||||
return *static_cast<ThreadSafeGlobalMap *>(static_cast<void *>(&mem_holder.map_mem[0]));
|
||||
}
|
||||
|
||||
static void initialize_global_map_handle()
|
||||
{
|
||||
//Obtain unique map name and size
|
||||
while(1){
|
||||
//Try to pass map state to initializing
|
||||
::boost::uint32_t tmp = atomic_cas32(&this_module_map_initialized, Initializing, Uninitialized);
|
||||
if(tmp == Initialized || tmp == Broken){
|
||||
break;
|
||||
}
|
||||
else if(tmp == Destroyed){
|
||||
tmp = atomic_cas32(&this_module_map_initialized, Uninitialized, Destroyed);
|
||||
continue;
|
||||
}
|
||||
//If some other thread is doing the work wait
|
||||
else if(tmp == Initializing){
|
||||
thread_yield();
|
||||
}
|
||||
else{ //(tmp == Uninitialized)
|
||||
//If not initialized try it again?
|
||||
try{
|
||||
//Remove old global map from the system
|
||||
intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem();
|
||||
//in-place construction of the global map class
|
||||
intermodule_singleton_helpers::thread_safe_global_map_dependant
|
||||
<ThreadSafeGlobalMap>::construct_map(static_cast<void*>(&get_map()));
|
||||
//Use global map's internal lock to initialize the lock file
|
||||
//that will mark this gmem as "in use".
|
||||
typename intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::
|
||||
lock_file_logic f(get_map());
|
||||
//If function failed (maybe a competing process has erased the shared
|
||||
//memory between creation and file locking), retry with a new instance.
|
||||
if(f.retry()){
|
||||
get_map().~ThreadSafeGlobalMap();
|
||||
atomic_write32(&this_module_map_initialized, Destroyed);
|
||||
}
|
||||
else{
|
||||
//Locking succeeded, so this global map module-instance is ready
|
||||
atomic_write32(&this_module_map_initialized, Initialized);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(...){
|
||||
//
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void destroy_global_map_handle()
|
||||
{
|
||||
if(!atomic_read32(&this_module_singleton_count)){
|
||||
//This module is being unloaded, so destroy
|
||||
//the global map object of this module
|
||||
//and unlink the global map if it's the last
|
||||
typename intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::
|
||||
unlink_map_logic f(get_map());
|
||||
(get_map()).~ThreadSafeGlobalMap();
|
||||
atomic_write32(&this_module_map_initialized, Destroyed);
|
||||
//Do some cleanup for other processes old gmem instances
|
||||
intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem();
|
||||
}
|
||||
}
|
||||
|
||||
//Static data, zero-initalized without any dependencies
|
||||
//this_module_singleton_count is the number of singletons used by this module
|
||||
static volatile boost::uint32_t this_module_singleton_count;
|
||||
|
||||
//this_module_map_initialized is the state of this module's map class object.
|
||||
//Values: Uninitialized, Initializing, Initialized, Broken
|
||||
static volatile boost::uint32_t this_module_map_initialized;
|
||||
|
||||
//Raw memory to construct the global map manager
|
||||
static struct mem_holder_t
|
||||
{
|
||||
::boost::detail::max_align aligner;
|
||||
char map_mem [sizeof(ThreadSafeGlobalMap)];
|
||||
} mem_holder;
|
||||
};
|
||||
|
||||
template<class ThreadSafeGlobalMap>
|
||||
volatile boost::uint32_t intermodule_singleton_common<ThreadSafeGlobalMap>::this_module_singleton_count;
|
||||
|
||||
template<class ThreadSafeGlobalMap>
|
||||
volatile boost::uint32_t intermodule_singleton_common<ThreadSafeGlobalMap>::this_module_map_initialized;
|
||||
|
||||
template<class ThreadSafeGlobalMap>
|
||||
typename intermodule_singleton_common<ThreadSafeGlobalMap>::mem_holder_t
|
||||
intermodule_singleton_common<ThreadSafeGlobalMap>::mem_holder;
|
||||
|
||||
//A reference count to be stored in global map holding the number
|
||||
//of singletons (one per module) attached to the instance pointed by
|
||||
//the internal ptr.
|
||||
struct ref_count_ptr
|
||||
{
|
||||
ref_count_ptr(void *p, boost::uint32_t count)
|
||||
: ptr(p), singleton_ref_count(count)
|
||||
{}
|
||||
void *ptr;
|
||||
//This reference count serves to count the number of attached
|
||||
//modules to this singleton
|
||||
volatile boost::uint32_t singleton_ref_count;
|
||||
};
|
||||
|
||||
|
||||
//Now this class is a singleton, initializing the singleton in
|
||||
//the first get() function call if LazyInit is false. If true
|
||||
//then the singleton will be initialized when loading the module.
|
||||
template<typename C, bool LazyInit, bool Phoenix, class ThreadSafeGlobalMap>
|
||||
class intermodule_singleton_impl
|
||||
{
|
||||
public:
|
||||
|
||||
static C& get() //Let's make inlining easy
|
||||
{
|
||||
if(!this_module_singleton_ptr){
|
||||
if(lifetime.dummy_function()){ //This forces lifetime instantiation, for reference counted destruction
|
||||
atentry_work();
|
||||
}
|
||||
}
|
||||
return *static_cast<C*>(this_module_singleton_ptr);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void atentry_work()
|
||||
{
|
||||
intermodule_singleton_common<ThreadSafeGlobalMap>::initialize_singleton_logic
|
||||
(this_module_singleton_ptr, this_module_singleton_initialized, singleton_constructor, Phoenix);
|
||||
}
|
||||
|
||||
static void atexit_work()
|
||||
{
|
||||
intermodule_singleton_common<ThreadSafeGlobalMap>::finalize_singleton_logic
|
||||
(this_module_singleton_ptr, this_module_singleton_initialized, singleton_destructor);
|
||||
}
|
||||
|
||||
//These statics will be zero-initialized without any constructor call dependency
|
||||
//this_module_singleton_ptr will be a module-local pointer to the singleton
|
||||
static void* this_module_singleton_ptr;
|
||||
|
||||
//this_module_singleton_count will be used to synchronize threads of the same module
|
||||
//for access to a singleton instance, and to flag the state of the
|
||||
//singleton.
|
||||
static volatile boost::uint32_t this_module_singleton_initialized;
|
||||
|
||||
//This class destructor will trigger singleton destruction
|
||||
struct lifetime_type_lazy
|
||||
{
|
||||
bool dummy_function()
|
||||
{ return m_dummy == 0; }
|
||||
|
||||
~lifetime_type_lazy()
|
||||
{
|
||||
if(!Phoenix){
|
||||
atexit_work();
|
||||
}
|
||||
}
|
||||
|
||||
//Dummy volatile so that the compiler can't resolve its value at compile-time
|
||||
//and can't avoid lifetime_type instantiation if dummy_function() is called.
|
||||
static volatile int m_dummy;
|
||||
};
|
||||
|
||||
struct lifetime_type_static
|
||||
: public lifetime_type_lazy
|
||||
{
|
||||
lifetime_type_static()
|
||||
{ atentry_work(); }
|
||||
};
|
||||
|
||||
typedef typename if_c
|
||||
<LazyInit, lifetime_type_lazy, lifetime_type_static>::type lifetime_type;
|
||||
|
||||
static lifetime_type lifetime;
|
||||
|
||||
//A functor to be executed inside global map lock that just
|
||||
//searches for the singleton in map and if not present creates a new one.
|
||||
//If singleton constructor throws, the exception is propagated
|
||||
struct init_atomic_func
|
||||
{
|
||||
init_atomic_func(ThreadSafeGlobalMap &m)
|
||||
: m_map(m)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant
|
||||
<ThreadSafeGlobalMap>::find(m_map, typeid(C).name());
|
||||
if(!rcount){
|
||||
C *p = new C;
|
||||
try{
|
||||
ref_count_ptr val(p, 0u);
|
||||
rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant
|
||||
<ThreadSafeGlobalMap>::insert(m_map, typeid(C).name(), val);
|
||||
}
|
||||
catch(...){
|
||||
intermodule_singleton_helpers::thread_safe_global_map_dependant
|
||||
<ThreadSafeGlobalMap>::erase(m_map, typeid(C).name());
|
||||
delete p;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
if(Phoenix){
|
||||
std::atexit(&atexit_work);
|
||||
}
|
||||
atomic_inc32(&rcount->singleton_ref_count);
|
||||
ret_ptr = rcount->ptr;
|
||||
}
|
||||
void *data() const
|
||||
{ return ret_ptr; }
|
||||
|
||||
private:
|
||||
ThreadSafeGlobalMap &m_map;
|
||||
void *ret_ptr;
|
||||
};
|
||||
|
||||
//A functor to be executed inside global map lock that just
|
||||
//deletes the singleton in map if the attached count reaches to zero
|
||||
struct fini_atomic_func
|
||||
{
|
||||
fini_atomic_func(ThreadSafeGlobalMap &m)
|
||||
: m_map(m)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant
|
||||
<ThreadSafeGlobalMap>::find(m_map, typeid(C).name());
|
||||
//The object must exist
|
||||
BOOST_ASSERT(rcount);
|
||||
BOOST_ASSERT(rcount->singleton_ref_count > 0);
|
||||
//Check if last reference
|
||||
if(atomic_dec32(&rcount->singleton_ref_count) == 1){
|
||||
//If last, destroy the object
|
||||
BOOST_ASSERT(rcount->ptr != 0);
|
||||
C *pc = static_cast<C*>(rcount->ptr);
|
||||
//Now destroy map entry
|
||||
bool destroyed = intermodule_singleton_helpers::thread_safe_global_map_dependant
|
||||
<ThreadSafeGlobalMap>::erase(m_map, typeid(C).name());
|
||||
(void)destroyed; BOOST_ASSERT(destroyed == true);
|
||||
delete pc;
|
||||
}
|
||||
}
|
||||
void *data() const
|
||||
{ return ret_ptr; }
|
||||
|
||||
private:
|
||||
ThreadSafeGlobalMap &m_map;
|
||||
void *ret_ptr;
|
||||
};
|
||||
|
||||
//A wrapper to execute init_atomic_func
|
||||
static void *singleton_constructor(ThreadSafeGlobalMap &map)
|
||||
{
|
||||
init_atomic_func f(map);
|
||||
intermodule_singleton_helpers::thread_safe_global_map_dependant
|
||||
<ThreadSafeGlobalMap>::atomic_func(map, f);
|
||||
return f.data();
|
||||
}
|
||||
|
||||
//A wrapper to execute fini_atomic_func
|
||||
static void singleton_destructor(void *p, ThreadSafeGlobalMap &map)
|
||||
{ (void)p;
|
||||
fini_atomic_func f(map);
|
||||
intermodule_singleton_helpers::thread_safe_global_map_dependant
|
||||
<ThreadSafeGlobalMap>::atomic_func(map, f);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
|
||||
volatile int intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime_type_lazy::m_dummy = 0;
|
||||
|
||||
//These will be zero-initialized by the loader
|
||||
template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
|
||||
void *intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::this_module_singleton_ptr = 0;
|
||||
|
||||
template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
|
||||
volatile boost::uint32_t intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::this_module_singleton_initialized = 0;
|
||||
|
||||
template <typename C, bool L, bool P, class ThreadSafeGlobalMap>
|
||||
typename intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime_type
|
||||
intermodule_singleton_impl<C, L, P, ThreadSafeGlobalMap>::lifetime;
|
||||
|
||||
} //namespace ipcdetail{
|
||||
} //namespace interprocess{
|
||||
} //namespace boost{
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2007-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2007-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -68,8 +68,8 @@ struct intersegment_base
|
||||
|
||||
static const std::size_t begin_bits = max_segment_size_bits - align_bits;
|
||||
static const std::size_t pow_size_bits_helper = static_log2<max_segment_size_bits>::value;
|
||||
static const std::size_t pow_size_bits =
|
||||
(max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ?
|
||||
static const std::size_t pow_size_bits =
|
||||
(max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ?
|
||||
pow_size_bits_helper : pow_size_bits_helper + 1;
|
||||
static const std::size_t frc_size_bits =
|
||||
size_t_bits - ctrl_bits - begin_bits - pow_size_bits;
|
||||
@@ -177,7 +177,7 @@ struct intersegment_base
|
||||
|
||||
void set_mode(std::size_t mode)
|
||||
{
|
||||
BOOST_ASSERT(mode < is_max_mode);
|
||||
BOOST_ASSERT(mode < is_max_mode);
|
||||
members.direct.ctrl = mode;
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ struct intersegment_base
|
||||
//!null pointer
|
||||
bool is_null() const
|
||||
{
|
||||
return (this->get_mode() < is_relative) &&
|
||||
return (this->get_mode() < is_relative) &&
|
||||
!members.direct.dummy &&
|
||||
!members.direct.addr;
|
||||
}
|
||||
@@ -309,13 +309,13 @@ struct flat_map_intersegment
|
||||
void *ptr_base;
|
||||
void *this_base;
|
||||
get_segment_info_and_offset(this, this_info, this_offset, this_base);
|
||||
|
||||
|
||||
if(!this_info.group){
|
||||
this->set_mode(is_in_stack);
|
||||
this->members.direct.addr = const_cast<void*>(ptr);
|
||||
}
|
||||
else{
|
||||
get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base);
|
||||
get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base);
|
||||
|
||||
if(ptr_info.group != this_info.group){
|
||||
this->set_mode(is_pointee_outside);
|
||||
@@ -340,7 +340,7 @@ struct flat_map_intersegment
|
||||
}
|
||||
}
|
||||
|
||||
//!Sets the object internals to represent the address pointed
|
||||
//!Sets the object internals to represent the address pointed
|
||||
//!by another flat_map_intersegment
|
||||
void set_from_other(const self_t &other)
|
||||
{
|
||||
@@ -383,7 +383,7 @@ struct flat_map_intersegment
|
||||
};
|
||||
vector<segment_data> m_segments;
|
||||
multi_segment_services &m_ms_services;
|
||||
|
||||
|
||||
public:
|
||||
segment_group_t(multi_segment_services &ms_services)
|
||||
: m_ms_services(ms_services)
|
||||
@@ -434,7 +434,7 @@ struct flat_map_intersegment
|
||||
typedef set<segment_group_t> segment_groups_t;
|
||||
|
||||
typedef boost::interprocess::flat_map
|
||||
<const void *
|
||||
<const void *
|
||||
,segment_info_t
|
||||
,std::less<const void *> > ptr_to_segment_info_t;
|
||||
|
||||
@@ -443,9 +443,9 @@ struct flat_map_intersegment
|
||||
//!Mutex to preserve integrity in multi-threaded
|
||||
//!enviroments
|
||||
typedef Mutex mutex_type;
|
||||
//!Maps base addresses and segment information
|
||||
//!Maps base addresses and segment information
|
||||
//!(size and segment group and id)*
|
||||
|
||||
|
||||
ptr_to_segment_info_t m_ptr_to_segment_info;
|
||||
|
||||
~mappings_t()
|
||||
@@ -476,7 +476,7 @@ struct flat_map_intersegment
|
||||
return;
|
||||
}
|
||||
//Find the first base address greater than ptr
|
||||
typename ptr_to_segment_info_t::iterator it
|
||||
typename ptr_to_segment_info_t::iterator it
|
||||
= s_map.m_ptr_to_segment_info.upper_bound(ptr);
|
||||
if(it == s_map.m_ptr_to_segment_info.begin()){
|
||||
segment = segment_info_t();
|
||||
@@ -486,7 +486,7 @@ struct flat_map_intersegment
|
||||
--it;
|
||||
char * segment_base = const_cast<char*>(reinterpret_cast<const char*>(it->first));
|
||||
std::size_t segment_size = it->second.size;
|
||||
|
||||
|
||||
if(segment_base <= reinterpret_cast<const char*>(ptr) &&
|
||||
(segment_base + segment_size) >= reinterpret_cast<const char*>(ptr)){
|
||||
segment = it->second;
|
||||
@@ -552,7 +552,7 @@ struct flat_map_intersegment
|
||||
s_groups.insert(segment_group_t(*services));
|
||||
BOOST_ASSERT(ret.second);
|
||||
return &*ret.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool delete_group(segment_group_id id)
|
||||
@@ -574,23 +574,23 @@ struct flat_map_intersegment
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//!Static map-segment_info associated with
|
||||
//!flat_map_intersegment<>
|
||||
template <class Mutex>
|
||||
typename flat_map_intersegment<Mutex>::mappings_t
|
||||
typename flat_map_intersegment<Mutex>::mappings_t
|
||||
flat_map_intersegment<Mutex>::s_map;
|
||||
|
||||
//!Static segment group container associated with
|
||||
//!flat_map_intersegment<>
|
||||
template <class Mutex>
|
||||
typename flat_map_intersegment<Mutex>::segment_groups_t
|
||||
typename flat_map_intersegment<Mutex>::segment_groups_t
|
||||
flat_map_intersegment<Mutex>::s_groups;
|
||||
|
||||
//!A smart pointer that can point to a pointee that resides in another memory
|
||||
//!A smart pointer that can point to a pointee that resides in another memory
|
||||
//!memory mapped or shared memory segment.
|
||||
template <class T>
|
||||
class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
|
||||
@@ -623,13 +623,13 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
|
||||
|
||||
//!Constructor from other intersegment_ptr
|
||||
//!Never throws
|
||||
intersegment_ptr(const intersegment_ptr& ptr)
|
||||
intersegment_ptr(const intersegment_ptr& ptr)
|
||||
{ base_t::set_from_other(ptr); }
|
||||
|
||||
//!Constructor from other intersegment_ptr. If pointers of pointee types are
|
||||
//!Constructor from other intersegment_ptr. If pointers of pointee types are
|
||||
//!convertible, intersegment_ptrs will be convertibles. Never throws.
|
||||
template<class T2>
|
||||
intersegment_ptr(const intersegment_ptr<T2> &ptr)
|
||||
intersegment_ptr(const intersegment_ptr<T2> &ptr)
|
||||
{ pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); }
|
||||
|
||||
//!Emulates static_cast operator.
|
||||
@@ -663,17 +663,17 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
|
||||
|
||||
//!Pointer-like -> operator. It can return 0 pointer.
|
||||
//!Never throws.
|
||||
pointer operator->() const
|
||||
pointer operator->() const
|
||||
{ return self_t::get(); }
|
||||
|
||||
//!Dereferencing operator, if it is a null intersegment_ptr behavior
|
||||
//!Dereferencing operator, if it is a null intersegment_ptr behavior
|
||||
//!is undefined. Never throws.
|
||||
reference operator* () const
|
||||
reference operator* () const
|
||||
{ return *(self_t::get()); }
|
||||
|
||||
//!Indexing operator.
|
||||
//!Never throws.
|
||||
reference operator[](std::ptrdiff_t idx) const
|
||||
reference operator[](std::ptrdiff_t idx) const
|
||||
{ return self_t::get()[idx]; }
|
||||
|
||||
//!Assignment from pointer (saves extra conversion).
|
||||
@@ -686,19 +686,19 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
|
||||
intersegment_ptr& operator= (const intersegment_ptr &ptr)
|
||||
{ base_t::set_from_other(ptr); return *this; }
|
||||
|
||||
//!Assignment from related intersegment_ptr. If pointers of pointee types
|
||||
//!Assignment from related intersegment_ptr. If pointers of pointee types
|
||||
//!are assignable, intersegment_ptrs will be assignable. Never throws.
|
||||
template <class T2>
|
||||
intersegment_ptr& operator= (const intersegment_ptr<T2> & ptr)
|
||||
{
|
||||
pointer p(ptr.get()); (void)p;
|
||||
base_t::set_from_other(ptr); return *this;
|
||||
{
|
||||
pointer p(ptr.get()); (void)p;
|
||||
base_t::set_from_other(ptr); return *this;
|
||||
}
|
||||
|
||||
|
||||
//!intersegment_ptr + std::ptrdiff_t.
|
||||
//!Never throws.
|
||||
intersegment_ptr operator+ (std::ptrdiff_t idx) const
|
||||
{
|
||||
intersegment_ptr operator+ (std::ptrdiff_t idx) const
|
||||
{
|
||||
intersegment_ptr result (*this);
|
||||
result.inc_offset(idx*sizeof(T));
|
||||
return result;
|
||||
@@ -706,8 +706,8 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
|
||||
|
||||
//!intersegment_ptr - std::ptrdiff_t.
|
||||
//!Never throws.
|
||||
intersegment_ptr operator- (std::ptrdiff_t idx) const
|
||||
{
|
||||
intersegment_ptr operator- (std::ptrdiff_t idx) const
|
||||
{
|
||||
intersegment_ptr result (*this);
|
||||
result.dec_offset(idx*sizeof(T));
|
||||
return result;
|
||||
@@ -727,7 +727,7 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
|
||||
//!Never throws.
|
||||
intersegment_ptr& operator++ (void)
|
||||
{ base_t::inc_offset(sizeof(T)); return *this; }
|
||||
|
||||
|
||||
//!intersegment_ptr++.
|
||||
//!Never throws.
|
||||
intersegment_ptr operator++ (int)
|
||||
@@ -745,10 +745,10 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
|
||||
|
||||
//!Safe bool conversion operator.
|
||||
//!Never throws.
|
||||
operator unspecified_bool_type() const
|
||||
operator unspecified_bool_type() const
|
||||
{ return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func; }
|
||||
|
||||
//!Not operator. Not needed in theory, but improves portability.
|
||||
//!Not operator. Not needed in theory, but improves portability.
|
||||
//!Never throws.
|
||||
bool operator! () const
|
||||
{ return base_t::is_null(); }
|
||||
@@ -784,12 +784,12 @@ class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
|
||||
template <class T1, class T2> inline
|
||||
bool operator ==(const intersegment_ptr<T1> &left,
|
||||
const intersegment_ptr<T2> &right)
|
||||
{
|
||||
{
|
||||
//Make sure both pointers can be compared
|
||||
bool e = typename intersegment_ptr<T1>::pointer(0) ==
|
||||
typename intersegment_ptr<T2>::pointer(0);
|
||||
(void)e;
|
||||
return left._equal(right);
|
||||
return left._equal(right);
|
||||
}
|
||||
|
||||
//!Returns true if *this is less than other.
|
||||
@@ -798,74 +798,74 @@ bool operator ==(const intersegment_ptr<T1> &left,
|
||||
template <class T1, class T2> inline
|
||||
bool operator <(const intersegment_ptr<T1> &left,
|
||||
const intersegment_ptr<T2> &right)
|
||||
{
|
||||
{
|
||||
//Make sure both pointers can be compared
|
||||
bool e = typename intersegment_ptr<T1>::pointer(0) <
|
||||
typename intersegment_ptr<T2>::pointer(0);
|
||||
(void)e;
|
||||
return left._less(right);
|
||||
return left._less(right);
|
||||
}
|
||||
|
||||
template<class T1, class T2> inline
|
||||
bool operator!= (const intersegment_ptr<T1> &pt1,
|
||||
bool operator!= (const intersegment_ptr<T1> &pt1,
|
||||
const intersegment_ptr<T2> &pt2)
|
||||
{ return !(pt1 ==pt2); }
|
||||
|
||||
//!intersegment_ptr<T1> <= intersegment_ptr<T2>.
|
||||
//!Never throws.
|
||||
template<class T1, class T2> inline
|
||||
bool operator<= (const intersegment_ptr<T1> &pt1,
|
||||
bool operator<= (const intersegment_ptr<T1> &pt1,
|
||||
const intersegment_ptr<T2> &pt2)
|
||||
{ return !(pt1 > pt2); }
|
||||
|
||||
//!intersegment_ptr<T1> > intersegment_ptr<T2>.
|
||||
//!Never throws.
|
||||
template<class T1, class T2> inline
|
||||
bool operator> (const intersegment_ptr<T1> &pt1,
|
||||
bool operator> (const intersegment_ptr<T1> &pt1,
|
||||
const intersegment_ptr<T2> &pt2)
|
||||
{ return (pt2 < pt1); }
|
||||
|
||||
//!intersegment_ptr<T1> >= intersegment_ptr<T2>.
|
||||
//!Never throws.
|
||||
template<class T1, class T2> inline
|
||||
bool operator>= (const intersegment_ptr<T1> &pt1,
|
||||
bool operator>= (const intersegment_ptr<T1> &pt1,
|
||||
const intersegment_ptr<T2> &pt2)
|
||||
{ return !(pt1 < pt2); }
|
||||
|
||||
//!operator<<
|
||||
template<class E, class T, class U> inline
|
||||
std::basic_ostream<E, T> & operator<<
|
||||
std::basic_ostream<E, T> & operator<<
|
||||
(std::basic_ostream<E, T> & os, const intersegment_ptr<U> & p)
|
||||
{ return os << p.get(); }
|
||||
|
||||
//!operator>>
|
||||
template<class E, class T, class U> inline
|
||||
std::basic_istream<E, T> & operator>>
|
||||
std::basic_istream<E, T> & operator>>
|
||||
(std::basic_istream<E, T> & os, intersegment_ptr<U> & p)
|
||||
{ U * tmp; return os >> tmp; p = tmp; }
|
||||
|
||||
//!std::ptrdiff_t + intersegment_ptr.
|
||||
//!std::ptrdiff_t + intersegment_ptr.
|
||||
//!The result is another pointer of the same segment
|
||||
template<class T> inline
|
||||
intersegment_ptr<T> operator+
|
||||
(std::ptrdiff_t diff, const intersegment_ptr<T>& right)
|
||||
{ return right + diff; }
|
||||
|
||||
//!intersegment_ptr - intersegment_ptr.
|
||||
//!intersegment_ptr - intersegment_ptr.
|
||||
//!This only works with two intersegment_ptr-s that point to the
|
||||
//!same segment
|
||||
template <class T, class T2> inline
|
||||
std::ptrdiff_t operator- (const intersegment_ptr<T> &pt,
|
||||
std::ptrdiff_t operator- (const intersegment_ptr<T> &pt,
|
||||
const intersegment_ptr<T2> &pt2)
|
||||
{ return pt._diff(pt2)/sizeof(T); }
|
||||
|
||||
//! swap specialization
|
||||
template<class T> inline
|
||||
void swap (boost::interprocess::intersegment_ptr<T> &pt,
|
||||
void swap (boost::interprocess::intersegment_ptr<T> &pt,
|
||||
boost::interprocess::intersegment_ptr<T> &pt2)
|
||||
{ pt.swap(pt2); }
|
||||
|
||||
//!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr.
|
||||
//!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr.
|
||||
//!Never throws.
|
||||
template<class T> inline
|
||||
T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p)
|
||||
@@ -873,19 +873,19 @@ T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p)
|
||||
|
||||
//!Simulation of static_cast between pointers.
|
||||
//!Never throws.
|
||||
template<class T, class U> inline
|
||||
template<class T, class U> inline
|
||||
boost::interprocess::intersegment_ptr<T> static_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
|
||||
{ return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::static_cast_tag()); }
|
||||
|
||||
//!Simulation of const_cast between pointers.
|
||||
//!Never throws.
|
||||
template<class T, class U> inline
|
||||
template<class T, class U> inline
|
||||
boost::interprocess::intersegment_ptr<T> const_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
|
||||
{ return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::const_cast_tag()); }
|
||||
|
||||
//!Simulation of dynamic_cast between pointers.
|
||||
//!Never throws.
|
||||
template<class T, class U> inline
|
||||
template<class T, class U> inline
|
||||
boost::interprocess::intersegment_ptr<T> dynamic_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
|
||||
{ return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::dynamic_cast_tag()); }
|
||||
|
||||
@@ -895,7 +895,7 @@ template<class T, class U> inline
|
||||
boost::interprocess::intersegment_ptr<T> reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
|
||||
{ return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::reinterpret_cast_tag()); }
|
||||
|
||||
//!Trait class to detect if an smart pointer has
|
||||
//!Trait class to detect if an smart pointer has
|
||||
//!multi-segment addressing capabilities.
|
||||
template <class T>
|
||||
struct is_multisegment_ptr
|
||||
@@ -907,7 +907,7 @@ struct is_multisegment_ptr
|
||||
} //namespace interprocess {
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1400)
|
||||
//!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr.
|
||||
//!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr.
|
||||
//!Never throws.
|
||||
template<class T> inline
|
||||
T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p)
|
||||
@@ -918,14 +918,14 @@ T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p)
|
||||
//!for optimizations
|
||||
template <class T>
|
||||
struct has_trivial_constructor
|
||||
< boost::interprocess::intersegment_ptr<T> >
|
||||
< boost::interprocess::intersegment_ptr<T> >
|
||||
: public true_type{};
|
||||
|
||||
//!has_trivial_destructor<> == true_type specialization
|
||||
//!for optimizations
|
||||
template <class T>
|
||||
struct has_trivial_destructor
|
||||
< boost::interprocess::intersegment_ptr<T> >
|
||||
< boost::interprocess::intersegment_ptr<T> >
|
||||
: public true_type{};
|
||||
|
||||
} //namespace boost {
|
||||
@@ -950,7 +950,7 @@ struct has_trivial_destructor
|
||||
// std::size_t offset;
|
||||
|
||||
//RELATIVE_SIZE_BITS = SIZE_T_BITS -
|
||||
// MAX_SEGMENT_BITS -
|
||||
// MAX_SEGMENT_BITS -
|
||||
// CTRL_BITS 10 10
|
||||
//MAX_SEGMENT_SIZE = SIZE_T_BITS - ALIGN_BITS 20 52
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2009-2012. 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_BASIC_GLOBAL_MEMORY_HPP
|
||||
#define BOOST_INTERPROCESS_BASIC_GLOBAL_MEMORY_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/offset_ptr.hpp>
|
||||
#include <boost/interprocess/sync/spin/mutex.hpp>
|
||||
#include <boost/interprocess/sync/spin/recursive_mutex.hpp>
|
||||
#include <boost/interprocess/detail/managed_memory_impl.hpp>
|
||||
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/indexes/iset_index.hpp>
|
||||
#include <boost/interprocess/creation_tags.hpp>
|
||||
#include <boost/interprocess/permissions.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace interprocess{
|
||||
namespace ipcdetail{
|
||||
|
||||
struct intermodule_singleton_mutex_family
|
||||
{
|
||||
typedef boost::interprocess::ipcdetail::spin_mutex mutex_type;
|
||||
typedef boost::interprocess::ipcdetail::spin_recursive_mutex recursive_mutex_type;
|
||||
};
|
||||
|
||||
struct intermodule_types
|
||||
{
|
||||
//We must use offset_ptr since a loaded DLL can map the singleton holder shared memory
|
||||
//at a different address than other DLLs or the main executable
|
||||
typedef rbtree_best_fit<intermodule_singleton_mutex_family, offset_ptr<void> > mem_algo;
|
||||
template<class Device, bool FileBased>
|
||||
struct open_or_create
|
||||
{
|
||||
typedef managed_open_or_create_impl
|
||||
<Device, mem_algo::Alignment, FileBased, false> type;
|
||||
};
|
||||
};
|
||||
|
||||
//we must implement our own managed shared memory to avoid circular dependencies
|
||||
template<class Device, bool FileBased>
|
||||
class basic_managed_global_memory
|
||||
: public basic_managed_memory_impl
|
||||
< char
|
||||
, intermodule_types::mem_algo
|
||||
, iset_index
|
||||
, intermodule_types::open_or_create<Device, FileBased>::type::ManagedOpenOrCreateUserOffset
|
||||
>
|
||||
, private intermodule_types::open_or_create<Device, FileBased>::type
|
||||
{
|
||||
/// @cond
|
||||
typedef typename intermodule_types::template open_or_create<Device, FileBased>::type base2_t;
|
||||
|
||||
typedef basic_managed_memory_impl
|
||||
< char
|
||||
, intermodule_types::mem_algo
|
||||
, iset_index
|
||||
, base2_t::ManagedOpenOrCreateUserOffset
|
||||
> base_t;
|
||||
|
||||
typedef create_open_func<base_t> create_open_func_t;
|
||||
|
||||
basic_managed_global_memory *get_this_pointer()
|
||||
{ return this; }
|
||||
|
||||
public:
|
||||
typedef typename base_t::size_type size_type;
|
||||
|
||||
private:
|
||||
typedef typename base_t::char_ptr_holder_t char_ptr_holder_t;
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_global_memory)
|
||||
/// @endcond
|
||||
|
||||
public: //functions
|
||||
|
||||
basic_managed_global_memory (open_or_create_t open_or_create,
|
||||
const char *name, size_type size,
|
||||
const void *addr = 0, const permissions& perm = permissions())
|
||||
: base_t()
|
||||
, base2_t(open_or_create, name, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
DoOpenOrCreate), perm)
|
||||
{}
|
||||
|
||||
basic_managed_global_memory (open_only_t open_only, const char* name,
|
||||
const void *addr = 0)
|
||||
: base_t()
|
||||
, base2_t(open_only, name, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
DoOpen))
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
} //namespace ipcdetail{
|
||||
} //namespace interprocess{
|
||||
} //namespace boost{
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_BASIC_GLOBAL_MEMORY_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
//!\file
|
||||
//!Describes a named shared memory allocation user class.
|
||||
//!Describes a named shared memory allocation user class.
|
||||
//!
|
||||
|
||||
namespace boost {
|
||||
@@ -45,7 +45,7 @@ template<class BasicManagedMemoryImpl>
|
||||
class create_open_func;
|
||||
|
||||
template<
|
||||
class CharType,
|
||||
class CharType,
|
||||
class MemoryAlgorithm,
|
||||
template<class IndexConfig> class IndexType
|
||||
>
|
||||
@@ -54,14 +54,14 @@ struct segment_manager_type
|
||||
typedef segment_manager<CharType, MemoryAlgorithm, IndexType> type;
|
||||
};
|
||||
|
||||
//!This class is designed to be a base class to classes that manage
|
||||
//!creation of objects in a fixed size memory buffer. Apart
|
||||
//!from allocating raw memory, the user can construct named objects. To
|
||||
//!This class is designed to be a base class to classes that manage
|
||||
//!creation of objects in a fixed size memory buffer. Apart
|
||||
//!from allocating raw memory, the user can construct named objects. To
|
||||
//!achieve this, this class uses the reserved space provided by the allocation
|
||||
//!algorithm to place a named_allocator_algo, who takes care of name mappings.
|
||||
//!The class can be customized with the char type used for object names
|
||||
//!and the memory allocation algorithm to be used.*/
|
||||
template < class CharType
|
||||
template < class CharType
|
||||
, class MemoryAlgorithm
|
||||
, template<class IndexConfig> class IndexType
|
||||
, std::size_t Offset = 0
|
||||
@@ -92,7 +92,7 @@ class basic_managed_memory_impl
|
||||
|
||||
/// @cond
|
||||
|
||||
typedef typename
|
||||
typedef typename
|
||||
segment_manager::char_ptr_holder_t char_ptr_holder_t;
|
||||
//Experimental. Don't use.
|
||||
|
||||
@@ -153,7 +153,7 @@ class basic_managed_memory_impl
|
||||
}
|
||||
|
||||
//!Constructor. Allocates basic resources. Never throws.
|
||||
basic_managed_memory_impl()
|
||||
basic_managed_memory_impl()
|
||||
: mp_header(0){}
|
||||
|
||||
//!Destructor. Calls close. Never throws.
|
||||
@@ -169,19 +169,19 @@ class basic_managed_memory_impl
|
||||
if(size < segment_manager::get_min_size())
|
||||
return false;
|
||||
|
||||
//This function should not throw. The index construction can
|
||||
//This function should not throw. The index construction can
|
||||
//throw if constructor allocates memory. So we must catch it.
|
||||
BOOST_TRY{
|
||||
//Let's construct the allocator in memory
|
||||
//Let's construct the allocator in memory
|
||||
mp_header = new(addr) segment_manager(size);
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
return false;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//!Connects to a segment manager in the reserved buffer. Never throws.
|
||||
bool open_impl (void *addr, size_type)
|
||||
{
|
||||
@@ -192,7 +192,7 @@ class basic_managed_memory_impl
|
||||
|
||||
//!Frees resources. Never throws.
|
||||
bool close_impl()
|
||||
{
|
||||
{
|
||||
bool ret = mp_header != 0;
|
||||
mp_header = 0;
|
||||
return ret;
|
||||
@@ -249,40 +249,40 @@ class basic_managed_memory_impl
|
||||
void zero_free_memory()
|
||||
{ mp_header->zero_free_memory(); }
|
||||
|
||||
//!Transforms an absolute address into an offset from base address.
|
||||
//!Transforms an absolute address into an offset from base address.
|
||||
//!The address must belong to the memory segment. Never throws.
|
||||
handle_t get_handle_from_address (const void *ptr) const
|
||||
{
|
||||
return (handle_t)(reinterpret_cast<const char*>(ptr) -
|
||||
reinterpret_cast<const char*>(this->get_address()));
|
||||
return (handle_t)(reinterpret_cast<const char*>(ptr) -
|
||||
reinterpret_cast<const char*>(this->get_address()));
|
||||
}
|
||||
|
||||
//!Returns true if the address belongs to the managed memory segment
|
||||
bool belongs_to_segment (const void *ptr) const
|
||||
{
|
||||
return ptr >= this->get_address() &&
|
||||
{
|
||||
return ptr >= this->get_address() &&
|
||||
ptr < (reinterpret_cast<const char*>(this->get_address()) + this->get_size());
|
||||
}
|
||||
|
||||
//!Transforms previously obtained offset into an absolute address in the
|
||||
//!Transforms previously obtained offset into an absolute address in the
|
||||
//!process space of the current process. Never throws.*/
|
||||
void * get_address_from_handle (handle_t offset) const
|
||||
{ return reinterpret_cast<char*>(this->get_address()) + offset; }
|
||||
|
||||
//!Searches for nbytes of free memory in the segment, marks the
|
||||
//!memory as used and return the pointer to the memory. If no
|
||||
//!memory as used and return the pointer to the memory. If no
|
||||
//!memory is available throws a boost::interprocess::bad_alloc exception
|
||||
void* allocate (size_type nbytes)
|
||||
{ return mp_header->allocate(nbytes); }
|
||||
|
||||
//!Searches for nbytes of free memory in the segment, marks the
|
||||
//!memory as used and return the pointer to the memory. If no memory
|
||||
//!Searches for nbytes of free memory in the segment, marks the
|
||||
//!memory as used and return the pointer to the memory. If no memory
|
||||
//!is available returns 0. Never throws.
|
||||
void* allocate (size_type nbytes, std::nothrow_t nothrow)
|
||||
{ return mp_header->allocate(nbytes, nothrow); }
|
||||
|
||||
//!Allocates nbytes bytes aligned to "alignment" bytes. "alignment"
|
||||
//!must be power of two. If no memory
|
||||
//!must be power of two. If no memory
|
||||
//!is available returns 0. Never throws.
|
||||
void * allocate_aligned (size_type nbytes, size_type alignment, std::nothrow_t nothrow)
|
||||
{ return mp_header->allocate_aligned(nbytes, alignment, nothrow); }
|
||||
@@ -292,13 +292,13 @@ class basic_managed_memory_impl
|
||||
allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
T *reuse_ptr = 0)
|
||||
{
|
||||
{
|
||||
return mp_header->allocation_command
|
||||
(command, limit_size, preferred_size, received_size, reuse_ptr);
|
||||
}
|
||||
|
||||
//!Allocates nbytes bytes aligned to "alignment" bytes. "alignment"
|
||||
//!must be power of two. If no
|
||||
//!must be power of two. If no
|
||||
//!memory is available throws a boost::interprocess::bad_alloc exception
|
||||
void * allocate_aligned(size_type nbytes, size_type alignment)
|
||||
{ return mp_header->allocate_aligned(nbytes, alignment); }
|
||||
@@ -307,25 +307,31 @@ class basic_managed_memory_impl
|
||||
|
||||
//Experimental. Don't use.
|
||||
|
||||
//!Allocates n_elements of elem_size bytes.
|
||||
multiallocation_chain allocate_many(size_type elem_bytes, size_type num_elements)
|
||||
{ return mp_header->allocate_many(elem_bytes, num_elements); }
|
||||
//!Allocates n_elements of elem_bytes bytes.
|
||||
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
|
||||
void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
|
||||
{ mp_header->allocate_many(elem_bytes, n_elements, chain); }
|
||||
|
||||
//!Allocates n_elements, each one of elem_sizes[i] bytes.
|
||||
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements)
|
||||
{ return mp_header->allocate_many(elem_sizes, n_elements); }
|
||||
//!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
|
||||
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
|
||||
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
|
||||
{ mp_header->allocate_many(element_lengths, n_elements, sizeof_element, chain); }
|
||||
|
||||
//!Allocates n_elements of elem_size bytes.
|
||||
multiallocation_chain allocate_many(size_type elem_bytes, size_type num_elements, std::nothrow_t nothrow)
|
||||
{ return mp_header->allocate_many(elem_bytes, num_elements, nothrow); }
|
||||
//!Allocates n_elements of elem_bytes bytes.
|
||||
//!Non-throwing version. chain.size() is not increased on failure.
|
||||
void allocate_many(std::nothrow_t, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
|
||||
{ mp_header->allocate_many(std::nothrow_t(), elem_bytes, n_elements, chain); }
|
||||
|
||||
//!Allocates n_elements, each one of elem_sizes[i] bytes.
|
||||
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements, std::nothrow_t nothrow)
|
||||
{ return mp_header->allocate_many(elem_sizes, n_elements, nothrow); }
|
||||
//!Allocates n_elements, each one of
|
||||
//!element_lengths[i]*sizeof_element bytes.
|
||||
//!Non-throwing version. chain.size() is not increased on failure.
|
||||
void allocate_many(std::nothrow_t, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
|
||||
{ mp_header->allocate_many(std::nothrow_t(), elem_sizes, n_elements, sizeof_element, chain); }
|
||||
|
||||
//!Allocates n_elements, each one of elem_sizes[i] bytes.
|
||||
void deallocate_many(multiallocation_chain chain)
|
||||
{ return mp_header->deallocate_many(boost::move(chain)); }
|
||||
//!Deallocates all elements contained in chain.
|
||||
//!Never throws.
|
||||
void deallocate_many(multiallocation_chain &chain)
|
||||
{ mp_header->deallocate_many(chain); }
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -342,18 +348,18 @@ class basic_managed_memory_impl
|
||||
|
||||
//!Creates a named object or array in memory
|
||||
//!
|
||||
//!Allocates and constructs a T object or an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!Allocates and constructs a T object or an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!created object. If an array is being constructed all objects are
|
||||
//!created using the same parameters given to this function.
|
||||
//!
|
||||
//!-> If the name was previously used, returns 0.
|
||||
//!
|
||||
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
|
||||
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
|
||||
//!
|
||||
//!-> If T's constructor throws, the function throws that exception.
|
||||
//!
|
||||
//!Memory is freed automatically if T's constructor throws and if an
|
||||
//!Memory is freed automatically if T's constructor throws and if an
|
||||
//!array was being constructed, destructors of created objects are called
|
||||
//!before freeing the memory.
|
||||
template <class T>
|
||||
@@ -363,18 +369,18 @@ class basic_managed_memory_impl
|
||||
|
||||
//!Finds or creates a named object or array in memory
|
||||
//!
|
||||
//!Tries to find an object with the given name in memory. If
|
||||
//!found, returns the pointer to this pointer. If the object is not found,
|
||||
//!allocates and constructs a T object or an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!Tries to find an object with the given name in memory. If
|
||||
//!found, returns the pointer to this pointer. If the object is not found,
|
||||
//!allocates and constructs a T object or an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!created object. If an array is being constructed all objects are
|
||||
//!created using the same parameters given to this function.
|
||||
//!
|
||||
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
|
||||
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
|
||||
//!
|
||||
//!-> If T's constructor throws, the function throws that exception.
|
||||
//!
|
||||
//!Memory is freed automatically if T's constructor throws and if an
|
||||
//!Memory is freed automatically if T's constructor throws and if an
|
||||
//!array was being constructed, destructors of created objects are called
|
||||
//!before freeing the memory.
|
||||
template <class T>
|
||||
@@ -384,18 +390,18 @@ class basic_managed_memory_impl
|
||||
|
||||
//!Creates a named object or array in memory
|
||||
//!
|
||||
//!Allocates and constructs a T object or an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!Allocates and constructs a T object or an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!created object. If an array is being constructed all objects are
|
||||
//!created using the same parameters given to this function.
|
||||
//!
|
||||
//!-> If the name was previously used, returns 0.
|
||||
//!
|
||||
//!-> Returns 0 if there is no available memory
|
||||
//!-> Returns 0 if there is no available memory
|
||||
//!
|
||||
//!-> If T's constructor throws, the function throws that exception.
|
||||
//!
|
||||
//!Memory is freed automatically if T's constructor throws and if an
|
||||
//!Memory is freed automatically if T's constructor throws and if an
|
||||
//!array was being constructed, destructors of created objects are called
|
||||
//!before freeing the memory.
|
||||
template <class T>
|
||||
@@ -405,18 +411,18 @@ class basic_managed_memory_impl
|
||||
|
||||
//!Finds or creates a named object or array in memory
|
||||
//!
|
||||
//!Tries to find an object with the given name in memory. If
|
||||
//!found, returns the pointer to this pointer. If the object is not found,
|
||||
//!allocates and constructs a T object or an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!Tries to find an object with the given name in memory. If
|
||||
//!found, returns the pointer to this pointer. If the object is not found,
|
||||
//!allocates and constructs a T object or an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!created object. If an array is being constructed all objects are
|
||||
//!created using the same parameters given to this function.
|
||||
//!
|
||||
//!-> Returns 0 if there is no available memory
|
||||
//!-> Returns 0 if there is no available memory
|
||||
//!
|
||||
//!-> If T's constructor throws, the function throws that exception.
|
||||
//!
|
||||
//!Memory is freed automatically if T's constructor throws and if an
|
||||
//!Memory is freed automatically if T's constructor throws and if an
|
||||
//!array was being constructed, destructors of created objects are called
|
||||
//!before freeing the memory.
|
||||
template <class T>
|
||||
@@ -424,54 +430,54 @@ class basic_managed_memory_impl
|
||||
find_or_construct(char_ptr_holder_t name, std::nothrow_t nothrow)
|
||||
{ return mp_header->template find_or_construct<T>(name, nothrow); }
|
||||
|
||||
//!Creates a named array from iterators in memory
|
||||
//!Creates a named array from iterators in memory
|
||||
//!
|
||||
//!Allocates and constructs an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!Allocates and constructs an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!created object. Each element in the array is created using the
|
||||
//!objects returned when dereferencing iterators as parameters
|
||||
//!and incrementing all iterators for each element.
|
||||
//!
|
||||
//!-> If the name was previously used, returns 0.
|
||||
//!
|
||||
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
|
||||
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
|
||||
//!
|
||||
//!-> If T's constructor throws, the function throws that exception.
|
||||
//!
|
||||
//!Memory is freed automatically if T's constructor throws and
|
||||
//!Memory is freed automatically if T's constructor throws and
|
||||
//!destructors of created objects are called before freeing the memory.
|
||||
template <class T>
|
||||
typename segment_manager::template construct_iter_proxy<T>::type
|
||||
construct_it(char_ptr_holder_t name)
|
||||
{ return mp_header->template construct_it<T>(name); }
|
||||
|
||||
//!Finds or creates a named array from iterators in memory
|
||||
//!Finds or creates a named array from iterators in memory
|
||||
//!
|
||||
//!Tries to find an object with the given name in memory. If
|
||||
//!found, returns the pointer to this pointer. If the object is not found,
|
||||
//!allocates and constructs an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!Tries to find an object with the given name in memory. If
|
||||
//!found, returns the pointer to this pointer. If the object is not found,
|
||||
//!allocates and constructs an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!created object. Each element in the array is created using the
|
||||
//!objects returned when dereferencing iterators as parameters
|
||||
//!and incrementing all iterators for each element.
|
||||
//!
|
||||
//!-> If the name was previously used, returns 0.
|
||||
//!
|
||||
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
|
||||
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
|
||||
//!
|
||||
//!-> If T's constructor throws, the function throws that exception.
|
||||
//!
|
||||
//!Memory is freed automatically if T's constructor throws and
|
||||
//!Memory is freed automatically if T's constructor throws and
|
||||
//!destructors of created objects are called before freeing the memory.
|
||||
template <class T>
|
||||
typename segment_manager::template construct_iter_proxy<T>::type
|
||||
find_or_construct_it(char_ptr_holder_t name)
|
||||
{ return mp_header->template find_or_construct_it<T>(name); }
|
||||
|
||||
//!Creates a named array from iterators in memory
|
||||
//!Creates a named array from iterators in memory
|
||||
//!
|
||||
//!Allocates and constructs an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!Allocates and constructs an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!created object. Each element in the array is created using the
|
||||
//!objects returned when dereferencing iterators as parameters
|
||||
//!and incrementing all iterators for each element.
|
||||
@@ -482,19 +488,19 @@ class basic_managed_memory_impl
|
||||
//!
|
||||
//!-> If T's constructor throws, the function throws that exception.
|
||||
//!
|
||||
//!Memory is freed automatically if T's constructor throws and
|
||||
//!Memory is freed automatically if T's constructor throws and
|
||||
//!destructors of created objects are called before freeing the memory.*/
|
||||
template <class T>
|
||||
typename segment_manager::template construct_iter_proxy<T>::type
|
||||
construct_it(char_ptr_holder_t name, std::nothrow_t nothrow)
|
||||
{ return mp_header->template construct_it<T>(name, nothrow); }
|
||||
|
||||
//!Finds or creates a named array from iterators in memory
|
||||
//!Finds or creates a named array from iterators in memory
|
||||
//!
|
||||
//!Tries to find an object with the given name in memory. If
|
||||
//!found, returns the pointer to this pointer. If the object is not found,
|
||||
//!allocates and constructs an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!Tries to find an object with the given name in memory. If
|
||||
//!found, returns the pointer to this pointer. If the object is not found,
|
||||
//!allocates and constructs an array of T in memory,
|
||||
//!associates this with the given name and returns a pointer to the
|
||||
//!created object. Each element in the array is created using the
|
||||
//!objects returned when dereferencing iterators as parameters
|
||||
//!and incrementing all iterators for each element.
|
||||
@@ -505,7 +511,7 @@ class basic_managed_memory_impl
|
||||
//!
|
||||
//!-> If T's constructor throws, the function throws that exception.
|
||||
//!
|
||||
//!Memory is freed automatically if T's constructor throws and
|
||||
//!Memory is freed automatically if T's constructor throws and
|
||||
//!destructors of created objects are called before freeing the memory.*/
|
||||
template <class T>
|
||||
typename segment_manager::template construct_iter_proxy<T>::type
|
||||
@@ -537,11 +543,11 @@ class basic_managed_memory_impl
|
||||
//!
|
||||
//!Exception Handling:
|
||||
//!
|
||||
//!When deleting a dynamically object or array, the Standard
|
||||
//!When deleting a dynamically object or array, the Standard
|
||||
//!does not guarantee that dynamically allocated memory, will be released.
|
||||
//!Also, when deleting arrays, the Standard doesn't require calling
|
||||
//!destructors for the rest of the objects if for one of them the destructor
|
||||
//!terminated with an exception.
|
||||
//!Also, when deleting arrays, the Standard doesn't require calling
|
||||
//!destructors for the rest of the objects if for one of them the destructor
|
||||
//!terminated with an exception.
|
||||
//!
|
||||
//!Destroying an object:
|
||||
//!
|
||||
@@ -550,13 +556,13 @@ class basic_managed_memory_impl
|
||||
//!
|
||||
//!Destroying an array:
|
||||
//!
|
||||
//!When destroying an array, if a destructor throws, the rest of
|
||||
//!When destroying an array, if a destructor throws, the rest of
|
||||
//!destructors are called. If any of these throws, the exceptions are
|
||||
//!ignored. The name association will be erased, memory will be freed and
|
||||
//!the first exception will be thrown. This guarantees the unlocking of
|
||||
//!mutexes and other resources.
|
||||
//!
|
||||
//!For all theses reasons, classes with throwing destructors are not
|
||||
//!For all theses reasons, classes with throwing destructors are not
|
||||
//!recommended.
|
||||
template <class T>
|
||||
bool destroy(const CharType *name)
|
||||
@@ -568,7 +574,7 @@ class basic_managed_memory_impl
|
||||
//!
|
||||
//!Exception Handling:
|
||||
//!
|
||||
//!When deleting a dynamically object, the Standard does not
|
||||
//!When deleting a dynamically object, the Standard does not
|
||||
//!guarantee that dynamically allocated memory will be released.
|
||||
//!
|
||||
//!Destroying an object:
|
||||
@@ -576,7 +582,7 @@ class basic_managed_memory_impl
|
||||
//!If the destructor throws, the memory will be freed and that exception
|
||||
//!will be thrown.
|
||||
//!
|
||||
//!For all theses reasons, classes with throwing destructors are not
|
||||
//!For all theses reasons, classes with throwing destructors are not
|
||||
//!recommended for memory.
|
||||
template <class T>
|
||||
bool destroy(const unique_instance_t *const )
|
||||
@@ -588,7 +594,7 @@ class basic_managed_memory_impl
|
||||
//!
|
||||
//!Exception Handling:
|
||||
//!
|
||||
//!When deleting a dynamically object, the Standard does not
|
||||
//!When deleting a dynamically object, the Standard does not
|
||||
//!guarantee that dynamically allocated memory will be released.
|
||||
//!
|
||||
//!Destroying an object:
|
||||
@@ -596,7 +602,7 @@ class basic_managed_memory_impl
|
||||
//!If the destructor throws, the memory will be freed and that exception
|
||||
//!will be thrown.
|
||||
//!
|
||||
//!For all theses reasons, classes with throwing destructors are not
|
||||
//!For all theses reasons, classes with throwing destructors are not
|
||||
//!recommended for memory.
|
||||
template <class T>
|
||||
void destroy_ptr(const T *ptr)
|
||||
@@ -620,13 +626,13 @@ class basic_managed_memory_impl
|
||||
static size_type get_instance_length(const T *ptr)
|
||||
{ return segment_manager::get_instance_length(ptr); }
|
||||
|
||||
//!Preallocates needed index resources to optimize the
|
||||
//!Preallocates needed index resources to optimize the
|
||||
//!creation of "num" named objects in the memory segment.
|
||||
//!Can throw boost::interprocess::bad_alloc if there is no enough memory.
|
||||
void reserve_named_objects(size_type num)
|
||||
{ mp_header->reserve_named_objects(num); }
|
||||
|
||||
//!Preallocates needed index resources to optimize the
|
||||
//!Preallocates needed index resources to optimize the
|
||||
//!creation of "num" unique objects in the memory segment.
|
||||
//!Can throw boost::interprocess::bad_alloc if there is no enough memory.
|
||||
void reserve_unique_objects(size_type num)
|
||||
@@ -652,7 +658,7 @@ class basic_managed_memory_impl
|
||||
const_named_iterator named_begin() const
|
||||
{ return mp_header->named_begin(); }
|
||||
|
||||
//!Returns a constant iterator to the end of the index
|
||||
//!Returns a constant iterator to the end of the index
|
||||
//!storing the named allocations. NOT thread-safe. Never throws.
|
||||
const_named_iterator named_end() const
|
||||
{ return mp_header->named_end(); }
|
||||
@@ -662,7 +668,7 @@ class basic_managed_memory_impl
|
||||
const_unique_iterator unique_begin() const
|
||||
{ return mp_header->unique_begin(); }
|
||||
|
||||
//!Returns a constant iterator to the end of the index
|
||||
//!Returns a constant iterator to the end of the index
|
||||
//!storing the unique allocations. NOT thread-safe. Never throws.
|
||||
const_unique_iterator unique_end() const
|
||||
{ return mp_header->unique_end(); }
|
||||
@@ -719,20 +725,40 @@ class basic_managed_memory_impl
|
||||
template<class BasicManagedMemoryImpl>
|
||||
class create_open_func
|
||||
{
|
||||
typedef typename BasicManagedMemoryImpl::size_type size_type;
|
||||
|
||||
public:
|
||||
|
||||
create_open_func(BasicManagedMemoryImpl * const frontend, create_enum_t type)
|
||||
: m_frontend(frontend), m_type(type){}
|
||||
|
||||
bool operator()(void *addr, typename BasicManagedMemoryImpl::size_type size, bool created) const
|
||||
{
|
||||
if(((m_type == DoOpen) && created) ||
|
||||
((m_type == DoCreate) && !created))
|
||||
bool operator()(void *addr, std::size_t size, bool created) const
|
||||
{
|
||||
if( ((m_type == DoOpen) && created) ||
|
||||
((m_type == DoCreate) && !created) ||
|
||||
//Check for overflow
|
||||
size_type(-1) < size ){
|
||||
return false;
|
||||
}
|
||||
else if(created){
|
||||
return m_frontend->create_impl(addr, static_cast<size_type>(size));
|
||||
}
|
||||
else{
|
||||
return m_frontend->open_impl (addr, static_cast<size_type>(size));
|
||||
}
|
||||
}
|
||||
|
||||
if(created)
|
||||
return m_frontend->create_impl(addr, size);
|
||||
else
|
||||
return m_frontend->open_impl (addr, size);
|
||||
std::size_t get_min_size() const
|
||||
{
|
||||
const size_type sz = m_frontend->get_segment_manager()->get_min_size();
|
||||
if(sz > std::size_t(-1)){
|
||||
//The minimum size is not representable by std::size_t
|
||||
BOOST_ASSERT(false);
|
||||
return std::size_t(-1);
|
||||
}
|
||||
else{
|
||||
return static_cast<std::size_t>(sz);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <boost/assert.hpp>
|
||||
//These includes needed to fulfill default template parameters of
|
||||
//predeclarations in interprocess_fwd.hpp
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
|
||||
//!\file
|
||||
@@ -51,28 +51,28 @@ namespace interprocess {
|
||||
//-Use GetSecurityInfo?
|
||||
//-Change everything to use only a shared memory object expanded via truncate()?
|
||||
|
||||
//!A basic shared memory named object creation class. Initializes the
|
||||
//!shared memory segment. Inherits all basic functionality from
|
||||
//!A basic shared memory named object creation class. Initializes the
|
||||
//!shared memory segment. Inherits all basic functionality from
|
||||
//!basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType>
|
||||
template
|
||||
<
|
||||
class CharType,
|
||||
class MemoryAlgorithm,
|
||||
class CharType,
|
||||
class MemoryAlgorithm,
|
||||
template<class IndexConfig> class IndexType
|
||||
>
|
||||
class basic_managed_multi_shared_memory
|
||||
class basic_managed_multi_shared_memory
|
||||
: public ipcdetail::basic_managed_memory_impl
|
||||
<CharType, MemoryAlgorithm, IndexType>
|
||||
{
|
||||
|
||||
typedef basic_managed_multi_shared_memory
|
||||
<CharType, MemoryAlgorithm, IndexType> self_t;
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
<CharType, MemoryAlgorithm, IndexType> base_t;
|
||||
|
||||
|
||||
typedef typename MemoryAlgorithm::void_pointer void_pointer;
|
||||
typedef typename ipcdetail::
|
||||
managed_open_or_create_impl<shared_memory_object, MemoryAlgorithm::Alignment> managed_impl;
|
||||
managed_open_or_create_impl<shared_memory_object, MemoryAlgorithm::Alignment, true, false> managed_impl;
|
||||
typedef typename void_pointer::segment_group_id segment_group_id;
|
||||
typedef typename base_t::size_type size_type;
|
||||
|
||||
@@ -91,7 +91,7 @@ class basic_managed_multi_shared_memory
|
||||
// {
|
||||
// public:
|
||||
// segment_creator(shared_memory &shmem,
|
||||
// const char *mem_name,
|
||||
// const char *mem_name,
|
||||
// const void *addr)
|
||||
// : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
|
||||
//
|
||||
@@ -99,8 +99,8 @@ class basic_managed_multi_shared_memory
|
||||
// {
|
||||
// if(!m_shmem.create(m_mem_name, size, m_addr))
|
||||
// return 0;
|
||||
// return m_shmem.get_address();
|
||||
// }
|
||||
// return m_shmem.get_address();
|
||||
// }
|
||||
// private:
|
||||
// shared_memory &m_shmem;
|
||||
// const char *m_mem_name;
|
||||
@@ -113,7 +113,7 @@ class basic_managed_multi_shared_memory
|
||||
public:
|
||||
typedef std::pair<void *, size_type> result_type;
|
||||
typedef basic_managed_multi_shared_memory frontend_t;
|
||||
typedef typename
|
||||
typedef typename
|
||||
basic_managed_multi_shared_memory::void_pointer void_pointer;
|
||||
typedef typename void_pointer::segment_group_id segment_group_id;
|
||||
group_services(frontend_t *const frontend)
|
||||
@@ -127,14 +127,14 @@ class basic_managed_multi_shared_memory
|
||||
alloc_size += 1;
|
||||
|
||||
//If requested size is less than minimum, update that
|
||||
alloc_size = (m_min_segment_size > alloc_size) ?
|
||||
alloc_size = (m_min_segment_size > alloc_size) ?
|
||||
m_min_segment_size : alloc_size;
|
||||
if(mp_frontend->priv_new_segment(create_open_func::DoCreate,
|
||||
alloc_size, 0, permissions())){
|
||||
typename shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin();
|
||||
return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1);
|
||||
}*/
|
||||
return result_type(static_cast<void *>(0), 0);
|
||||
return result_type(static_cast<void *>(0), 0);
|
||||
}
|
||||
|
||||
virtual bool update_segments ()
|
||||
@@ -166,7 +166,7 @@ class basic_managed_multi_shared_memory
|
||||
struct create_open_func
|
||||
{
|
||||
enum type_t { DoCreate, DoOpen, DoOpenOrCreate };
|
||||
typedef typename
|
||||
typedef typename
|
||||
basic_managed_multi_shared_memory::void_pointer void_pointer;
|
||||
|
||||
create_open_func(self_t * const frontend,
|
||||
@@ -174,8 +174,8 @@ class basic_managed_multi_shared_memory
|
||||
: mp_frontend(frontend), m_type(type), m_segment_number(segment_number){}
|
||||
|
||||
bool operator()(void *addr, size_type size, bool created) const
|
||||
{
|
||||
if(((m_type == DoOpen) && created) ||
|
||||
{
|
||||
if(((m_type == DoOpen) && created) ||
|
||||
((m_type == DoCreate) && !created))
|
||||
return false;
|
||||
segment_group_id group = mp_frontend->m_group_services.get_group();
|
||||
@@ -191,7 +191,7 @@ class basic_managed_multi_shared_memory
|
||||
//Check if this is the master segment
|
||||
if(!m_segment_number){
|
||||
//Create or open the Interprocess machinery
|
||||
if((impl_done = created ?
|
||||
if((impl_done = created ?
|
||||
mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){
|
||||
return true;
|
||||
}
|
||||
@@ -211,22 +211,36 @@ class basic_managed_multi_shared_memory
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t get_min_size() const
|
||||
{
|
||||
const size_type sz = mp_frontend->get_segment_manager()->get_min_size();
|
||||
if(sz > std::size_t(-1)){
|
||||
//The minimum size is not representable by std::size_t
|
||||
BOOST_ASSERT(false);
|
||||
return std::size_t(-1);
|
||||
}
|
||||
else{
|
||||
return static_cast<std::size_t>(sz);
|
||||
}
|
||||
}
|
||||
|
||||
self_t * const mp_frontend;
|
||||
type_t m_type;
|
||||
size_type m_segment_number;
|
||||
size_type m_segment_number;
|
||||
};
|
||||
|
||||
//!Functor to execute atomically when closing a shared memory segment.
|
||||
struct close_func
|
||||
{
|
||||
typedef typename
|
||||
typedef typename
|
||||
basic_managed_multi_shared_memory::void_pointer void_pointer;
|
||||
|
||||
close_func(self_t * const frontend)
|
||||
: mp_frontend(frontend){}
|
||||
|
||||
void operator()(const mapped_region ®ion, bool last) const
|
||||
{
|
||||
{
|
||||
if(last) mp_frontend->destroy_impl();
|
||||
else mp_frontend->close_impl();
|
||||
}
|
||||
@@ -251,7 +265,7 @@ class basic_managed_multi_shared_memory
|
||||
const permissions &perm = permissions())
|
||||
: m_group_services(get_this_pointer())
|
||||
{
|
||||
priv_open_or_create(create_open_func::DoCreate,name, size, perm);
|
||||
priv_open_or_create(create_open_func::DoCreate,name, size, perm);
|
||||
}
|
||||
|
||||
basic_managed_multi_shared_memory(open_or_create_t,
|
||||
@@ -273,7 +287,7 @@ class basic_managed_multi_shared_memory
|
||||
{ this->priv_close(); }
|
||||
|
||||
private:
|
||||
bool priv_open_or_create(typename create_open_func::type_t type,
|
||||
bool priv_open_or_create(typename create_open_func::type_t type,
|
||||
const char *name,
|
||||
size_type size,
|
||||
const permissions &perm)
|
||||
@@ -301,7 +315,7 @@ class basic_managed_multi_shared_memory
|
||||
if(group){
|
||||
void_pointer::delete_group(group);
|
||||
}
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool priv_new_segment(typename create_open_func::type_t type,
|
||||
@@ -312,7 +326,7 @@ class basic_managed_multi_shared_memory
|
||||
BOOST_TRY{
|
||||
//Get the number of groups of this multi_segment group
|
||||
size_type segment_id = m_shmem_list.size();
|
||||
//Format the name of the shared memory: append segment number.
|
||||
//Format the name of the shared memory: append segment number.
|
||||
boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter;
|
||||
//Pre-reserve string size
|
||||
size_type str_size = m_root_name.length()+10;
|
||||
@@ -368,7 +382,7 @@ class basic_managed_multi_shared_memory
|
||||
|
||||
//!Frees resources. Never throws.
|
||||
void priv_close()
|
||||
{
|
||||
{
|
||||
if(!m_shmem_list.empty()){
|
||||
bool ret;
|
||||
//Obtain group identifier
|
||||
@@ -385,7 +399,7 @@ class basic_managed_multi_shared_memory
|
||||
m_shmem_list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
shmem_list_t m_shmem_list;
|
||||
group_services m_group_services;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2006-2012. 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)
|
||||
//
|
||||
@@ -48,12 +48,12 @@ class xsi_key;
|
||||
|
||||
template<>
|
||||
struct managed_open_or_create_impl_device_id_t<xsi_shared_memory_file_wrapper>
|
||||
{
|
||||
{
|
||||
typedef xsi_key type;
|
||||
};
|
||||
|
||||
#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
|
||||
|
||||
|
||||
/// @endcond
|
||||
|
||||
namespace ipcdetail {
|
||||
@@ -79,12 +79,12 @@ class managed_open_or_create_impl_device_holder<true, DeviceAbstraction>
|
||||
|
||||
const DeviceAbstraction &get_device() const
|
||||
{ return dev; }
|
||||
|
||||
|
||||
private:
|
||||
DeviceAbstraction dev;
|
||||
};
|
||||
|
||||
template<class DeviceAbstraction, std::size_t MemAlignment = 0, bool FileBased = true, bool StoreDevice = true>
|
||||
template<class DeviceAbstraction, std::size_t MemAlignment, bool FileBased, bool StoreDevice>
|
||||
class managed_open_or_create_impl
|
||||
: public managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction>
|
||||
{
|
||||
@@ -94,16 +94,16 @@ class managed_open_or_create_impl
|
||||
typedef typename managed_open_or_create_impl_device_id_t<DeviceAbstraction>::type device_id_t;
|
||||
typedef managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction> DevHolder;
|
||||
enum
|
||||
{
|
||||
UninitializedSegment,
|
||||
InitializingSegment,
|
||||
{
|
||||
UninitializedSegment,
|
||||
InitializingSegment,
|
||||
InitializedSegment,
|
||||
CorruptedSegment
|
||||
};
|
||||
|
||||
public:
|
||||
static const std::size_t
|
||||
ManagedOpenOrCreateUserOffset =
|
||||
ManagedOpenOrCreateUserOffset =
|
||||
ct_rounded_size
|
||||
< sizeof(boost::uint32_t)
|
||||
, MemAlignment ? (MemAlignment) :
|
||||
@@ -113,7 +113,7 @@ class managed_open_or_create_impl
|
||||
managed_open_or_create_impl()
|
||||
{}
|
||||
|
||||
managed_open_or_create_impl(create_only_t,
|
||||
managed_open_or_create_impl(create_only_t,
|
||||
const device_id_t & id,
|
||||
std::size_t size,
|
||||
mode_t mode,
|
||||
@@ -130,7 +130,7 @@ class managed_open_or_create_impl
|
||||
, null_mapped_region_function());
|
||||
}
|
||||
|
||||
managed_open_or_create_impl(open_only_t,
|
||||
managed_open_or_create_impl(open_only_t,
|
||||
const device_id_t & id,
|
||||
mode_t mode,
|
||||
const void *addr)
|
||||
@@ -146,7 +146,7 @@ class managed_open_or_create_impl
|
||||
}
|
||||
|
||||
|
||||
managed_open_or_create_impl(open_or_create_t,
|
||||
managed_open_or_create_impl(open_or_create_t,
|
||||
const device_id_t & id,
|
||||
std::size_t size,
|
||||
mode_t mode,
|
||||
@@ -164,7 +164,7 @@ class managed_open_or_create_impl
|
||||
}
|
||||
|
||||
template <class ConstructFunc>
|
||||
managed_open_or_create_impl(create_only_t,
|
||||
managed_open_or_create_impl(create_only_t,
|
||||
const device_id_t & id,
|
||||
std::size_t size,
|
||||
mode_t mode,
|
||||
@@ -183,7 +183,7 @@ class managed_open_or_create_impl
|
||||
}
|
||||
|
||||
template <class ConstructFunc>
|
||||
managed_open_or_create_impl(open_only_t,
|
||||
managed_open_or_create_impl(open_only_t,
|
||||
const device_id_t & id,
|
||||
mode_t mode,
|
||||
const void *addr,
|
||||
@@ -200,7 +200,7 @@ class managed_open_or_create_impl
|
||||
}
|
||||
|
||||
template <class ConstructFunc>
|
||||
managed_open_or_create_impl(open_or_create_t,
|
||||
managed_open_or_create_impl(open_or_create_t,
|
||||
const device_id_t & id,
|
||||
std::size_t size,
|
||||
mode_t mode,
|
||||
@@ -222,10 +222,10 @@ class managed_open_or_create_impl
|
||||
{ this->swap(moved); }
|
||||
|
||||
managed_open_or_create_impl &operator=(BOOST_RV_REF(managed_open_or_create_impl) moved)
|
||||
{
|
||||
{
|
||||
managed_open_or_create_impl tmp(boost::move(moved));
|
||||
this->swap(tmp);
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~managed_open_or_create_impl()
|
||||
@@ -298,10 +298,10 @@ class managed_open_or_create_impl
|
||||
tmp.swap(dev);
|
||||
}
|
||||
|
||||
template <class ConstructFunc> inline
|
||||
template <class ConstructFunc> inline
|
||||
void priv_open_or_create
|
||||
(create_enum_t type,
|
||||
const device_id_t & id,
|
||||
(create_enum_t type,
|
||||
const device_id_t & id,
|
||||
std::size_t size,
|
||||
mode_t mode, const void *addr,
|
||||
const permissions &perm,
|
||||
@@ -315,8 +315,13 @@ class managed_open_or_create_impl
|
||||
bool cow = false;
|
||||
DeviceAbstraction dev;
|
||||
|
||||
if(type != DoOpen && size < ManagedOpenOrCreateUserOffset){
|
||||
throw interprocess_exception(error_info(size_error));
|
||||
if(type != DoOpen){
|
||||
//Check if the requested size is enough to build the managed metadata
|
||||
const std::size_t func_min_size = construct_func.get_min_size();
|
||||
if( (std::size_t(-1) - ManagedOpenOrCreateUserOffset) < func_min_size ||
|
||||
size < (func_min_size + ManagedOpenOrCreateUserOffset) ){
|
||||
throw interprocess_exception(error_info(size_error));
|
||||
}
|
||||
}
|
||||
//Check size can be represented by offset_t (used by truncate)
|
||||
if(type != DoOpen && !check_offset_t_size<FileBased>(size, file_like_t())){
|
||||
@@ -366,8 +371,8 @@ class managed_open_or_create_impl
|
||||
created = false;
|
||||
completed = true;
|
||||
}
|
||||
catch(interprocess_exception &ex){
|
||||
if(ex.get_error_code() != not_found_error){
|
||||
catch(interprocess_exception &e){
|
||||
if(e.get_error_code() != not_found_error){
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -396,7 +401,8 @@ class managed_open_or_create_impl
|
||||
|
||||
if(previous == UninitializedSegment){
|
||||
try{
|
||||
construct_func(static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset, size - ManagedOpenOrCreateUserOffset, true);
|
||||
construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
|
||||
, size - ManagedOpenOrCreateUserOffset, true);
|
||||
//All ok, just move resources to the external mapped region
|
||||
m_mapped_region.swap(region);
|
||||
}
|
||||
@@ -460,6 +466,11 @@ class managed_open_or_create_impl
|
||||
}
|
||||
}
|
||||
|
||||
friend void swap(managed_open_or_create_impl &left, managed_open_or_create_impl &right)
|
||||
{
|
||||
left.swap(right);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class interprocess_tester;
|
||||
void dont_close_on_destruction()
|
||||
@@ -468,11 +479,6 @@ class managed_open_or_create_impl
|
||||
mapped_region m_mapped_region;
|
||||
};
|
||||
|
||||
template<class DeviceAbstraction>
|
||||
inline void swap(managed_open_or_create_impl<DeviceAbstraction> &x
|
||||
,managed_open_or_create_impl<DeviceAbstraction> &y)
|
||||
{ x.swap(y); }
|
||||
|
||||
} //namespace ipcdetail {
|
||||
|
||||
} //namespace interprocess {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Stephen Cleary 2000.
|
||||
// (C) Copyright Ion Gaztanaga 2007-2011.
|
||||
// (C) Copyright Ion Gaztanaga 2007-2012.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// (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.
|
||||
@@ -93,7 +93,7 @@ inline std::size_t floor_log2 (std::size_t x)
|
||||
|
||||
std::size_t n = x;
|
||||
std::size_t log2 = 0;
|
||||
|
||||
|
||||
for(std::size_t shift = Bits >> 1; shift; shift >>= 1){
|
||||
std::size_t tmp = n >> shift;
|
||||
if (tmp)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011.
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace interprocess {
|
||||
|
||||
template<class T>
|
||||
const T &max_value(const T &a, const T &b)
|
||||
@@ -31,7 +31,7 @@ template<class T>
|
||||
const T &min_value(const T &a, const T &b)
|
||||
{ return a < b ? a : b; }
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2010-2011.
|
||||
// (C) Copyright Ion Gaztanaga 2010-2012.
|
||||
// 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)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011.
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
template <class T, T val>
|
||||
@@ -105,24 +105,24 @@ struct if_
|
||||
|
||||
|
||||
template <class Pair>
|
||||
struct select1st
|
||||
// : public std::unary_function<Pair, typename Pair::first_type>
|
||||
struct select1st
|
||||
// : public std::unary_function<Pair, typename Pair::first_type>
|
||||
{
|
||||
template<class OtherPair>
|
||||
const typename Pair::first_type& operator()(const OtherPair& x) const
|
||||
const typename Pair::first_type& operator()(const OtherPair& x) const
|
||||
{ return x.first; }
|
||||
|
||||
const typename Pair::first_type& operator()(const typename Pair::first_type& x) const
|
||||
const typename Pair::first_type& operator()(const typename Pair::first_type& x) const
|
||||
{ return x; }
|
||||
};
|
||||
|
||||
// identity is an extension: it is not part of the standard.
|
||||
template <class T>
|
||||
struct identity
|
||||
// : public std::unary_function<T,T>
|
||||
struct identity
|
||||
// : public std::unary_function<T,T>
|
||||
{
|
||||
typedef T type;
|
||||
const T& operator()(const T& x) const
|
||||
const T& operator()(const T& x) const
|
||||
{ return x; }
|
||||
};
|
||||
|
||||
@@ -144,8 +144,8 @@ struct ls_zeros<1>
|
||||
static const std::size_t value = 0;
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
} //namespace interprocess {
|
||||
} //namespace ipcdetail {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MPL_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
|
||||
/*!\file
|
||||
Describes a named shared memory allocation user class.
|
||||
Describes a named shared memory allocation user class.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <boost/interprocess/detail/mpl.hpp>
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
|
||||
#include <boost/interprocess/detail/preprocessor.hpp>
|
||||
#include <boost/interprocess/detail/preprocessor.hpp>
|
||||
#else
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/interprocess/detail/variadic_templates_tools.hpp>
|
||||
@@ -34,7 +34,7 @@
|
||||
//!Describes a proxy class that implements named allocation syntax.
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
|
||||
@@ -83,7 +83,7 @@ struct CtorNArg : public placement_destroy<T>
|
||||
{
|
||||
this->expansion_helper(++get<IdxPack>(args_)...);
|
||||
}
|
||||
|
||||
|
||||
template<class ...ExpansionArgs>
|
||||
void expansion_helper(ExpansionArgs &&...)
|
||||
{}
|
||||
@@ -93,11 +93,11 @@ struct CtorNArg : public placement_destroy<T>
|
||||
{}
|
||||
|
||||
tuple<Args&...> args_;
|
||||
};
|
||||
};
|
||||
|
||||
//!Describes a proxy class that implements named
|
||||
//!allocation syntax.
|
||||
template
|
||||
template
|
||||
< class SegmentManager //segment manager to construct the object
|
||||
, class T //type of object to build
|
||||
, bool is_iterator //passing parameters are normal object or iterators?
|
||||
@@ -119,10 +119,10 @@ class named_proxy
|
||||
|
||||
template<class ...Args>
|
||||
T *operator()(Args &&...args) const
|
||||
{
|
||||
{
|
||||
CtorNArg<T, is_iterator, Args...> &&ctor_obj = CtorNArg<T, is_iterator, Args...>
|
||||
(boost::forward<Args>(args)...);
|
||||
return mp_mngr->template
|
||||
return mp_mngr->template
|
||||
generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj);
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ struct Ctor0Arg : public placement_destroy<T>
|
||||
// private:
|
||||
// void construct(void *mem, true_)
|
||||
// { new((void*)mem)T(*m_p1, *m_p2); }
|
||||
//
|
||||
//
|
||||
// void construct(void *mem, false_)
|
||||
// { new((void*)mem)T(m_p1, m_p2); }
|
||||
//
|
||||
@@ -270,7 +270,7 @@ struct Ctor0Arg : public placement_destroy<T>
|
||||
|
||||
//!Describes a proxy class that implements named
|
||||
//!allocation syntax.
|
||||
template
|
||||
template
|
||||
< class SegmentManager //segment manager to construct the object
|
||||
, class T //type of object to build
|
||||
, bool is_iterator //passing parameters are normal object or iterators?
|
||||
@@ -293,9 +293,9 @@ class named_proxy
|
||||
//!makes a named allocation and calls the
|
||||
//!default constructor
|
||||
T *operator()() const
|
||||
{
|
||||
{
|
||||
Ctor0Arg<T> ctor_obj;
|
||||
return mp_mngr->template
|
||||
return mp_mngr->template
|
||||
generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj);
|
||||
}
|
||||
//!
|
||||
@@ -322,7 +322,7 @@ class named_proxy
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// template <class P1, class P2>
|
||||
// T *operator()(P1 &p1, P2 &p2) const
|
||||
// T *operator()(P1 &p1, P2 &p2) const
|
||||
// {
|
||||
// typedef Ctor2Arg
|
||||
// <T, is_iterator, P1, P2>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -32,7 +32,7 @@
|
||||
# include <cstdio>
|
||||
# include <dirent.h>
|
||||
# if 0
|
||||
# include <sys/file.h>
|
||||
# include <sys/file.h>
|
||||
# endif
|
||||
# else
|
||||
# error Unknown platform
|
||||
@@ -58,7 +58,7 @@ typedef enum { read_only = winapi::generic_read
|
||||
, read_write = winapi::generic_read | winapi::generic_write
|
||||
, copy_on_write
|
||||
, read_private
|
||||
, invalid_mode = 0xffff
|
||||
, invalid_mode = 0xffff
|
||||
} mode_t;
|
||||
|
||||
typedef enum { file_begin = winapi::file_begin
|
||||
@@ -96,28 +96,28 @@ inline const char *get_temporary_path()
|
||||
|
||||
inline file_handle_t create_new_file
|
||||
(const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false)
|
||||
{
|
||||
{
|
||||
unsigned long attr = temporary ? winapi::file_attribute_temporary : 0;
|
||||
return winapi::create_file
|
||||
( name, (unsigned int)mode, winapi::create_new, attr
|
||||
, (winapi::interprocess_security_attributes*)perm.get_permissions());
|
||||
, (winapi::interprocess_security_attributes*)perm.get_permissions());
|
||||
}
|
||||
|
||||
inline file_handle_t create_or_open_file
|
||||
(const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false)
|
||||
{
|
||||
{
|
||||
unsigned long attr = temporary ? winapi::file_attribute_temporary : 0;
|
||||
return winapi::create_file
|
||||
( name, (unsigned int)mode, winapi::open_always, attr
|
||||
, (winapi::interprocess_security_attributes*)perm.get_permissions());
|
||||
, (winapi::interprocess_security_attributes*)perm.get_permissions());
|
||||
}
|
||||
|
||||
inline file_handle_t open_existing_file
|
||||
(const char *name, mode_t mode, bool temporary = false)
|
||||
{
|
||||
{
|
||||
unsigned long attr = temporary ? winapi::file_attribute_temporary : 0;
|
||||
return winapi::create_file
|
||||
(name, (unsigned int)mode, winapi::open_existing, attr, 0);
|
||||
(name, (unsigned int)mode, winapi::open_existing, attr, 0);
|
||||
}
|
||||
|
||||
inline bool delete_file(const char *name)
|
||||
@@ -140,7 +140,7 @@ inline bool truncate_file (file_handle_t hnd, std::size_t size)
|
||||
if(offset_t(size) > filesize){
|
||||
if(!winapi::set_file_pointer_ex(hnd, filesize, 0, winapi::file_begin)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//We will write zeros in the end of the file
|
||||
//since set_end_of_file does not guarantee this
|
||||
for(std::size_t remaining = size - filesize, write_size = 0
|
||||
@@ -177,7 +177,7 @@ inline bool get_file_pointer(file_handle_t hnd, offset_t &off)
|
||||
{ return winapi::set_file_pointer_ex(hnd, 0, &off, winapi::file_current); }
|
||||
|
||||
inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata)
|
||||
{
|
||||
{
|
||||
unsigned long written;
|
||||
return 0 != winapi::write_file(hnd, data, (unsigned long)numdata, &written, 0);
|
||||
}
|
||||
@@ -189,9 +189,9 @@ inline bool close_file(file_handle_t hnd)
|
||||
{ return 0 != winapi::close_handle(hnd); }
|
||||
|
||||
inline bool acquire_file_lock(file_handle_t hnd)
|
||||
{
|
||||
{
|
||||
static winapi::interprocess_overlapped overlapped;
|
||||
const unsigned long len = 0xffffffff;
|
||||
const unsigned long len = ((unsigned long)-1);
|
||||
// winapi::interprocess_overlapped overlapped;
|
||||
// std::memset(&overlapped, 0, sizeof(overlapped));
|
||||
return winapi::lock_file_ex
|
||||
@@ -199,44 +199,44 @@ inline bool acquire_file_lock(file_handle_t hnd)
|
||||
}
|
||||
|
||||
inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired)
|
||||
{
|
||||
const unsigned long len = 0xffffffff;
|
||||
{
|
||||
const unsigned long len = ((unsigned long)-1);
|
||||
winapi::interprocess_overlapped overlapped;
|
||||
std::memset(&overlapped, 0, sizeof(overlapped));
|
||||
if(!winapi::lock_file_ex
|
||||
(hnd, winapi::lockfile_exclusive_lock | winapi::lockfile_fail_immediately,
|
||||
(hnd, winapi::lockfile_exclusive_lock | winapi::lockfile_fail_immediately,
|
||||
0, len, len, &overlapped)){
|
||||
return winapi::get_last_error() == winapi::error_lock_violation ?
|
||||
return winapi::get_last_error() == winapi::error_lock_violation ?
|
||||
acquired = false, true : false;
|
||||
|
||||
|
||||
}
|
||||
return (acquired = true);
|
||||
}
|
||||
|
||||
inline bool release_file_lock(file_handle_t hnd)
|
||||
{
|
||||
const unsigned long len = 0xffffffff;
|
||||
{
|
||||
const unsigned long len = ((unsigned long)-1);
|
||||
winapi::interprocess_overlapped overlapped;
|
||||
std::memset(&overlapped, 0, sizeof(overlapped));
|
||||
return winapi::unlock_file_ex(hnd, 0, len, len, &overlapped);
|
||||
}
|
||||
|
||||
inline bool acquire_file_lock_sharable(file_handle_t hnd)
|
||||
{
|
||||
const unsigned long len = 0xffffffff;
|
||||
{
|
||||
const unsigned long len = ((unsigned long)-1);
|
||||
winapi::interprocess_overlapped overlapped;
|
||||
std::memset(&overlapped, 0, sizeof(overlapped));
|
||||
return winapi::lock_file_ex(hnd, 0, 0, len, len, &overlapped);
|
||||
}
|
||||
|
||||
inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired)
|
||||
{
|
||||
const unsigned long len = 0xffffffff;
|
||||
{
|
||||
const unsigned long len = ((unsigned long)-1);
|
||||
winapi::interprocess_overlapped overlapped;
|
||||
std::memset(&overlapped, 0, sizeof(overlapped));
|
||||
if(!winapi::lock_file_ex
|
||||
(hnd, winapi::lockfile_fail_immediately, 0, len, len, &overlapped)){
|
||||
return winapi::get_last_error() == winapi::error_lock_violation ?
|
||||
return winapi::get_last_error() == winapi::error_lock_violation ?
|
||||
acquired = false, true : false;
|
||||
}
|
||||
return (acquired = true);
|
||||
@@ -367,7 +367,7 @@ typedef enum { read_only = O_RDONLY
|
||||
, read_write = O_RDWR
|
||||
, copy_on_write
|
||||
, read_private
|
||||
, invalid_mode = 0xffff
|
||||
, invalid_mode = 0xffff
|
||||
} mode_t;
|
||||
|
||||
typedef enum { file_begin = SEEK_SET
|
||||
@@ -406,7 +406,7 @@ inline const char *get_temporary_path()
|
||||
|
||||
inline file_handle_t create_new_file
|
||||
(const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false)
|
||||
{
|
||||
{
|
||||
(void)temporary;
|
||||
int ret = ::open(name, ((int)mode) | O_EXCL | O_CREAT, perm.get_permissions());
|
||||
if(ret >= 0){
|
||||
@@ -439,7 +439,7 @@ inline file_handle_t create_or_open_file
|
||||
|
||||
inline file_handle_t open_existing_file
|
||||
(const char *name, mode_t mode, bool temporary = false)
|
||||
{
|
||||
{
|
||||
(void)temporary;
|
||||
return ::open(name, (int)mode);
|
||||
}
|
||||
@@ -459,7 +459,7 @@ inline bool truncate_file (file_handle_t hnd, std::size_t size)
|
||||
}
|
||||
|
||||
inline bool get_file_size(file_handle_t hnd, offset_t &size)
|
||||
{
|
||||
{
|
||||
struct stat data;
|
||||
bool ret = 0 == ::fstat(hnd, &data);
|
||||
if(ret){
|
||||
@@ -472,7 +472,7 @@ inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos)
|
||||
{ return ((off_t)(-1)) != ::lseek(hnd, off, (int)pos); }
|
||||
|
||||
inline bool get_file_pointer(file_handle_t hnd, offset_t &off)
|
||||
{
|
||||
{
|
||||
off = ::lseek(hnd, 0, SEEK_CUR);
|
||||
return off != ((off_t)-1);
|
||||
}
|
||||
@@ -522,7 +522,7 @@ inline bool release_file_lock(file_handle_t hnd)
|
||||
}
|
||||
|
||||
inline bool acquire_file_lock_sharable(file_handle_t hnd)
|
||||
{
|
||||
{
|
||||
struct ::flock lock;
|
||||
lock.l_type = F_RDLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
@@ -532,7 +532,7 @@ inline bool acquire_file_lock_sharable(file_handle_t hnd)
|
||||
}
|
||||
|
||||
inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired)
|
||||
{
|
||||
{
|
||||
struct flock lock;
|
||||
lock.l_type = F_RDLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
@@ -540,7 +540,7 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired)
|
||||
lock.l_len = 0;
|
||||
int ret = ::fcntl(hnd, F_SETLK, &lock);
|
||||
if(ret == -1){
|
||||
return (errno == EAGAIN || errno == EACCES) ?
|
||||
return (errno == EAGAIN || errno == EACCES) ?
|
||||
acquired = false, true : false;
|
||||
}
|
||||
return (acquired = true);
|
||||
@@ -601,7 +601,7 @@ inline bool delete_subdirectories_recursive
|
||||
|| (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){
|
||||
continue;
|
||||
}
|
||||
if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){
|
||||
if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){
|
||||
continue;
|
||||
}
|
||||
fn = refcstrRootDirectory;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -104,7 +104,7 @@ typedef pthread_t OS_thread_id_t;
|
||||
typedef pid_t OS_process_id_t;
|
||||
|
||||
struct OS_systemwide_thread_id_t
|
||||
{
|
||||
{
|
||||
OS_systemwide_thread_id_t()
|
||||
: pid(), tid()
|
||||
{}
|
||||
@@ -153,7 +153,7 @@ inline OS_thread_id_t get_current_thread_id()
|
||||
{ return ::pthread_self(); }
|
||||
|
||||
inline OS_thread_id_t get_invalid_thread_id()
|
||||
{
|
||||
{
|
||||
static pthread_t invalid_id;
|
||||
return invalid_id;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011.
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012.
|
||||
// (C) Copyright Gennaro Prota 2003 - 2004.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
@@ -61,11 +61,11 @@ template <class T, class D>
|
||||
struct pointer_type
|
||||
{
|
||||
typedef typename pointer_type_imp::pointer_type<T,
|
||||
typename ipcdetail::remove_reference<D>::type>::type type;
|
||||
typename remove_reference<D>::type>::type type;
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
} //namespace interprocess {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
@@ -0,0 +1,356 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2009-2012. 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_PORTABLE_INTERMODULE_SINGLETON_HPP
|
||||
#define BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_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/detail/managed_global_memory.hpp>
|
||||
#include <boost/interprocess/detail/intermodule_singleton_common.hpp>
|
||||
#include <boost/interprocess/shared_memory_object.hpp>
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include <boost/interprocess/detail/os_thread_functions.hpp>
|
||||
#include <boost/interprocess/detail/tmp_dir_helpers.hpp>
|
||||
#include <boost/interprocess/detail/os_file_functions.hpp>
|
||||
#include <boost/interprocess/detail/file_locking_helpers.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace boost{
|
||||
namespace interprocess{
|
||||
namespace ipcdetail{
|
||||
|
||||
typedef basic_managed_global_memory<shared_memory_object, true> managed_global_memory;
|
||||
|
||||
namespace intermodule_singleton_helpers {
|
||||
|
||||
static void create_tmp_subdir_and_get_pid_based_filepath
|
||||
(const char *subdir_name, const char *file_prefix, OS_process_id_t pid, std::string &s, bool creation_time = false)
|
||||
{
|
||||
//Let's create a lock file for each process gmem that will mark if
|
||||
//the process is alive or not
|
||||
create_tmp_and_clean_old(s);
|
||||
s += "/";
|
||||
s += subdir_name;
|
||||
if(!open_or_create_directory(s.c_str())){
|
||||
throw interprocess_exception(error_info(system_error_code()));
|
||||
}
|
||||
s += "/";
|
||||
s += file_prefix;
|
||||
if(creation_time){
|
||||
std::string sstamp;
|
||||
get_pid_creation_time_str(sstamp);
|
||||
s += sstamp;
|
||||
}
|
||||
else{
|
||||
pid_str_t pid_str;
|
||||
get_pid_str(pid_str, pid);
|
||||
s += pid_str;
|
||||
}
|
||||
}
|
||||
|
||||
static bool check_if_filename_complies_with_pid
|
||||
(const char *filename, const char *prefix, OS_process_id_t pid, std::string &file_suffix, bool creation_time = false)
|
||||
{
|
||||
//Check if filename complies with lock file name pattern
|
||||
std::string fname(filename);
|
||||
std::string fprefix(prefix);
|
||||
if(fname.size() <= fprefix.size()){
|
||||
return false;
|
||||
}
|
||||
fname.resize(fprefix.size());
|
||||
if(fname != fprefix){
|
||||
return false;
|
||||
}
|
||||
|
||||
//If not our lock file, delete it if we can lock it
|
||||
fname = filename;
|
||||
fname.erase(0, fprefix.size());
|
||||
pid_str_t pid_str;
|
||||
get_pid_str(pid_str, pid);
|
||||
file_suffix = pid_str;
|
||||
if(creation_time){
|
||||
std::size_t p = fname.find('_');
|
||||
if (p == std::string::npos){
|
||||
return false;
|
||||
}
|
||||
std::string save_suffix(fname);
|
||||
fname.erase(p);
|
||||
fname.swap(file_suffix);
|
||||
bool ret = (file_suffix == fname);
|
||||
file_suffix.swap(save_suffix);
|
||||
return ret;
|
||||
}
|
||||
else{
|
||||
fname.swap(file_suffix);
|
||||
return (file_suffix == fname);
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
struct thread_safe_global_map_dependant<managed_global_memory>
|
||||
{
|
||||
private:
|
||||
static const int GMemMarkToBeRemoved = -1;
|
||||
static const int GMemNotPresent = -2;
|
||||
|
||||
static const char *get_lock_file_subdir_name()
|
||||
{ return "gmem"; }
|
||||
|
||||
static const char *get_lock_file_base_name()
|
||||
{ return "lck"; }
|
||||
|
||||
static void create_and_get_singleton_lock_file_path(std::string &s)
|
||||
{
|
||||
create_tmp_subdir_and_get_pid_based_filepath
|
||||
(get_lock_file_subdir_name(), get_lock_file_base_name(), get_current_process_id(), s, true);
|
||||
}
|
||||
|
||||
struct gmem_erase_func
|
||||
{
|
||||
gmem_erase_func(const char *shm_name, const char *singleton_lock_file_path, managed_global_memory & shm)
|
||||
:shm_name_(shm_name), singleton_lock_file_path_(singleton_lock_file_path), shm_(shm)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
locking_file_serial_id *pserial_id = shm_.find<locking_file_serial_id>("lock_file_fd").first;
|
||||
if(pserial_id){
|
||||
pserial_id->fd = GMemMarkToBeRemoved;
|
||||
}
|
||||
delete_file(singleton_lock_file_path_);
|
||||
shared_memory_object::remove(shm_name_);
|
||||
}
|
||||
|
||||
const char * const shm_name_;
|
||||
const char * const singleton_lock_file_path_;
|
||||
managed_global_memory & shm_;
|
||||
};
|
||||
|
||||
//This function applies shared memory erasure logic based on the passed lock file.
|
||||
static void apply_gmem_erase_logic(const char *filepath, const char *filename)
|
||||
{
|
||||
int fd = GMemMarkToBeRemoved;
|
||||
try{
|
||||
std::string str;
|
||||
//If the filename is current process lock file, then avoid it
|
||||
if(check_if_filename_complies_with_pid
|
||||
(filename, get_lock_file_base_name(), get_current_process_id(), str, true)){
|
||||
return;
|
||||
}
|
||||
//Open and lock the other process' lock file
|
||||
fd = try_open_and_lock_file(filepath);
|
||||
if(fd < 0){
|
||||
return;
|
||||
}
|
||||
//If done, then the process is dead so take global shared memory name
|
||||
//(the name is based on the lock file name) and try to apply erasure logic
|
||||
str.insert(0, get_map_base_name());
|
||||
try{
|
||||
managed_global_memory shm(open_only, str.c_str());
|
||||
gmem_erase_func func(str.c_str(), filepath, shm);
|
||||
shm.try_atomic_func(func);
|
||||
}
|
||||
catch(interprocess_exception &e){
|
||||
//If shared memory is not found erase the lock file
|
||||
if(e.get_error_code() == not_found_error){
|
||||
delete_file(filepath);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...){
|
||||
|
||||
}
|
||||
if(fd >= 0){
|
||||
close_lock_file(fd);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static bool remove_old_gmem()
|
||||
{
|
||||
std::string refcstrRootDirectory;
|
||||
tmp_folder(refcstrRootDirectory);
|
||||
refcstrRootDirectory += "/";
|
||||
refcstrRootDirectory += get_lock_file_subdir_name();
|
||||
return for_each_file_in_dir(refcstrRootDirectory.c_str(), apply_gmem_erase_logic);
|
||||
}
|
||||
|
||||
struct lock_file_logic
|
||||
{
|
||||
lock_file_logic(managed_global_memory &shm)
|
||||
: mshm(shm)
|
||||
{ shm.atomic_func(*this); }
|
||||
|
||||
void operator()(void)
|
||||
{
|
||||
retry_with_new_map = false;
|
||||
|
||||
//First find the file locking descriptor id
|
||||
locking_file_serial_id *pserial_id =
|
||||
mshm.find<locking_file_serial_id>("lock_file_fd").first;
|
||||
|
||||
int fd;
|
||||
//If not found schedule a creation
|
||||
if(!pserial_id){
|
||||
fd = GMemNotPresent;
|
||||
}
|
||||
//Else get it
|
||||
else{
|
||||
fd = pserial_id->fd;
|
||||
}
|
||||
//If we need to create a new one, do it
|
||||
if(fd == GMemNotPresent){
|
||||
std::string lck_str;
|
||||
//Create a unique current pid based lock file path
|
||||
create_and_get_singleton_lock_file_path(lck_str);
|
||||
//Open or create and lock file
|
||||
int fd_lockfile = open_or_create_and_lock_file(lck_str.c_str());
|
||||
//If failed, write a bad file descriptor to notify other modules that
|
||||
//something was wrong and unlink shared memory. Mark the function object
|
||||
//to tell caller to retry with another shared memory
|
||||
if(fd_lockfile < 0){
|
||||
this->register_lock_file(GMemMarkToBeRemoved);
|
||||
std::string s;
|
||||
get_map_name(s);
|
||||
shared_memory_object::remove(s.c_str());
|
||||
retry_with_new_map = true;
|
||||
}
|
||||
//If successful, register the file descriptor
|
||||
else{
|
||||
this->register_lock_file(fd_lockfile);
|
||||
}
|
||||
}
|
||||
//If the fd was invalid (maybe a previous try failed) notify caller that
|
||||
//should retry creation logic, since this shm might have been already
|
||||
//unlinked since the shm was removed
|
||||
else if (fd == GMemMarkToBeRemoved){
|
||||
retry_with_new_map = true;
|
||||
}
|
||||
//If the stored fd is not valid (a open fd, a normal file with the
|
||||
//expected size, or does not have the same file id number,
|
||||
//then it's an old shm from an old process with the same pid.
|
||||
//If that's the case, mark it as invalid
|
||||
else if(!is_valid_fd(fd) ||
|
||||
!is_normal_file(fd) ||
|
||||
0 != get_size(fd) ||
|
||||
!compare_file_serial(fd, *pserial_id)){
|
||||
pserial_id->fd = GMemMarkToBeRemoved;
|
||||
std::string s;
|
||||
get_map_name(s);
|
||||
shared_memory_object::remove(s.c_str());
|
||||
retry_with_new_map = true;
|
||||
}
|
||||
else{
|
||||
//If the lock file is ok, increment reference count of
|
||||
//attached modules to shared memory
|
||||
atomic_inc32(&pserial_id->modules_attached_to_gmem_count);
|
||||
}
|
||||
}
|
||||
|
||||
bool retry() const { return retry_with_new_map; }
|
||||
|
||||
private:
|
||||
locking_file_serial_id * register_lock_file(int fd)
|
||||
{
|
||||
locking_file_serial_id *pinfo = mshm.construct<locking_file_serial_id>("lock_file_fd")();
|
||||
fill_file_serial_id(fd, *pinfo);
|
||||
return pinfo;
|
||||
}
|
||||
|
||||
managed_global_memory &mshm;
|
||||
bool retry_with_new_map;
|
||||
};
|
||||
|
||||
static void construct_map(void *addr)
|
||||
{
|
||||
std::string s;
|
||||
intermodule_singleton_helpers::get_map_name(s);
|
||||
const char *MapName = s.c_str();
|
||||
const std::size_t MapSize = intermodule_singleton_helpers::get_map_size();;
|
||||
::new (addr)managed_global_memory(open_or_create, MapName, MapSize);
|
||||
}
|
||||
|
||||
struct unlink_map_logic
|
||||
{
|
||||
unlink_map_logic(managed_global_memory &mshm)
|
||||
: mshm_(mshm)
|
||||
{ mshm.atomic_func(*this); }
|
||||
|
||||
void operator()()
|
||||
{
|
||||
locking_file_serial_id *pserial_id =
|
||||
mshm_.find<locking_file_serial_id>
|
||||
("lock_file_fd").first;
|
||||
BOOST_ASSERT(0 != pserial_id);
|
||||
if(1 == atomic_dec32(&pserial_id->modules_attached_to_gmem_count)){
|
||||
int fd = pserial_id->fd;
|
||||
if(fd > 0){
|
||||
pserial_id->fd = GMemMarkToBeRemoved;
|
||||
std::string s;
|
||||
create_and_get_singleton_lock_file_path(s);
|
||||
delete_file(s.c_str());
|
||||
close_lock_file(fd);
|
||||
intermodule_singleton_helpers::get_map_name(s);
|
||||
shared_memory_object::remove(s.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
managed_global_memory &mshm_;
|
||||
};
|
||||
|
||||
static ref_count_ptr *find(managed_global_memory &map, const char *name)
|
||||
{
|
||||
return map.find<ref_count_ptr>(name).first;
|
||||
}
|
||||
|
||||
static ref_count_ptr *insert(managed_global_memory &map, const char *name, const ref_count_ptr &ref)
|
||||
{
|
||||
return map.construct<ref_count_ptr>(name)(ref);
|
||||
}
|
||||
|
||||
static bool erase(managed_global_memory &map, const char *name)
|
||||
{
|
||||
return map.destroy<ref_count_ptr>(name);
|
||||
}
|
||||
|
||||
template<class F>
|
||||
static void atomic_func(managed_global_memory &map, F &f)
|
||||
{
|
||||
map.atomic_func(f);
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace intermodule_singleton_helpers {
|
||||
|
||||
template<typename C, bool LazyInit = true, bool Phoenix = true>
|
||||
class portable_intermodule_singleton
|
||||
: public intermodule_singleton_impl<C, LazyInit, Phoenix, managed_global_memory>
|
||||
{};
|
||||
|
||||
} //namespace ipcdetail{
|
||||
} //namespace interprocess{
|
||||
} //namespace boost{
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_PORTABLE_INTERMODULE_SINGLETON_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
|
||||
#endif //#ifndef WIN32_LEAN_AND_MEAN
|
||||
#endif //#ifdef _WIN32
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
@@ -21,7 +21,7 @@
|
||||
#error "This file is not needed when perfect forwarding is available"
|
||||
#endif
|
||||
|
||||
#include <boost/preprocessor/iteration/local.hpp>
|
||||
#include <boost/preprocessor/iteration/local.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/repetition/enum.hpp>
|
||||
@@ -35,7 +35,7 @@
|
||||
//This cast is ugly but it is necessary until "perfect forwarding"
|
||||
//is achieved in C++0x. Meanwhile, if we want to be able to
|
||||
//bind rvalues with non-const references, we have to be ugly
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \
|
||||
BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \
|
||||
//!
|
||||
@@ -45,7 +45,7 @@
|
||||
//!
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#define BOOST_INTERPROCESS_PP_PARAM(U, u) \
|
||||
U && u \
|
||||
//!
|
||||
@@ -55,78 +55,144 @@
|
||||
//!
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
|
||||
#ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \
|
||||
BOOST_PP_CAT(m_p, n) (::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) )) \
|
||||
//!
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \
|
||||
BOOST_PP_CAT(m_p, n) (BOOST_INTERPROCESS_MOVE_NAMESPACE::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) )) \
|
||||
//!
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \
|
||||
BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \
|
||||
//!
|
||||
#else //#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \
|
||||
BOOST_PP_CAT(m_p, n) (const_cast<BOOST_PP_CAT(P, n) &>(BOOST_PP_CAT(p, n))) \
|
||||
//!
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \
|
||||
BOOST_PP_CAT(m_p, n) (const_cast<BOOST_PP_CAT(P, n) &>(BOOST_PP_CAT(p, n))) \
|
||||
//!
|
||||
#endif
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_INC(z, n, data) \
|
||||
BOOST_PP_CAT(++m_p, n) \
|
||||
//!
|
||||
#if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG)
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
template<class T>
|
||||
struct ref_holder;
|
||||
|
||||
#if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG)
|
||||
template<class T>
|
||||
struct ref_holder<T &>
|
||||
{
|
||||
ref_holder(T &t)
|
||||
: t_(t)
|
||||
{}
|
||||
T &t_;
|
||||
T & get() { return t_; }
|
||||
T & get_lvalue() { return t_; }
|
||||
};
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data) \
|
||||
BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \
|
||||
//!
|
||||
template<class T>
|
||||
struct ref_holder<const T>
|
||||
{
|
||||
ref_holder(const T &t)
|
||||
: t_(t)
|
||||
{}
|
||||
const T &t_;
|
||||
const T & get() { return t_; }
|
||||
const T & get_lvalue() { return t_; }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct ref_holder<const T &&>
|
||||
{
|
||||
ref_holder(const T &t)
|
||||
: t_(t)
|
||||
{}
|
||||
const T &t_;
|
||||
const T & get() { return t_; }
|
||||
const T & get_lvalue() { return t_; }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct ref_holder
|
||||
{
|
||||
ref_holder(T &&t)
|
||||
: t_(t)
|
||||
{}
|
||||
T &t_;
|
||||
T && get() { return ::boost::move(t_); }
|
||||
T & get_lvalue() { return t_; }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct ref_holder<T &&>
|
||||
{
|
||||
ref_holder(T &&t)
|
||||
: t(t)
|
||||
{}
|
||||
T &t;
|
||||
T && get() { return ::boost::move(t_); }
|
||||
T & get_lvalue() { return t_; }
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data) \
|
||||
::boost::interprocess::ipcdetail::ref_holder<BOOST_PP_CAT(P, n)> BOOST_PP_CAT(m_p, n); \
|
||||
//!
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_INC(z, n, data) \
|
||||
BOOST_PP_CAT(++m_p, n).get_lvalue() \
|
||||
//!
|
||||
|
||||
#else //BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data)\
|
||||
BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \
|
||||
//!
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_INC(z, n, data) \
|
||||
BOOST_PP_CAT(++m_p, n) \
|
||||
//!
|
||||
|
||||
#endif //defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG)
|
||||
|
||||
#else
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data) \
|
||||
BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \
|
||||
//!
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data) \
|
||||
BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \
|
||||
//!
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_INC(z, n, data) \
|
||||
BOOST_PP_CAT(++m_p, n) \
|
||||
//!
|
||||
|
||||
#endif //defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG)
|
||||
|
||||
|
||||
#else
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data) \
|
||||
BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \
|
||||
//!
|
||||
#endif
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \
|
||||
::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \
|
||||
//!
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG)
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG)
|
||||
|
||||
#include <boost/container/detail/stored_ref.hpp>
|
||||
#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) BOOST_PP_CAT(this->m_p, n).get() \
|
||||
//!
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \
|
||||
::boost::container::container_detail::stored_ref< BOOST_PP_CAT(P, n) >::forward( BOOST_PP_CAT(m_p, n) ) \
|
||||
//!
|
||||
#define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \
|
||||
BOOST_PP_CAT(*m_p, n).get_lvalue() \
|
||||
//!
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \
|
||||
::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \
|
||||
//!
|
||||
#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \
|
||||
::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \
|
||||
//!
|
||||
|
||||
#endif //!defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG)
|
||||
#define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \
|
||||
BOOST_PP_CAT(*m_p, n) \
|
||||
//!
|
||||
|
||||
#define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \
|
||||
BOOST_PP_CAT(*m_p, n) \
|
||||
//!
|
||||
|
||||
#endif //!defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG)
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2006-2012. 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)
|
||||
//
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
|
||||
#endif //#ifndef WIN32_LEAN_AND_MEAN
|
||||
#endif //#ifdef _WIN32
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2010-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2010-2012. 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)
|
||||
//
|
||||
@@ -68,7 +68,7 @@ inline void robust_lock_path(std::string &s)
|
||||
|
||||
inline void create_and_get_robust_lock_file_path(std::string &s, OS_process_id_t pid)
|
||||
{
|
||||
file_locking_helpers::create_tmp_subdir_and_get_pid_based_filepath
|
||||
intermodule_singleton_helpers::create_tmp_subdir_and_get_pid_based_filepath
|
||||
(robust_lock_subdir_path(), robust_lock_prefix(), pid, s);
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ class robust_mutex_lock_file
|
||||
throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: create_file filed with unexpected error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~robust_mutex_lock_file()
|
||||
{
|
||||
@@ -154,7 +154,7 @@ class robust_mutex_lock_file
|
||||
{
|
||||
std::string pid_str;
|
||||
//If the lock file is not our own lock file, then try to do the cleanup
|
||||
if(!file_locking_helpers::check_if_filename_complies_with_pid
|
||||
if(!intermodule_singleton_helpers::check_if_filename_complies_with_pid
|
||||
(filename, robust_lock_prefix(), get_current_process_id(), pid_str)){
|
||||
remove_if_can_lock_file(filepath);
|
||||
}
|
||||
@@ -197,8 +197,8 @@ class robust_spin_mutex
|
||||
bool lock_own_unique_file();
|
||||
bool robust_check();
|
||||
bool check_if_owner_dead_and_take_ownership_atomically();
|
||||
bool is_owner_dead(boost::uint32_t owner);
|
||||
void owner_to_filename(boost::uint32_t owner, std::string &s);
|
||||
bool is_owner_dead(boost::uint32_t own);
|
||||
void owner_to_filename(boost::uint32_t own, std::string &s);
|
||||
//The real mutex
|
||||
Mutex mtx;
|
||||
//The pid of the owner
|
||||
@@ -309,9 +309,9 @@ inline bool robust_spin_mutex<Mutex>::timed_lock
|
||||
}
|
||||
|
||||
template<class Mutex>
|
||||
inline void robust_spin_mutex<Mutex>::owner_to_filename(boost::uint32_t owner, std::string &s)
|
||||
inline void robust_spin_mutex<Mutex>::owner_to_filename(boost::uint32_t own, std::string &s)
|
||||
{
|
||||
robust_emulation_helpers::create_and_get_robust_lock_file_path(s, owner);
|
||||
robust_emulation_helpers::create_and_get_robust_lock_file_path(s, own);
|
||||
}
|
||||
|
||||
template<class Mutex>
|
||||
@@ -324,7 +324,7 @@ inline bool robust_spin_mutex<Mutex>::robust_check()
|
||||
return false;
|
||||
}
|
||||
atomic_write32(&this->state, fixing_state);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Mutex>
|
||||
@@ -349,16 +349,16 @@ inline bool robust_spin_mutex<Mutex>::check_if_owner_dead_and_take_ownership_ato
|
||||
}
|
||||
|
||||
template<class Mutex>
|
||||
inline bool robust_spin_mutex<Mutex>::is_owner_dead(boost::uint32_t owner)
|
||||
inline bool robust_spin_mutex<Mutex>::is_owner_dead(boost::uint32_t own)
|
||||
{
|
||||
//If owner is an invalid id, then it's clear it's dead
|
||||
if(owner == (boost::uint32_t)get_invalid_process_id()){
|
||||
if(own == (boost::uint32_t)get_invalid_process_id()){
|
||||
return true;
|
||||
}
|
||||
|
||||
//Obtain the lock filename of the owner field
|
||||
std::string file;
|
||||
this->owner_to_filename(owner, file);
|
||||
this->owner_to_filename(own, file);
|
||||
|
||||
//Now the logic is to open and lock it
|
||||
file_handle_t fhnd = open_existing_file(file.c_str(), read_write);
|
||||
@@ -424,7 +424,7 @@ template<class Mutex>
|
||||
inline bool robust_spin_mutex<Mutex>::lock_own_unique_file()
|
||||
{
|
||||
//This function forces instantiation of the singleton
|
||||
robust_emulation_helpers::robust_mutex_lock_file* dummy =
|
||||
robust_emulation_helpers::robust_mutex_lock_file* dummy =
|
||||
&ipcdetail::intermodule_singleton
|
||||
<robust_emulation_helpers::robust_mutex_lock_file>::get();
|
||||
return dummy != 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -81,21 +81,18 @@ struct block_header
|
||||
unsigned char m_value_alignment;
|
||||
unsigned char m_alloc_type_sizeof_char;
|
||||
|
||||
block_header(size_type value_bytes
|
||||
,size_type value_alignment
|
||||
,unsigned char alloc_type
|
||||
,std::size_t sizeof_char
|
||||
block_header(size_type val_bytes
|
||||
,size_type val_alignment
|
||||
,unsigned char al_type
|
||||
,std::size_t szof_char
|
||||
,std::size_t num_char
|
||||
)
|
||||
: m_value_bytes(value_bytes)
|
||||
: m_value_bytes(val_bytes)
|
||||
, m_num_char((unsigned short)num_char)
|
||||
, m_value_alignment((unsigned char)value_alignment)
|
||||
, m_alloc_type_sizeof_char
|
||||
( (alloc_type << 5u) |
|
||||
((unsigned char)sizeof_char & 0x1F) )
|
||||
, m_value_alignment((unsigned char)val_alignment)
|
||||
, m_alloc_type_sizeof_char( (al_type << 5u) | ((unsigned char)szof_char & 0x1F) )
|
||||
{};
|
||||
|
||||
|
||||
template<class T>
|
||||
block_header &operator= (const T& )
|
||||
{ return *this; }
|
||||
@@ -130,7 +127,7 @@ struct block_header
|
||||
|
||||
template<class CharType>
|
||||
CharType *name() const
|
||||
{
|
||||
{
|
||||
return const_cast<CharType*>(reinterpret_cast<const CharType*>
|
||||
(reinterpret_cast<const char*>(this) + name_offset()));
|
||||
}
|
||||
@@ -139,7 +136,7 @@ struct block_header
|
||||
{ return m_num_char; }
|
||||
|
||||
size_type name_offset() const
|
||||
{
|
||||
{
|
||||
return this->value_offset() + get_rounded_size(size_type(m_value_bytes), size_type(sizeof_char()));
|
||||
}
|
||||
|
||||
@@ -157,7 +154,7 @@ struct block_header
|
||||
bool less_comp(const block_header<size_type> &b) const
|
||||
{
|
||||
return m_num_char < b.m_num_char ||
|
||||
(m_num_char < b.m_num_char &&
|
||||
(m_num_char < b.m_num_char &&
|
||||
std::char_traits<CharType>::compare
|
||||
(name<CharType>(), b.name<CharType>(), m_num_char) < 0);
|
||||
}
|
||||
@@ -175,10 +172,10 @@ struct block_header
|
||||
{ return block_header_from_value(value, sizeof(T), ::boost::alignment_of<T>::value); }
|
||||
|
||||
static block_header<size_type> *block_header_from_value(const void *value, std::size_t sz, std::size_t algn)
|
||||
{
|
||||
block_header * hdr =
|
||||
{
|
||||
block_header * hdr =
|
||||
const_cast<block_header*>
|
||||
(reinterpret_cast<const block_header*>(reinterpret_cast<const char*>(value) -
|
||||
(reinterpret_cast<const block_header*>(reinterpret_cast<const char*>(value) -
|
||||
get_rounded_size(sizeof(block_header), algn)));
|
||||
(void)sz;
|
||||
//Some sanity checks
|
||||
@@ -189,9 +186,9 @@ struct block_header
|
||||
|
||||
template<class Header>
|
||||
static block_header<size_type> *from_first_header(Header *header)
|
||||
{
|
||||
block_header<size_type> * hdr =
|
||||
reinterpret_cast<block_header<size_type>*>(reinterpret_cast<char*>(header) +
|
||||
{
|
||||
block_header<size_type> * hdr =
|
||||
reinterpret_cast<block_header<size_type>*>(reinterpret_cast<char*>(header) +
|
||||
get_rounded_size(size_type(sizeof(Header)), size_type(::boost::alignment_of<block_header<size_type> >::value)));
|
||||
//Some sanity checks
|
||||
return hdr;
|
||||
@@ -199,9 +196,9 @@ struct block_header
|
||||
|
||||
template<class Header>
|
||||
static Header *to_first_header(block_header<size_type> *bheader)
|
||||
{
|
||||
Header * hdr =
|
||||
reinterpret_cast<Header*>(reinterpret_cast<char*>(bheader) -
|
||||
{
|
||||
Header * hdr =
|
||||
reinterpret_cast<Header*>(reinterpret_cast<char*>(bheader) -
|
||||
get_rounded_size(size_type(sizeof(Header)), size_type(::boost::alignment_of<block_header<size_type> >::value)));
|
||||
//Some sanity checks
|
||||
return hdr;
|
||||
@@ -311,15 +308,15 @@ template<class CharType>
|
||||
class char_ptr_holder
|
||||
{
|
||||
public:
|
||||
char_ptr_holder(const CharType *name)
|
||||
char_ptr_holder(const CharType *name)
|
||||
: m_name(name)
|
||||
{}
|
||||
|
||||
char_ptr_holder(const anonymous_instance_t *)
|
||||
char_ptr_holder(const anonymous_instance_t *)
|
||||
: m_name(static_cast<CharType*>(0))
|
||||
{}
|
||||
|
||||
char_ptr_holder(const unique_instance_t *)
|
||||
char_ptr_holder(const unique_instance_t *)
|
||||
: m_name(reinterpret_cast<CharType*>(-1))
|
||||
{}
|
||||
|
||||
@@ -330,7 +327,7 @@ class char_ptr_holder
|
||||
const CharType *m_name;
|
||||
};
|
||||
|
||||
//!The key of the the named allocation information index. Stores an offset pointer
|
||||
//!The key of the the named allocation information index. Stores an offset pointer
|
||||
//!to a null terminated string and the length of the string to speed up sorting
|
||||
template<class CharT, class VoidPointer>
|
||||
struct index_key
|
||||
@@ -350,15 +347,16 @@ struct index_key
|
||||
public:
|
||||
|
||||
//!Constructor of the key
|
||||
index_key (const char_type *name, size_type length)
|
||||
: mp_str(name), m_len(length) {}
|
||||
index_key (const char_type *nm, size_type length)
|
||||
: mp_str(nm), m_len(length)
|
||||
{}
|
||||
|
||||
//!Less than function for index ordering
|
||||
bool operator < (const index_key & right) const
|
||||
{
|
||||
return (m_len < right.m_len) ||
|
||||
(m_len == right.m_len &&
|
||||
std::char_traits<char_type>::compare
|
||||
return (m_len < right.m_len) ||
|
||||
(m_len == right.m_len &&
|
||||
std::char_traits<char_type>::compare
|
||||
(to_raw_pointer(mp_str)
|
||||
,to_raw_pointer(right.mp_str), m_len) < 0);
|
||||
}
|
||||
@@ -366,14 +364,14 @@ struct index_key
|
||||
//!Equal to function for index ordering
|
||||
bool operator == (const index_key & right) const
|
||||
{
|
||||
return m_len == right.m_len &&
|
||||
std::char_traits<char_type>::compare
|
||||
return m_len == right.m_len &&
|
||||
std::char_traits<char_type>::compare
|
||||
(to_raw_pointer(mp_str),
|
||||
to_raw_pointer(right.mp_str), m_len) == 0;
|
||||
}
|
||||
|
||||
void name(const CharT *name)
|
||||
{ mp_str = name; }
|
||||
void name(const CharT *nm)
|
||||
{ mp_str = nm; }
|
||||
|
||||
void name_length(size_type len)
|
||||
{ m_len = len; }
|
||||
@@ -478,14 +476,14 @@ struct segment_manager_iterator_transform
|
||||
, segment_manager_iterator_value_adaptor<Iterator, intrusive> >
|
||||
{
|
||||
typedef segment_manager_iterator_value_adaptor<Iterator, intrusive> result_type;
|
||||
|
||||
|
||||
result_type operator()(const typename Iterator::value_type &arg) const
|
||||
{ return result_type(arg); }
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
|
||||
//These pointers are the ones the user will use to
|
||||
//These pointers are the ones the user will use to
|
||||
//indicate previous allocation types
|
||||
static const ipcdetail::anonymous_instance_t * anonymous_instance = 0;
|
||||
static const ipcdetail::unique_instance_t * unique_instance = 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2007-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2007-2012. 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)
|
||||
//
|
||||
@@ -18,80 +18,87 @@
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <string>
|
||||
|
||||
#if defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
//#define BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME
|
||||
//#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
|
||||
//#include <boost/interprocess/detail/win32_api.hpp>
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||||
//#include <sys/sysctl.h>
|
||||
//#if defined(CTL_KERN) && defined (KERN_BOOTTIME)
|
||||
//#define BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME
|
||||
//#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
|
||||
//#endif
|
||||
#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) && defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
#include <boost/interprocess/detail/windows_intermodule_singleton.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
#if defined (BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME)
|
||||
inline void get_bootstamp(std::string &s, bool add = false)
|
||||
{
|
||||
std::string bootstamp;
|
||||
winapi::get_last_bootup_time(bootstamp);
|
||||
if(add){
|
||||
s += bootstamp;
|
||||
}
|
||||
else{
|
||||
s.swap(bootstamp);
|
||||
}
|
||||
}
|
||||
#elif defined(BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME)
|
||||
inline void get_bootstamp(std::string &s, bool add = false)
|
||||
{
|
||||
// FreeBSD specific: sysctl "kern.boottime"
|
||||
int request[2] = { CTL_KERN, KERN_BOOTTIME };
|
||||
struct ::timeval result;
|
||||
std::size_t result_len = sizeof result;
|
||||
#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME)
|
||||
#if defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
//This type will initialize the stamp
|
||||
struct windows_bootstamp
|
||||
{
|
||||
windows_bootstamp()
|
||||
{
|
||||
winapi::get_last_bootup_time(stamp);
|
||||
}
|
||||
//Use std::string. Even if this will be constructed in shared memory, all
|
||||
//modules/dlls are from this process so internal raw pointers to heap are always valid
|
||||
std::string stamp;
|
||||
};
|
||||
|
||||
if (::sysctl (request, 2, &result, &result_len, NULL, 0) < 0)
|
||||
return;
|
||||
|
||||
char bootstamp_str[256];
|
||||
|
||||
const char Characters [] =
|
||||
{ '0', '1', '2', '3', '4', '5', '6', '7'
|
||||
, '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
std::size_t char_counter = 0;
|
||||
//32 bit values to allow 32 and 64 bit process IPC
|
||||
boost::uint32_t fields[2] = { boost::uint32_t(result.tv_sec), boost::uint32_t(result.tv_usec) };
|
||||
for(std::size_t field = 0; field != 2; ++field){
|
||||
for(std::size_t i = 0; i != sizeof(fields[0]); ++i){
|
||||
const char *ptr = (const char *)&fields[field];
|
||||
bootstamp_str[char_counter++] = Characters[(ptr[i]&0xF0)>>4];
|
||||
bootstamp_str[char_counter++] = Characters[(ptr[i]&0x0F)];
|
||||
inline void get_bootstamp(std::string &s, bool add = false)
|
||||
{
|
||||
const windows_bootstamp &bootstamp = windows_intermodule_singleton<windows_bootstamp>::get();
|
||||
if(add){
|
||||
s += bootstamp.stamp;
|
||||
}
|
||||
else{
|
||||
s = bootstamp.stamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
bootstamp_str[char_counter] = 0;
|
||||
if(add){
|
||||
s += bootstamp_str;
|
||||
}
|
||||
else{
|
||||
s = bootstamp_str;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#elif defined(BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME)
|
||||
inline void get_bootstamp(std::string &s, bool add = false)
|
||||
{
|
||||
// FreeBSD specific: sysctl "kern.boottime"
|
||||
int request[2] = { CTL_KERN, KERN_BOOTTIME };
|
||||
struct ::timeval result;
|
||||
std::size_t result_len = sizeof result;
|
||||
|
||||
if (::sysctl (request, 2, &result, &result_len, NULL, 0) < 0)
|
||||
return;
|
||||
|
||||
char bootstamp_str[256];
|
||||
|
||||
const char Characters [] =
|
||||
{ '0', '1', '2', '3', '4', '5', '6', '7'
|
||||
, '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
std::size_t char_counter = 0;
|
||||
//32 bit values to allow 32 and 64 bit process IPC
|
||||
boost::uint32_t fields[2] = { boost::uint32_t(result.tv_sec), boost::uint32_t(result.tv_usec) };
|
||||
for(std::size_t field = 0; field != 2; ++field){
|
||||
for(std::size_t i = 0; i != sizeof(fields[0]); ++i){
|
||||
const char *ptr = (const char *)&fields[field];
|
||||
bootstamp_str[char_counter++] = Characters[(ptr[i]&0xF0)>>4];
|
||||
bootstamp_str[char_counter++] = Characters[(ptr[i]&0x0F)];
|
||||
}
|
||||
}
|
||||
bootstamp_str[char_counter] = 0;
|
||||
if(add){
|
||||
s += bootstamp_str;
|
||||
}
|
||||
else{
|
||||
s = bootstamp_str;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME defined with no known implementation"
|
||||
#endif
|
||||
#endif //#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME)
|
||||
|
||||
inline void get_tmp_base_dir(std::string &tmp_name)
|
||||
{
|
||||
#if defined (BOOST_INTERPROCESS_WINDOWS)
|
||||
winapi::get_shared_documents_folder(tmp_name);
|
||||
if(tmp_name.empty() || !winapi::is_directory(tmp_name.c_str())){
|
||||
tmp_name = get_temporary_path();
|
||||
}
|
||||
winapi::get_shared_documents_folder(tmp_name);
|
||||
if(tmp_name.empty() || !winapi::is_directory(tmp_name.c_str())){
|
||||
tmp_name = get_temporary_path();
|
||||
}
|
||||
#else
|
||||
tmp_name = get_temporary_path();
|
||||
tmp_name = get_temporary_path();
|
||||
#endif
|
||||
if(tmp_name.empty()){
|
||||
error_info err = system_error_code();
|
||||
@@ -104,9 +111,9 @@ inline void get_tmp_base_dir(std::string &tmp_name)
|
||||
inline void tmp_folder(std::string &tmp_name)
|
||||
{
|
||||
get_tmp_base_dir(tmp_name);
|
||||
#ifdef BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
|
||||
tmp_name += "/";
|
||||
get_bootstamp(tmp_name, true);
|
||||
#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME)
|
||||
tmp_name += "/";
|
||||
get_bootstamp(tmp_name, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -131,22 +138,22 @@ inline void create_tmp_and_clean_old(std::string &tmp_name)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
|
||||
tmp_folder(tmp_name);
|
||||
#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME)
|
||||
tmp_folder(tmp_name);
|
||||
|
||||
//If fails, check that it's because already exists
|
||||
if(!create_directory(tmp_name.c_str())){
|
||||
error_info info(system_error_code());
|
||||
if(info.get_error_code() != already_exists_error){
|
||||
throw interprocess_exception(info);
|
||||
//If fails, check that it's because already exists
|
||||
if(!create_directory(tmp_name.c_str())){
|
||||
error_info info(system_error_code());
|
||||
if(info.get_error_code() != already_exists_error){
|
||||
throw interprocess_exception(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Now erase all old directories created in the previous boot sessions
|
||||
std::string subdir = tmp_name;
|
||||
subdir.erase(0, root_tmp_name.size()+1);
|
||||
delete_subdirectories(root_tmp_name, subdir.c_str());
|
||||
//Now erase all old directories created in the previous boot sessions
|
||||
std::string subdir = tmp_name;
|
||||
subdir.erase(0, root_tmp_name.size()+1);
|
||||
delete_subdirectories(root_tmp_name, subdir.c_str());
|
||||
#else
|
||||
tmp_name = root_tmp_name;
|
||||
tmp_name = root_tmp_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011.
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012.
|
||||
// (C) Copyright Gennaro Prota 2003 - 2004.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace interprocess {
|
||||
|
||||
template <class PseudoReference>
|
||||
struct operator_arrow_proxy
|
||||
@@ -77,7 +77,7 @@ class transform_iterator
|
||||
{}
|
||||
|
||||
//Constructors
|
||||
transform_iterator& operator++()
|
||||
transform_iterator& operator++()
|
||||
{ increment(); return *this; }
|
||||
|
||||
transform_iterator operator++(int)
|
||||
@@ -87,7 +87,7 @@ class transform_iterator
|
||||
return result;
|
||||
}
|
||||
|
||||
transform_iterator& operator--()
|
||||
transform_iterator& operator--()
|
||||
{ decrement(); return *this; }
|
||||
|
||||
transform_iterator operator--(int)
|
||||
@@ -186,7 +186,7 @@ make_transform_iterator(Iterator it, UnaryFunc fun)
|
||||
return transform_iterator<Iterator, UnaryFunc>(it, fun);
|
||||
}
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// (C) Copyright John Maddock 2000.
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011.
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
struct nat{};
|
||||
@@ -117,6 +117,12 @@ struct remove_volatile<volatile T>
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct remove_const_volatile
|
||||
{
|
||||
typedef typename remove_const<typename remove_volatile<T>::type>::type type;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct is_same
|
||||
{
|
||||
@@ -136,8 +142,15 @@ struct is_same
|
||||
static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u));
|
||||
};
|
||||
|
||||
template<class T, class U>
|
||||
struct is_cv_same
|
||||
{
|
||||
static const bool value = is_same< typename remove_const_volatile<T>::type
|
||||
, typename remove_const_volatile<U>::type >::value;
|
||||
};
|
||||
|
||||
} // namespace ipcdetail
|
||||
} //namespace interprocess {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011.
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012.
|
||||
// (C) Copyright Gennaro Prota 2003 - 2004.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
@@ -31,11 +31,13 @@
|
||||
#include <boost/interprocess/containers/version_type.hpp>
|
||||
#include <boost/intrusive/pointer_traits.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
template <class T>
|
||||
@@ -86,7 +88,10 @@ inline SizeType get_truncated_size_po2(SizeType orig_size, SizeType multiple)
|
||||
template <std::size_t OrigSize, std::size_t RoundTo>
|
||||
struct ct_rounded_size
|
||||
{
|
||||
static const std::size_t value = ((OrigSize-1)/RoundTo+1)*RoundTo;
|
||||
BOOST_STATIC_ASSERT((RoundTo != 0));
|
||||
static const std::size_t intermediate_value = (OrigSize-1)/RoundTo+1;
|
||||
BOOST_STATIC_ASSERT(intermediate_value <= std::size_t(-1)/RoundTo);
|
||||
static const std::size_t value = intermediate_value*RoundTo;
|
||||
};
|
||||
|
||||
// Gennaro Prota wrote this. Thanks!
|
||||
@@ -133,14 +138,67 @@ addressof(T& v)
|
||||
&const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
|
||||
}
|
||||
|
||||
template<class SizeType>
|
||||
struct sqrt_size_type_max
|
||||
{
|
||||
static const SizeType value = (SizeType(1) << (sizeof(SizeType)*(CHAR_BIT/2)))-1;
|
||||
};
|
||||
|
||||
template<class SizeType>
|
||||
inline bool multiplication_overflows(SizeType a, SizeType b)
|
||||
{
|
||||
const SizeType sqrt_size_max = sqrt_size_type_max<SizeType>::value;
|
||||
return //Fast runtime check
|
||||
( (a | b) > sqrt_size_max &&
|
||||
//Slow division check
|
||||
b && a > SizeType(-1)/b
|
||||
);
|
||||
}
|
||||
|
||||
template<std::size_t SztSizeOfType, class SizeType>
|
||||
inline bool size_overflows(SizeType count)
|
||||
{
|
||||
//Compile time-check
|
||||
BOOST_STATIC_ASSERT(SztSizeOfType <= SizeType(-1));
|
||||
//Runtime check
|
||||
return multiplication_overflows(SizeType(SztSizeOfType), count);
|
||||
}
|
||||
|
||||
template<class RawPointer>
|
||||
class pointer_size_t_caster
|
||||
{
|
||||
public:
|
||||
explicit pointer_size_t_caster(std::size_t sz)
|
||||
: m_ptr(reinterpret_cast<RawPointer>(sz))
|
||||
{}
|
||||
|
||||
explicit pointer_size_t_caster(RawPointer p)
|
||||
: m_ptr(p)
|
||||
{}
|
||||
|
||||
std::size_t size() const
|
||||
{ return reinterpret_cast<std::size_t>(m_ptr); }
|
||||
|
||||
RawPointer pointer() const
|
||||
{ return m_ptr; }
|
||||
|
||||
private:
|
||||
RawPointer m_ptr;
|
||||
};
|
||||
|
||||
|
||||
template<class SizeType>
|
||||
inline bool sum_overflows(SizeType a, SizeType b)
|
||||
{ return SizeType(-1) - a < b; }
|
||||
|
||||
//Anti-exception node eraser
|
||||
template<class Cont>
|
||||
class value_eraser
|
||||
{
|
||||
public:
|
||||
value_eraser(Cont & cont, typename Cont::iterator it)
|
||||
value_eraser(Cont & cont, typename Cont::iterator it)
|
||||
: m_cont(cont), m_index_it(it), m_erase(true){}
|
||||
~value_eraser()
|
||||
~value_eraser()
|
||||
{ if(m_erase) m_cont.erase(m_index_it); }
|
||||
|
||||
void release() { m_erase = false; }
|
||||
@@ -151,7 +209,7 @@ class value_eraser
|
||||
bool m_erase;
|
||||
};
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <cstddef> //std::size_t
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
template<typename... Values>
|
||||
@@ -136,7 +136,7 @@ struct index_tuple{};
|
||||
template<std::size_t Num, typename Tuple = index_tuple<> >
|
||||
struct build_number_seq;
|
||||
|
||||
template<std::size_t Num, int... Indexes>
|
||||
template<std::size_t Num, int... Indexes>
|
||||
struct build_number_seq<Num, index_tuple<Indexes...> >
|
||||
: build_number_seq<Num - 1, index_tuple<Indexes..., sizeof...(Indexes)> >
|
||||
{};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,306 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2009-2012. 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_WINDOWS_INTERMODULE_SINGLETON_HPP
|
||||
#define BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP
|
||||
|
||||
#if defined(_MSC_VER)&&(_MSC_VER>=1200)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
#error "This header can't be included from non-windows operating systems"
|
||||
#endif
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/interprocess/detail/intermodule_singleton_common.hpp>
|
||||
#include <boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp>
|
||||
#include <boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp>
|
||||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace boost{
|
||||
namespace interprocess{
|
||||
namespace ipcdetail{
|
||||
|
||||
namespace intermodule_singleton_helpers {
|
||||
|
||||
//This global map will be implemented using 3 sync primitives:
|
||||
//
|
||||
//1) A named mutex that will implement global mutual exclusion between
|
||||
// threads from different modules/dlls
|
||||
//
|
||||
//2) A semaphore that will act as a global counter for modules attached to the global map
|
||||
// so that the global map can be destroyed when the last module is detached.
|
||||
//
|
||||
//3) A semaphore that will be hacked to hold the address of a heap-allocated map in the
|
||||
// max and current semaphore count.
|
||||
class windows_semaphore_based_map
|
||||
{
|
||||
typedef std::map<std::string, ref_count_ptr> map_type;
|
||||
|
||||
public:
|
||||
windows_semaphore_based_map()
|
||||
{
|
||||
map_type *m = new map_type;
|
||||
boost::uint32_t initial_count = 0;
|
||||
boost::uint32_t max_count = 0;
|
||||
|
||||
//Windows user address space sizes:
|
||||
//32 bit windows: [32 bit processes] 2GB or 3GB (31/32 bits)
|
||||
//64 bit windows: [32 bit processes] 2GB or 4GB (31/32 bits)
|
||||
// [64 bit processes] 2GB or 8TB (31/43 bits)
|
||||
//
|
||||
//Windows semaphores use 'long' parameters (32 bits in LLP64 data model) and
|
||||
//those values can't be negative, so we have 31 bits to store something
|
||||
//in max_count and initial count parameters.
|
||||
//Also, max count must be bigger than 0 and bigger or equal than initial count.
|
||||
if(sizeof(void*) == sizeof(boost::uint32_t)){
|
||||
//This means that for 32 bit processes, a semaphore count (31 usable bits) is
|
||||
//enough to store 4 byte aligned memory (4GB -> 32 bits - 2 bits = 30 bits).
|
||||
//The max count will hold the pointer value and current semaphore count
|
||||
//will be zero.
|
||||
//
|
||||
//Relying in UB with a cast through union, but all known windows compilers
|
||||
//accept this (C11 also accepts this).
|
||||
union caster_union
|
||||
{
|
||||
void *addr;
|
||||
boost::uint32_t addr_uint32;
|
||||
} caster;
|
||||
caster.addr = m;
|
||||
//memory is at least 4 byte aligned in windows
|
||||
BOOST_ASSERT((caster.addr_uint32 & boost::uint32_t(3)) == 0);
|
||||
max_count = caster.addr_uint32 >> 2;
|
||||
}
|
||||
else if(sizeof(void*) == sizeof(boost::uint64_t)){
|
||||
//Relying in UB with a cast through union, but all known windows compilers
|
||||
//accept this (C11 accepts this).
|
||||
union caster_union
|
||||
{
|
||||
void *addr;
|
||||
boost::uint64_t addr_uint64;
|
||||
} caster;
|
||||
caster.addr = m;
|
||||
//We'll encode the address using 30 bits in each 32 bit high and low parts.
|
||||
//High part will be the sem max count, low part will be the sem initial count.
|
||||
//(restrictions: max count > 0, initial count >= 0 and max count >= initial count):
|
||||
//
|
||||
// - Low part will be shifted two times (4 byte alignment) so that top
|
||||
// two bits are cleared (the top one for sign, the next one to
|
||||
// assure low part value is always less than the high part value.
|
||||
// - The top bit of the high part will be cleared and the next bit will be 1
|
||||
// (so high part is always bigger than low part due to the quasi-top bit).
|
||||
//
|
||||
// This means that the addresses we can store must be 4 byte aligned
|
||||
// and less than 1 ExbiBytes ( 2^60 bytes, ~1 ExaByte). User-level address space in Windows 64
|
||||
// is much less than this (8TB, 2^43 bytes): "1 EByte (or it was 640K?) ought to be enough for anybody" ;-).
|
||||
caster.addr = m;
|
||||
BOOST_ASSERT((caster.addr_uint64 & boost::uint64_t(3)) == 0);
|
||||
max_count = boost::uint32_t(caster.addr_uint64 >> 32);
|
||||
initial_count = boost::uint32_t(caster.addr_uint64);
|
||||
initial_count = initial_count/4;
|
||||
//Make sure top two bits are zero
|
||||
BOOST_ASSERT((max_count & boost::uint32_t(0xC0000000)) == 0);
|
||||
//Set quasi-top bit
|
||||
max_count |= boost::uint32_t(0x40000000);
|
||||
}
|
||||
bool created = false;
|
||||
const permissions & perm = permissions();
|
||||
std::string pid_creation_time, name;
|
||||
get_pid_creation_time_str(pid_creation_time);
|
||||
name = "bipc_gmap_sem_lock_";
|
||||
name += pid_creation_time;
|
||||
bool success = m_mtx_lock.open_or_create(name.c_str(), perm);
|
||||
name = "bipc_gmap_sem_count_";
|
||||
name += pid_creation_time;
|
||||
scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
|
||||
{
|
||||
success = success && m_sem_count.open_or_create
|
||||
( name.c_str(), static_cast<long>(0), winapi_semaphore_wrapper::MaxCount, perm, created);
|
||||
name = "bipc_gmap_sem_map_";
|
||||
name += pid_creation_time;
|
||||
success = success && m_sem_map.open_or_create
|
||||
(name.c_str(), initial_count, max_count, perm, created);
|
||||
if(!success){
|
||||
//winapi_xxx wrappers do the cleanup...
|
||||
throw int(0);
|
||||
}
|
||||
if(!created){
|
||||
delete m;
|
||||
}
|
||||
else{
|
||||
BOOST_ASSERT(&get_map_unlocked() == m);
|
||||
}
|
||||
m_sem_count.post();
|
||||
}
|
||||
}
|
||||
|
||||
map_type &get_map_unlocked()
|
||||
{
|
||||
if(sizeof(void*) == sizeof(boost::uint32_t)){
|
||||
union caster_union
|
||||
{
|
||||
void *addr;
|
||||
boost::uint32_t addr_uint32;
|
||||
} caster;
|
||||
caster.addr = 0;
|
||||
caster.addr_uint32 = m_sem_map.limit();
|
||||
caster.addr_uint32 = caster.addr_uint32 << 2;
|
||||
return *static_cast<map_type*>(caster.addr);
|
||||
}
|
||||
else{
|
||||
union caster_union
|
||||
{
|
||||
void *addr;
|
||||
boost::uint64_t addr_uint64;
|
||||
} caster;
|
||||
boost::uint32_t max_count(m_sem_map.limit()), initial_count(m_sem_map.value());
|
||||
//Clear quasi-top bit
|
||||
max_count &= boost::uint32_t(0xBFFFFFFF);
|
||||
caster.addr_uint64 = max_count;
|
||||
caster.addr_uint64 = caster.addr_uint64 << 32;
|
||||
caster.addr_uint64 |= boost::uint64_t(initial_count) << 2;
|
||||
return *static_cast<map_type*>(caster.addr);
|
||||
}
|
||||
}
|
||||
|
||||
ref_count_ptr *find(const char *name)
|
||||
{
|
||||
scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
|
||||
map_type &map = this->get_map_unlocked();
|
||||
map_type::iterator it = map.find(std::string(name));
|
||||
if(it != map.end()){
|
||||
return &it->second;
|
||||
}
|
||||
else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ref_count_ptr * insert(const char *name, const ref_count_ptr &ref)
|
||||
{
|
||||
scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
|
||||
map_type &map = this->get_map_unlocked();
|
||||
map_type::iterator it = map.insert(map_type::value_type(std::string(name), ref)).first;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
bool erase(const char *name)
|
||||
{
|
||||
scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
|
||||
map_type &map = this->get_map_unlocked();
|
||||
return map.erase(std::string(name)) != 0;
|
||||
}
|
||||
|
||||
template<class F>
|
||||
void atomic_func(F &f)
|
||||
{
|
||||
scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
|
||||
f();
|
||||
}
|
||||
|
||||
~windows_semaphore_based_map()
|
||||
{
|
||||
scoped_lock<winapi_mutex_wrapper> lck(m_mtx_lock);
|
||||
m_sem_count.wait();
|
||||
if(0 == m_sem_count.value()){
|
||||
delete &this->get_map_unlocked();
|
||||
}
|
||||
//First close sems to protect this with the external mutex
|
||||
m_sem_map.close();
|
||||
m_sem_count.close();
|
||||
//Once scoped_lock unlocks the mutex, the destructor will close the handle...
|
||||
}
|
||||
|
||||
private:
|
||||
winapi_mutex_wrapper m_mtx_lock;
|
||||
winapi_semaphore_wrapper m_sem_map;
|
||||
winapi_semaphore_wrapper m_sem_count;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct thread_safe_global_map_dependant<windows_semaphore_based_map>
|
||||
{
|
||||
static void apply_gmem_erase_logic(const char *, const char *){}
|
||||
|
||||
static bool remove_old_gmem()
|
||||
{ return true; }
|
||||
|
||||
struct lock_file_logic
|
||||
{
|
||||
lock_file_logic(windows_semaphore_based_map &)
|
||||
: retry_with_new_map(false)
|
||||
{}
|
||||
|
||||
void operator()(void){}
|
||||
bool retry() const { return retry_with_new_map; }
|
||||
private:
|
||||
const bool retry_with_new_map;
|
||||
};
|
||||
|
||||
static void construct_map(void *addr)
|
||||
{
|
||||
::new (addr)windows_semaphore_based_map;
|
||||
}
|
||||
|
||||
struct unlink_map_logic
|
||||
{
|
||||
unlink_map_logic(windows_semaphore_based_map &)
|
||||
{}
|
||||
void operator()(){}
|
||||
};
|
||||
|
||||
static ref_count_ptr *find(windows_semaphore_based_map &map, const char *name)
|
||||
{
|
||||
return map.find(name);
|
||||
}
|
||||
|
||||
static ref_count_ptr * insert(windows_semaphore_based_map &map, const char *name, const ref_count_ptr &ref)
|
||||
{
|
||||
return map.insert(name, ref);
|
||||
}
|
||||
|
||||
static bool erase(windows_semaphore_based_map &map, const char *name)
|
||||
{
|
||||
return map.erase(name);
|
||||
}
|
||||
|
||||
template<class F>
|
||||
static void atomic_func(windows_semaphore_based_map &map, F &f)
|
||||
{
|
||||
map.atomic_func(f);
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace intermodule_singleton_helpers {
|
||||
|
||||
template<typename C, bool LazyInit = true, bool Phoenix = true>
|
||||
class windows_intermodule_singleton
|
||||
: public intermodule_singleton_impl
|
||||
< C
|
||||
, LazyInit
|
||||
, Phoenix
|
||||
, intermodule_singleton_helpers::windows_semaphore_based_map
|
||||
>
|
||||
{};
|
||||
|
||||
} //namespace ipcdetail{
|
||||
} //namespace interprocess{
|
||||
} //namespace boost{
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -13,43 +13,34 @@
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
|
||||
#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32))
|
||||
|
||||
#define BOOST_INTERPROCESS_WINDOWS
|
||||
|
||||
/*
|
||||
#if !defined(_MSC_EXTENSIONS)
|
||||
#error "Turn on Microsoft language extensions (_MSC_EXTENSIONS) to be able to call Windows API functions"
|
||||
#endif
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
#define BOOST_INTERPROCESS_WINDOWS
|
||||
#define BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION
|
||||
#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
|
||||
#else
|
||||
#include <unistd.h>
|
||||
|
||||
#if ((_POSIX_THREAD_PROCESS_SHARED - 0) > 0)
|
||||
//Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it.
|
||||
//Mac Os X >= Leopard defines _POSIX_THREAD_PROCESS_SHARED but does not seems to work.
|
||||
# if !defined(__CYGWIN__) && !defined(__APPLE__)
|
||||
# define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED
|
||||
# endif
|
||||
#if defined(_POSIX_THREAD_PROCESS_SHARED) && ((_POSIX_THREAD_PROCESS_SHARED - 0) > 0)
|
||||
//Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it.
|
||||
//Mac Os X >= Leopard defines _POSIX_THREAD_PROCESS_SHARED but does not seem to work.
|
||||
#if !defined(__CYGWIN__) && !defined(__APPLE__)
|
||||
#define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ((_POSIX_BARRIERS - 0) > 0)
|
||||
# define BOOST_INTERPROCESS_POSIX_BARRIERS
|
||||
# endif
|
||||
|
||||
#if ((_POSIX_SEMAPHORES - 0) > 0)
|
||||
# define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
|
||||
# if defined(__CYGWIN__)
|
||||
#define BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK
|
||||
# endif
|
||||
#if defined(_POSIX_BARRIERS) && ((_POSIX_BARRIERS - 0) > 0)
|
||||
#define BOOST_INTERPROCESS_POSIX_BARRIERS
|
||||
#endif
|
||||
|
||||
#if defined(_POSIX_SEMAPHORES) && ((_POSIX_SEMAPHORES - 0) > 0)
|
||||
#define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
|
||||
#if defined(__CYGWIN__)
|
||||
#define BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK
|
||||
#endif
|
||||
//Some platforms have a limited (name length) named semaphore support
|
||||
#elif (defined(__FreeBSD__) && (__FreeBSD__ >= 4)) || defined(__APPLE__)
|
||||
# define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
|
||||
#endif
|
||||
#define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
|
||||
#endif
|
||||
|
||||
#if ((defined _V6_ILP32_OFFBIG) &&(_V6_ILP32_OFFBIG - 0 > 0)) ||\
|
||||
((defined _V6_LP64_OFF64) &&(_V6_LP64_OFF64 - 0 > 0)) ||\
|
||||
@@ -60,87 +51,119 @@
|
||||
((defined _FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64))||\
|
||||
((defined _FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64))
|
||||
#define BOOST_INTERPROCESS_UNIX_64_BIT_OR_BIGGER_OFF_T
|
||||
#else
|
||||
#endif
|
||||
|
||||
//Check for XSI shared memory objects. They are available in nearly all UNIX platforms
|
||||
#if !defined(__QNXNTO__) && !defined(ANDROID)
|
||||
# define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
|
||||
#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
|
||||
#endif
|
||||
|
||||
#if ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0)
|
||||
# define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
|
||||
#if defined(_POSIX_SHARED_MEMORY_OBJECTS) && ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0)
|
||||
#define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
|
||||
#else
|
||||
//VMS and MACOS don't define it but the have shm_open/close interface
|
||||
# if defined(__vms)
|
||||
# if __CRTL_VER >= 70200000
|
||||
# define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
|
||||
# endif
|
||||
//Mac OS has some non-conformant features like names limited to SHM_NAME_MAX
|
||||
# elif defined (__APPLE__)
|
||||
// # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
|
||||
// # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS_NO_GROW
|
||||
# endif
|
||||
//VMS and MACOS don't define it but they have shm_open/close interface
|
||||
#if defined(__vms)
|
||||
#if __CRTL_VER >= 70200000
|
||||
#define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
|
||||
#endif
|
||||
//Mac OS has some non-conformant features like names limited to SHM_NAME_MAX
|
||||
#elif defined (__APPLE__)
|
||||
//#define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
|
||||
//#define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS_NO_GROW
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//Now check if we have only XSI shared memory
|
||||
#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) &&\
|
||||
!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
|
||||
//# define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS_ONLY
|
||||
//#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS_ONLY
|
||||
#endif
|
||||
|
||||
#if ((_POSIX_TIMEOUTS - 0) > 0)
|
||||
# define BOOST_INTERPROCESS_POSIX_TIMEOUTS
|
||||
#endif
|
||||
|
||||
#if defined(_POSIX_TIMEOUTS) && ((_POSIX_TIMEOUTS - 0) > 0)
|
||||
#define BOOST_INTERPROCESS_POSIX_TIMEOUTS
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
|
||||
//Some systems have filesystem-based resources, so the
|
||||
//portable "/shmname" format does not work due to permission issues
|
||||
//For those systems we need to form a path to a temporary directory:
|
||||
// hp-ux tru64 vms freebsd
|
||||
#if defined(__hpux) || defined(__osf__) || defined(__vms) || (defined(__FreeBSD__) && (__FreeBSD__ < 7))
|
||||
#define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
|
||||
#if defined(__hpux) || defined(__osf__) || defined(__vms) || (defined(__FreeBSD__) && (__FreeBSD__ < 7))
|
||||
#define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
|
||||
//Some systems have "jailed" environments where shm usage is restricted at runtime
|
||||
//and temporary file file based shm is possible in those executions.
|
||||
#elif defined(__FreeBSD__)
|
||||
#define BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
|
||||
#define BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
|
||||
#if defined(__osf__) || defined(__vms)
|
||||
#define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
|
||||
#define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ((_POSIX_VERSION + 0)>= 200112L || (_XOPEN_VERSION + 0)>= 500)
|
||||
#define BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES
|
||||
#if defined(_POSIX_VERSION) && defined(_XOPEN_VERSION) && \
|
||||
(((_POSIX_VERSION + 0)>= 200112L || (_XOPEN_VERSION + 0)>= 500))
|
||||
#define BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||||
#define BOOST_INTERPROCESS_BSD_DERIVATIVE
|
||||
#include <sys/sysctl.h>
|
||||
#if defined(CTL_KERN) && defined (KERN_BOOTTIME)
|
||||
//#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
|
||||
#endif
|
||||
#endif
|
||||
#endif //!defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)\
|
||||
&& !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL)
|
||||
#define BOOST_INTERPROCESS_PERFECT_FORWARDING
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
#define BOOST_INTERPROCESS_PERFECT_FORWARDING
|
||||
#endif
|
||||
|
||||
//Now declare some Boost.Interprocess features depending on the implementation
|
||||
|
||||
#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK)
|
||||
|
||||
#define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK)
|
||||
|
||||
#define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES
|
||||
#define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES
|
||||
|
||||
#define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES
|
||||
#define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES
|
||||
#endif
|
||||
|
||||
// Timeout duration use if BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING is set
|
||||
#ifndef BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS
|
||||
#define BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS 10000
|
||||
#define BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS 10000
|
||||
#endif
|
||||
|
||||
//Other switches
|
||||
//BOOST_INTERPROCESS_MSG_QUEUE_USES_CIRC_INDEX
|
||||
//message queue uses a circular queue as index instead of an array (better performance)
|
||||
//Boost version < 1.52 uses an array, so undef this if you want to communicate
|
||||
//with processes compiled with those versions.
|
||||
#define BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX
|
||||
|
||||
//Inline attributes
|
||||
#if defined(_MSC_VER)
|
||||
#define BOOST_INTERPROCESS_ALWAYS_INLINE __forceinline
|
||||
#elif defined (__GNUC__)
|
||||
#define BOOST_INTERPROCESS_ALWAYS_INLINE __attribute__((__always_inline__))
|
||||
#else
|
||||
#define BOOST_INTERPROCESS_ALWAYS_INLINE inline
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define BOOST_INTERPROCESS_NEVER_INLINE __declspec(noinline)
|
||||
#elif defined (__GNUC__)
|
||||
#define BOOST_INTERPROCESS_NEVER_INLINE __attribute__((__noinline__))
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_NO_CXX11_NOEXCEPT)
|
||||
#if defined(BOOST_MSVC)
|
||||
#define BOOST_INTERPROCESS_NOEXCEPT throw()
|
||||
#else
|
||||
#define BOOST_INTERPROCESS_NOEXCEPT
|
||||
#endif
|
||||
#define BOOST_INTERPROCESS_NOEXCEPT_IF(x)
|
||||
#else
|
||||
#define BOOST_INTERPROCESS_NOEXCEPT noexcept
|
||||
#define BOOST_INTERPROCESS_NOEXCEPT_IF(x) noexcept(x)
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2009-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2009-2012. 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)
|
||||
//
|
||||
@@ -46,7 +46,7 @@ class xsi_shared_memory_device
|
||||
{
|
||||
/// @cond
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper)
|
||||
/// @endcond
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
|
||||
@@ -74,10 +74,10 @@ class xsi_shared_memory_device
|
||||
{ this->swap(moved); }
|
||||
|
||||
xsi_shared_memory_device &operator=(BOOST_RV_REF(xsi_shared_memory_device) moved)
|
||||
{
|
||||
{
|
||||
xsi_shared_memory_device tmp(boost::move(moved));
|
||||
this->swap(tmp);
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Swaps two xsi_shared_memory_device. Does not throw
|
||||
@@ -168,7 +168,7 @@ inline xsi_shared_memory_device::xsi_shared_memory_device()
|
||||
: m_shm(), m_mode(invalid_mode), m_name()
|
||||
{}
|
||||
|
||||
inline xsi_shared_memory_device::~xsi_shared_memory_device()
|
||||
inline xsi_shared_memory_device::~xsi_shared_memory_device()
|
||||
{}
|
||||
|
||||
inline const char *xsi_shared_memory_device::get_name() const
|
||||
@@ -178,7 +178,7 @@ inline void xsi_shared_memory_device::swap(xsi_shared_memory_device &other)
|
||||
{
|
||||
m_shm.swap(other.m_shm);
|
||||
std::swap(m_mode, other.m_mode);
|
||||
m_name.swap(other.m_name);
|
||||
m_name.swap(other.m_name);
|
||||
}
|
||||
|
||||
inline mapping_handle_t xsi_shared_memory_device::get_mapping_handle() const
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2009-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2009-2012. 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)
|
||||
//
|
||||
@@ -40,7 +40,7 @@ class xsi_shared_memory_file_wrapper
|
||||
{
|
||||
/// @cond
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper)
|
||||
/// @endcond
|
||||
/// @endcond
|
||||
public:
|
||||
|
||||
xsi_shared_memory_file_wrapper() : xsi_shared_memory() {}
|
||||
@@ -61,10 +61,10 @@ class xsi_shared_memory_file_wrapper
|
||||
{ this->swap(moved); }
|
||||
|
||||
xsi_shared_memory_file_wrapper &operator=(BOOST_RV_REF(xsi_shared_memory_file_wrapper) moved)
|
||||
{
|
||||
{
|
||||
xsi_shared_memory_file_wrapper tmp(boost::move(moved));
|
||||
this->swap(tmp);
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Swaps two xsi_shared_memory_file_wrapper. Does not throw
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -11,7 +11,7 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002 Beman Dawes
|
||||
// Copyright (C) 2001 Dietmar Kuehl
|
||||
// Copyright (C) 2001 Dietmar Kuehl
|
||||
// Use, modification, and distribution is subject to 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)
|
||||
@@ -64,16 +64,16 @@ inline int system_error_code() // artifact of POSIX and WINDOWS error reporting
|
||||
inline void fill_system_message(int sys_err_code, std::string &str)
|
||||
{
|
||||
void *lpMsgBuf;
|
||||
winapi::format_message(
|
||||
winapi::format_message_allocate_buffer |
|
||||
winapi::format_message_from_system |
|
||||
winapi::format_message(
|
||||
winapi::format_message_allocate_buffer |
|
||||
winapi::format_message_from_system |
|
||||
winapi::format_message_ignore_inserts,
|
||||
0,
|
||||
sys_err_code,
|
||||
winapi::make_lang_id(winapi::lang_neutral, winapi::sublang_default), // Default language
|
||||
reinterpret_cast<char *>(&lpMsgBuf),
|
||||
0,
|
||||
0
|
||||
0
|
||||
);
|
||||
str += static_cast<const char*>(lpMsgBuf);
|
||||
winapi::local_free( lpMsgBuf ); // free the buffer
|
||||
@@ -123,7 +123,7 @@ typedef int native_error_t;
|
||||
struct ec_xlate
|
||||
{
|
||||
native_error_t sys_ec;
|
||||
error_code_t ec;
|
||||
error_code_t ec;
|
||||
};
|
||||
|
||||
static const ec_xlate ec_table[] =
|
||||
@@ -183,9 +183,9 @@ static const ec_xlate ec_table[] =
|
||||
};
|
||||
|
||||
inline error_code_t lookup_error(native_error_t err)
|
||||
{
|
||||
{
|
||||
const ec_xlate *cur = &ec_table[0],
|
||||
*end = cur + sizeof(ec_table)/sizeof(ec_xlate);
|
||||
*end = cur + sizeof(ec_table)/sizeof(ec_xlate);
|
||||
for (;cur != end; ++cur ){
|
||||
if ( err == cur->sys_ec ) return cur->ec;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -41,27 +41,27 @@ class file_mapping
|
||||
//!Does not throw
|
||||
file_mapping();
|
||||
|
||||
//!Opens a file mapping of file "filename", starting in offset
|
||||
//!"file_offset", and the mapping's size will be "size". The mapping
|
||||
//!Opens a file mapping of file "filename", starting in offset
|
||||
//!"file_offset", and the mapping's size will be "size". The mapping
|
||||
//!can be opened for read-only "read_only" or read-write "read_write"
|
||||
//!modes. Throws interprocess_exception on error.
|
||||
file_mapping(const char *filename, mode_t mode);
|
||||
|
||||
//!Moves the ownership of "moved"'s file mapping object to *this.
|
||||
//!After the call, "moved" does not represent any file mapping object.
|
||||
//!Moves the ownership of "moved"'s file mapping object to *this.
|
||||
//!After the call, "moved" does not represent any file mapping object.
|
||||
//!Does not throw
|
||||
file_mapping(BOOST_RV_REF(file_mapping) moved)
|
||||
: m_handle(file_handle_t(ipcdetail::invalid_file()))
|
||||
{ this->swap(moved); }
|
||||
|
||||
//!Moves the ownership of "moved"'s file mapping to *this.
|
||||
//!After the call, "moved" does not represent any file mapping.
|
||||
//!After the call, "moved" does not represent any file mapping.
|
||||
//!Does not throw
|
||||
file_mapping &operator=(BOOST_RV_REF(file_mapping) moved)
|
||||
{
|
||||
file_mapping tmp(boost::move(moved));
|
||||
this->swap(tmp);
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Swaps to file_mappings.
|
||||
@@ -100,21 +100,21 @@ class file_mapping
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
inline file_mapping::file_mapping()
|
||||
inline file_mapping::file_mapping()
|
||||
: m_handle(file_handle_t(ipcdetail::invalid_file()))
|
||||
{}
|
||||
|
||||
inline file_mapping::~file_mapping()
|
||||
inline file_mapping::~file_mapping()
|
||||
{ this->priv_close(); }
|
||||
|
||||
inline const char *file_mapping::get_name() const
|
||||
{ return m_filename.c_str(); }
|
||||
|
||||
inline void file_mapping::swap(file_mapping &other)
|
||||
{
|
||||
{
|
||||
std::swap(m_handle, other.m_handle);
|
||||
std::swap(m_mode, other.m_mode);
|
||||
m_filename.swap(other.m_filename);
|
||||
m_filename.swap(other.m_filename);
|
||||
}
|
||||
|
||||
inline mapping_handle_t file_mapping::get_mapping_handle() const
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -34,17 +34,17 @@ namespace interprocess {
|
||||
template <class MapConfig>
|
||||
struct iset_index_aux
|
||||
{
|
||||
typedef typename
|
||||
typedef typename
|
||||
MapConfig::segment_manager_base segment_manager_base;
|
||||
|
||||
typedef typename
|
||||
typedef typename
|
||||
segment_manager_base::void_pointer void_pointer;
|
||||
typedef typename bi::make_set_base_hook
|
||||
< bi::void_pointer<void_pointer>
|
||||
, bi::optimize_size<true>
|
||||
>::type derivation_hook;
|
||||
|
||||
typedef typename MapConfig::template
|
||||
typedef typename MapConfig::template
|
||||
intrusive_value_type<derivation_hook>::type value_type;
|
||||
typedef std::less<value_type> value_compare;
|
||||
typedef typename bi::make_set
|
||||
@@ -82,20 +82,20 @@ class iset_index
|
||||
struct intrusive_key_value_less
|
||||
{
|
||||
bool operator()(const intrusive_compare_key_type &i, const value_type &b) const
|
||||
{
|
||||
{
|
||||
std::size_t blen = b.name_length();
|
||||
return (i.m_len < blen) ||
|
||||
(i.m_len == blen &&
|
||||
std::char_traits<char_type>::compare
|
||||
return (i.m_len < blen) ||
|
||||
(i.m_len == blen &&
|
||||
std::char_traits<char_type>::compare
|
||||
(i.mp_str, b.name(), i.m_len) < 0);
|
||||
}
|
||||
|
||||
bool operator()(const value_type &b, const intrusive_compare_key_type &i) const
|
||||
{
|
||||
{
|
||||
std::size_t blen = b.name_length();
|
||||
return (blen < i.m_len) ||
|
||||
return (blen < i.m_len) ||
|
||||
(blen == i.m_len &&
|
||||
std::char_traits<char_type>::compare
|
||||
std::char_traits<char_type>::compare
|
||||
(b.name(), i.mp_str, i.m_len) < 0);
|
||||
}
|
||||
};
|
||||
@@ -143,7 +143,7 @@ struct is_intrusive_index
|
||||
/// @endcond
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost
|
||||
} //namespace boost
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -35,17 +35,17 @@ namespace boost { namespace interprocess {
|
||||
template <class MapConfig>
|
||||
struct iunordered_set_index_aux
|
||||
{
|
||||
typedef typename
|
||||
typedef typename
|
||||
MapConfig::segment_manager_base segment_manager_base;
|
||||
|
||||
typedef typename
|
||||
typedef typename
|
||||
segment_manager_base::void_pointer void_pointer;
|
||||
|
||||
typedef typename bi::make_unordered_set_base_hook
|
||||
< bi::void_pointer<void_pointer>
|
||||
>::type derivation_hook;
|
||||
|
||||
typedef typename MapConfig::template
|
||||
typedef typename MapConfig::template
|
||||
intrusive_value_type<derivation_hook>::type value_type;
|
||||
|
||||
typedef typename MapConfig::
|
||||
@@ -58,23 +58,23 @@ struct iunordered_set_index_aux
|
||||
struct equal_function
|
||||
{
|
||||
bool operator()(const intrusive_compare_key_type &i, const value_type &b) const
|
||||
{
|
||||
{
|
||||
return (i.m_len == b.name_length()) &&
|
||||
(std::char_traits<char_type>::compare
|
||||
(std::char_traits<char_type>::compare
|
||||
(i.mp_str, b.name(), i.m_len) == 0);
|
||||
}
|
||||
|
||||
bool operator()(const value_type &b, const intrusive_compare_key_type &i) const
|
||||
{
|
||||
{
|
||||
return (i.m_len == b.name_length()) &&
|
||||
(std::char_traits<char_type>::compare
|
||||
(std::char_traits<char_type>::compare
|
||||
(i.mp_str, b.name(), i.m_len) == 0);
|
||||
}
|
||||
|
||||
bool operator()(const value_type &b1, const value_type &b2) const
|
||||
{
|
||||
{
|
||||
return (b1.name_length() == b2.name_length()) &&
|
||||
(std::char_traits<char_type>::compare
|
||||
(std::char_traits<char_type>::compare
|
||||
(b1.name(), b2.name(), b1.name_length()) == 0);
|
||||
}
|
||||
};
|
||||
@@ -119,7 +119,7 @@ struct iunordered_set_index_aux
|
||||
/// @endcond
|
||||
|
||||
//!Index type based in boost::intrusive::set.
|
||||
//!Just derives from boost::intrusive::set
|
||||
//!Just derives from boost::intrusive::set
|
||||
//!and defines the interface needed by managed memory segments
|
||||
template <class MapConfig>
|
||||
class iunordered_set_index
|
||||
@@ -135,9 +135,9 @@ class iunordered_set_index
|
||||
typedef typename index_aux::equal_function equal_function;
|
||||
typedef typename index_aux::hash_function hash_function;
|
||||
typedef typename MapConfig::char_type char_type;
|
||||
typedef typename
|
||||
typedef typename
|
||||
iunordered_set_index_aux<MapConfig>::allocator_type allocator_type;
|
||||
typedef typename
|
||||
typedef typename
|
||||
iunordered_set_index_aux<MapConfig>::allocator_holder allocator_holder;
|
||||
/// @endcond
|
||||
|
||||
@@ -190,7 +190,7 @@ class iunordered_set_index
|
||||
|
||||
bucket_ptr shunk_p = alloc.allocation_command
|
||||
(boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_size, received_size, received_size, buckets).first;
|
||||
BOOST_ASSERT(buckets == shunk_p);
|
||||
BOOST_ASSERT(buckets == shunk_p); (void)shunk_p;
|
||||
|
||||
bucket_ptr buckets_init = buckets + received_size;
|
||||
for(size_type i = 0; i < (old_size - received_size); ++i){
|
||||
@@ -290,7 +290,7 @@ class iunordered_set_index
|
||||
size_type cur_size = this->size();
|
||||
size_type cur_count = this->bucket_count();
|
||||
bucket_ptr old_p = this->bucket_pointer();
|
||||
|
||||
|
||||
if(!this->size() && old_p != bucket_ptr(&this->init_bucket)){
|
||||
this->rehash(bucket_traits(bucket_ptr(&this->init_bucket), 1));
|
||||
destroy_buckets(this->alloc, old_p, cur_count);
|
||||
@@ -337,7 +337,7 @@ class iunordered_set_index
|
||||
//Strong guarantee: if something goes wrong
|
||||
//we should remove the insertion.
|
||||
//
|
||||
//We can use the iterator because the hash function
|
||||
//We can use the iterator because the hash function
|
||||
//can't throw and this means that "reserve" will
|
||||
//throw only because of the memory allocation:
|
||||
//the iterator has not been invalidated.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -48,7 +48,7 @@ struct map_index_aux
|
||||
|
||||
} //namespace ipcdetail {
|
||||
|
||||
//!Index type based in boost::interprocess::map. Just derives from boost::interprocess::map
|
||||
//!Index type based in boost::interprocess::map. Just derives from boost::interprocess::map
|
||||
//!and defines the interface needed by managed memory segments
|
||||
template <class MapConfig>
|
||||
class map_index
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <boost/interprocess/offset_ptr.hpp>
|
||||
|
||||
//!\file
|
||||
//!Describes a null index adaptor, so that if we don't want to construct
|
||||
//!Describes a null index adaptor, so that if we don't want to construct
|
||||
//!named objects, we can use this null index type to save resources.
|
||||
|
||||
namespace boost {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -69,7 +69,7 @@ class unordered_map_index
|
||||
/// @cond
|
||||
typedef unordered_map_index_aux<MapConfig> index_aux;
|
||||
typedef typename index_aux::index_t base_type;
|
||||
typedef typename
|
||||
typedef typename
|
||||
MapConfig::segment_manager_base segment_manager_base;
|
||||
/// @endcond
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -214,7 +214,7 @@ template <class CharType
|
||||
,template<class IndexConfig> class IndexType>
|
||||
class basic_managed_shared_memory;
|
||||
|
||||
typedef basic_managed_shared_memory
|
||||
typedef basic_managed_shared_memory
|
||||
<char
|
||||
,rbtree_best_fit<mutex_family>
|
||||
,iset_index>
|
||||
@@ -238,7 +238,7 @@ template <class CharType
|
||||
,template<class IndexConfig> class IndexType>
|
||||
class basic_managed_windows_shared_memory;
|
||||
|
||||
typedef basic_managed_windows_shared_memory
|
||||
typedef basic_managed_windows_shared_memory
|
||||
<char
|
||||
,rbtree_best_fit<mutex_family>
|
||||
,iset_index>
|
||||
@@ -259,7 +259,7 @@ template <class CharType
|
||||
,template<class IndexConfig> class IndexType>
|
||||
class basic_managed_xsi_shared_memory;
|
||||
|
||||
typedef basic_managed_xsi_shared_memory
|
||||
typedef basic_managed_xsi_shared_memory
|
||||
<char
|
||||
,rbtree_best_fit<mutex_family>
|
||||
,iset_index>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -42,6 +42,12 @@
|
||||
|
||||
namespace boost{ namespace interprocess{
|
||||
|
||||
namespace ipcdetail
|
||||
{
|
||||
template<class VoidPointer>
|
||||
class msg_queue_initialization_func_t;
|
||||
}
|
||||
|
||||
//!A class that allows sending messages
|
||||
//!between processes.
|
||||
template<class VoidPointer>
|
||||
@@ -66,24 +72,24 @@ class message_queue_t
|
||||
//!the maximum number of messages will be "max_num_msg" and the maximum message size
|
||||
//!will be "max_msg_size". Throws on error and if the queue was previously created.
|
||||
message_queue_t(create_only_t create_only,
|
||||
const char *name,
|
||||
size_type max_num_msg,
|
||||
const char *name,
|
||||
size_type max_num_msg,
|
||||
size_type max_msg_size,
|
||||
const permissions &perm = permissions());
|
||||
|
||||
//!Opens or creates a process shared message queue with name "name".
|
||||
//!If the queue is created, the maximum number of messages will be "max_num_msg"
|
||||
//!and the maximum message size will be "max_msg_size". If queue was previously
|
||||
//!Opens or creates a process shared message queue with name "name".
|
||||
//!If the queue is created, the maximum number of messages will be "max_num_msg"
|
||||
//!and the maximum message size will be "max_msg_size". If queue was previously
|
||||
//!created the queue will be opened and "max_num_msg" and "max_msg_size" parameters
|
||||
//!are ignored. Throws on error.
|
||||
message_queue_t(open_or_create_t open_or_create,
|
||||
const char *name,
|
||||
size_type max_num_msg,
|
||||
const char *name,
|
||||
size_type max_num_msg,
|
||||
size_type max_msg_size,
|
||||
const permissions &perm = permissions());
|
||||
|
||||
//!Opens a previously created process shared message queue with name "name".
|
||||
//!If the queue was not previously created or there are no free resources,
|
||||
//!Opens a previously created process shared message queue with name "name".
|
||||
//!If the queue was not previously created or there are no free resources,
|
||||
//!throws an error.
|
||||
message_queue_t(open_only_t open_only,
|
||||
const char *name);
|
||||
@@ -95,65 +101,65 @@ class message_queue_t
|
||||
//!this resource. The resource can still be opened again calling
|
||||
//!the open constructor overload. To erase the message queue from the system
|
||||
//!use remove().
|
||||
~message_queue_t();
|
||||
~message_queue_t();
|
||||
|
||||
//!Sends a message stored in buffer "buffer" with size "buffer_size" in the
|
||||
//!Sends a message stored in buffer "buffer" with size "buffer_size" in the
|
||||
//!message queue with priority "priority". If the message queue is full
|
||||
//!the sender is blocked. Throws interprocess_error on error.*/
|
||||
void send (const void *buffer, size_type buffer_size,
|
||||
//!the sender is blocked. Throws interprocess_error on error.
|
||||
void send (const void *buffer, size_type buffer_size,
|
||||
unsigned int priority);
|
||||
|
||||
//!Sends a message stored in buffer "buffer" with size "buffer_size" through the
|
||||
//!Sends a message stored in buffer "buffer" with size "buffer_size" through the
|
||||
//!message queue with priority "priority". If the message queue is full
|
||||
//!the sender is not blocked and returns false, otherwise returns true.
|
||||
//!Throws interprocess_error on error.
|
||||
bool try_send (const void *buffer, size_type buffer_size,
|
||||
bool try_send (const void *buffer, size_type buffer_size,
|
||||
unsigned int priority);
|
||||
|
||||
//!Sends a message stored in buffer "buffer" with size "buffer_size" in the
|
||||
//!Sends a message stored in buffer "buffer" with size "buffer_size" in the
|
||||
//!message queue with priority "priority". If the message queue is full
|
||||
//!the sender retries until time "abs_time" is reached. Returns true if
|
||||
//!the message has been successfully sent. Returns false if timeout is reached.
|
||||
//!Throws interprocess_error on error.
|
||||
bool timed_send (const void *buffer, size_type buffer_size,
|
||||
bool timed_send (const void *buffer, size_type buffer_size,
|
||||
unsigned int priority, const boost::posix_time::ptime& abs_time);
|
||||
|
||||
//!Receives a message from the message queue. The message is stored in buffer
|
||||
//!"buffer", which has size "buffer_size". The received message has size
|
||||
//!Receives a message from the message queue. The message is stored in buffer
|
||||
//!"buffer", which has size "buffer_size". The received message has size
|
||||
//!"recvd_size" and priority "priority". If the message queue is empty
|
||||
//!the receiver is blocked. Throws interprocess_error on error.
|
||||
void receive (void *buffer, size_type buffer_size,
|
||||
void receive (void *buffer, size_type buffer_size,
|
||||
size_type &recvd_size,unsigned int &priority);
|
||||
|
||||
//!Receives a message from the message queue. The message is stored in buffer
|
||||
//!"buffer", which has size "buffer_size". The received message has size
|
||||
//!Receives a message from the message queue. The message is stored in buffer
|
||||
//!"buffer", which has size "buffer_size". The received message has size
|
||||
//!"recvd_size" and priority "priority". If the message queue is empty
|
||||
//!the receiver is not blocked and returns false, otherwise returns true.
|
||||
//!Throws interprocess_error on error.
|
||||
bool try_receive (void *buffer, size_type buffer_size,
|
||||
bool try_receive (void *buffer, size_type buffer_size,
|
||||
size_type &recvd_size,unsigned int &priority);
|
||||
|
||||
//!Receives a message from the message queue. The message is stored in buffer
|
||||
//!"buffer", which has size "buffer_size". The received message has size
|
||||
//!Receives a message from the message queue. The message is stored in buffer
|
||||
//!"buffer", which has size "buffer_size". The received message has size
|
||||
//!"recvd_size" and priority "priority". If the message queue is empty
|
||||
//!the receiver retries until time "abs_time" is reached. Returns true if
|
||||
//!the message has been successfully sent. Returns false if timeout is reached.
|
||||
//!Throws interprocess_error on error.
|
||||
bool timed_receive (void *buffer, size_type buffer_size,
|
||||
bool timed_receive (void *buffer, size_type buffer_size,
|
||||
size_type &recvd_size,unsigned int &priority,
|
||||
const boost::posix_time::ptime &abs_time);
|
||||
|
||||
//!Returns the maximum number of messages allowed by the queue. The message
|
||||
//!queue must be opened or created previously. Otherwise, returns 0.
|
||||
//!queue must be opened or created previously. Otherwise, returns 0.
|
||||
//!Never throws
|
||||
size_type get_max_msg() const;
|
||||
|
||||
//!Returns the maximum size of message allowed by the queue. The message
|
||||
//!queue must be opened or created previously. Otherwise, returns 0.
|
||||
//!queue must be opened or created previously. Otherwise, returns 0.
|
||||
//!Never throws
|
||||
size_type get_max_msg_size() const;
|
||||
|
||||
//!Returns the number of messages currently stored.
|
||||
//!Returns the number of messages currently stored.
|
||||
//!Never throws
|
||||
size_type get_num_msg();
|
||||
|
||||
@@ -161,23 +167,26 @@ class message_queue_t
|
||||
//!Returns false on error. Never throws
|
||||
static bool remove(const char *name);
|
||||
|
||||
/// @cond
|
||||
/// @cond
|
||||
private:
|
||||
typedef boost::posix_time::ptime ptime;
|
||||
|
||||
friend class ipcdetail::msg_queue_initialization_func_t<VoidPointer>;
|
||||
|
||||
bool do_receive(block_t block,
|
||||
void *buffer, size_type buffer_size,
|
||||
void *buffer, size_type buffer_size,
|
||||
size_type &recvd_size, unsigned int &priority,
|
||||
const ptime &abs_time);
|
||||
|
||||
bool do_send(block_t block,
|
||||
const void *buffer, size_type buffer_size,
|
||||
const void *buffer, size_type buffer_size,
|
||||
unsigned int priority, const ptime &abs_time);
|
||||
|
||||
//!Returns the needed memory size for the shared message queue.
|
||||
//!Never throws
|
||||
static size_type get_mem_size(size_type max_msg_size, size_type max_num_msg);
|
||||
|
||||
ipcdetail::managed_open_or_create_impl<shared_memory_object> m_shmem;
|
||||
typedef ipcdetail::managed_open_or_create_impl<shared_memory_object, 0, true, false> open_create_impl_t;
|
||||
open_create_impl_t m_shmem;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
@@ -187,7 +196,7 @@ namespace ipcdetail {
|
||||
|
||||
//!This header is the prefix of each message in the queue
|
||||
template<class VoidPointer>
|
||||
class msg_hdr_t
|
||||
class msg_hdr_t
|
||||
{
|
||||
typedef VoidPointer void_pointer;
|
||||
typedef typename boost::intrusive::
|
||||
@@ -212,36 +221,55 @@ class priority_functor
|
||||
rebind_pointer<msg_hdr_t<VoidPointer> >::type msg_hdr_ptr_t;
|
||||
|
||||
public:
|
||||
bool operator()(const msg_hdr_ptr_t &msg1,
|
||||
bool operator()(const msg_hdr_ptr_t &msg1,
|
||||
const msg_hdr_ptr_t &msg2) const
|
||||
{ return msg1->priority < msg2->priority; }
|
||||
};
|
||||
|
||||
//!This header is placed in the beginning of the shared memory and contains
|
||||
//!the data to control the queue. This class initializes the shared memory
|
||||
//!This header is placed in the beginning of the shared memory and contains
|
||||
//!the data to control the queue. This class initializes the shared memory
|
||||
//!in the following way: in ascending memory address with proper alignment
|
||||
//!fillings:
|
||||
//!
|
||||
//!-> mq_hdr_t:
|
||||
//!-> mq_hdr_t:
|
||||
//! Main control block that controls the rest of the elements
|
||||
//!
|
||||
//!-> offset_ptr<msg_hdr_t> index [max_num_msg]
|
||||
//! An array of pointers with size "max_num_msg" called index. Each pointer
|
||||
//! points to a preallocated message. The elements of this array are
|
||||
//! An array of pointers with size "max_num_msg" called index. Each pointer
|
||||
//! points to a preallocated message. Elements of this array are
|
||||
//! reordered in runtime in the following way:
|
||||
//!
|
||||
//! When the current number of messages is "cur_num_msg", the first
|
||||
//! IF BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX is defined:
|
||||
//!
|
||||
//! When the current number of messages is "cur_num_msg", the array
|
||||
//! is treated like a circular buffer. Starting from position "cur_first_msg"
|
||||
//! "cur_num_msg" in a circular way, pointers point to inserted messages and the rest
|
||||
//! point to free messages. Those "cur_num_msg" pointers are
|
||||
//! ordered by the priority of the pointed message and by insertion order
|
||||
//! if two messages have the same priority. So the next message to be
|
||||
//! used in a "receive" is pointed by index [(cur_first_msg + cur_num_msg-1)%max_num_msg]
|
||||
//! and the first free message ready to be used in a "send" operation is
|
||||
//! [cur_first_msg] if circular buffer is extended from front,
|
||||
//! [(cur_first_msg + cur_num_msg)%max_num_msg] otherwise.
|
||||
//!
|
||||
//! This transforms the index in a circular buffer with an embedded free
|
||||
//! message queue.
|
||||
//!
|
||||
//! ELSE (BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX is NOT defined):
|
||||
//!
|
||||
//! When the current number of messages is "cur_num_msg", the first
|
||||
//! "cur_num_msg" pointers point to inserted messages and the rest
|
||||
//! point to free messages. The first "cur_num_msg" pointers are
|
||||
//! ordered by the priority of the pointed message and by insertion order
|
||||
//! if two messages have the same priority. So the next message to be
|
||||
//! ordered by the priority of the pointed message and by insertion order
|
||||
//! if two messages have the same priority. So the next message to be
|
||||
//! used in a "receive" is pointed by index [cur_num_msg-1] and the first free
|
||||
//! message ready to be used in a "send" operation is index [cur_num_msg].
|
||||
//! This transforms index in a fixed size priority queue with an embedded free
|
||||
//!
|
||||
//! This transforms the index in a fixed size priority queue with an embedded free
|
||||
//! message queue.
|
||||
//!
|
||||
//!-> struct message_t
|
||||
//! {
|
||||
//! {
|
||||
//! msg_hdr_t header;
|
||||
//! char[max_msg_size] data;
|
||||
//! } messages [max_num_msg];
|
||||
@@ -252,7 +280,7 @@ class priority_functor
|
||||
template<class VoidPointer>
|
||||
class mq_hdr_t
|
||||
: public ipcdetail::priority_functor<VoidPointer>
|
||||
{
|
||||
{
|
||||
typedef VoidPointer void_pointer;
|
||||
typedef msg_hdr_t<void_pointer> msg_header;
|
||||
typedef typename boost::intrusive::
|
||||
@@ -264,22 +292,22 @@ class mq_hdr_t
|
||||
typedef typename boost::intrusive::
|
||||
pointer_traits<void_pointer>::template
|
||||
rebind_pointer<msg_hdr_ptr_t>::type msg_hdr_ptr_ptr_t;
|
||||
typedef ipcdetail::managed_open_or_create_impl<shared_memory_object, 0, true, false> open_create_impl_t;
|
||||
|
||||
public:
|
||||
//!Constructor. This object must be constructed in the beginning of the
|
||||
//!Constructor. This object must be constructed in the beginning of the
|
||||
//!shared memory of the size returned by the function "get_mem_size".
|
||||
//!This constructor initializes the needed resources and creates
|
||||
//!the internal structures like the priority index. This can throw.*/
|
||||
//!the internal structures like the priority index. This can throw.
|
||||
mq_hdr_t(size_type max_num_msg, size_type max_msg_size)
|
||||
: m_max_num_msg(max_num_msg),
|
||||
: m_max_num_msg(max_num_msg),
|
||||
m_max_msg_size(max_msg_size),
|
||||
m_cur_num_msg(0)
|
||||
#if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX)
|
||||
,m_cur_first_msg(0u)
|
||||
#endif
|
||||
{ this->initialize_memory(); }
|
||||
|
||||
//!Returns the inserted message with top priority
|
||||
msg_header * top_msg()
|
||||
{ return mp_index[m_cur_num_msg-1].get(); }
|
||||
|
||||
//!Returns true if the message queue is full
|
||||
bool is_full() const
|
||||
{ return m_cur_num_msg == m_max_num_msg; }
|
||||
@@ -292,51 +320,223 @@ class mq_hdr_t
|
||||
void free_top_msg()
|
||||
{ --m_cur_num_msg; }
|
||||
|
||||
//!Returns the first free msg of the free message queue
|
||||
msg_header * free_msg()
|
||||
{ return mp_index[m_cur_num_msg].get(); }
|
||||
#if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX)
|
||||
|
||||
//!Inserts the first free message in the priority queue
|
||||
void queue_free_msg()
|
||||
{
|
||||
//Get free msg
|
||||
msg_hdr_ptr_t free = mp_index[m_cur_num_msg];
|
||||
//Get priority queue's range
|
||||
msg_hdr_ptr_t *it = &mp_index[0], *it_end = &mp_index[m_cur_num_msg];
|
||||
//Check where the free message should be placed
|
||||
it = std::lower_bound(it, it_end, free, static_cast<priority_functor<VoidPointer>&>(*this));
|
||||
//Make room in that position
|
||||
std::copy_backward(it, it_end, it_end+1);
|
||||
//Insert the free message in the correct position
|
||||
*it = free;
|
||||
++m_cur_num_msg;
|
||||
typedef msg_hdr_ptr_t *iterator;
|
||||
|
||||
size_type end_pos() const
|
||||
{
|
||||
const size_type space_until_bufend = m_max_num_msg - m_cur_first_msg;
|
||||
return space_until_bufend > m_cur_num_msg
|
||||
? m_cur_first_msg + m_cur_num_msg : m_cur_num_msg - space_until_bufend;
|
||||
}
|
||||
|
||||
//!Returns the number of bytes needed to construct a message queue with
|
||||
//!"max_num_size" maximum number of messages and "max_msg_size" maximum
|
||||
//!Returns the inserted message with top priority
|
||||
msg_header &top_msg()
|
||||
{
|
||||
size_type pos = this->end_pos();
|
||||
return *mp_index[pos ? --pos : m_max_num_msg - 1];
|
||||
}
|
||||
|
||||
//!Returns the inserted message with bottom priority
|
||||
msg_header &bottom_msg()
|
||||
{ return *mp_index[m_cur_first_msg]; }
|
||||
|
||||
iterator inserted_ptr_begin() const
|
||||
{ return &mp_index[m_cur_first_msg]; }
|
||||
|
||||
iterator inserted_ptr_end() const
|
||||
{ return &mp_index[this->end_pos()]; }
|
||||
|
||||
iterator lower_bound(const msg_hdr_ptr_t & value, priority_functor<VoidPointer> func)
|
||||
{
|
||||
iterator begin(this->inserted_ptr_begin()), end(this->inserted_ptr_end());
|
||||
if(end < begin){
|
||||
iterator idx_end = &mp_index[m_max_num_msg];
|
||||
iterator ret = std::lower_bound(begin, idx_end, value, func);
|
||||
if(idx_end == ret){
|
||||
iterator idx_beg = &mp_index[0];
|
||||
ret = std::lower_bound(idx_beg, end, value, func);
|
||||
//sanity check, these cases should not call lower_bound (optimized out)
|
||||
assert(ret != end);
|
||||
assert(ret != begin);
|
||||
return ret;
|
||||
}
|
||||
else{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else{
|
||||
return std::lower_bound(begin, end, value, func);
|
||||
}
|
||||
}
|
||||
|
||||
msg_header & insert_at(iterator where)
|
||||
{
|
||||
iterator it_inserted_ptr_end = this->inserted_ptr_end();
|
||||
iterator it_inserted_ptr_beg = this->inserted_ptr_begin();
|
||||
if(where == it_inserted_ptr_end){
|
||||
++m_cur_num_msg;
|
||||
return **it_inserted_ptr_end;
|
||||
}
|
||||
else if(where == it_inserted_ptr_beg){
|
||||
//unsigned integer guarantees underflow
|
||||
m_cur_first_msg = m_cur_first_msg ? m_cur_first_msg : m_max_num_msg;
|
||||
--m_cur_first_msg;
|
||||
++m_cur_num_msg;
|
||||
return *mp_index[m_cur_first_msg];
|
||||
}
|
||||
else{
|
||||
size_type pos = where - &mp_index[0];
|
||||
size_type circ_pos = pos >= m_cur_first_msg ? pos - m_cur_first_msg : pos + (m_max_num_msg - m_cur_first_msg);
|
||||
//Check if it's more efficient to move back or move front
|
||||
if(circ_pos < m_cur_num_msg/2){
|
||||
//The queue can't be full so m_cur_num_msg == 0 or m_cur_num_msg <= pos
|
||||
//indicates two step insertion
|
||||
if(!pos){
|
||||
pos = m_max_num_msg;
|
||||
where = &mp_index[m_max_num_msg-1];
|
||||
}
|
||||
else{
|
||||
--where;
|
||||
}
|
||||
const bool unique_segment = m_cur_first_msg && m_cur_first_msg <= pos;
|
||||
const size_type first_segment_beg = unique_segment ? m_cur_first_msg : 1u;
|
||||
const size_type first_segment_end = pos;
|
||||
const size_type second_segment_beg = unique_segment || !m_cur_first_msg ? m_max_num_msg : m_cur_first_msg;
|
||||
const size_type second_segment_end = m_max_num_msg;
|
||||
const msg_hdr_ptr_t backup = *(&mp_index[0] + (unique_segment ? first_segment_beg : second_segment_beg) - 1);
|
||||
|
||||
//First segment
|
||||
if(!unique_segment){
|
||||
std::copy( &mp_index[0] + second_segment_beg
|
||||
, &mp_index[0] + second_segment_end
|
||||
, &mp_index[0] + second_segment_beg - 1);
|
||||
mp_index[m_max_num_msg-1] = mp_index[0];
|
||||
}
|
||||
std::copy( &mp_index[0] + first_segment_beg
|
||||
, &mp_index[0] + first_segment_end
|
||||
, &mp_index[0] + first_segment_beg - 1);
|
||||
*where = backup;
|
||||
m_cur_first_msg = m_cur_first_msg ? m_cur_first_msg : m_max_num_msg;
|
||||
--m_cur_first_msg;
|
||||
++m_cur_num_msg;
|
||||
return **where;
|
||||
}
|
||||
else{
|
||||
//The queue can't be full so end_pos < m_cur_first_msg
|
||||
//indicates two step insertion
|
||||
const size_type pos_end = this->end_pos();
|
||||
const bool unique_segment = pos < pos_end;
|
||||
const size_type first_segment_beg = pos;
|
||||
const size_type first_segment_end = unique_segment ? pos_end : m_max_num_msg-1;
|
||||
const size_type second_segment_beg = 0u;
|
||||
const size_type second_segment_end = unique_segment ? 0u : pos_end;
|
||||
const msg_hdr_ptr_t backup = *it_inserted_ptr_end;
|
||||
|
||||
//First segment
|
||||
if(!unique_segment){
|
||||
std::copy_backward( &mp_index[0] + second_segment_beg
|
||||
, &mp_index[0] + second_segment_end
|
||||
, &mp_index[0] + second_segment_end + 1);
|
||||
mp_index[0] = mp_index[m_max_num_msg-1];
|
||||
}
|
||||
std::copy_backward( &mp_index[0] + first_segment_beg
|
||||
, &mp_index[0] + first_segment_end
|
||||
, &mp_index[0] + first_segment_end + 1);
|
||||
*where = backup;
|
||||
++m_cur_num_msg;
|
||||
return **where;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef msg_hdr_ptr_t *iterator;
|
||||
|
||||
//!Returns the inserted message with top priority
|
||||
msg_header &top_msg()
|
||||
{ return *mp_index[m_cur_num_msg-1]; }
|
||||
|
||||
//!Returns the inserted message with bottom priority
|
||||
msg_header &bottom_msg()
|
||||
{ return *mp_index[0]; }
|
||||
|
||||
iterator inserted_ptr_begin() const
|
||||
{ return &mp_index[0]; }
|
||||
|
||||
iterator inserted_ptr_end() const
|
||||
{ return &mp_index[m_cur_num_msg]; }
|
||||
|
||||
iterator lower_bound(const msg_hdr_ptr_t & value, priority_functor<VoidPointer> func)
|
||||
{ return std::lower_bound(this->inserted_ptr_begin(), this->inserted_ptr_end(), value, func); }
|
||||
|
||||
msg_header & insert_at(iterator pos)
|
||||
{
|
||||
const msg_hdr_ptr_t backup = *inserted_ptr_end();
|
||||
std::copy_backward(pos, inserted_ptr_end(), inserted_ptr_end()+1);
|
||||
*pos = backup;
|
||||
++m_cur_num_msg;
|
||||
return **pos;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//!Inserts the first free message in the priority queue
|
||||
msg_header & queue_free_msg(unsigned int priority)
|
||||
{
|
||||
//Get priority queue's range
|
||||
iterator it (inserted_ptr_begin()), it_end(inserted_ptr_end());
|
||||
//Optimize for non-priority usage
|
||||
if(m_cur_num_msg && priority > this->bottom_msg().priority){
|
||||
//Check for higher priority than all stored messages
|
||||
if(priority > this->top_msg().priority){
|
||||
it = it_end;
|
||||
}
|
||||
else{
|
||||
//Since we don't now which free message we will pick
|
||||
//build a dummy header for searches
|
||||
msg_header dummy_hdr;
|
||||
dummy_hdr.priority = priority;
|
||||
|
||||
//Get free msg
|
||||
msg_hdr_ptr_t dummy_ptr(&dummy_hdr);
|
||||
|
||||
//Check where the free message should be placed
|
||||
it = this->lower_bound(dummy_ptr, static_cast<priority_functor<VoidPointer>&>(*this));
|
||||
}
|
||||
|
||||
}
|
||||
//Insert the free message in the correct position
|
||||
return this->insert_at(it);
|
||||
}
|
||||
|
||||
//!Returns the number of bytes needed to construct a message queue with
|
||||
//!"max_num_size" maximum number of messages and "max_msg_size" maximum
|
||||
//!message size. Never throws.
|
||||
static size_type get_mem_size
|
||||
(size_type max_msg_size, size_type max_num_msg)
|
||||
{
|
||||
const size_type
|
||||
const size_type
|
||||
msg_hdr_align = ::boost::alignment_of<msg_header>::value,
|
||||
index_align = ::boost::alignment_of<msg_hdr_ptr_t>::value,
|
||||
r_hdr_size = ipcdetail::ct_rounded_size<sizeof(mq_hdr_t), index_align>::value,
|
||||
r_index_size = ipcdetail::get_rounded_size(sizeof(msg_hdr_ptr_t)*max_num_msg, msg_hdr_align),
|
||||
r_index_size = ipcdetail::get_rounded_size(max_num_msg*sizeof(msg_hdr_ptr_t), msg_hdr_align),
|
||||
r_max_msg_size = ipcdetail::get_rounded_size(max_msg_size, msg_hdr_align) + sizeof(msg_header);
|
||||
return r_hdr_size + r_index_size + (max_num_msg*r_max_msg_size) +
|
||||
ipcdetail::managed_open_or_create_impl<shared_memory_object>::ManagedOpenOrCreateUserOffset;
|
||||
return r_hdr_size + r_index_size + (max_num_msg*r_max_msg_size) +
|
||||
open_create_impl_t::ManagedOpenOrCreateUserOffset;
|
||||
}
|
||||
|
||||
//!Initializes the memory structures to preallocate messages and constructs the
|
||||
//!message index. Never throws.
|
||||
void initialize_memory()
|
||||
{
|
||||
const size_type
|
||||
const size_type
|
||||
msg_hdr_align = ::boost::alignment_of<msg_header>::value,
|
||||
index_align = ::boost::alignment_of<msg_hdr_ptr_t>::value,
|
||||
r_hdr_size = ipcdetail::ct_rounded_size<sizeof(mq_hdr_t), index_align>::value,
|
||||
r_index_size = ipcdetail::get_rounded_size(sizeof(msg_hdr_ptr_t)*m_max_num_msg, msg_hdr_align),
|
||||
r_index_size = ipcdetail::get_rounded_size(m_max_num_msg*sizeof(msg_hdr_ptr_t), msg_hdr_align),
|
||||
r_max_msg_size = ipcdetail::get_rounded_size(m_max_msg_size, msg_hdr_align) + sizeof(msg_header);
|
||||
|
||||
//Pointer to the index
|
||||
@@ -345,7 +545,7 @@ class mq_hdr_t
|
||||
|
||||
//Pointer to the first message header
|
||||
msg_header *msg_hdr = reinterpret_cast<msg_header*>
|
||||
(reinterpret_cast<char*>(this)+r_hdr_size+r_index_size);
|
||||
(reinterpret_cast<char*>(this)+r_hdr_size+r_index_size);
|
||||
|
||||
//Initialize the pointer to the index
|
||||
mp_index = index;
|
||||
@@ -373,13 +573,17 @@ class mq_hdr_t
|
||||
interprocess_condition m_cond_recv;
|
||||
//Condition block senders when the queue is full
|
||||
interprocess_condition m_cond_send;
|
||||
#if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX)
|
||||
//Current start offset in the circular index
|
||||
size_type m_cur_first_msg;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
//!This is the atomic functor to be executed when creating or opening
|
||||
//!This is the atomic functor to be executed when creating or opening
|
||||
//!shared memory. Never throws
|
||||
template<class VoidPointer>
|
||||
class initialization_func_t
|
||||
class msg_queue_initialization_func_t
|
||||
{
|
||||
public:
|
||||
typedef typename boost::intrusive::
|
||||
@@ -388,7 +592,7 @@ class initialization_func_t
|
||||
typedef typename boost::intrusive::pointer_traits<char_ptr>::difference_type difference_type;
|
||||
typedef typename boost::make_unsigned<difference_type>::type size_type;
|
||||
|
||||
initialization_func_t(size_type maxmsg = 0,
|
||||
msg_queue_initialization_func_t(size_type maxmsg = 0,
|
||||
size_type maxmsgsize = 0)
|
||||
: m_maxmsg (maxmsg), m_maxmsgsize(maxmsgsize) {}
|
||||
|
||||
@@ -403,12 +607,19 @@ class initialization_func_t
|
||||
new (mptr) mq_hdr_t<VoidPointer>(m_maxmsg, m_maxmsgsize);
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t get_min_size() const
|
||||
{
|
||||
return mq_hdr_t<VoidPointer>::get_mem_size(m_maxmsgsize, m_maxmsg)
|
||||
- message_queue_t<VoidPointer>::open_create_impl_t::ManagedOpenOrCreateUserOffset;
|
||||
}
|
||||
|
||||
const size_type m_maxmsg;
|
||||
const size_type m_maxmsgsize;
|
||||
};
|
||||
@@ -425,49 +636,48 @@ inline typename message_queue_t<VoidPointer>::size_type message_queue_t<VoidPoin
|
||||
{ return ipcdetail::mq_hdr_t<VoidPointer>::get_mem_size(max_msg_size, max_num_msg); }
|
||||
|
||||
template<class VoidPointer>
|
||||
inline message_queue_t<VoidPointer>::message_queue_t(create_only_t create_only,
|
||||
const char *name,
|
||||
size_type max_num_msg,
|
||||
inline message_queue_t<VoidPointer>::message_queue_t(create_only_t,
|
||||
const char *name,
|
||||
size_type max_num_msg,
|
||||
size_type max_msg_size,
|
||||
const permissions &perm)
|
||||
//Create shared memory and execute functor atomically
|
||||
: m_shmem(create_only,
|
||||
name,
|
||||
get_mem_size(max_msg_size, max_num_msg),
|
||||
read_write,
|
||||
static_cast<void*>(0),
|
||||
//Prepare initialization functor
|
||||
ipcdetail::initialization_func_t<VoidPointer> (max_num_msg, max_msg_size),
|
||||
perm)
|
||||
{}
|
||||
|
||||
template<class VoidPointer>
|
||||
inline message_queue_t<VoidPointer>::message_queue_t(open_or_create_t open_or_create,
|
||||
const char *name,
|
||||
size_type max_num_msg,
|
||||
size_type max_msg_size,
|
||||
const permissions &perm)
|
||||
//Create shared memory and execute functor atomically
|
||||
: m_shmem(open_or_create,
|
||||
name,
|
||||
: m_shmem(create_only,
|
||||
name,
|
||||
get_mem_size(max_msg_size, max_num_msg),
|
||||
read_write,
|
||||
static_cast<void*>(0),
|
||||
//Prepare initialization functor
|
||||
ipcdetail::initialization_func_t<VoidPointer> (max_num_msg, max_msg_size),
|
||||
ipcdetail::msg_queue_initialization_func_t<VoidPointer> (max_num_msg, max_msg_size),
|
||||
perm)
|
||||
{}
|
||||
|
||||
template<class VoidPointer>
|
||||
inline message_queue_t<VoidPointer>::message_queue_t(open_only_t open_only,
|
||||
const char *name)
|
||||
inline message_queue_t<VoidPointer>::message_queue_t(open_or_create_t,
|
||||
const char *name,
|
||||
size_type max_num_msg,
|
||||
size_type max_msg_size,
|
||||
const permissions &perm)
|
||||
//Create shared memory and execute functor atomically
|
||||
: m_shmem(open_or_create,
|
||||
name,
|
||||
get_mem_size(max_msg_size, max_num_msg),
|
||||
read_write,
|
||||
static_cast<void*>(0),
|
||||
//Prepare initialization functor
|
||||
ipcdetail::msg_queue_initialization_func_t<VoidPointer> (max_num_msg, max_msg_size),
|
||||
perm)
|
||||
{}
|
||||
|
||||
template<class VoidPointer>
|
||||
inline message_queue_t<VoidPointer>::message_queue_t(open_only_t, const char *name)
|
||||
//Create shared memory and execute functor atomically
|
||||
: m_shmem(open_only,
|
||||
: m_shmem(open_only,
|
||||
name,
|
||||
read_write,
|
||||
static_cast<void*>(0),
|
||||
//Prepare initialization functor
|
||||
ipcdetail::initialization_func_t<VoidPointer> ())
|
||||
ipcdetail::msg_queue_initialization_func_t<VoidPointer> ())
|
||||
{}
|
||||
|
||||
template<class VoidPointer>
|
||||
@@ -494,7 +704,7 @@ inline bool message_queue_t<VoidPointer>::timed_send
|
||||
|
||||
template<class VoidPointer>
|
||||
inline bool message_queue_t<VoidPointer>::do_send(block_t block,
|
||||
const void *buffer, size_type buffer_size,
|
||||
const void *buffer, size_type buffer_size,
|
||||
unsigned int priority, const boost::posix_time::ptime &abs_time)
|
||||
{
|
||||
ipcdetail::mq_hdr_t<VoidPointer> *p_hdr = static_cast<ipcdetail::mq_hdr_t<VoidPointer>*>(m_shmem.get_user_address());
|
||||
@@ -503,13 +713,13 @@ inline bool message_queue_t<VoidPointer>::do_send(block_t block,
|
||||
throw interprocess_exception(size_error);
|
||||
}
|
||||
|
||||
bool was_empty = false;
|
||||
//---------------------------------------------
|
||||
scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
|
||||
//---------------------------------------------
|
||||
{
|
||||
//If the queue is full execute blocking logic
|
||||
if (p_hdr->is_full()) {
|
||||
|
||||
switch(block){
|
||||
case non_blocking :
|
||||
return false;
|
||||
@@ -536,47 +746,47 @@ inline bool message_queue_t<VoidPointer>::do_send(block_t block,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Get the first free message from free message queue
|
||||
ipcdetail::msg_hdr_t<VoidPointer> *free_msg = p_hdr->free_msg();
|
||||
if (free_msg == 0) {
|
||||
throw interprocess_exception("boost::interprocess::message_queue corrupted");
|
||||
}
|
||||
|
||||
was_empty = p_hdr->is_empty();
|
||||
//Insert the first free message in the priority queue
|
||||
ipcdetail::msg_hdr_t<VoidPointer> &free_msg_hdr = p_hdr->queue_free_msg(priority);
|
||||
|
||||
//Sanity check, free msgs are always cleaned when received
|
||||
assert(free_msg_hdr.priority == 0);
|
||||
assert(free_msg_hdr.len == 0);
|
||||
|
||||
//Copy control data to the free message
|
||||
free_msg->priority = priority;
|
||||
free_msg->len = buffer_size;
|
||||
free_msg_hdr.priority = priority;
|
||||
free_msg_hdr.len = buffer_size;
|
||||
|
||||
//Copy user buffer to the message
|
||||
std::memcpy(free_msg->data(), buffer, buffer_size);
|
||||
|
||||
// bool was_empty = p_hdr->is_empty();
|
||||
//Insert the first free message in the priority queue
|
||||
p_hdr->queue_free_msg();
|
||||
|
||||
//If this message changes the queue empty state, notify it to receivers
|
||||
// if (was_empty){
|
||||
p_hdr->m_cond_recv.notify_one();
|
||||
// }
|
||||
std::memcpy(free_msg_hdr.data(), buffer, buffer_size);
|
||||
} // Lock end
|
||||
|
||||
//Notify outside lock to avoid contention. This might produce some
|
||||
//spurious wakeups, but it's usually far better than notifying inside.
|
||||
//If this message changes the queue empty state, notify it to receivers
|
||||
if (was_empty){
|
||||
p_hdr->m_cond_recv.notify_one();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class VoidPointer>
|
||||
inline void message_queue_t<VoidPointer>::receive(void *buffer, size_type buffer_size,
|
||||
inline void message_queue_t<VoidPointer>::receive(void *buffer, size_type buffer_size,
|
||||
size_type &recvd_size, unsigned int &priority)
|
||||
{ this->do_receive(blocking, buffer, buffer_size, recvd_size, priority, ptime()); }
|
||||
|
||||
template<class VoidPointer>
|
||||
inline bool
|
||||
message_queue_t<VoidPointer>::try_receive(void *buffer, size_type buffer_size,
|
||||
message_queue_t<VoidPointer>::try_receive(void *buffer, size_type buffer_size,
|
||||
size_type &recvd_size, unsigned int &priority)
|
||||
{ return this->do_receive(non_blocking, buffer, buffer_size, recvd_size, priority, ptime()); }
|
||||
|
||||
template<class VoidPointer>
|
||||
inline bool
|
||||
message_queue_t<VoidPointer>::timed_receive(void *buffer, size_type buffer_size,
|
||||
message_queue_t<VoidPointer>::timed_receive(void *buffer, size_type buffer_size,
|
||||
size_type &recvd_size, unsigned int &priority,
|
||||
const boost::posix_time::ptime &abs_time)
|
||||
{
|
||||
@@ -590,7 +800,7 @@ inline bool
|
||||
template<class VoidPointer>
|
||||
inline bool
|
||||
message_queue_t<VoidPointer>::do_receive(block_t block,
|
||||
void *buffer, size_type buffer_size,
|
||||
void *buffer, size_type buffer_size,
|
||||
size_type &recvd_size, unsigned int &priority,
|
||||
const boost::posix_time::ptime &abs_time)
|
||||
{
|
||||
@@ -600,6 +810,7 @@ inline bool
|
||||
throw interprocess_exception(size_error);
|
||||
}
|
||||
|
||||
bool was_full = false;
|
||||
//---------------------------------------------
|
||||
scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
|
||||
//---------------------------------------------
|
||||
@@ -635,51 +846,52 @@ inline bool
|
||||
}
|
||||
}
|
||||
|
||||
//Thre is at least message ready to pick, get the top one
|
||||
ipcdetail::msg_hdr_t<VoidPointer> *top_msg = p_hdr->top_msg();
|
||||
|
||||
//Paranoia check
|
||||
if (top_msg == 0) {
|
||||
throw interprocess_exception("boost::interprocess::message_queue corrupted");
|
||||
}
|
||||
//There is at least one message ready to pick, get the top one
|
||||
ipcdetail::msg_hdr_t<VoidPointer> &top_msg = p_hdr->top_msg();
|
||||
|
||||
//Get data from the message
|
||||
recvd_size = top_msg->len;
|
||||
priority = top_msg->priority;
|
||||
recvd_size = top_msg.len;
|
||||
priority = top_msg.priority;
|
||||
|
||||
//Some cleanup to ease debugging
|
||||
top_msg.len = 0;
|
||||
top_msg.priority = 0;
|
||||
|
||||
//Copy data to receiver's bufers
|
||||
std::memcpy(buffer, top_msg->data(), recvd_size);
|
||||
std::memcpy(buffer, top_msg.data(), recvd_size);
|
||||
|
||||
// bool was_full = p_hdr->is_full();
|
||||
was_full = p_hdr->is_full();
|
||||
|
||||
//Free top message and put it in the free message list
|
||||
p_hdr->free_top_msg();
|
||||
|
||||
//If this reception changes the queue full state, notify senders
|
||||
// if (was_full){
|
||||
p_hdr->m_cond_send.notify_one();
|
||||
// }
|
||||
} //Lock end
|
||||
|
||||
//Notify outside lock to avoid contention. This might produce some
|
||||
//spurious wakeups, but it's usually far better than notifying inside.
|
||||
//If this reception changes the queue full state, notify senders
|
||||
if (was_full){
|
||||
p_hdr->m_cond_send.notify_one();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class VoidPointer>
|
||||
inline typename message_queue_t<VoidPointer>::size_type message_queue_t<VoidPointer>::get_max_msg() const
|
||||
{
|
||||
{
|
||||
ipcdetail::mq_hdr_t<VoidPointer> *p_hdr = static_cast<ipcdetail::mq_hdr_t<VoidPointer>*>(m_shmem.get_user_address());
|
||||
return p_hdr ? p_hdr->m_max_num_msg : 0; }
|
||||
|
||||
template<class VoidPointer>
|
||||
inline typename message_queue_t<VoidPointer>::size_type message_queue_t<VoidPointer>::get_max_msg_size() const
|
||||
{
|
||||
{
|
||||
ipcdetail::mq_hdr_t<VoidPointer> *p_hdr = static_cast<ipcdetail::mq_hdr_t<VoidPointer>*>(m_shmem.get_user_address());
|
||||
return p_hdr ? p_hdr->m_max_msg_size : 0;
|
||||
return p_hdr ? p_hdr->m_max_msg_size : 0;
|
||||
}
|
||||
|
||||
template<class VoidPointer>
|
||||
inline typename message_queue_t<VoidPointer>::size_type message_queue_t<VoidPointer>::get_num_msg()
|
||||
{
|
||||
{
|
||||
ipcdetail::mq_hdr_t<VoidPointer> *p_hdr = static_cast<ipcdetail::mq_hdr_t<VoidPointer>*>(m_shmem.get_user_address());
|
||||
if(p_hdr){
|
||||
//---------------------------------------------
|
||||
@@ -688,7 +900,7 @@ inline typename message_queue_t<VoidPointer>::size_type message_queue_t<VoidPoin
|
||||
return p_hdr->m_cur_num_msg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class VoidPointer>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -23,34 +23,34 @@
|
||||
#include <boost/assert.hpp>
|
||||
//These includes needed to fulfill default template parameters of
|
||||
//predeclarations in interprocess_fwd.hpp
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
#include <boost/interprocess/indexes/iset_index.hpp>
|
||||
|
||||
//!\file
|
||||
//!Describes a named user memory allocation user class.
|
||||
//!Describes a named user memory allocation user class.
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
//!A basic user memory named object creation class. Inherits all
|
||||
//!basic functionality from
|
||||
//!A basic user memory named object creation class. Inherits all
|
||||
//!basic functionality from
|
||||
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
|
||||
template
|
||||
<
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
template<class IndexConfig> class IndexType
|
||||
>
|
||||
class basic_managed_external_buffer
|
||||
class basic_managed_external_buffer
|
||||
: public ipcdetail::basic_managed_memory_impl <CharType, AllocationAlgorithm, IndexType>
|
||||
{
|
||||
/// @cond
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType> base_t;
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_external_buffer)
|
||||
/// @endcond
|
||||
|
||||
|
||||
public:
|
||||
typedef typename base_t::size_type size_type;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -24,32 +24,32 @@
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
//These includes needed to fulfill default template parameters of
|
||||
//predeclarations in interprocess_fwd.hpp
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
#include <boost/interprocess/indexes/iset_index.hpp>
|
||||
|
||||
//!\file
|
||||
//!Describes a named heap memory allocation user class.
|
||||
//!Describes a named heap memory allocation user class.
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
//!A basic heap memory named object creation class. Initializes the
|
||||
//!heap memory segment. Inherits all basic functionality from
|
||||
//!A basic heap memory named object creation class. Initializes the
|
||||
//!heap memory segment. Inherits all basic functionality from
|
||||
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
|
||||
template
|
||||
<
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
template<class IndexConfig> class IndexType
|
||||
>
|
||||
class basic_managed_heap_memory
|
||||
class basic_managed_heap_memory
|
||||
: public ipcdetail::basic_managed_memory_impl <CharType, AllocationAlgorithm, IndexType>
|
||||
{
|
||||
/// @cond
|
||||
private:
|
||||
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType> base_t;
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_heap_memory)
|
||||
/// @endcond
|
||||
@@ -90,16 +90,16 @@ class basic_managed_heap_memory
|
||||
}
|
||||
|
||||
//!Tries to resize internal heap memory so that
|
||||
//!we have room for more objects.
|
||||
//!WARNING: If memory is reallocated, all the objects will
|
||||
//!we have room for more objects.
|
||||
//!WARNING: If memory is reallocated, all the objects will
|
||||
//!be binary-copied to the new buffer. To be able to use
|
||||
//!this function, all pointers constructed in this buffer
|
||||
//!must be offset pointers. Otherwise, the result is undefined.
|
||||
//!Returns true if the growth has been successful, so you will
|
||||
//!have some extra bytes to allocate new objects. If returns
|
||||
//!have some extra bytes to allocate new objects. If returns
|
||||
//!false, the heap allocation has failed.
|
||||
bool grow(size_type extra_bytes)
|
||||
{
|
||||
{
|
||||
//If memory is reallocated, data will
|
||||
//be automatically copied
|
||||
BOOST_TRY{
|
||||
@@ -129,7 +129,7 @@ class basic_managed_heap_memory
|
||||
private:
|
||||
//!Frees resources. Never throws.
|
||||
void priv_close()
|
||||
{
|
||||
{
|
||||
base_t::destroy_impl();
|
||||
std::vector<char>().swap(m_heapmem);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -26,44 +26,48 @@
|
||||
#include <boost/interprocess/permissions.hpp>
|
||||
//These includes needed to fulfill default template parameters of
|
||||
//predeclarations in interprocess_fwd.hpp
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
#include <boost/interprocess/indexes/iset_index.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
//!A basic mapped file named object creation class. Initializes the
|
||||
//!mapped file. Inherits all basic functionality from
|
||||
template<class AllocationAlgorithm>
|
||||
struct mfile_open_or_create
|
||||
{
|
||||
typedef ipcdetail::managed_open_or_create_impl
|
||||
< file_wrapper, AllocationAlgorithm::Alignment, true, false> type;
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
|
||||
//!A basic mapped file named object creation class. Initializes the
|
||||
//!mapped file. Inherits all basic functionality from
|
||||
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>
|
||||
template
|
||||
<
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
template<class IndexConfig> class IndexType
|
||||
>
|
||||
class basic_managed_mapped_file
|
||||
class basic_managed_mapped_file
|
||||
: public ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType
|
||||
,ipcdetail::managed_open_or_create_impl< ipcdetail::file_wrapper
|
||||
, AllocationAlgorithm::Alignment>::ManagedOpenOrCreateUserOffset
|
||||
>
|
||||
,ipcdetail::mfile_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset>
|
||||
{
|
||||
/// @cond
|
||||
public:
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType,
|
||||
ipcdetail::managed_open_or_create_impl
|
||||
<ipcdetail::file_wrapper, AllocationAlgorithm::Alignment>::ManagedOpenOrCreateUserOffset
|
||||
> base_t;
|
||||
ipcdetail::mfile_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset> base_t;
|
||||
typedef ipcdetail::file_wrapper device_type;
|
||||
typedef typename base_t::size_type size_type;
|
||||
|
||||
private:
|
||||
|
||||
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
|
||||
typedef ipcdetail::managed_open_or_create_impl< ipcdetail::file_wrapper
|
||||
, AllocationAlgorithm::Alignment> managed_open_or_create_type;
|
||||
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
|
||||
|
||||
basic_managed_mapped_file *get_this_pointer()
|
||||
{ return this; }
|
||||
@@ -75,16 +79,16 @@ class basic_managed_mapped_file
|
||||
|
||||
public: //functions
|
||||
|
||||
//!Creates mapped file and creates and places the segment manager.
|
||||
//!Creates mapped file and creates and places the segment manager.
|
||||
//!This can throw.
|
||||
basic_managed_mapped_file()
|
||||
{}
|
||||
|
||||
//!Creates mapped file and creates and places the segment manager.
|
||||
//!Creates mapped file and creates and places the segment manager.
|
||||
//!This can throw.
|
||||
basic_managed_mapped_file(create_only_t create_only, const char *name,
|
||||
basic_managed_mapped_file(create_only_t, const char *name,
|
||||
size_type size, const void *addr = 0, const permissions &perm = permissions())
|
||||
: m_mfile(create_only, name, size, read_write, addr,
|
||||
: m_mfile(create_only, name, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm)
|
||||
{}
|
||||
|
||||
@@ -92,40 +96,40 @@ class basic_managed_mapped_file
|
||||
//!segment was not created. If segment was created it connects to the
|
||||
//!segment.
|
||||
//!This can throw.
|
||||
basic_managed_mapped_file (open_or_create_t open_or_create,
|
||||
const char *name, size_type size,
|
||||
basic_managed_mapped_file (open_or_create_t,
|
||||
const char *name, size_type size,
|
||||
const void *addr = 0, const permissions &perm = permissions())
|
||||
: m_mfile(open_or_create, name, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpenOrCreate), perm)
|
||||
{}
|
||||
|
||||
//!Connects to a created mapped file and its segment manager.
|
||||
//!This can throw.
|
||||
basic_managed_mapped_file (open_only_t open_only, const char* name,
|
||||
basic_managed_mapped_file (open_only_t, const char* name,
|
||||
const void *addr = 0)
|
||||
: m_mfile(open_only, name, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
//!Connects to a created mapped file and its segment manager
|
||||
//!in copy_on_write mode.
|
||||
//!This can throw.
|
||||
basic_managed_mapped_file (open_copy_on_write_t, const char* name,
|
||||
basic_managed_mapped_file (open_copy_on_write_t, const char* name,
|
||||
const void *addr = 0)
|
||||
: m_mfile(open_only, name, copy_on_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
: m_mfile(open_only, name, copy_on_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
//!Connects to a created mapped file and its segment manager
|
||||
//!in read-only mode.
|
||||
//!This can throw.
|
||||
basic_managed_mapped_file (open_read_only_t, const char* name,
|
||||
basic_managed_mapped_file (open_read_only_t, const char* name,
|
||||
const void *addr = 0)
|
||||
: m_mfile(open_only, name, read_only, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
: m_mfile(open_only, name, read_only, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
@@ -167,8 +171,8 @@ class basic_managed_mapped_file
|
||||
bool flush()
|
||||
{ return m_mfile.flush(); }
|
||||
|
||||
//!Tries to resize mapped file so that we have room for
|
||||
//!more objects.
|
||||
//!Tries to resize mapped file so that we have room for
|
||||
//!more objects.
|
||||
//!
|
||||
//!This function is not synchronized so no other thread or process should
|
||||
//!be reading or writing the file
|
||||
@@ -205,7 +209,7 @@ class basic_managed_mapped_file
|
||||
}
|
||||
|
||||
private:
|
||||
managed_open_or_create_type m_mfile;
|
||||
typename ipcdetail::mfile_open_or_create<AllocationAlgorithm>::type m_mfile;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -25,37 +25,43 @@
|
||||
#include <boost/interprocess/permissions.hpp>
|
||||
//These includes needed to fulfill default template parameters of
|
||||
//predeclarations in interprocess_fwd.hpp
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace interprocess {
|
||||
|
||||
//!A basic shared memory named object creation class. Initializes the
|
||||
//!shared memory segment. Inherits all basic functionality from
|
||||
namespace ipcdetail {
|
||||
|
||||
template<class AllocationAlgorithm>
|
||||
struct shmem_open_or_create
|
||||
{
|
||||
typedef ipcdetail::managed_open_or_create_impl
|
||||
< shared_memory_object, AllocationAlgorithm::Alignment, true, false> type;
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
|
||||
//!A basic shared memory named object creation class. Initializes the
|
||||
//!shared memory segment. Inherits all basic functionality from
|
||||
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
|
||||
template
|
||||
<
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
template<class IndexConfig> class IndexType
|
||||
>
|
||||
class basic_managed_shared_memory
|
||||
class basic_managed_shared_memory
|
||||
: public ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType
|
||||
,ipcdetail::managed_open_or_create_impl<shared_memory_object
|
||||
, AllocationAlgorithm::Alignment>::ManagedOpenOrCreateUserOffset>
|
||||
, private ipcdetail::managed_open_or_create_impl<shared_memory_object
|
||||
, AllocationAlgorithm::Alignment>
|
||||
,ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset>
|
||||
, private ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type
|
||||
{
|
||||
/// @cond
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType,
|
||||
ipcdetail::managed_open_or_create_impl
|
||||
< shared_memory_object, AllocationAlgorithm::Alignment>::ManagedOpenOrCreateUserOffset> base_t;
|
||||
typedef ipcdetail::managed_open_or_create_impl
|
||||
<shared_memory_object, AllocationAlgorithm::Alignment> base2_t;
|
||||
ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset> base_t;
|
||||
typedef typename ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type base2_t;
|
||||
|
||||
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
|
||||
|
||||
@@ -87,12 +93,12 @@ class basic_managed_shared_memory
|
||||
basic_managed_shared_memory()
|
||||
{}
|
||||
|
||||
//!Creates shared memory and creates and places the segment manager.
|
||||
//!Creates shared memory and creates and places the segment manager.
|
||||
//!This can throw.
|
||||
basic_managed_shared_memory(create_only_t create_only, const char *name,
|
||||
basic_managed_shared_memory(create_only_t, const char *name,
|
||||
size_type size, const void *addr = 0, const permissions& perm = permissions())
|
||||
: base_t()
|
||||
, base2_t(create_only, name, size, read_write, addr,
|
||||
, base2_t(create_only, name, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm)
|
||||
{}
|
||||
|
||||
@@ -100,44 +106,44 @@ class basic_managed_shared_memory
|
||||
//!segment was not created. If segment was created it connects to the
|
||||
//!segment.
|
||||
//!This can throw.
|
||||
basic_managed_shared_memory (open_or_create_t open_or_create,
|
||||
const char *name, size_type size,
|
||||
basic_managed_shared_memory (open_or_create_t,
|
||||
const char *name, size_type size,
|
||||
const void *addr = 0, const permissions& perm = permissions())
|
||||
: base_t()
|
||||
, base2_t(open_or_create, name, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
, base2_t(open_or_create, name, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpenOrCreate), perm)
|
||||
{}
|
||||
|
||||
//!Connects to a created shared memory and its segment manager.
|
||||
//!in copy_on_write mode.
|
||||
//!This can throw.
|
||||
basic_managed_shared_memory (open_copy_on_write_t, const char* name,
|
||||
basic_managed_shared_memory (open_copy_on_write_t, const char* name,
|
||||
const void *addr = 0)
|
||||
: base_t()
|
||||
, base2_t(open_only, name, copy_on_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
, base2_t(open_only, name, copy_on_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
//!Connects to a created shared memory and its segment manager.
|
||||
//!in read-only mode.
|
||||
//!This can throw.
|
||||
basic_managed_shared_memory (open_read_only_t, const char* name,
|
||||
basic_managed_shared_memory (open_read_only_t, const char* name,
|
||||
const void *addr = 0)
|
||||
: base_t()
|
||||
, base2_t(open_only, name, read_only, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
, base2_t(open_only, name, read_only, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
//!Connects to a created shared memory and its segment manager.
|
||||
//!This can throw.
|
||||
basic_managed_shared_memory (open_only_t open_only, const char* name,
|
||||
basic_managed_shared_memory (open_only_t, const char* name,
|
||||
const void *addr = 0)
|
||||
: base_t()
|
||||
, base2_t(open_only, name, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
, base2_t(open_only, name, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
@@ -168,7 +174,7 @@ class basic_managed_shared_memory
|
||||
}
|
||||
|
||||
//!Tries to resize the managed shared memory object so that we have
|
||||
//!room for more objects.
|
||||
//!room for more objects.
|
||||
//!
|
||||
//!This function is not synchronized so no other thread or process should
|
||||
//!be reading or writing the file
|
||||
@@ -187,12 +193,6 @@ class basic_managed_shared_memory
|
||||
return base_t::template shrink_to_fit
|
||||
<basic_managed_shared_memory>(shmname);
|
||||
}
|
||||
|
||||
bool flush()
|
||||
{
|
||||
return this->base2_t::flush();
|
||||
}
|
||||
|
||||
/// @cond
|
||||
|
||||
//!Tries to find a previous named allocation address. Returns a memory
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -25,15 +25,26 @@
|
||||
#include <boost/move/move.hpp>
|
||||
//These includes needed to fulfill default template parameters of
|
||||
//predeclarations in interprocess_fwd.hpp
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
#include <boost/interprocess/indexes/iset_index.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
//!A basic managed windows shared memory creation class. Initializes the
|
||||
//!shared memory segment. Inherits all basic functionality from
|
||||
namespace ipcdetail {
|
||||
|
||||
template<class AllocationAlgorithm>
|
||||
struct wshmem_open_or_create
|
||||
{
|
||||
typedef ipcdetail::managed_open_or_create_impl
|
||||
< windows_shared_memory, AllocationAlgorithm::Alignment, false, false> type;
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
|
||||
//!A basic managed windows shared memory creation class. Initializes the
|
||||
//!shared memory segment. Inherits all basic functionality from
|
||||
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>
|
||||
//!Unlike basic_managed_shared_memory, it has
|
||||
//!no kernel persistence and the shared memory is destroyed
|
||||
@@ -45,25 +56,20 @@ namespace interprocess {
|
||||
//!basic_managed_shared_memory can't communicate between them.
|
||||
template
|
||||
<
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
template<class IndexConfig> class IndexType
|
||||
>
|
||||
class basic_managed_windows_shared_memory
|
||||
class basic_managed_windows_shared_memory
|
||||
: public ipcdetail::basic_managed_memory_impl
|
||||
< CharType, AllocationAlgorithm, IndexType
|
||||
, ipcdetail::managed_open_or_create_impl
|
||||
< windows_shared_memory
|
||||
, AllocationAlgorithm::Alignment
|
||||
, false>::ManagedOpenOrCreateUserOffset
|
||||
>
|
||||
, ipcdetail::wshmem_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset>
|
||||
{
|
||||
/// @cond
|
||||
private:
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType,
|
||||
ipcdetail::managed_open_or_create_impl
|
||||
<windows_shared_memory, AllocationAlgorithm::Alignment, false>::ManagedOpenOrCreateUserOffset> base_t;
|
||||
ipcdetail::wshmem_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset> base_t;
|
||||
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
|
||||
|
||||
basic_managed_windows_shared_memory *get_this_pointer()
|
||||
@@ -82,12 +88,12 @@ class basic_managed_windows_shared_memory
|
||||
basic_managed_windows_shared_memory()
|
||||
{}
|
||||
|
||||
//!Creates shared memory and creates and places the segment manager.
|
||||
//!Creates shared memory and creates and places the segment manager.
|
||||
//!This can throw.
|
||||
basic_managed_windows_shared_memory
|
||||
(create_only_t create_only, const char *name,
|
||||
(create_only_t, const char *name,
|
||||
size_type size, const void *addr = 0, const permissions &perm = permissions())
|
||||
: m_wshm(create_only, name, size, read_write, addr,
|
||||
: m_wshm(create_only, name, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm)
|
||||
{}
|
||||
|
||||
@@ -96,21 +102,21 @@ class basic_managed_windows_shared_memory
|
||||
//!segment.
|
||||
//!This can throw.
|
||||
basic_managed_windows_shared_memory
|
||||
(open_or_create_t open_or_create,
|
||||
const char *name, size_type size,
|
||||
(open_or_create_t,
|
||||
const char *name, size_type size,
|
||||
const void *addr = 0,
|
||||
const permissions &perm = permissions())
|
||||
: m_wshm(open_or_create, name, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
: m_wshm(open_or_create, name, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpenOrCreate), perm)
|
||||
{}
|
||||
|
||||
//!Connects to a created shared memory and its segment manager.
|
||||
//!This can throw.
|
||||
basic_managed_windows_shared_memory
|
||||
(open_only_t open_only, const char* name, const void *addr = 0)
|
||||
: m_wshm(open_only, name, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
(open_only_t, const char* name, const void *addr = 0)
|
||||
: m_wshm(open_only, name, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
@@ -119,7 +125,7 @@ class basic_managed_windows_shared_memory
|
||||
//!This can throw.
|
||||
basic_managed_windows_shared_memory
|
||||
(open_copy_on_write_t, const char* name, const void *addr = 0)
|
||||
: m_wshm(open_only, name, copy_on_write, addr,
|
||||
: m_wshm(open_only, name, copy_on_write, addr,
|
||||
create_open_func_t(get_this_pointer(), ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
@@ -129,7 +135,7 @@ class basic_managed_windows_shared_memory
|
||||
basic_managed_windows_shared_memory
|
||||
(open_read_only_t, const char* name, const void *addr = 0)
|
||||
: base_t()
|
||||
, m_wshm(open_only, name, read_only, addr,
|
||||
, m_wshm(open_only, name, read_only, addr,
|
||||
create_open_func_t(get_this_pointer(), ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
@@ -181,8 +187,7 @@ class basic_managed_windows_shared_memory
|
||||
}
|
||||
|
||||
private:
|
||||
ipcdetail::managed_open_or_create_impl< windows_shared_memory
|
||||
, AllocationAlgorithm::Alignment, false> m_wshm;
|
||||
typename ipcdetail::wshmem_open_or_create<AllocationAlgorithm>::type m_wshm;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. 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)
|
||||
//
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <boost/interprocess/creation_tags.hpp>
|
||||
//These includes needed to fulfill default template parameters of
|
||||
//predeclarations in interprocess_fwd.hpp
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
#include <boost/interprocess/indexes/iset_index.hpp>
|
||||
|
||||
@@ -36,32 +36,39 @@ namespace boost {
|
||||
|
||||
namespace interprocess {
|
||||
|
||||
//!A basic X/Open System Interface (XSI) shared memory named object creation class. Initializes the
|
||||
//!shared memory segment. Inherits all basic functionality from
|
||||
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
|
||||
namespace ipcdetail {
|
||||
|
||||
template<class AllocationAlgorithm>
|
||||
struct xsishmem_open_or_create
|
||||
{
|
||||
typedef ipcdetail::managed_open_or_create_impl //!FileBased, StoreDevice
|
||||
< xsi_shared_memory_file_wrapper, AllocationAlgorithm::Alignment, false, true> type;
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
|
||||
//!A basic X/Open System Interface (XSI) shared memory named object creation class. Initializes the
|
||||
//!shared memory segment. Inherits all basic functionality from
|
||||
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>
|
||||
template
|
||||
<
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
template<class IndexConfig> class IndexType
|
||||
>
|
||||
class basic_managed_xsi_shared_memory
|
||||
class basic_managed_xsi_shared_memory
|
||||
: public ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType
|
||||
,ipcdetail::managed_open_or_create_impl
|
||||
< xsi_shared_memory_file_wrapper, AllocationAlgorithm::Alignment
|
||||
, false, true>::ManagedOpenOrCreateUserOffset>
|
||||
, private ipcdetail::managed_open_or_create_impl
|
||||
<xsi_shared_memory_file_wrapper, AllocationAlgorithm::Alignment, false, true>
|
||||
,ipcdetail::xsishmem_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset>
|
||||
, private ipcdetail::xsishmem_open_or_create<AllocationAlgorithm>::type
|
||||
{
|
||||
/// @cond
|
||||
public:
|
||||
typedef xsi_shared_memory_file_wrapper device_type;
|
||||
|
||||
public:
|
||||
typedef ipcdetail::managed_open_or_create_impl
|
||||
<xsi_shared_memory_file_wrapper, AllocationAlgorithm::Alignment, false, true> base2_t;
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
typedef typename ipcdetail::xsishmem_open_or_create<AllocationAlgorithm>::type base2_t;
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType,
|
||||
base2_t::ManagedOpenOrCreateUserOffset> base_t;
|
||||
|
||||
@@ -92,12 +99,12 @@ class basic_managed_xsi_shared_memory
|
||||
basic_managed_xsi_shared_memory()
|
||||
{}
|
||||
|
||||
//!Creates shared memory and creates and places the segment manager.
|
||||
//!Creates shared memory and creates and places the segment manager.
|
||||
//!This can throw.
|
||||
basic_managed_xsi_shared_memory(create_only_t create_only, const xsi_key &key,
|
||||
basic_managed_xsi_shared_memory(create_only_t, const xsi_key &key,
|
||||
std::size_t size, const void *addr = 0, const permissions& perm = permissions())
|
||||
: base_t()
|
||||
, base2_t(create_only, key, size, read_write, addr,
|
||||
, base2_t(create_only, key, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm)
|
||||
{}
|
||||
|
||||
@@ -105,33 +112,33 @@ class basic_managed_xsi_shared_memory
|
||||
//!segment was not created. If segment was created it connects to the
|
||||
//!segment.
|
||||
//!This can throw.
|
||||
basic_managed_xsi_shared_memory (open_or_create_t open_or_create,
|
||||
const xsi_key &key, std::size_t size,
|
||||
basic_managed_xsi_shared_memory (open_or_create_t,
|
||||
const xsi_key &key, std::size_t size,
|
||||
const void *addr = 0, const permissions& perm = permissions())
|
||||
: base_t()
|
||||
, base2_t(open_or_create, key, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
, base2_t(open_or_create, key, size, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpenOrCreate), perm)
|
||||
{}
|
||||
|
||||
//!Connects to a created shared memory and its segment manager.
|
||||
//!in read-only mode.
|
||||
//!This can throw.
|
||||
basic_managed_xsi_shared_memory (open_read_only_t, const xsi_key &key,
|
||||
basic_managed_xsi_shared_memory (open_read_only_t, const xsi_key &key,
|
||||
const void *addr = 0)
|
||||
: base_t()
|
||||
, base2_t(open_only, key, read_only, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
, base2_t(open_only, key, read_only, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
//!Connects to a created shared memory and its segment manager.
|
||||
//!This can throw.
|
||||
basic_managed_xsi_shared_memory (open_only_t open_only, const xsi_key &key,
|
||||
basic_managed_xsi_shared_memory (open_only_t, const xsi_key &key,
|
||||
const void *addr = 0)
|
||||
: base_t()
|
||||
, base2_t(open_only, key, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
, base2_t(open_only, key, read_write, addr,
|
||||
create_open_func_t(get_this_pointer(),
|
||||
ipcdetail::DoOpen))
|
||||
{}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -20,10 +20,23 @@
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/detail/os_file_functions.hpp>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <boost/cstdint.hpp>
|
||||
//Some Unixes use caddr_t instead of void * in madvise
|
||||
// SunOS Tru64 HP-UX AIX
|
||||
#if defined(sun) || defined(__sun) || defined(__osf__) || defined(__osf) || defined(_hpux) || defined(hpux) || defined(_AIX)
|
||||
#define BOOST_INTERPROCESS_MADVISE_USES_CADDR_T
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if (defined BOOST_INTERPROCESS_WINDOWS)
|
||||
//A lot of UNIXes have destructive semantics for MADV_DONTNEED, so
|
||||
//we need to be careful to allow it.
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
||||
#define BOOST_INTERPROCESS_MADV_DONTNEED_HAS_NONDESTRUCTIVE_SEMANTICS
|
||||
#endif
|
||||
|
||||
#if defined (BOOST_INTERPROCESS_WINDOWS)
|
||||
# include <boost/interprocess/detail/win32_api.hpp>
|
||||
# include <boost/interprocess/sync/windows/sync_utils.hpp>
|
||||
#else
|
||||
# ifdef BOOST_HAS_UNISTD_H
|
||||
# include <fcntl.h>
|
||||
@@ -48,6 +61,13 @@ namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
/// @cond
|
||||
|
||||
//Solaris declares madvise only in some configurations but defines MADV_XXX, a bit confusing.
|
||||
//Predeclare it here to avoid any compilation error
|
||||
#if (defined(sun) || defined(__sun)) && defined(MADV_NORMAL)
|
||||
extern "C" int madvise(caddr_t, size_t, int);
|
||||
#endif
|
||||
|
||||
namespace ipcdetail{ class interprocess_tester; }
|
||||
namespace ipcdetail{ class raw_mapped_region_creator; }
|
||||
|
||||
@@ -55,6 +75,10 @@ namespace ipcdetail{ class raw_mapped_region_creator; }
|
||||
|
||||
//!The mapped_region class represents a portion or region created from a
|
||||
//!memory_mappable object.
|
||||
//!
|
||||
//!The OS can map a region bigger than the requested one, as region must
|
||||
//!be multiple of the page size, but mapped_region will always refer to
|
||||
//!the region specified by the user.
|
||||
class mapped_region
|
||||
{
|
||||
/// @cond
|
||||
@@ -65,9 +89,15 @@ class mapped_region
|
||||
public:
|
||||
|
||||
//!Creates a mapping region of the mapped memory "mapping", starting in
|
||||
//!offset "offset", and the mapping's size will be "size". The mapping
|
||||
//!can be opened for read-only "read_only" or read-write
|
||||
//!"read_write.
|
||||
//!offset "offset", and the mapping's size will be "size". The mapping
|
||||
//!can be opened for read only, read-write or copy-on-write.
|
||||
//!
|
||||
//!If an address is specified, both the offset and the address must be
|
||||
//!multiples of the page size.
|
||||
//!
|
||||
//!The OS could allocate more pages than size/page_size(), but get_address()
|
||||
//!will always return the address passed in this function (if not null) and
|
||||
//!get_size() will return the specified size.
|
||||
template<class MemoryMappable>
|
||||
mapped_region(const MemoryMappable& mapping
|
||||
,mode_t mode
|
||||
@@ -75,8 +105,8 @@ class mapped_region
|
||||
,std::size_t size = 0
|
||||
,const void *address = 0);
|
||||
|
||||
//!Default constructor. Default constructor. Address will be 0 (nullptr).
|
||||
//!Size and offset will be 0.
|
||||
//!Default constructor. Address will be 0 (nullptr).
|
||||
//!Size will be 0.
|
||||
//!Does not throw
|
||||
mapped_region();
|
||||
|
||||
@@ -84,12 +114,12 @@ class mapped_region
|
||||
//!region and "other" will be left in default constructor state.
|
||||
mapped_region(BOOST_RV_REF(mapped_region) other)
|
||||
#if defined (BOOST_INTERPROCESS_WINDOWS)
|
||||
: m_base(0), m_size(0), m_offset(0)
|
||||
, m_extra_offset(0)
|
||||
: m_base(0), m_size(0)
|
||||
, m_page_offset(0)
|
||||
, m_mode(read_only)
|
||||
, m_file_mapping_hnd(ipcdetail::invalid_file())
|
||||
, m_file_or_mapping_hnd(ipcdetail::invalid_file())
|
||||
#else
|
||||
: m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only), m_is_xsi(false)
|
||||
: m_base(0), m_size(0), m_page_offset(0), m_mode(read_only), m_is_xsi(false)
|
||||
#endif
|
||||
{ this->swap(other); }
|
||||
|
||||
@@ -106,33 +136,67 @@ class mapped_region
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Returns the size of the mapping. Note for windows users: If
|
||||
//!windows_shared_memory is mapped using 0 as the size, it returns 0
|
||||
//!because the size is unknown. Never throws.
|
||||
//!Swaps the mapped_region with another
|
||||
//!mapped region
|
||||
void swap(mapped_region &other);
|
||||
|
||||
//!Returns the size of the mapping. Never throws.
|
||||
std::size_t get_size() const;
|
||||
|
||||
//!Returns the base address of the mapping.
|
||||
//!Never throws.
|
||||
void* get_address() const;
|
||||
|
||||
//!Returns the offset of the mapping from the beginning of the
|
||||
//!mapped memory. Never throws.
|
||||
offset_t get_offset() const;
|
||||
|
||||
//!Returns the mode of the mapping used to construct the mapped file.
|
||||
//!Returns the mode of the mapping used to construct the mapped region.
|
||||
//!Never throws.
|
||||
mode_t get_mode() const;
|
||||
|
||||
//!Flushes to the disk a byte range within the mapped memory.
|
||||
//!Never throws
|
||||
bool flush(std::size_t mapping_offset = 0, std::size_t numbytes = 0);
|
||||
//!Flushes to the disk a byte range within the mapped memory.
|
||||
//!If 'async' is true, the function will return before flushing operation is completed
|
||||
//!If 'async' is false, function will return once data has been written into the underlying
|
||||
//!device (i.e., in mapped files OS cached information is written to disk).
|
||||
//!Never throws. Returns false if operation could not be performed.
|
||||
bool flush(std::size_t mapping_offset = 0, std::size_t numbytes = 0, bool async = true);
|
||||
|
||||
//!Swaps the mapped_region with another
|
||||
//!mapped region
|
||||
void swap(mapped_region &other);
|
||||
//!Shrinks current mapped region. If after shrinking there is no longer need for a previously
|
||||
//!mapped memory page, accessing that page can trigger a segmentation fault.
|
||||
//!Depending on the OS, this operation might fail (XSI shared memory), it can decommit storage
|
||||
//!and free a portion of the virtual address space (e.g.POSIX) or this
|
||||
//!function can release some physical memory wihout freeing any virtual address space(Windows).
|
||||
//!Returns true on success. Never throws.
|
||||
bool shrink_by(std::size_t bytes, bool from_back = true);
|
||||
|
||||
//!This enum specifies region usage behaviors that an application can specify
|
||||
//!to the mapped region implementation.
|
||||
enum advice_types{
|
||||
//!Specifies that the application has no advice to give on its behavior with respect to
|
||||
//!the region. It is the default characteristic if no advice is given for a range of memory.
|
||||
advice_normal,
|
||||
//!Specifies that the application expects to access the region sequentially from
|
||||
//!lower addresses to higher addresses. The implementation can lower the priority of
|
||||
//!preceding pages within the region once a page have been accessed.
|
||||
advice_sequential,
|
||||
//!Specifies that the application expects to access the region in a random order,
|
||||
//!and prefetching is likely not advantageous.
|
||||
advice_random,
|
||||
//!Specifies that the application expects to access the region in the near future.
|
||||
//!The implementation can prefetch pages of the region.
|
||||
advice_willneed,
|
||||
//!Specifies that the application expects that it will not access the region in the near future.
|
||||
//!The implementation can unload pages within the range to save system resources.
|
||||
advice_dontneed
|
||||
};
|
||||
|
||||
//!Advises the implementation on the expected behavior of the application with respect to the data
|
||||
//!in the region. The implementation may use this information to optimize handling of the region data.
|
||||
//!This function has no effect on the semantics of access to memory in the region, although it may affect
|
||||
//!the performance of access.
|
||||
//!If the advise type is not known to the implementation, the function returns false. True otherwise.
|
||||
bool advise(advice_types advise);
|
||||
|
||||
//!Returns the size of the page. This size is the minimum memory that
|
||||
//!will be used by the system when mapping a memory mappable source.
|
||||
//!will be used by the system when mapping a memory mappable source and
|
||||
//!will restrict the address and the offset to map.
|
||||
static std::size_t get_page_size();
|
||||
|
||||
/// @cond
|
||||
@@ -140,6 +204,14 @@ class mapped_region
|
||||
//!Closes a previously opened memory mapping. Never throws
|
||||
void priv_close();
|
||||
|
||||
void* priv_map_address() const;
|
||||
std::size_t priv_map_size() const;
|
||||
bool priv_flush_param_check(std::size_t mapping_offset, void *&addr, std::size_t &numbytes) const;
|
||||
bool priv_shrink_param_check(std::size_t bytes, bool from_back, void *&shrink_page_start, std::size_t &shrink_page_bytes);
|
||||
static void priv_size_from_mapping_size
|
||||
(offset_t mapping_size, offset_t offset, offset_t page_offset, std::size_t &size);
|
||||
static offset_t priv_page_offset_addr_fixup(offset_t page_offset, const void *&addr);
|
||||
|
||||
template<int dummy>
|
||||
struct page_size_holder
|
||||
{
|
||||
@@ -149,11 +221,10 @@ class mapped_region
|
||||
|
||||
void* m_base;
|
||||
std::size_t m_size;
|
||||
offset_t m_offset;
|
||||
offset_t m_extra_offset;
|
||||
std::size_t m_page_offset;
|
||||
mode_t m_mode;
|
||||
#if (defined BOOST_INTERPROCESS_WINDOWS)
|
||||
file_handle_t m_file_mapping_hnd;
|
||||
#if defined(BOOST_INTERPROCESS_WINDOWS)
|
||||
file_handle_t m_file_or_mapping_hnd;
|
||||
#else
|
||||
bool m_is_xsi;
|
||||
#endif
|
||||
@@ -161,6 +232,10 @@ class mapped_region
|
||||
friend class ipcdetail::interprocess_tester;
|
||||
friend class ipcdetail::raw_mapped_region_creator;
|
||||
void dont_close_on_destruction();
|
||||
#if defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION)
|
||||
template<int Dummy>
|
||||
static void destroy_syncs_in_range(const void *addr, std::size_t size);
|
||||
#endif
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
@@ -175,20 +250,106 @@ inline mapped_region::~mapped_region()
|
||||
inline std::size_t mapped_region::get_size() const
|
||||
{ return m_size; }
|
||||
|
||||
inline offset_t mapped_region::get_offset() const
|
||||
{ return m_offset; }
|
||||
|
||||
inline mode_t mapped_region::get_mode() const
|
||||
{ return m_mode; }
|
||||
|
||||
inline void* mapped_region::get_address() const
|
||||
{ return m_base; }
|
||||
|
||||
inline void* mapped_region::priv_map_address() const
|
||||
{ return static_cast<char*>(m_base) - m_page_offset; }
|
||||
|
||||
inline std::size_t mapped_region::priv_map_size() const
|
||||
{ return m_size + m_page_offset; }
|
||||
|
||||
inline bool mapped_region::priv_flush_param_check
|
||||
(std::size_t mapping_offset, void *&addr, std::size_t &numbytes) const
|
||||
{
|
||||
//Check some errors
|
||||
if(m_base == 0)
|
||||
return false;
|
||||
|
||||
if(mapping_offset >= m_size || (mapping_offset + numbytes) > m_size){
|
||||
return false;
|
||||
}
|
||||
|
||||
//Update flush size if the user does not provide it
|
||||
if(numbytes == 0){
|
||||
numbytes = m_size - mapping_offset;
|
||||
}
|
||||
addr = (char*)this->priv_map_address() + mapping_offset;
|
||||
numbytes += m_page_offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool mapped_region::priv_shrink_param_check
|
||||
(std::size_t bytes, bool from_back, void *&shrink_page_start, std::size_t &shrink_page_bytes)
|
||||
{
|
||||
//Check some errors
|
||||
if(m_base == 0 || bytes > m_size){
|
||||
return false;
|
||||
}
|
||||
else if(bytes == m_size){
|
||||
this->priv_close();
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
const std::size_t page_size = mapped_region::get_page_size();
|
||||
if(from_back){
|
||||
const std::size_t new_pages = (m_size + m_page_offset - bytes - 1)/page_size + 1;
|
||||
shrink_page_start = static_cast<char*>(this->priv_map_address()) + new_pages*page_size;
|
||||
shrink_page_bytes = m_page_offset + m_size - new_pages*page_size;
|
||||
m_size -= bytes;
|
||||
}
|
||||
else{
|
||||
shrink_page_start = this->priv_map_address();
|
||||
m_page_offset += bytes;
|
||||
shrink_page_bytes = (m_page_offset/page_size)*page_size;
|
||||
m_page_offset = m_page_offset % page_size;
|
||||
m_size -= bytes;
|
||||
m_base = static_cast<char *>(m_base) + bytes;
|
||||
assert(shrink_page_bytes%page_size == 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inline void mapped_region::priv_size_from_mapping_size
|
||||
(offset_t mapping_size, offset_t offset, offset_t page_offset, std::size_t &size)
|
||||
{
|
||||
//Check if mapping size fits in the user address space
|
||||
//as offset_t is the maximum file size and its signed.
|
||||
if(mapping_size < offset ||
|
||||
boost::uintmax_t(mapping_size - (offset - page_offset)) >
|
||||
boost::uintmax_t(std::size_t(-1))){
|
||||
error_info err(size_error);
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
size = static_cast<std::size_t>(mapping_size - (offset - page_offset));
|
||||
}
|
||||
|
||||
inline offset_t mapped_region::priv_page_offset_addr_fixup(offset_t offset, const void *&address)
|
||||
{
|
||||
//We can't map any offset so we have to obtain system's
|
||||
//memory granularity
|
||||
const std::size_t page_size = mapped_region::get_page_size();
|
||||
|
||||
//We calculate the difference between demanded and valid offset
|
||||
//(always less than a page in std::size_t, thus, representable by std::size_t)
|
||||
const std::size_t page_offset =
|
||||
static_cast<std::size_t>(offset - (offset / page_size) * page_size);
|
||||
//Update the mapping address
|
||||
if(address){
|
||||
address = static_cast<const char*>(address) - page_offset;
|
||||
}
|
||||
return page_offset;
|
||||
}
|
||||
|
||||
#if defined (BOOST_INTERPROCESS_WINDOWS)
|
||||
|
||||
inline mapped_region::mapped_region()
|
||||
: m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only)
|
||||
, m_file_mapping_hnd(ipcdetail::invalid_file())
|
||||
: m_base(0), m_size(0), m_page_offset(0), m_mode(read_only)
|
||||
, m_file_or_mapping_hnd(ipcdetail::invalid_file())
|
||||
{}
|
||||
|
||||
template<int dummy>
|
||||
@@ -206,169 +367,177 @@ inline mapped_region::mapped_region
|
||||
,offset_t offset
|
||||
,std::size_t size
|
||||
,const void *address)
|
||||
: m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode)
|
||||
, m_file_mapping_hnd(ipcdetail::invalid_file())
|
||||
: m_base(0), m_size(0), m_page_offset(0), m_mode(mode)
|
||||
, m_file_or_mapping_hnd(ipcdetail::invalid_file())
|
||||
{
|
||||
mapping_handle_t mhandle = mapping.get_mapping_handle();
|
||||
file_handle_t native_mapping_handle = 0;
|
||||
|
||||
//Set accesses
|
||||
unsigned long file_map_access = 0;
|
||||
unsigned long map_access = 0;
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case read_only:
|
||||
case read_private:
|
||||
file_map_access |= winapi::page_readonly;
|
||||
map_access |= winapi::file_map_read;
|
||||
break;
|
||||
case read_write:
|
||||
file_map_access |= winapi::page_readwrite;
|
||||
map_access |= winapi::file_map_write;
|
||||
break;
|
||||
case copy_on_write:
|
||||
file_map_access |= winapi::page_writecopy;
|
||||
map_access |= winapi::file_map_copy;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
error_info err(mode_error);
|
||||
file_handle_t native_mapping_handle = 0;
|
||||
|
||||
//Set accesses
|
||||
//For "create_file_mapping"
|
||||
unsigned long protection = 0;
|
||||
//For "mapviewoffile"
|
||||
unsigned long map_access = 0;
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case read_only:
|
||||
case read_private:
|
||||
protection |= winapi::page_readonly;
|
||||
map_access |= winapi::file_map_read;
|
||||
break;
|
||||
case read_write:
|
||||
protection |= winapi::page_readwrite;
|
||||
map_access |= winapi::file_map_write;
|
||||
break;
|
||||
case copy_on_write:
|
||||
protection |= winapi::page_writecopy;
|
||||
map_access |= winapi::file_map_copy;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
error_info err(mode_error);
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//For file mapping (including emulated shared memory through temporary files),
|
||||
//the device is a file handle so we need to obtain file's size and call create_file_mapping
|
||||
//to obtain the mapping handle.
|
||||
//For files we don't need the file mapping after mapping the memory, as the file is there
|
||||
//so we'll program the handle close
|
||||
void * handle_to_close = winapi::invalid_handle_value;
|
||||
if(!mhandle.is_shm){
|
||||
//Create mapping handle
|
||||
native_mapping_handle = winapi::create_file_mapping
|
||||
( ipcdetail::file_handle_from_mapping_handle(mapping.get_mapping_handle())
|
||||
, protection, 0, 0, 0);
|
||||
|
||||
//Check if all is correct
|
||||
if(!native_mapping_handle){
|
||||
error_info err = winapi::get_last_error();
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
handle_to_close = native_mapping_handle;
|
||||
}
|
||||
else{
|
||||
//For windows_shared_memory the device handle is already a mapping handle
|
||||
//and we need to maintain it
|
||||
native_mapping_handle = mhandle.handle;
|
||||
}
|
||||
//RAII handle close on scope exit
|
||||
const winapi::handle_closer close_handle(handle_to_close);
|
||||
(void)close_handle;
|
||||
|
||||
if(!mhandle.is_shm){
|
||||
//Update mapping size if the user does not specify it
|
||||
const offset_t page_offset = priv_page_offset_addr_fixup(offset, address);
|
||||
|
||||
//Obtain mapping size if user provides 0 size
|
||||
if(size == 0){
|
||||
__int64 total_size;
|
||||
if(!winapi::get_file_size
|
||||
(ipcdetail::file_handle_from_mapping_handle
|
||||
(mapping.get_mapping_handle()), total_size)){
|
||||
error_info err(winapi::get_last_error());
|
||||
offset_t mapping_size;
|
||||
if(!winapi::get_file_mapping_size(native_mapping_handle, mapping_size)){
|
||||
error_info err = winapi::get_last_error();
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
|
||||
if(static_cast<unsigned __int64>(total_size) >
|
||||
(std::numeric_limits<std::size_t>::max)()){
|
||||
error_info err(size_error);
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
size = static_cast<std::size_t>(total_size - offset);
|
||||
//This can throw
|
||||
priv_size_from_mapping_size(mapping_size, offset, page_offset, size);
|
||||
}
|
||||
|
||||
//Create file mapping
|
||||
native_mapping_handle =
|
||||
winapi::create_file_mapping
|
||||
(ipcdetail::file_handle_from_mapping_handle(mapping.get_mapping_handle()), file_map_access, 0, 0, 0, 0);
|
||||
|
||||
//Check if all is correct
|
||||
if(!native_mapping_handle){
|
||||
//Map with new offsets and size
|
||||
void *base = winapi::map_view_of_file_ex
|
||||
(native_mapping_handle,
|
||||
map_access,
|
||||
offset - page_offset,
|
||||
static_cast<std::size_t>(page_offset + size),
|
||||
const_cast<void*>(address));
|
||||
//Check error
|
||||
if(!base){
|
||||
error_info err = winapi::get_last_error();
|
||||
this->priv_close();
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
|
||||
//Calculate new base for the user
|
||||
m_base = static_cast<char*>(base) + page_offset;
|
||||
m_page_offset = page_offset;
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
//We can't map any offset so we have to obtain system's
|
||||
//memory granularity
|
||||
unsigned long granularity = 0;
|
||||
unsigned long foffset_low;
|
||||
unsigned long foffset_high;
|
||||
|
||||
winapi::system_info info;
|
||||
get_system_info(&info);
|
||||
granularity = info.dwAllocationGranularity;
|
||||
|
||||
//Now we calculate valid offsets
|
||||
foffset_low = (unsigned long)(offset / granularity) * granularity;
|
||||
foffset_high = (unsigned long)(((offset / granularity) * granularity) >> 32);
|
||||
|
||||
//We calculate the difference between demanded and valid offset
|
||||
m_extra_offset = (offset - (offset / granularity) * granularity);
|
||||
|
||||
//Store user values in memory
|
||||
m_offset = offset;
|
||||
m_size = size;
|
||||
|
||||
//Update the mapping address
|
||||
if(address){
|
||||
address = static_cast<const char*>(address) - m_extra_offset;
|
||||
}
|
||||
|
||||
if(mhandle.is_shm){
|
||||
//Windows shared memory needs the duplication of the handle if we want to
|
||||
//make mapped_region independent from the mappable device
|
||||
if(!winapi::duplicate_current_process_handle(mhandle.handle, &m_file_mapping_hnd)){
|
||||
error_info err = winapi::get_last_error();
|
||||
this->priv_close();
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
native_mapping_handle = m_file_mapping_hnd;
|
||||
}
|
||||
|
||||
//Map with new offsets and size
|
||||
m_base = winapi::map_view_of_file_ex
|
||||
(native_mapping_handle,
|
||||
map_access,
|
||||
foffset_high,
|
||||
foffset_low,
|
||||
m_size ? static_cast<std::size_t>(m_extra_offset + m_size) : 0,
|
||||
const_cast<void*>(address));
|
||||
|
||||
if(!mhandle.is_shm){
|
||||
//For files we don't need the file mapping anymore
|
||||
winapi::close_handle(native_mapping_handle);
|
||||
}
|
||||
|
||||
//Check error
|
||||
if(!m_base){
|
||||
//Windows shared memory needs the duplication of the handle if we want to
|
||||
//make mapped_region independent from the mappable device
|
||||
//
|
||||
//For mapped files, we duplicate the file handle to be able to FlushFileBuffers
|
||||
if(!winapi::duplicate_current_process_handle(mhandle.handle, &m_file_or_mapping_hnd)){
|
||||
error_info err = winapi::get_last_error();
|
||||
this->priv_close();
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
|
||||
//Calculate new base for the user
|
||||
m_base = static_cast<char*>(m_base) + m_extra_offset;
|
||||
}
|
||||
|
||||
inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes)
|
||||
inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes, bool async)
|
||||
{
|
||||
//Check some errors
|
||||
if(m_base == 0)
|
||||
return false;
|
||||
|
||||
if(mapping_offset >= m_size || (mapping_offset + numbytes) > m_size){
|
||||
void *addr;
|
||||
if(!this->priv_flush_param_check(mapping_offset, addr, numbytes)){
|
||||
return false;
|
||||
}
|
||||
|
||||
//Update flush size if the user does not provide it
|
||||
if(m_size == 0){
|
||||
numbytes = 0;
|
||||
}
|
||||
else if(numbytes == 0){
|
||||
numbytes = m_size - mapping_offset;
|
||||
}
|
||||
|
||||
//Flush it all
|
||||
return winapi::flush_view_of_file
|
||||
(static_cast<char*>(m_base)+mapping_offset,
|
||||
static_cast<std::size_t>(numbytes));
|
||||
if(!winapi::flush_view_of_file(addr, numbytes)){
|
||||
return false;
|
||||
}
|
||||
//m_file_or_mapping_hnd can be a file handle or a mapping handle.
|
||||
//so flushing file buffers has only sense for files...
|
||||
else if(async && m_file_or_mapping_hnd != winapi::invalid_handle_value &&
|
||||
winapi::get_file_type(m_file_or_mapping_hnd) == winapi::file_type_disk){
|
||||
return winapi::flush_file_buffers(m_file_or_mapping_hnd);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool mapped_region::shrink_by(std::size_t bytes, bool from_back)
|
||||
{
|
||||
void *shrink_page_start;
|
||||
std::size_t shrink_page_bytes;
|
||||
if(!this->priv_shrink_param_check(bytes, from_back, shrink_page_start, shrink_page_bytes)){
|
||||
return false;
|
||||
}
|
||||
else if(shrink_page_bytes){
|
||||
//In Windows, we can't decommit the storage or release the virtual address space,
|
||||
//the best we can do is try to remove some memory from the process working set.
|
||||
//With a bit of luck we can free some physical memory.
|
||||
unsigned long old_protect_ignored;
|
||||
bool b_ret = winapi::virtual_unlock(shrink_page_start, shrink_page_bytes)
|
||||
|| (winapi::get_last_error() == winapi::error_not_locked);
|
||||
(void)old_protect_ignored;
|
||||
//Change page protection to forbid any further access
|
||||
b_ret = b_ret && winapi::virtual_protect
|
||||
(shrink_page_start, shrink_page_bytes, winapi::page_noaccess, old_protect_ignored);
|
||||
return b_ret;
|
||||
}
|
||||
else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool mapped_region::advise(advice_types)
|
||||
{
|
||||
//Windows has no madvise/posix_madvise equivalent
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void mapped_region::priv_close()
|
||||
{
|
||||
if(m_base){
|
||||
winapi::unmap_view_of_file(static_cast<char*>(m_base) - m_extra_offset);
|
||||
void *addr = this->priv_map_address();
|
||||
#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION)
|
||||
mapped_region::destroy_syncs_in_range<0>(addr, m_size);
|
||||
#endif
|
||||
winapi::unmap_view_of_file(addr);
|
||||
m_base = 0;
|
||||
}
|
||||
#if (defined BOOST_INTERPROCESS_WINDOWS)
|
||||
if(m_file_mapping_hnd != ipcdetail::invalid_file()){
|
||||
winapi::close_handle(m_file_mapping_hnd);
|
||||
m_file_mapping_hnd = ipcdetail::invalid_file();
|
||||
}
|
||||
#endif
|
||||
if(m_file_or_mapping_hnd != ipcdetail::invalid_file()){
|
||||
winapi::close_handle(m_file_or_mapping_hnd);
|
||||
m_file_or_mapping_hnd = ipcdetail::invalid_file();
|
||||
}
|
||||
}
|
||||
|
||||
inline void mapped_region::dont_close_on_destruction()
|
||||
@@ -377,7 +546,7 @@ inline void mapped_region::dont_close_on_destruction()
|
||||
#else //#if (defined BOOST_INTERPROCESS_WINDOWS)
|
||||
|
||||
inline mapped_region::mapped_region()
|
||||
: m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only), m_is_xsi(false)
|
||||
: m_base(0), m_size(0), m_page_offset(0), m_mode(read_only), m_is_xsi(false)
|
||||
{}
|
||||
|
||||
template<int dummy>
|
||||
@@ -391,7 +560,7 @@ inline mapped_region::mapped_region
|
||||
, offset_t offset
|
||||
, std::size_t size
|
||||
, const void *address)
|
||||
: m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode), m_is_xsi(false)
|
||||
: m_base(0), m_size(0), m_page_offset(0), m_mode(mode), m_is_xsi(false)
|
||||
{
|
||||
mapping_handle_t map_hnd = mapping.get_mapping_handle();
|
||||
|
||||
@@ -430,33 +599,36 @@ inline mapped_region::mapped_region
|
||||
}
|
||||
//Update members
|
||||
m_base = base;
|
||||
m_offset = offset;
|
||||
m_size = size;
|
||||
m_mode = mode;
|
||||
m_extra_offset = 0;
|
||||
m_page_offset = 0;
|
||||
m_is_xsi = true;
|
||||
return;
|
||||
}
|
||||
#endif //ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
|
||||
|
||||
//We calculate the difference between demanded and valid offset
|
||||
const offset_t page_offset = priv_page_offset_addr_fixup(offset, address);
|
||||
|
||||
if(size == 0){
|
||||
struct ::stat buf;
|
||||
if(0 != fstat(map_hnd.handle, &buf)){
|
||||
error_info err(system_error_code());
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
std::size_t filesize = (std::size_t)buf.st_size;
|
||||
if((std::size_t)offset >= filesize){
|
||||
error_info err(size_error);
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
|
||||
filesize -= offset;
|
||||
size = filesize;
|
||||
//This can throw
|
||||
priv_size_from_mapping_size(buf.st_size, offset, page_offset, size);
|
||||
}
|
||||
|
||||
//Create new mapping
|
||||
int prot = 0;
|
||||
int flags = 0;
|
||||
int flags =
|
||||
#ifdef MAP_NOSYNC
|
||||
//Avoid excessive syncing in BSD systems
|
||||
MAP_NOSYNC;
|
||||
#else
|
||||
0;
|
||||
#endif
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
@@ -488,35 +660,23 @@ inline mapped_region::mapped_region
|
||||
break;
|
||||
}
|
||||
|
||||
//We calculate the difference between demanded and valid offset
|
||||
const std::size_t page_size = this->get_page_size();
|
||||
const offset_t extra_offset = offset - (offset / page_size) * page_size;
|
||||
|
||||
|
||||
//Update the mapping address
|
||||
if(address){
|
||||
address = static_cast<const char*>(address) - extra_offset;
|
||||
}
|
||||
|
||||
//Map it to the address space
|
||||
void* base = mmap ( const_cast<void*>(address)
|
||||
, static_cast<std::size_t>(extra_offset + size)
|
||||
, static_cast<std::size_t>(page_offset + size)
|
||||
, prot
|
||||
, flags
|
||||
, mapping.get_mapping_handle().handle
|
||||
, offset - extra_offset);
|
||||
, offset - page_offset);
|
||||
|
||||
//Check if mapping was successful
|
||||
if(base == MAP_FAILED){
|
||||
error_info err = system_error_code();
|
||||
this->priv_close();
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
|
||||
//Calculate new base for the user
|
||||
m_base = static_cast<char*>(base) + extra_offset;
|
||||
m_extra_offset = extra_offset;
|
||||
m_offset = offset;
|
||||
m_base = static_cast<char*>(base) + page_offset;
|
||||
m_page_offset = page_offset;
|
||||
m_size = size;
|
||||
|
||||
//Check for fixed mapping error
|
||||
@@ -527,17 +687,107 @@ inline mapped_region::mapped_region
|
||||
}
|
||||
}
|
||||
|
||||
inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes)
|
||||
inline bool mapped_region::shrink_by(std::size_t bytes, bool from_back)
|
||||
{
|
||||
if(mapping_offset >= m_size || (mapping_offset+numbytes)> m_size){
|
||||
void *shrink_page_start = 0;
|
||||
std::size_t shrink_page_bytes = 0;
|
||||
if(m_is_xsi || !this->priv_shrink_param_check(bytes, from_back, shrink_page_start, shrink_page_bytes)){
|
||||
return false;
|
||||
}
|
||||
else if(shrink_page_bytes){
|
||||
//In UNIX we can decommit and free virtual address space.
|
||||
return 0 == munmap(shrink_page_start, shrink_page_bytes);
|
||||
}
|
||||
else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(numbytes == 0){
|
||||
numbytes = m_size - mapping_offset;
|
||||
inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes, bool async)
|
||||
{
|
||||
void *addr;
|
||||
if(m_is_xsi || !this->priv_flush_param_check(mapping_offset, addr, numbytes)){
|
||||
return false;
|
||||
}
|
||||
//Flush it all
|
||||
return msync(static_cast<char*>(m_base)+mapping_offset, numbytes, MS_ASYNC) == 0;
|
||||
return msync(addr, numbytes, async ? MS_ASYNC : MS_SYNC) == 0;
|
||||
}
|
||||
|
||||
inline bool mapped_region::advise(advice_types advice)
|
||||
{
|
||||
int unix_advice = 0;
|
||||
//Modes; 0: none, 2: posix, 1: madvise
|
||||
const unsigned int mode_none = 0;
|
||||
const unsigned int mode_padv = 1;
|
||||
const unsigned int mode_madv = 2;
|
||||
unsigned int mode = mode_none;
|
||||
//Choose advice either from POSIX (preferred) or native Unix
|
||||
switch(advice){
|
||||
case advice_normal:
|
||||
#if defined(POSIX_MADV_NORMAL)
|
||||
unix_advice = POSIX_MADV_NORMAL;
|
||||
mode = mode_padv;
|
||||
#elif defined(MADV_NORMAL)
|
||||
unix_advice = MADV_NORMAL;
|
||||
mode = mode_madv;
|
||||
#endif
|
||||
break;
|
||||
case advice_sequential:
|
||||
#if defined(POSIX_MADV_SEQUENTIAL)
|
||||
unix_advice = POSIX_MADV_SEQUENTIAL;
|
||||
mode = mode_padv;
|
||||
#elif defined(MADV_SEQUENTIAL)
|
||||
unix_advice = MADV_SEQUENTIAL;
|
||||
mode = mode_madv;
|
||||
#endif
|
||||
break;
|
||||
case advice_random:
|
||||
#if defined(POSIX_MADV_RANDOM)
|
||||
unix_advice = POSIX_MADV_RANDOM;
|
||||
mode = mode_padv;
|
||||
#elif defined(MADV_RANDOM)
|
||||
unix_advice = MADV_RANDOM;
|
||||
mode = mode_madv;
|
||||
#endif
|
||||
break;
|
||||
case advice_willneed:
|
||||
#if defined(POSIX_MADV_WILLNEED)
|
||||
unix_advice = POSIX_MADV_WILLNEED;
|
||||
mode = mode_padv;
|
||||
#elif defined(MADV_WILLNEED)
|
||||
unix_advice = MADV_WILLNEED;
|
||||
mode = mode_madv;
|
||||
#endif
|
||||
break;
|
||||
case advice_dontneed:
|
||||
#if defined(POSIX_MADV_DONTNEED)
|
||||
unix_advice = POSIX_MADV_DONTNEED;
|
||||
mode = mode_padv;
|
||||
#elif defined(MADV_DONTNEED) && defined(BOOST_INTERPROCESS_MADV_DONTNEED_HAS_NONDESTRUCTIVE_SEMANTICS)
|
||||
unix_advice = MADV_DONTNEED;
|
||||
mode = mode_madv;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
switch(mode){
|
||||
#if defined(POSIX_MADV_NORMAL)
|
||||
case mode_padv:
|
||||
return 0 == posix_madvise(this->priv_map_address(), this->priv_map_size(), unix_advice);
|
||||
#endif
|
||||
#if defined(MADV_NORMAL)
|
||||
case mode_madv:
|
||||
return 0 == madvise(
|
||||
#if defined(BOOST_INTERPROCESS_MADVISE_USES_CADDR_T)
|
||||
(caddr_t)
|
||||
#endif
|
||||
this->priv_map_address(), this->priv_map_size(), unix_advice);
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline void mapped_region::priv_close()
|
||||
@@ -551,7 +801,7 @@ inline void mapped_region::priv_close()
|
||||
return;
|
||||
}
|
||||
#endif //#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
|
||||
munmap(static_cast<char*>(m_base) - m_extra_offset, m_size + m_extra_offset);
|
||||
munmap(this->priv_map_address(), this->priv_map_size());
|
||||
m_base = 0;
|
||||
}
|
||||
}
|
||||
@@ -577,11 +827,10 @@ inline void mapped_region::swap(mapped_region &other)
|
||||
{
|
||||
ipcdetail::do_swap(this->m_base, other.m_base);
|
||||
ipcdetail::do_swap(this->m_size, other.m_size);
|
||||
ipcdetail::do_swap(this->m_offset, other.m_offset);
|
||||
ipcdetail::do_swap(this->m_extra_offset, other.m_extra_offset);
|
||||
ipcdetail::do_swap(this->m_page_offset, other.m_page_offset);
|
||||
ipcdetail::do_swap(this->m_mode, other.m_mode);
|
||||
#if (defined BOOST_INTERPROCESS_WINDOWS)
|
||||
ipcdetail::do_swap(this->m_file_mapping_hnd, other.m_file_mapping_hnd);
|
||||
ipcdetail::do_swap(this->m_file_or_mapping_hnd, other.m_file_or_mapping_hnd);
|
||||
#else
|
||||
ipcdetail::do_swap(this->m_is_xsi, other.m_is_xsi);
|
||||
#endif
|
||||
@@ -592,6 +841,9 @@ struct null_mapped_region_function
|
||||
{
|
||||
bool operator()(void *, std::size_t , bool) const
|
||||
{ return true; }
|
||||
|
||||
std::size_t get_min_size() const
|
||||
{ return 0; }
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
@@ -603,3 +855,32 @@ struct null_mapped_region_function
|
||||
|
||||
#endif //BOOST_INTERPROCESS_MAPPED_REGION_HPP
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP
|
||||
#define BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP
|
||||
|
||||
#if defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION)
|
||||
# include <boost/interprocess/sync/windows/sync_utils.hpp>
|
||||
# include <boost/interprocess/detail/windows_intermodule_singleton.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
template<int Dummy>
|
||||
inline void mapped_region::destroy_syncs_in_range(const void *addr, std::size_t size)
|
||||
{
|
||||
ipcdetail::sync_handles &handles =
|
||||
ipcdetail::windows_intermodule_singleton<ipcdetail::sync_handles>::get();
|
||||
handles.destroy_syncs_in_range(addr, size);
|
||||
}
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#endif //defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION)
|
||||
|
||||
#endif //#ifdef BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP
|
||||
|
||||
#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/interprocess/detail/min_max.hpp>
|
||||
#include <boost/container/detail/multiallocation_chain.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <algorithm>
|
||||
@@ -40,6 +41,37 @@ namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
template<class VoidPointer>
|
||||
class basic_multiallocation_chain
|
||||
: public boost::container::container_detail::
|
||||
basic_multiallocation_chain<VoidPointer>
|
||||
{
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_multiallocation_chain)
|
||||
typedef boost::container::container_detail::
|
||||
basic_multiallocation_chain<VoidPointer> base_t;
|
||||
public:
|
||||
|
||||
basic_multiallocation_chain()
|
||||
: base_t()
|
||||
{}
|
||||
|
||||
basic_multiallocation_chain(BOOST_RV_REF(basic_multiallocation_chain) other)
|
||||
: base_t(::boost::move(static_cast<base_t&>(other)))
|
||||
{}
|
||||
|
||||
basic_multiallocation_chain& operator=(BOOST_RV_REF(basic_multiallocation_chain) other)
|
||||
{
|
||||
this->base_t::operator=(::boost::move(static_cast<base_t&>(other)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void *pop_front()
|
||||
{
|
||||
return boost::interprocess::ipcdetail::to_raw_pointer(this->base_t::pop_front());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//!This class implements several allocation functions shared by different algorithms
|
||||
//!(aligned allocation, multiple allocation...).
|
||||
template<class MemoryAlgorithm>
|
||||
@@ -81,15 +113,15 @@ class memory_algorithm_common
|
||||
static size_type multiple_of_units(size_type size)
|
||||
{ return get_rounded_size(size, Alignment); }
|
||||
|
||||
static multiallocation_chain allocate_many
|
||||
(MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements)
|
||||
static void allocate_many
|
||||
(MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
|
||||
{
|
||||
return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0);
|
||||
return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0, chain);
|
||||
}
|
||||
|
||||
static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain)
|
||||
static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain)
|
||||
{
|
||||
return this_type::priv_deallocate_many(memory_algo, boost::move(chain));
|
||||
return this_type::priv_deallocate_many(memory_algo, chain);
|
||||
}
|
||||
|
||||
static bool calculate_lcm_and_needs_backwards_lcmed
|
||||
@@ -117,7 +149,7 @@ class memory_algorithm_common
|
||||
|
||||
lcm_val = max;
|
||||
//If we want to use minbytes data to get a buffer between maxbytes
|
||||
//and minbytes if maxbytes can't be achieved, calculate the
|
||||
//and minbytes if maxbytes can't be achieved, calculate the
|
||||
//biggest of all possibilities
|
||||
current_forward = get_truncated_size_po2(received_size, backwards_multiple);
|
||||
needs_backwards = size_to_achieve - current_forward;
|
||||
@@ -176,7 +208,7 @@ class memory_algorithm_common
|
||||
lcm_val = lcm(max, min);
|
||||
}
|
||||
//If we want to use minbytes data to get a buffer between maxbytes
|
||||
//and minbytes if maxbytes can't be achieved, calculate the
|
||||
//and minbytes if maxbytes can't be achieved, calculate the
|
||||
//biggest of all possibilities
|
||||
current_forward = get_truncated_size(received_size, backwards_multiple);
|
||||
needs_backwards = size_to_achieve - current_forward;
|
||||
@@ -187,19 +219,20 @@ class memory_algorithm_common
|
||||
return true;
|
||||
}
|
||||
|
||||
static multiallocation_chain allocate_many
|
||||
static void allocate_many
|
||||
( MemoryAlgorithm *memory_algo
|
||||
, const size_type *elem_sizes
|
||||
, size_type n_elements
|
||||
, size_type sizeof_element)
|
||||
, size_type sizeof_element
|
||||
, multiallocation_chain &chain)
|
||||
{
|
||||
return this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element);
|
||||
this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, chain);
|
||||
}
|
||||
|
||||
static void* allocate_aligned
|
||||
(MemoryAlgorithm *memory_algo, size_type nbytes, size_type alignment)
|
||||
{
|
||||
|
||||
|
||||
//Ensure power of 2
|
||||
if ((alignment & (alignment - size_type(1u))) != 0){
|
||||
//Alignment is not power of two
|
||||
@@ -215,7 +248,7 @@ class memory_algorithm_common
|
||||
|
||||
if(nbytes > UsableByPreviousChunk)
|
||||
nbytes -= UsableByPreviousChunk;
|
||||
|
||||
|
||||
//We can find a aligned portion if we allocate a block that has alignment
|
||||
//nbytes + alignment bytes or more.
|
||||
size_type minimum_allocation = max_value
|
||||
@@ -223,13 +256,13 @@ class memory_algorithm_common
|
||||
//Since we will split that block, we must request a bit more memory
|
||||
//if the alignment is near the beginning of the buffer, because otherwise,
|
||||
//there is no space for a new block before the alignment.
|
||||
//
|
||||
//
|
||||
// ____ Aligned here
|
||||
// |
|
||||
// -----------------------------------------------------
|
||||
// | MBU |
|
||||
// | MBU |
|
||||
// -----------------------------------------------------
|
||||
size_type request =
|
||||
size_type request =
|
||||
minimum_allocation + (2*MinBlockUnits*Alignment - AllocatedCtrlBytes
|
||||
//prevsize - UsableByPreviousChunk
|
||||
);
|
||||
@@ -263,7 +296,7 @@ class memory_algorithm_common
|
||||
}
|
||||
|
||||
//Buffer not aligned, find the aligned part.
|
||||
//
|
||||
//
|
||||
// ____ Aligned here
|
||||
// |
|
||||
// -----------------------------------------------------
|
||||
@@ -324,7 +357,7 @@ class memory_algorithm_common
|
||||
return memory_algo->priv_get_user_buffer(second);
|
||||
}
|
||||
|
||||
static bool try_shrink
|
||||
static bool try_shrink
|
||||
(MemoryAlgorithm *memory_algo, void *ptr
|
||||
,const size_type max_size, const size_type preferred_size
|
||||
,size_type &received_size)
|
||||
@@ -361,8 +394,8 @@ class memory_algorithm_common
|
||||
if(old_user_units == preferred_user_units)
|
||||
return true;
|
||||
|
||||
size_type shrunk_user_units =
|
||||
((BlockCtrlUnits - AllocatedCtrlUnits) > preferred_user_units)
|
||||
size_type shrunk_user_units =
|
||||
((BlockCtrlUnits - AllocatedCtrlUnits) >= preferred_user_units)
|
||||
? (BlockCtrlUnits - AllocatedCtrlUnits)
|
||||
: preferred_user_units;
|
||||
|
||||
@@ -380,7 +413,7 @@ class memory_algorithm_common
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool shrink
|
||||
static bool shrink
|
||||
(MemoryAlgorithm *memory_algo, void *ptr
|
||||
,const size_type max_size, const size_type preferred_size
|
||||
,size_type &received_size)
|
||||
@@ -389,7 +422,7 @@ class memory_algorithm_common
|
||||
block_ctrl *block = memory_algo->priv_get_block(ptr);
|
||||
size_type old_block_units = (size_type)block->m_size;
|
||||
|
||||
if(!try_shrink
|
||||
if(!try_shrink
|
||||
(memory_algo, ptr, max_size, preferred_size, received_size)){
|
||||
return false;
|
||||
}
|
||||
@@ -416,11 +449,12 @@ class memory_algorithm_common
|
||||
}
|
||||
|
||||
private:
|
||||
static multiallocation_chain priv_allocate_many
|
||||
static void priv_allocate_many
|
||||
( MemoryAlgorithm *memory_algo
|
||||
, const size_type *elem_sizes
|
||||
, size_type n_elements
|
||||
, size_type sizeof_element)
|
||||
, size_type sizeof_element
|
||||
, multiallocation_chain &chain)
|
||||
{
|
||||
//Note: sizeof_element == 0 indicates that we want to
|
||||
//allocate n_elements of the same size "*elem_sizes"
|
||||
@@ -436,111 +470,114 @@ class memory_algorithm_common
|
||||
}
|
||||
else{
|
||||
for(size_type i = 0; i < n_elements; ++i){
|
||||
if(multiplication_overflows(elem_sizes[i], sizeof_element)){
|
||||
total_request_units = 0;
|
||||
break;
|
||||
}
|
||||
elem_units = memory_algo->priv_get_total_units(elem_sizes[i]*sizeof_element);
|
||||
elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
|
||||
if(sum_overflows(total_request_units, elem_units)){
|
||||
total_request_units = 0;
|
||||
break;
|
||||
}
|
||||
total_request_units += elem_units;
|
||||
}
|
||||
}
|
||||
|
||||
multiallocation_chain chain;
|
||||
if(total_request_units && !multiplication_overflows(total_request_units, Alignment)){
|
||||
size_type low_idx = 0;
|
||||
while(low_idx < n_elements){
|
||||
size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
|
||||
size_type min_allocation = (!sizeof_element)
|
||||
? elem_units
|
||||
: memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
|
||||
min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
|
||||
|
||||
size_type low_idx = 0;
|
||||
while(low_idx < n_elements){
|
||||
size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
|
||||
size_type min_allocation = (!sizeof_element)
|
||||
? elem_units
|
||||
: memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
|
||||
min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
|
||||
|
||||
size_type received_size;
|
||||
std::pair<void *, bool> ret = memory_algo->priv_allocate
|
||||
(boost::interprocess::allocate_new, min_allocation, total_bytes, received_size, 0);
|
||||
if(!ret.first){
|
||||
break;
|
||||
}
|
||||
|
||||
block_ctrl *block = memory_algo->priv_get_block(ret.first);
|
||||
size_type received_units = (size_type)block->m_size;
|
||||
char *block_address = reinterpret_cast<char*>(block);
|
||||
|
||||
size_type total_used_units = 0;
|
||||
// block_ctrl *prev_block = 0;
|
||||
while(total_used_units < received_units){
|
||||
if(sizeof_element){
|
||||
elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
|
||||
elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
|
||||
}
|
||||
if(total_used_units + elem_units > received_units)
|
||||
size_type received_size;
|
||||
std::pair<void *, bool> ret = memory_algo->priv_allocate
|
||||
(boost::interprocess::allocate_new, min_allocation, total_bytes, received_size, 0);
|
||||
if(!ret.first){
|
||||
break;
|
||||
total_request_units -= elem_units;
|
||||
//This is the position where the new block must be created
|
||||
block_ctrl *new_block = reinterpret_cast<block_ctrl *>(block_address);
|
||||
assert_alignment(new_block);
|
||||
}
|
||||
|
||||
//The last block should take all the remaining space
|
||||
if((low_idx + 1) == n_elements ||
|
||||
(total_used_units + elem_units +
|
||||
((!sizeof_element)
|
||||
? elem_units
|
||||
: std::max(memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element), ptr_size_units))
|
||||
) > received_units){
|
||||
//By default, the new block will use the rest of the buffer
|
||||
new_block->m_size = received_units - total_used_units;
|
||||
memory_algo->priv_mark_new_allocated_block(new_block);
|
||||
block_ctrl *block = memory_algo->priv_get_block(ret.first);
|
||||
size_type received_units = (size_type)block->m_size;
|
||||
char *block_address = reinterpret_cast<char*>(block);
|
||||
|
||||
//If the remaining units are bigger than needed and we can
|
||||
//split it obtaining a new free memory block do it.
|
||||
if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){
|
||||
size_type shrunk_received;
|
||||
size_type shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
|
||||
bool shrink_ok = shrink
|
||||
(memory_algo
|
||||
,memory_algo->priv_get_user_buffer(new_block)
|
||||
,shrunk_request
|
||||
,shrunk_request
|
||||
,shrunk_received);
|
||||
(void)shrink_ok;
|
||||
//Shrink must always succeed with passed parameters
|
||||
BOOST_ASSERT(shrink_ok);
|
||||
//Some sanity checks
|
||||
BOOST_ASSERT(shrunk_request == shrunk_received);
|
||||
BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits));
|
||||
//"new_block->m_size" must have been reduced to elem_units by "shrink"
|
||||
BOOST_ASSERT(new_block->m_size == elem_units);
|
||||
//Now update the total received units with the reduction
|
||||
received_units = elem_units + total_used_units;
|
||||
size_type total_used_units = 0;
|
||||
while(total_used_units < received_units){
|
||||
if(sizeof_element){
|
||||
elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
|
||||
elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
|
||||
}
|
||||
}
|
||||
else{
|
||||
new_block->m_size = elem_units;
|
||||
memory_algo->priv_mark_new_allocated_block(new_block);
|
||||
}
|
||||
if(total_used_units + elem_units > received_units)
|
||||
break;
|
||||
total_request_units -= elem_units;
|
||||
//This is the position where the new block must be created
|
||||
block_ctrl *new_block = reinterpret_cast<block_ctrl *>(block_address);
|
||||
assert_alignment(new_block);
|
||||
|
||||
block_address += new_block->m_size*Alignment;
|
||||
total_used_units += (size_type)new_block->m_size;
|
||||
//Check we have enough room to overwrite the intrusive pointer
|
||||
BOOST_ASSERT((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer));
|
||||
void_pointer p = new(memory_algo->priv_get_user_buffer(new_block))void_pointer(0);
|
||||
chain.push_back(p);
|
||||
++low_idx;
|
||||
//prev_block = new_block;
|
||||
//The last block should take all the remaining space
|
||||
if((low_idx + 1) == n_elements ||
|
||||
(total_used_units + elem_units +
|
||||
((!sizeof_element)
|
||||
? elem_units
|
||||
: std::max(memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element), ptr_size_units))
|
||||
) > received_units){
|
||||
//By default, the new block will use the rest of the buffer
|
||||
new_block->m_size = received_units - total_used_units;
|
||||
memory_algo->priv_mark_new_allocated_block(new_block);
|
||||
|
||||
//If the remaining units are bigger than needed and we can
|
||||
//split it obtaining a new free memory block do it.
|
||||
if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){
|
||||
size_type shrunk_received;
|
||||
size_type shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
|
||||
bool shrink_ok = shrink
|
||||
(memory_algo
|
||||
,memory_algo->priv_get_user_buffer(new_block)
|
||||
,shrunk_request
|
||||
,shrunk_request
|
||||
,shrunk_received);
|
||||
(void)shrink_ok;
|
||||
//Shrink must always succeed with passed parameters
|
||||
BOOST_ASSERT(shrink_ok);
|
||||
//Some sanity checks
|
||||
BOOST_ASSERT(shrunk_request == shrunk_received);
|
||||
BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits));
|
||||
//"new_block->m_size" must have been reduced to elem_units by "shrink"
|
||||
BOOST_ASSERT(new_block->m_size == elem_units);
|
||||
//Now update the total received units with the reduction
|
||||
received_units = elem_units + total_used_units;
|
||||
}
|
||||
}
|
||||
else{
|
||||
new_block->m_size = elem_units;
|
||||
memory_algo->priv_mark_new_allocated_block(new_block);
|
||||
}
|
||||
|
||||
block_address += new_block->m_size*Alignment;
|
||||
total_used_units += (size_type)new_block->m_size;
|
||||
//Check we have enough room to overwrite the intrusive pointer
|
||||
BOOST_ASSERT((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer));
|
||||
void_pointer p = new(memory_algo->priv_get_user_buffer(new_block))void_pointer(0);
|
||||
chain.push_back(p);
|
||||
++low_idx;
|
||||
}
|
||||
//Sanity check
|
||||
BOOST_ASSERT(total_used_units == received_units);
|
||||
}
|
||||
|
||||
if(low_idx != n_elements){
|
||||
priv_deallocate_many(memory_algo, chain);
|
||||
}
|
||||
//Sanity check
|
||||
BOOST_ASSERT(total_used_units == received_units);
|
||||
}
|
||||
|
||||
if(low_idx != n_elements){
|
||||
priv_deallocate_many(memory_algo, boost::move(chain));
|
||||
}
|
||||
return boost::move(chain);
|
||||
}
|
||||
|
||||
static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain)
|
||||
static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain)
|
||||
{
|
||||
while(!chain.empty()){
|
||||
void *addr = to_raw_pointer(chain.front());
|
||||
chain.pop_front();
|
||||
memory_algo->priv_deallocate(addr);
|
||||
memory_algo->priv_deallocate(to_raw_pointer(chain.pop_front()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -60,7 +60,7 @@ class simple_seq_fit_impl
|
||||
simple_seq_fit_impl();
|
||||
simple_seq_fit_impl(const simple_seq_fit_impl &);
|
||||
simple_seq_fit_impl &operator=(const simple_seq_fit_impl &);
|
||||
|
||||
|
||||
typedef typename boost::intrusive::
|
||||
pointer_traits<VoidPointer>::template
|
||||
rebind_pointer<char>::type char_ptr;
|
||||
@@ -93,10 +93,10 @@ class simple_seq_fit_impl
|
||||
public:
|
||||
//!Offset pointer to the next block.
|
||||
block_ctrl_ptr m_next;
|
||||
//!This block's memory size (including block_ctrl
|
||||
//!This block's memory size (including block_ctrl
|
||||
//!header) in BasicSize units
|
||||
size_type m_size;
|
||||
|
||||
|
||||
size_type get_user_bytes() const
|
||||
{ return this->m_size*Alignment - BlockCtrlBytes; }
|
||||
|
||||
@@ -126,7 +126,7 @@ class simple_seq_fit_impl
|
||||
typedef ipcdetail::memory_algorithm_common<simple_seq_fit_impl> algo_impl_t;
|
||||
|
||||
public:
|
||||
//!Constructor. "size" is the total size of the managed memory segment,
|
||||
//!Constructor. "size" is the total size of the managed memory segment,
|
||||
//!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(simple_seq_fit_impl)
|
||||
//!offset that the allocator should not use at all.
|
||||
simple_seq_fit_impl (size_type size, size_type extra_hdr_bytes);
|
||||
@@ -145,27 +145,25 @@ class simple_seq_fit_impl
|
||||
/// @cond
|
||||
|
||||
//!Multiple element allocation, same size
|
||||
multiallocation_chain
|
||||
allocate_many(size_type elem_bytes, size_type num_elements)
|
||||
void allocate_many(size_type elem_bytes, size_type num_elements, multiallocation_chain &chain)
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
|
||||
//-----------------------
|
||||
return algo_impl_t::allocate_many(this, elem_bytes, num_elements);
|
||||
algo_impl_t::allocate_many(this, elem_bytes, num_elements, chain);
|
||||
}
|
||||
|
||||
//!Multiple element allocation, different size
|
||||
multiallocation_chain
|
||||
allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element)
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
|
||||
//-----------------------
|
||||
return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element);
|
||||
algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, chain);
|
||||
}
|
||||
|
||||
//!Multiple element deallocation
|
||||
void deallocate_many(multiallocation_chain chain);
|
||||
void deallocate_many(multiallocation_chain &chain);
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -197,12 +195,12 @@ class simple_seq_fit_impl
|
||||
template<class T>
|
||||
std::pair<T *, bool>
|
||||
allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
T *reuse_ptr = 0);
|
||||
|
||||
std::pair<void *, bool>
|
||||
raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
void *reuse_ptr = 0, size_type sizeof_object = 1);
|
||||
|
||||
//!Returns the size of the buffer previously allocated pointed by ptr
|
||||
@@ -306,7 +304,7 @@ simple_seq_fit_impl<MutexFamily, VoidPointer>
|
||||
size_type uint_this = (std::size_t)this_ptr;
|
||||
size_type uint_aligned_this = uint_this/Alignment*Alignment;
|
||||
size_type this_disalignment = (uint_this - uint_aligned_this);
|
||||
size_type block1_off =
|
||||
size_type block1_off =
|
||||
ipcdetail::get_rounded_size(sizeof(simple_seq_fit_impl) + extra_hdr_bytes + this_disalignment, Alignment)
|
||||
- this_disalignment;
|
||||
algo_impl_t::assert_alignment(this_disalignment + block1_off);
|
||||
@@ -322,7 +320,7 @@ simple_seq_fit_impl<MutexFamily, VoidPointer>
|
||||
size_type uint_this = (std::size_t)this;
|
||||
size_type uint_aligned_this = uint_this/Alignment*Alignment;
|
||||
size_type this_disalignment = (uint_this - uint_aligned_this);
|
||||
size_type old_end =
|
||||
size_type old_end =
|
||||
ipcdetail::get_truncated_size(m_header.m_size + this_disalignment, Alignment)
|
||||
- this_disalignment;
|
||||
algo_impl_t::assert_alignment(old_end + this_disalignment);
|
||||
@@ -331,11 +329,11 @@ simple_seq_fit_impl<MutexFamily, VoidPointer>
|
||||
|
||||
template<class MutexFamily, class VoidPointer>
|
||||
inline simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
simple_seq_fit_impl(size_type size, size_type extra_hdr_bytes)
|
||||
simple_seq_fit_impl(size_type segment_size, size_type extra_hdr_bytes)
|
||||
{
|
||||
//Initialize sizes and counters
|
||||
m_header.m_allocated = 0;
|
||||
m_header.m_size = size;
|
||||
m_header.m_size = segment_size;
|
||||
m_header.m_extra_hdr_bytes = extra_hdr_bytes;
|
||||
|
||||
//Initialize pointers
|
||||
@@ -344,7 +342,7 @@ inline simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
m_header.m_root.m_next = reinterpret_cast<block_ctrl*>
|
||||
((reinterpret_cast<char*>(this) + block1_off));
|
||||
algo_impl_t::assert_alignment(ipcdetail::to_raw_pointer(m_header.m_root.m_next));
|
||||
m_header.m_root.m_next->m_size = (size - block1_off)/Alignment;
|
||||
m_header.m_root.m_next->m_size = (segment_size - block1_off)/Alignment;
|
||||
m_header.m_root.m_next->m_next = &m_header.m_root;
|
||||
}
|
||||
|
||||
@@ -426,7 +424,7 @@ void simple_seq_fit_impl<MutexFamily, VoidPointer>::shrink_to_fit()
|
||||
(void)addr;
|
||||
BOOST_ASSERT(addr);
|
||||
BOOST_ASSERT(received_size == last_units*Alignment - AllocatedCtrlBytes);
|
||||
|
||||
|
||||
//Shrink it
|
||||
m_header.m_size /= Alignment;
|
||||
m_header.m_size -= last->m_size;
|
||||
@@ -462,19 +460,19 @@ void *simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
}
|
||||
|
||||
template<class MutexFamily, class VoidPointer>
|
||||
inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_add_segment(void *addr, size_type size)
|
||||
{
|
||||
inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_add_segment(void *addr, size_type segment_size)
|
||||
{
|
||||
algo_impl_t::assert_alignment(addr);
|
||||
//Check size
|
||||
BOOST_ASSERT(!(size < MinBlockSize));
|
||||
if(size < MinBlockSize)
|
||||
BOOST_ASSERT(!(segment_size < MinBlockSize));
|
||||
if(segment_size < MinBlockSize)
|
||||
return;
|
||||
//Construct big block using the new segment
|
||||
block_ctrl *new_block = static_cast<block_ctrl *>(addr);
|
||||
new_block->m_size = size/Alignment;
|
||||
new_block->m_size = segment_size/Alignment;
|
||||
new_block->m_next = 0;
|
||||
//Simulate this block was previously allocated
|
||||
m_header.m_allocated += new_block->m_size*Alignment;
|
||||
m_header.m_allocated += new_block->m_size*Alignment;
|
||||
//Return block and insert it in the free block list
|
||||
this->priv_deallocate(priv_get_user_buffer(new_block));
|
||||
}
|
||||
@@ -488,7 +486,7 @@ template<class MutexFamily, class VoidPointer>
|
||||
inline typename simple_seq_fit_impl<MutexFamily, VoidPointer>::size_type
|
||||
simple_seq_fit_impl<MutexFamily, VoidPointer>::get_free_memory() const
|
||||
{
|
||||
return m_header.m_size - m_header.m_allocated -
|
||||
return m_header.m_size - m_header.m_allocated -
|
||||
algo_impl_t::multiple_of_units(sizeof(*this) + m_header.m_extra_hdr_bytes);
|
||||
}
|
||||
|
||||
@@ -523,7 +521,7 @@ inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::zero_free_memory()
|
||||
|
||||
//Iterate through all free portions
|
||||
do{
|
||||
//Just clear user the memory part reserved for the user
|
||||
//Just clear user the memory part reserved for the user
|
||||
std::memset( priv_get_user_buffer(block)
|
||||
, 0
|
||||
, block->get_user_bytes());
|
||||
@@ -583,19 +581,19 @@ inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
template<class MutexFamily, class VoidPointer>
|
||||
inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
allocate_aligned(size_type nbytes, size_type alignment)
|
||||
{
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
|
||||
//-----------------------
|
||||
return algo_impl_t::
|
||||
allocate_aligned(this, nbytes, alignment);
|
||||
allocate_aligned(this, nbytes, alignment);
|
||||
}
|
||||
|
||||
template<class MutexFamily, class VoidPointer>
|
||||
template<class T>
|
||||
inline std::pair<T*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
T *reuse_ptr)
|
||||
{
|
||||
std::pair<void*, bool> ret = priv_allocation_command
|
||||
@@ -608,7 +606,7 @@ inline std::pair<T*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
template<class MutexFamily, class VoidPointer>
|
||||
inline std::pair<void*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects,
|
||||
size_type preferred_objects,size_type &received_objects,
|
||||
size_type preferred_objects,size_type &received_objects,
|
||||
void *reuse_ptr, size_type sizeof_object)
|
||||
{
|
||||
if(!sizeof_object)
|
||||
@@ -627,7 +625,7 @@ inline std::pair<void*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
template<class MutexFamily, class VoidPointer>
|
||||
inline std::pair<void*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
priv_allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
|
||||
size_type preferred_size, size_type &received_size,
|
||||
size_type preferred_size, size_type &received_size,
|
||||
void *reuse_ptr, size_type sizeof_object)
|
||||
{
|
||||
command &= ~boost::interprocess::expand_bwd;
|
||||
@@ -653,8 +651,7 @@ inline std::pair<void*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
|
||||
template<class MutexFamily, class VoidPointer>
|
||||
inline typename simple_seq_fit_impl<MutexFamily, VoidPointer>::size_type
|
||||
simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
size(const void *ptr) const
|
||||
simple_seq_fit_impl<MutexFamily, VoidPointer>::size(const void *ptr) const
|
||||
{
|
||||
//We need no synchronization since this block is not going
|
||||
//to be modified
|
||||
@@ -696,9 +693,9 @@ void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_type needs_backwards =
|
||||
size_type needs_backwards =
|
||||
ipcdetail::get_rounded_size(preferred_size - extra_forward, Alignment);
|
||||
|
||||
|
||||
if(!only_preferred_backwards){
|
||||
max_value(ipcdetail::get_rounded_size(min_size - extra_forward, Alignment)
|
||||
,min_value(prev->get_user_bytes(), needs_backwards));
|
||||
@@ -710,16 +707,16 @@ void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
if(!priv_expand(reuse_ptr, received_size, received_size, received_size)){
|
||||
BOOST_ASSERT(0);
|
||||
}
|
||||
|
||||
|
||||
//We need a minimum size to split the previous one
|
||||
if((prev->get_user_bytes() - needs_backwards) > 2*BlockCtrlBytes){
|
||||
block_ctrl *new_block = reinterpret_cast<block_ctrl*>
|
||||
(reinterpret_cast<char*>(reuse) - needs_backwards - BlockCtrlBytes);
|
||||
|
||||
new_block->m_next = 0;
|
||||
new_block->m_size =
|
||||
new_block->m_size =
|
||||
BlockCtrlUnits + (needs_backwards + extra_forward)/Alignment;
|
||||
prev->m_size =
|
||||
prev->m_size =
|
||||
(prev->get_total_bytes() - needs_backwards)/Alignment - BlockCtrlUnits;
|
||||
received_size = needs_backwards + extra_forward;
|
||||
m_header.m_allocated += needs_backwards + BlockCtrlBytes;
|
||||
@@ -744,15 +741,13 @@ void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
|
||||
template<class MutexFamily, class VoidPointer>
|
||||
inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
deallocate_many(typename simple_seq_fit_impl<MutexFamily, VoidPointer>::multiallocation_chain chain)
|
||||
deallocate_many(typename simple_seq_fit_impl<MutexFamily, VoidPointer>::multiallocation_chain &chain)
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
|
||||
//-----------------------
|
||||
while(!chain.empty()){
|
||||
void *addr = chain.front();
|
||||
chain.pop_front();
|
||||
this->priv_deallocate(addr);
|
||||
this->priv_deallocate(to_raw_pointer(chain.pop_front()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,7 +770,7 @@ std::pair<void *, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
,void *reuse_ptr)
|
||||
{
|
||||
if(command & boost::interprocess::shrink_in_place){
|
||||
bool success =
|
||||
bool success =
|
||||
algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size);
|
||||
return std::pair<void *, bool> ((success ? reuse_ptr : 0), true);
|
||||
}
|
||||
@@ -885,7 +880,7 @@ inline typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *
|
||||
}
|
||||
|
||||
template<class MutexFamily, class VoidPointer>
|
||||
inline
|
||||
inline
|
||||
std::pair<typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *
|
||||
,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *>
|
||||
simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
@@ -969,7 +964,7 @@ inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
//We can fill expand. Merge both blocks,
|
||||
block->m_next = next_block->m_next;
|
||||
block->m_size = merged_size;
|
||||
|
||||
|
||||
//Find the previous free block of next_block
|
||||
block_ctrl *prev = &m_header.m_root;
|
||||
while(ipcdetail::to_raw_pointer(prev->m_next) != next_block){
|
||||
@@ -978,7 +973,7 @@ inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
|
||||
//Now insert merged block in the free list
|
||||
//This allows reusing allocation logic in this function
|
||||
m_header.m_allocated -= old_block_size*Alignment;
|
||||
m_header.m_allocated -= old_block_size*Alignment;
|
||||
prev->m_next = block;
|
||||
|
||||
//Now use check and allocate to do the allocation logic
|
||||
@@ -992,7 +987,7 @@ inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
|
||||
BOOST_ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class MutexFamily, class VoidPointer> inline
|
||||
@@ -1006,7 +1001,7 @@ void* simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_check_and_allocate
|
||||
bool found = false;
|
||||
|
||||
if (block->m_size > upper_nunits){
|
||||
//This block is bigger than needed, split it in
|
||||
//This block is bigger than needed, split it in
|
||||
//two blocks, the first's size will be "units"
|
||||
//the second's size will be "block->m_size-units"
|
||||
size_type total_size = block->m_size;
|
||||
@@ -1057,7 +1052,7 @@ void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_deallocate(void* addr)
|
||||
|
||||
//Let's get free block list. List is always sorted
|
||||
//by memory address to allow block merging.
|
||||
//Pointer next always points to the first
|
||||
//Pointer next always points to the first
|
||||
//(lower address) block
|
||||
block_ctrl * prev = &m_header.m_root;
|
||||
block_ctrl * pos = ipcdetail::to_raw_pointer(m_header.m_root.m_next);
|
||||
@@ -1071,9 +1066,9 @@ void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_deallocate(void* addr)
|
||||
|
||||
size_type total_size = Alignment*block->m_size;
|
||||
BOOST_ASSERT(m_header.m_allocated >= total_size);
|
||||
|
||||
|
||||
//Update used memory count
|
||||
m_header.m_allocated -= total_size;
|
||||
m_header.m_allocated -= total_size;
|
||||
|
||||
//Let's find the previous and the next block of the block to deallocate
|
||||
//This ordering comparison must be done with original pointers
|
||||
@@ -1087,7 +1082,7 @@ void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_deallocate(void* addr)
|
||||
//Try to combine with upper block
|
||||
char *block_char_ptr = reinterpret_cast<char*>(ipcdetail::to_raw_pointer(block));
|
||||
|
||||
if ((block_char_ptr + Alignment*block->m_size) ==
|
||||
if ((block_char_ptr + Alignment*block->m_size) ==
|
||||
reinterpret_cast<char*>(ipcdetail::to_raw_pointer(pos))){
|
||||
block->m_size += pos->m_size;
|
||||
block->m_next = pos->m_next;
|
||||
@@ -1098,7 +1093,7 @@ void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_deallocate(void* addr)
|
||||
|
||||
//Try to combine with lower block
|
||||
if ((reinterpret_cast<char*>(ipcdetail::to_raw_pointer(prev))
|
||||
+ Alignment*prev->m_size) ==
|
||||
+ Alignment*prev->m_size) ==
|
||||
block_char_ptr){
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -88,8 +88,7 @@ class rbtree_best_fit
|
||||
typedef MutexFamily mutex_family;
|
||||
//!Pointer type to be used with the rest of the Interprocess framework
|
||||
typedef VoidPointer void_pointer;
|
||||
typedef boost::container::container_detail::
|
||||
basic_multiallocation_chain<VoidPointer> multiallocation_chain;
|
||||
typedef ipcdetail::basic_multiallocation_chain<VoidPointer> multiallocation_chain;
|
||||
|
||||
typedef typename boost::intrusive::pointer_traits<char_ptr>::difference_type difference_type;
|
||||
typedef typename boost::make_unsigned<difference_type>::type size_type;
|
||||
@@ -105,7 +104,7 @@ class rbtree_best_fit
|
||||
|
||||
struct SizeHolder
|
||||
{
|
||||
//!This block's memory size (including block_ctrl
|
||||
//!This block's memory size (including block_ctrl
|
||||
//!header) in Alignment units
|
||||
size_type m_prev_size : sizeof(size_type)*CHAR_BIT;
|
||||
size_type m_size : sizeof(size_type)*CHAR_BIT - 2;
|
||||
@@ -132,7 +131,7 @@ class rbtree_best_fit
|
||||
{ return size < block.m_size; }
|
||||
|
||||
bool operator()(const block_ctrl &block, size_type size) const
|
||||
{ return block.m_size < size; }
|
||||
{ return block.m_size < size; }
|
||||
};
|
||||
|
||||
//!Shared mutex to protect memory allocate/deallocate
|
||||
@@ -157,13 +156,13 @@ class rbtree_best_fit
|
||||
} m_header;
|
||||
|
||||
friend class ipcdetail::memory_algorithm_common<rbtree_best_fit>;
|
||||
|
||||
|
||||
typedef ipcdetail::memory_algorithm_common<rbtree_best_fit> algo_impl_t;
|
||||
|
||||
public:
|
||||
/// @endcond
|
||||
|
||||
//!Constructor. "size" is the total size of the managed memory segment,
|
||||
//!Constructor. "size" is the total size of the managed memory segment,
|
||||
//!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(rbtree_best_fit)
|
||||
//!offset that the allocator should not use at all.
|
||||
rbtree_best_fit (size_type size, size_type extra_hdr_bytes);
|
||||
@@ -184,27 +183,25 @@ class rbtree_best_fit
|
||||
//Experimental. Dont' use
|
||||
|
||||
//!Multiple element allocation, same size
|
||||
multiallocation_chain allocate_many(size_type elem_bytes, size_type num_elements)
|
||||
void allocate_many(size_type elem_bytes, size_type num_elements, multiallocation_chain &chain)
|
||||
{
|
||||
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
|
||||
//-----------------------
|
||||
return algo_impl_t::allocate_many(this, elem_bytes, num_elements);
|
||||
algo_impl_t::allocate_many(this, elem_bytes, num_elements, chain);
|
||||
}
|
||||
|
||||
//!Multiple element allocation, different size
|
||||
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element)
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
|
||||
{
|
||||
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
|
||||
//-----------------------
|
||||
return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element);
|
||||
algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, chain);
|
||||
}
|
||||
|
||||
//!Multiple element allocation, different size
|
||||
void deallocate_many(multiallocation_chain chain);
|
||||
void deallocate_many(multiallocation_chain &chain);
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -238,12 +235,12 @@ class rbtree_best_fit
|
||||
template<class T>
|
||||
std::pair<T *, bool>
|
||||
allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
T *reuse_ptr = 0);
|
||||
|
||||
std::pair<void *, bool>
|
||||
raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_object,
|
||||
size_type preferred_object,size_type &received_object,
|
||||
size_type preferred_object,size_type &received_object,
|
||||
void *reuse_ptr = 0, size_type sizeof_object = 1);
|
||||
|
||||
//!Returns the size of the buffer previously allocated pointed by ptr
|
||||
@@ -263,7 +260,7 @@ class rbtree_best_fit
|
||||
|
||||
std::pair<void*, bool>
|
||||
priv_allocation_command(boost::interprocess::allocation_type command, size_type limit_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
void *reuse_ptr, size_type sizeof_object);
|
||||
|
||||
|
||||
@@ -339,7 +336,7 @@ class rbtree_best_fit
|
||||
void priv_add_segment(void *addr, size_type size);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
static const size_type Alignment = !MemAlignment
|
||||
? size_type(::boost::alignment_of< ::boost::detail::max_align>::value)
|
||||
: size_type(MemAlignment)
|
||||
@@ -370,7 +367,7 @@ class rbtree_best_fit
|
||||
/// @cond
|
||||
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
inline typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::size_type
|
||||
inline typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::size_type
|
||||
rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>
|
||||
::priv_first_block_offset_from_this(const void *this_ptr, size_type extra_hdr_bytes)
|
||||
{
|
||||
@@ -385,29 +382,29 @@ inline typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::size_ty
|
||||
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
priv_add_segment(void *addr, size_type size)
|
||||
{
|
||||
priv_add_segment(void *addr, size_type segment_size)
|
||||
{
|
||||
//Check alignment
|
||||
algo_impl_t::check_alignment(addr);
|
||||
//Check size
|
||||
BOOST_ASSERT(size >= (BlockCtrlBytes + EndCtrlBlockBytes));
|
||||
BOOST_ASSERT(segment_size >= (BlockCtrlBytes + EndCtrlBlockBytes));
|
||||
|
||||
//Initialize the first big block and the "end" node
|
||||
block_ctrl *first_big_block = new(addr)block_ctrl;
|
||||
first_big_block->m_size = size/Alignment - EndCtrlBlockUnits;
|
||||
first_big_block->m_size = segment_size/Alignment - EndCtrlBlockUnits;
|
||||
BOOST_ASSERT(first_big_block->m_size >= BlockCtrlUnits);
|
||||
|
||||
//The "end" node is just a node of size 0 with the "end" bit set
|
||||
block_ctrl *end_block = static_cast<block_ctrl*>
|
||||
block_ctrl *end_block = static_cast<block_ctrl*>
|
||||
(new (reinterpret_cast<char*>(addr) + first_big_block->m_size*Alignment)SizeHolder);
|
||||
|
||||
//This will overwrite the prev part of the "end" node
|
||||
priv_mark_as_free_block (first_big_block);
|
||||
#ifdef BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP
|
||||
first_big_block->m_prev_size = end_block->m_size =
|
||||
first_big_block->m_prev_size = end_block->m_size =
|
||||
(reinterpret_cast<char*>(first_big_block) - reinterpret_cast<char*>(end_block))/Alignment;
|
||||
#else
|
||||
first_big_block->m_prev_size = end_block->m_size =
|
||||
first_big_block->m_prev_size = end_block->m_size =
|
||||
(reinterpret_cast<char*>(end_block) - reinterpret_cast<char*>(first_big_block))/Alignment;
|
||||
#endif
|
||||
end_block->m_allocated = 1;
|
||||
@@ -444,25 +441,25 @@ inline typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_c
|
||||
{
|
||||
size_type block1_off = priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes);
|
||||
const size_type original_first_block_size = m_header.m_size/Alignment*Alignment - block1_off/Alignment*Alignment - EndCtrlBlockBytes;
|
||||
block_ctrl *end_block = reinterpret_cast<block_ctrl*>
|
||||
block_ctrl *end_block = reinterpret_cast<block_ctrl*>
|
||||
(reinterpret_cast<char*>(this) + block1_off + original_first_block_size);
|
||||
return end_block;
|
||||
}
|
||||
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
inline rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
rbtree_best_fit(size_type size, size_type extra_hdr_bytes)
|
||||
rbtree_best_fit(size_type segment_size, size_type extra_hdr_bytes)
|
||||
{
|
||||
//Initialize the header
|
||||
m_header.m_allocated = 0;
|
||||
m_header.m_size = size;
|
||||
m_header.m_size = segment_size;
|
||||
m_header.m_extra_hdr_bytes = extra_hdr_bytes;
|
||||
|
||||
//Now write calculate the offset of the first big block that will
|
||||
//cover the whole segment
|
||||
BOOST_ASSERT(get_min_size(extra_hdr_bytes) <= size);
|
||||
BOOST_ASSERT(get_min_size(extra_hdr_bytes) <= segment_size);
|
||||
size_type block1_off = priv_first_block_offset_from_this(this, extra_hdr_bytes);
|
||||
priv_add_segment(reinterpret_cast<char*>(this) + block1_off, size - block1_off);
|
||||
priv_add_segment(reinterpret_cast<char*>(this) + block1_off, segment_size - block1_off);
|
||||
}
|
||||
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
@@ -479,7 +476,7 @@ void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::grow(size_type ext
|
||||
//Get the address of the first block
|
||||
block_ctrl *first_block = priv_first_block();
|
||||
block_ctrl *old_end_block = priv_end_block();
|
||||
size_type old_border_offset = (size_type)(reinterpret_cast<char*>(old_end_block) -
|
||||
size_type old_border_offset = (size_type)(reinterpret_cast<char*>(old_end_block) -
|
||||
reinterpret_cast<char*>(this)) + EndCtrlBlockBytes;
|
||||
|
||||
//Update managed buffer's size
|
||||
@@ -500,10 +497,10 @@ void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::grow(size_type ext
|
||||
//between them
|
||||
new_end_block->m_allocated = 1;
|
||||
#ifdef BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP
|
||||
new_end_block->m_size = (reinterpret_cast<char*>(first_block) -
|
||||
new_end_block->m_size = (reinterpret_cast<char*>(first_block) -
|
||||
reinterpret_cast<char*>(new_end_block))/Alignment;
|
||||
#else
|
||||
new_end_block->m_size = (reinterpret_cast<char*>(new_end_block) -
|
||||
new_end_block->m_size = (reinterpret_cast<char*>(new_end_block) -
|
||||
reinterpret_cast<char*>(first_block))/Alignment;
|
||||
#endif
|
||||
first_block->m_prev_size = new_end_block->m_size;
|
||||
@@ -512,7 +509,7 @@ void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::grow(size_type ext
|
||||
|
||||
//The old end block is the new block
|
||||
block_ctrl *new_block = old_end_block;
|
||||
new_block->m_size = (reinterpret_cast<char*>(new_end_block) -
|
||||
new_block->m_size = (reinterpret_cast<char*>(new_end_block) -
|
||||
reinterpret_cast<char*>(new_block))/Alignment;
|
||||
BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits);
|
||||
priv_mark_as_allocated_block(new_block);
|
||||
@@ -568,18 +565,18 @@ void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::shrink_to_fit()
|
||||
//Erase block from the free tree, since we will erase it
|
||||
m_header.m_imultiset.erase(Imultiset::s_iterator_to(*last_block));
|
||||
|
||||
size_type shrunk_border_offset = (size_type)(reinterpret_cast<char*>(last_block) -
|
||||
size_type shrunk_border_offset = (size_type)(reinterpret_cast<char*>(last_block) -
|
||||
reinterpret_cast<char*>(this)) + EndCtrlBlockBytes;
|
||||
|
||||
|
||||
block_ctrl *new_end_block = last_block;
|
||||
algo_impl_t::assert_alignment(new_end_block);
|
||||
|
||||
//Write new end block attributes
|
||||
#ifdef BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP
|
||||
new_end_block->m_size = first_block->m_prev_size =
|
||||
new_end_block->m_size = first_block->m_prev_size =
|
||||
(reinterpret_cast<char*>(first_block) - reinterpret_cast<char*>(new_end_block))/Alignment;
|
||||
#else
|
||||
new_end_block->m_size = first_block->m_prev_size =
|
||||
new_end_block->m_size = first_block->m_prev_size =
|
||||
(reinterpret_cast<char*>(new_end_block) - reinterpret_cast<char*>(first_block))/Alignment;
|
||||
#endif
|
||||
|
||||
@@ -604,7 +601,7 @@ template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::size_type
|
||||
rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::get_free_memory() const
|
||||
{
|
||||
return m_header.m_size - m_header.m_allocated -
|
||||
return m_header.m_size - m_header.m_allocated -
|
||||
priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes);
|
||||
}
|
||||
|
||||
@@ -614,7 +611,7 @@ rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
get_min_size (size_type extra_hdr_bytes)
|
||||
{
|
||||
return (algo_impl_t::ceil_units(sizeof(rbtree_best_fit)) +
|
||||
algo_impl_t::ceil_units(extra_hdr_bytes) +
|
||||
algo_impl_t::ceil_units(extra_hdr_bytes) +
|
||||
MinBlockUnits + EndCtrlBlockUnits)*Alignment;
|
||||
}
|
||||
|
||||
@@ -625,13 +622,13 @@ inline bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
|
||||
//-----------------------
|
||||
size_type block1_off =
|
||||
size_type block1_off =
|
||||
priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes);
|
||||
|
||||
return m_header.m_allocated == 0 &&
|
||||
return m_header.m_allocated == 0 &&
|
||||
m_header.m_imultiset.begin() != m_header.m_imultiset.end() &&
|
||||
(++m_header.m_imultiset.begin()) == m_header.m_imultiset.end()
|
||||
&& m_header.m_imultiset.begin()->m_size ==
|
||||
&& m_header.m_imultiset.begin()->m_size ==
|
||||
(m_header.m_size - block1_off - EndCtrlBlockBytes)/Alignment;
|
||||
}
|
||||
|
||||
@@ -659,7 +656,7 @@ bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
return false;
|
||||
}
|
||||
|
||||
size_type block1_off =
|
||||
size_type block1_off =
|
||||
priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes);
|
||||
|
||||
//Check free bytes are less than size
|
||||
@@ -672,7 +669,7 @@ bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
allocate(size_type nbytes)
|
||||
{
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
|
||||
//-----------------------
|
||||
@@ -684,18 +681,18 @@ inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
allocate_aligned(size_type nbytes, size_type alignment)
|
||||
{
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
|
||||
//-----------------------
|
||||
return algo_impl_t::allocate_aligned(this, nbytes, alignment);
|
||||
return algo_impl_t::allocate_aligned(this, nbytes, alignment);
|
||||
}
|
||||
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
template<class T>
|
||||
inline std::pair<T*, bool> rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
T *reuse_ptr)
|
||||
{
|
||||
std::pair<void*, bool> ret = priv_allocation_command
|
||||
@@ -708,7 +705,7 @@ inline std::pair<T*, bool> rbtree_best_fit<MutexFamily, VoidPointer, MemAlignmen
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
inline std::pair<void*, bool> rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects,
|
||||
size_type preferred_objects,size_type &received_objects,
|
||||
size_type preferred_objects,size_type &received_objects,
|
||||
void *reuse_ptr, size_type sizeof_object)
|
||||
{
|
||||
if(!sizeof_object)
|
||||
@@ -728,7 +725,7 @@ inline std::pair<void*, bool> rbtree_best_fit<MutexFamily, VoidPointer, MemAlign
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
inline std::pair<void*, bool> rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
priv_allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
size_type preferred_size,size_type &received_size,
|
||||
void *reuse_ptr, size_type sizeof_object)
|
||||
{
|
||||
std::pair<void*, bool> ret;
|
||||
@@ -815,7 +812,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
//Obtain the real size of the block
|
||||
block_ctrl *reuse = priv_get_block(reuse_ptr);
|
||||
|
||||
//Sanity check
|
||||
//Sanity check
|
||||
//BOOST_ASSERT(reuse->m_size == priv_tail_size(reuse));
|
||||
algo_impl_t::assert_alignment(reuse);
|
||||
|
||||
@@ -859,12 +856,12 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
(reinterpret_cast<char*>(reuse) - needs_backwards_aligned);
|
||||
|
||||
//Free old previous buffer
|
||||
new_block->m_size =
|
||||
new_block->m_size =
|
||||
AllocatedCtrlUnits + (needs_backwards_aligned + (received_size - UsableByPreviousChunk))/Alignment;
|
||||
BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits);
|
||||
priv_mark_as_allocated_block(new_block);
|
||||
|
||||
prev_block->m_size = (reinterpret_cast<char*>(new_block) -
|
||||
prev_block->m_size = (reinterpret_cast<char*>(new_block) -
|
||||
reinterpret_cast<char*>(prev_block))/Alignment;
|
||||
BOOST_ASSERT(prev_block->m_size >= BlockCtrlUnits);
|
||||
priv_mark_as_free_block(prev_block);
|
||||
@@ -875,7 +872,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
{
|
||||
imultiset_iterator prev_block_it(Imultiset::s_iterator_to(*prev_block));
|
||||
imultiset_iterator was_smaller_it(prev_block_it);
|
||||
if(prev_block_it != m_header.m_imultiset.begin() &&
|
||||
if(prev_block_it != m_header.m_imultiset.begin() &&
|
||||
(--(was_smaller_it = prev_block_it))->m_size > prev_block->m_size){
|
||||
m_header.m_imultiset.erase(prev_block_it);
|
||||
m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *prev_block);
|
||||
@@ -884,7 +881,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
|
||||
received_size = needs_backwards_aligned + received_size;
|
||||
m_header.m_allocated += needs_backwards_aligned;
|
||||
|
||||
|
||||
//Check alignment
|
||||
algo_impl_t::assert_alignment(new_block);
|
||||
|
||||
@@ -930,12 +927,12 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
inline void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
deallocate_many(typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::multiallocation_chain chain)
|
||||
deallocate_many(typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::multiallocation_chain &chain)
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
|
||||
//-----------------------
|
||||
algo_impl_t::deallocate_many(this, boost::move(chain));
|
||||
algo_impl_t::deallocate_many(this, chain);
|
||||
}
|
||||
|
||||
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
|
||||
@@ -951,7 +948,7 @@ std::pair<void *, bool> rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>:
|
||||
//command &= (~boost::interprocess::expand_bwd);
|
||||
|
||||
if(command & boost::interprocess::shrink_in_place){
|
||||
bool success =
|
||||
bool success =
|
||||
algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size);
|
||||
return std::pair<void *, bool> ((success ? reuse_ptr : 0), true);
|
||||
}
|
||||
@@ -1044,7 +1041,7 @@ bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
//The block must be marked as allocated and the sizes must be equal
|
||||
BOOST_ASSERT(priv_is_allocated_block(block));
|
||||
//BOOST_ASSERT(old_block_units == priv_tail_size(block));
|
||||
|
||||
|
||||
//Put this to a safe value
|
||||
received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
|
||||
if(received_size >= preferred_size || received_size >= min_size)
|
||||
@@ -1084,7 +1081,7 @@ bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
|
||||
//Check if we can split the next one in two parts
|
||||
if((merged_units - intended_units) >= BlockCtrlUnits){
|
||||
//This block is bigger than needed, split it in
|
||||
//This block is bigger than needed, split it in
|
||||
//two blocks, the first one will be merged and
|
||||
//the second's size will be the remaining space
|
||||
BOOST_ASSERT(next_block->m_size == priv_next_block(next_block)->m_prev_size);
|
||||
@@ -1098,9 +1095,9 @@ bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
|
||||
//overwrite the tree hook of the old next block. So we first erase the
|
||||
//old if needed and we'll insert the new one after creating the new next
|
||||
imultiset_iterator old_next_block_it(Imultiset::s_iterator_to(*next_block));
|
||||
const bool size_invariants_broken =
|
||||
const bool size_invariants_broken =
|
||||
(next_block->m_size - rem_units ) < BlockCtrlUnits ||
|
||||
(old_next_block_it != m_header.m_imultiset.begin() &&
|
||||
(old_next_block_it != m_header.m_imultiset.begin() &&
|
||||
(--imultiset_iterator(old_next_block_it))->m_size > rem_units);
|
||||
if(size_invariants_broken){
|
||||
m_header.m_imultiset.erase(old_next_block_it);
|
||||
@@ -1267,7 +1264,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_check_and_al
|
||||
algo_impl_t::assert_alignment(block);
|
||||
|
||||
if (block->m_size >= upper_nunits){
|
||||
//This block is bigger than needed, split it in
|
||||
//This block is bigger than needed, split it in
|
||||
//two blocks, the first's size will be "units" and
|
||||
//the second's size "block->m_size-units"
|
||||
size_type block_old_size = block->m_size;
|
||||
@@ -1298,7 +1295,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_check_and_al
|
||||
m_header.m_imultiset.erase(it_old);
|
||||
m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *rem_block);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (block->m_size >= nunits){
|
||||
m_header.m_imultiset.erase(it_old);
|
||||
@@ -1318,9 +1315,9 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_check_and_al
|
||||
//Clear the memory occupied by the tree hook, since this won't be
|
||||
//cleared with zero_free_memory
|
||||
TreeHook *t = static_cast<TreeHook*>(block);
|
||||
//Just clear the memory part reserved for the user
|
||||
//Just clear the memory part reserved for the user
|
||||
std::size_t tree_hook_offset_in_block = (char*)t - (char*)block;
|
||||
//volatile char *ptr =
|
||||
//volatile char *ptr =
|
||||
char *ptr = reinterpret_cast<char*>(block)+tree_hook_offset_in_block;
|
||||
const std::size_t s = BlockCtrlBytes - tree_hook_offset_in_block;
|
||||
std::memset(ptr, 0, s);
|
||||
@@ -1344,7 +1341,7 @@ void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_deallocate(vo
|
||||
if(!addr) return;
|
||||
|
||||
block_ctrl *block = priv_get_block(addr);
|
||||
|
||||
|
||||
//The blocks must be marked as allocated and the sizes must be equal
|
||||
BOOST_ASSERT(priv_is_allocated_block(block));
|
||||
// BOOST_ASSERT(block->m_size == priv_tail_size(block));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -31,7 +31,7 @@ namespace interprocess {
|
||||
//!This class implements the simple sequential fit algorithm with a simply
|
||||
//!linked list of free buffers.
|
||||
template<class MutexFamily, class VoidPointer>
|
||||
class simple_seq_fit
|
||||
class simple_seq_fit
|
||||
: public ipcdetail::simple_seq_fit_impl<MutexFamily, VoidPointer>
|
||||
{
|
||||
/// @cond
|
||||
@@ -41,11 +41,11 @@ class simple_seq_fit
|
||||
public:
|
||||
typedef typename base_t::size_type size_type;
|
||||
|
||||
//!Constructor. "size" is the total size of the managed memory segment,
|
||||
//!Constructor. "size" is the total size of the managed memory segment,
|
||||
//!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(simple_seq_fit)
|
||||
//!offset that the allocator should not use at all.*/
|
||||
simple_seq_fit (size_type size, size_type extra_hdr_bytes)
|
||||
: base_t(size, extra_hdr_bytes){}
|
||||
simple_seq_fit(size_type segment_size, size_type extra_hdr_bytes)
|
||||
: base_t(segment_size, extra_hdr_bytes){}
|
||||
};
|
||||
|
||||
} //namespace interprocess {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -44,6 +44,175 @@ struct has_trivial_destructor;
|
||||
|
||||
namespace interprocess {
|
||||
|
||||
/// @cond
|
||||
namespace ipcdetail {
|
||||
|
||||
template<class OffsetType, std::size_t OffsetAlignment>
|
||||
union offset_ptr_internal
|
||||
{
|
||||
explicit offset_ptr_internal(OffsetType off)
|
||||
: m_offset(off)
|
||||
{}
|
||||
OffsetType m_offset; //Distance between this object and pointee address
|
||||
typename ::boost::aligned_storage
|
||||
< sizeof(OffsetType)
|
||||
, (OffsetAlignment == offset_type_alignment) ?
|
||||
::boost::alignment_of<OffsetType>::value : OffsetAlignment
|
||||
>::type alignment_helper;
|
||||
};
|
||||
|
||||
//Note: using the address of a local variable to point to another address
|
||||
//is not standard conforming and this can be optimized-away by the compiler.
|
||||
//Non-inlining is a method to remain illegal but correct
|
||||
|
||||
//Undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_XXX if your compiler can inline
|
||||
//this code without breaking the library
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// offset_ptr_to_raw_pointer
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
#define BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_PTR
|
||||
#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR
|
||||
|
||||
template<int Dummy>
|
||||
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_PTR
|
||||
BOOST_INTERPROCESS_NEVER_INLINE
|
||||
#elif defined(NDEBUG)
|
||||
inline
|
||||
#endif
|
||||
void * offset_ptr_to_raw_pointer(const volatile void *this_ptr, std::size_t offset)
|
||||
{
|
||||
typedef pointer_size_t_caster<void*> caster_t;
|
||||
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR
|
||||
if(offset == 1){
|
||||
return 0;
|
||||
}
|
||||
else{
|
||||
caster_t caster((void*)this_ptr);
|
||||
return caster_t(caster.size() + offset).pointer();
|
||||
}
|
||||
#else
|
||||
caster_t caster((void*)this_ptr);
|
||||
return caster_t((caster.size() + offset) & -std::size_t(offset != 1)).pointer();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_PTR
|
||||
#undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_PTR
|
||||
#endif
|
||||
#ifdef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR
|
||||
#undef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// offset_ptr_to_offset
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
#define BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF
|
||||
//Branchless seems slower in x86
|
||||
//#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF
|
||||
|
||||
template<int Dummy>
|
||||
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF
|
||||
BOOST_INTERPROCESS_NEVER_INLINE
|
||||
#elif defined(NDEBUG)
|
||||
inline
|
||||
#endif
|
||||
std::size_t offset_ptr_to_offset(const volatile void *ptr, const volatile void *this_ptr)
|
||||
{
|
||||
typedef pointer_size_t_caster<void*> caster_t;
|
||||
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF
|
||||
//offset == 1 && ptr != 0 is not legal for this pointer
|
||||
if(!ptr){
|
||||
return 1;
|
||||
}
|
||||
else{
|
||||
caster_t this_caster((void*)this_ptr);
|
||||
caster_t ptr_caster((void*)ptr);
|
||||
std::size_t offset = ptr_caster.size() - this_caster.size();
|
||||
BOOST_ASSERT(offset != 1);
|
||||
return offset;
|
||||
}
|
||||
#else
|
||||
caster_t this_caster((void*)this_ptr);
|
||||
caster_t ptr_caster((void*)ptr);
|
||||
std::size_t offset = (ptr_caster.size() - this_caster.size() - 1) & -std::size_t(ptr != 0);
|
||||
++offset;
|
||||
return offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF
|
||||
#undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF
|
||||
#endif
|
||||
#ifdef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF
|
||||
#undef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// offset_ptr_to_offset_from_other
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
#define BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF_FROM_OTHER
|
||||
//Branchless seems slower in x86
|
||||
//#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER
|
||||
|
||||
template<int Dummy>
|
||||
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF_FROM_OTHER
|
||||
BOOST_INTERPROCESS_NEVER_INLINE
|
||||
#elif defined(NDEBUG)
|
||||
inline
|
||||
#endif
|
||||
std::size_t offset_ptr_to_offset_from_other
|
||||
(const volatile void *this_ptr, const volatile void *other_ptr, std::size_t other_offset)
|
||||
{
|
||||
typedef pointer_size_t_caster<void*> caster_t;
|
||||
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER
|
||||
if(other_offset == 1){
|
||||
return 1;
|
||||
}
|
||||
else{
|
||||
caster_t this_caster((void*)this_ptr);
|
||||
caster_t other_caster((void*)other_ptr);
|
||||
std::size_t offset = other_caster.size() - this_caster.size() + other_offset;
|
||||
BOOST_ASSERT(offset != 1);
|
||||
return offset;
|
||||
}
|
||||
#else
|
||||
caster_t this_caster((void*)this_ptr);
|
||||
caster_t other_caster((void*)other_ptr);
|
||||
std::size_t offset = (other_caster.size() - this_caster.size()) & -std::size_t(other_offset != 1);
|
||||
offset += other_offset;
|
||||
return offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF_FROM_OTHER
|
||||
#undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF_FROM_OTHER
|
||||
#endif
|
||||
#ifdef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER
|
||||
#undef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Let's assume cast to void and cv cast don't change any target address
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
template<class From, class To>
|
||||
struct offset_ptr_maintains_address
|
||||
{
|
||||
static const bool value = ipcdetail::is_cv_same<From, To>::value
|
||||
|| ipcdetail::is_cv_same<void, To>::value;
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
/// @endcond
|
||||
|
||||
//!A smart pointer that stores the offset between between the pointer and the
|
||||
//!the object it points. This allows offset allows special properties, since
|
||||
//!the pointer is independent from the address address of the pointee, if the
|
||||
@@ -74,69 +243,111 @@ class offset_ptr
|
||||
|
||||
public: //Public Functions
|
||||
|
||||
//!Default constructor (null pointer).
|
||||
//!Never throws.
|
||||
offset_ptr()
|
||||
: internal(1)
|
||||
{}
|
||||
|
||||
//!Constructor from raw pointer (allows "0" pointer conversion).
|
||||
//!Never throws.
|
||||
offset_ptr(pointer ptr = 0) { this->set_offset(ptr); }
|
||||
offset_ptr(pointer ptr)
|
||||
: internal(static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset<0>(ptr, this)))
|
||||
{}
|
||||
|
||||
//!Constructor from other pointer.
|
||||
//!Never throws.
|
||||
template <class T>
|
||||
offset_ptr( T *ptr
|
||||
, typename ipcdetail::enable_if< ipcdetail::is_convertible<T*, PointedType*> >::type * = 0)
|
||||
{ this->set_offset(static_cast<PointedType*>(ptr)); }
|
||||
, typename ipcdetail::enable_if< ipcdetail::is_convertible<T*, PointedType*> >::type * = 0)
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset<0>(static_cast<PointedType*>(ptr), this)))
|
||||
{}
|
||||
|
||||
//!Constructor from other offset_ptr
|
||||
//!Never throws.
|
||||
offset_ptr(const offset_ptr& ptr)
|
||||
{ this->set_offset(ptr.get()); }
|
||||
offset_ptr(const offset_ptr& ptr)
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset_from_other<0>(this, &ptr, ptr.internal.m_offset)))
|
||||
{}
|
||||
|
||||
//!Constructor from other offset_ptr. If pointers of pointee types are
|
||||
//!Constructor from other offset_ptr. If pointers of pointee types are
|
||||
//!convertible, offset_ptrs will be convertibles. Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
offset_ptr( const offset_ptr<T2, P2, O2, A2> &ptr
|
||||
, typename ipcdetail::enable_if< ipcdetail::is_convertible<T2*, PointedType*> >::type * = 0)
|
||||
{ this->set_offset(static_cast<PointedType*>(ptr.get())); }
|
||||
template<class T2>
|
||||
offset_ptr( const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
, typename ipcdetail::enable_if_c< ipcdetail::is_convertible<T2*, PointedType*>::value
|
||||
&& ipcdetail::offset_ptr_maintains_address<T2, PointedType>::value
|
||||
>::type * = 0
|
||||
#endif
|
||||
)
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset_from_other<0>(this, &ptr, ptr.get_offset())))
|
||||
{}
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!Constructor from other offset_ptr. If pointers of pointee types are
|
||||
//!convertible, offset_ptrs will be convertibles. Never throws.
|
||||
template<class T2>
|
||||
offset_ptr( const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
|
||||
, typename ipcdetail::enable_if_c< ipcdetail::is_convertible<T2*, PointedType*>::value
|
||||
&& !ipcdetail::offset_ptr_maintains_address<T2, PointedType>::value
|
||||
>::type * = 0)
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset<0>(static_cast<PointedType*>(ptr.get()), this)))
|
||||
{}
|
||||
|
||||
#endif
|
||||
|
||||
//!Emulates static_cast operator.
|
||||
//!Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::static_cast_tag)
|
||||
{ this->set_offset(static_cast<PointedType*>(r.get())); }
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset<0>(static_cast<PointedType*>(r.get()), this)))
|
||||
{}
|
||||
|
||||
//!Emulates const_cast operator.
|
||||
//!Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::const_cast_tag)
|
||||
{ this->set_offset(const_cast<PointedType*>(r.get())); }
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset<0>(const_cast<PointedType*>(r.get()), this)))
|
||||
{}
|
||||
|
||||
//!Emulates dynamic_cast operator.
|
||||
//!Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::dynamic_cast_tag)
|
||||
{ this->set_offset(dynamic_cast<PointedType*>(r.get())); }
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset<0>(dynamic_cast<PointedType*>(r.get()), this)))
|
||||
{}
|
||||
|
||||
//!Emulates reinterpret_cast operator.
|
||||
//!Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::reinterpret_cast_tag)
|
||||
{ this->set_offset(reinterpret_cast<PointedType*>(r.get())); }
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset<0>(reinterpret_cast<PointedType*>(r.get()), this)))
|
||||
{}
|
||||
|
||||
//!Obtains raw pointer from offset.
|
||||
//!Never throws.
|
||||
pointer get()const
|
||||
{ return this->to_raw_pointer(); }
|
||||
pointer get() const
|
||||
{ return (pointer)ipcdetail::offset_ptr_to_raw_pointer<0>(this, this->internal.m_offset); }
|
||||
|
||||
offset_type get_offset() const
|
||||
{ return internal.m_offset; }
|
||||
{ return this->internal.m_offset; }
|
||||
|
||||
//!Pointer-like -> operator. It can return 0 pointer.
|
||||
//!Never throws.
|
||||
pointer operator->() const
|
||||
pointer operator->() const
|
||||
{ return this->get(); }
|
||||
|
||||
//!Dereferencing operator, if it is a null offset_ptr behavior
|
||||
//!Dereferencing operator, if it is a null offset_ptr behavior
|
||||
//! is undefined. Never throws.
|
||||
reference operator* () const
|
||||
reference operator* () const
|
||||
{
|
||||
pointer p = this->get();
|
||||
reference r = *p;
|
||||
@@ -145,27 +356,57 @@ class offset_ptr
|
||||
|
||||
//!Indexing operator.
|
||||
//!Never throws.
|
||||
template<class T>
|
||||
reference operator[](T idx) const
|
||||
reference operator[](difference_type idx) const
|
||||
{ return this->get()[idx]; }
|
||||
|
||||
//!Assignment from pointer (saves extra conversion).
|
||||
//!Never throws.
|
||||
offset_ptr& operator= (pointer from)
|
||||
{ this->set_offset(from); return *this; }
|
||||
{
|
||||
this->internal.m_offset =
|
||||
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset<0>(from, this));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Assignment from other offset_ptr.
|
||||
//!Never throws.
|
||||
offset_ptr& operator= (const offset_ptr & pt)
|
||||
{ pointer p(pt.get()); (void)p; this->set_offset(p); return *this; }
|
||||
offset_ptr& operator= (const offset_ptr & ptr)
|
||||
{
|
||||
this->internal.m_offset =
|
||||
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset_from_other<0>(this, &ptr, ptr.internal.m_offset));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Assignment from related offset_ptr. If pointers of pointee types
|
||||
//!Assignment from related offset_ptr. If pointers of pointee types
|
||||
//! are assignable, offset_ptrs will be assignable. Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
typename ipcdetail::enable_if<ipcdetail::is_convertible<T2*, PointedType*>, offset_ptr&>::type
|
||||
operator= (const offset_ptr<T2, P2, O2, A2> & ptr)
|
||||
{ this->set_offset(static_cast<PointedType*>(ptr.get())); return *this; }
|
||||
|
||||
template<class T2>
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
typename ipcdetail::enable_if_c< ipcdetail::is_convertible<T2*, PointedType*>::value
|
||||
&& ipcdetail::offset_ptr_maintains_address<T2, PointedType>::value
|
||||
, offset_ptr&>::type
|
||||
#else
|
||||
offset_ptr&
|
||||
#endif
|
||||
operator= (const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr)
|
||||
{
|
||||
this->internal.m_offset =
|
||||
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset_from_other<0>(this, &ptr, ptr.get_offset()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
template<class T2>
|
||||
typename ipcdetail::enable_if_c<ipcdetail::is_convertible<T2*, PointedType*>::value
|
||||
&& !ipcdetail::offset_ptr_maintains_address<T2, PointedType>::value
|
||||
, offset_ptr&>::type
|
||||
operator= (const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr)
|
||||
{
|
||||
this->internal.m_offset =
|
||||
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset<0>(static_cast<PointedType*>(ptr.get()), this));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//!offset_ptr += difference_type.
|
||||
//!Never throws.
|
||||
offset_ptr &operator+= (difference_type offset)
|
||||
@@ -173,39 +414,46 @@ class offset_ptr
|
||||
|
||||
//!offset_ptr -= difference_type.
|
||||
//!Never throws.
|
||||
template<class T>
|
||||
offset_ptr &operator-= (T offset)
|
||||
offset_ptr &operator-= (difference_type offset)
|
||||
{ this->dec_offset(offset * sizeof (PointedType)); return *this; }
|
||||
|
||||
//!++offset_ptr.
|
||||
//!Never throws.
|
||||
offset_ptr& operator++ (void)
|
||||
offset_ptr& operator++ (void)
|
||||
{ this->inc_offset(sizeof (PointedType)); return *this; }
|
||||
|
||||
//!offset_ptr++.
|
||||
//!Never throws.
|
||||
offset_ptr operator++ (int)
|
||||
{ offset_ptr temp(*this); ++*this; return temp; }
|
||||
{
|
||||
offset_ptr tmp(*this);
|
||||
this->inc_offset(sizeof (PointedType));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//!--offset_ptr.
|
||||
//!Never throws.
|
||||
offset_ptr& operator-- (void)
|
||||
offset_ptr& operator-- (void)
|
||||
{ this->dec_offset(sizeof (PointedType)); return *this; }
|
||||
|
||||
//!offset_ptr--.
|
||||
//!Never throws.
|
||||
offset_ptr operator-- (int)
|
||||
{ offset_ptr temp(*this); --*this; return temp; }
|
||||
{
|
||||
offset_ptr tmp(*this);
|
||||
this->dec_offset(sizeof (PointedType));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//!safe bool conversion operator.
|
||||
//!Never throws.
|
||||
operator unspecified_bool_type() const
|
||||
{ return this->get()? &self_t::unspecified_bool_type_func : 0; }
|
||||
operator unspecified_bool_type() const
|
||||
{ return this->internal.m_offset != 1? &self_t::unspecified_bool_type_func : 0; }
|
||||
|
||||
//!Not operator. Not needed in theory, but improves portability.
|
||||
//!Not operator. Not needed in theory, but improves portability.
|
||||
//!Never throws
|
||||
bool operator! () const
|
||||
{ return this->get() == 0; }
|
||||
{ return this->internal.m_offset == 1; }
|
||||
|
||||
//!Compatibility with pointer_traits
|
||||
//!
|
||||
@@ -220,23 +468,23 @@ class offset_ptr
|
||||
|
||||
//!difference_type + offset_ptr
|
||||
//!operation
|
||||
friend offset_ptr operator+(difference_type diff, const offset_ptr& right)
|
||||
{ offset_ptr tmp(right); tmp += diff; return tmp; }
|
||||
friend offset_ptr operator+(difference_type diff, offset_ptr right)
|
||||
{ right += diff; return right; }
|
||||
|
||||
//!offset_ptr + difference_type
|
||||
//!operation
|
||||
friend offset_ptr operator+(const offset_ptr& left, difference_type diff)
|
||||
{ offset_ptr tmp(left); tmp += diff; return tmp; }
|
||||
friend offset_ptr operator+(offset_ptr left, difference_type diff)
|
||||
{ left += diff; return left; }
|
||||
|
||||
//!offset_ptr - diff
|
||||
//!operation
|
||||
friend offset_ptr operator-(const offset_ptr &left, difference_type diff)
|
||||
{ offset_ptr tmp(left); tmp -= diff; return tmp; }
|
||||
friend offset_ptr operator-(offset_ptr left, difference_type diff)
|
||||
{ left -= diff; return left; }
|
||||
|
||||
//!offset_ptr - diff
|
||||
//!operation
|
||||
friend offset_ptr operator-(difference_type diff, const offset_ptr &right)
|
||||
{ offset_ptr tmp(right); tmp -= diff; return tmp; }
|
||||
friend offset_ptr operator-(difference_type diff, offset_ptr right)
|
||||
{ right -= diff; return right; }
|
||||
|
||||
//!offset_ptr - offset_ptr
|
||||
//!operation
|
||||
@@ -309,114 +557,64 @@ class offset_ptr
|
||||
|
||||
private:
|
||||
/// @cond
|
||||
|
||||
//Note: using the address of a local variable to point to another address
|
||||
//is not standard conforming and this can be optimized-away by the compiler.
|
||||
//Non-inlining is a method to remain illegal and correct
|
||||
#if defined(_MSC_VER)
|
||||
__declspec(noinline) //this workaround is needed for MSVC compilers
|
||||
#elif defined (__GNUC__)//this workaround is needed for GCC
|
||||
__attribute__((__noinline__))
|
||||
#endif
|
||||
void set_offset(const PointedType *ptr)
|
||||
{
|
||||
#if defined (__GNUC__)
|
||||
//asm(""); //Prevents the function to be optimized-away (provokes an special "side-effect")
|
||||
#endif
|
||||
//offset == 1 && ptr != 0 is not legal for this pointer
|
||||
if(!ptr){
|
||||
internal.m_offset = 1;
|
||||
}
|
||||
else{
|
||||
internal.m_offset = (OffsetType)((const char*)ptr - (const char*)(this));
|
||||
BOOST_ASSERT(internal.m_offset != 1);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
__declspec(noinline)
|
||||
#elif defined (__GNUC__)
|
||||
__attribute__((__noinline__))
|
||||
#endif
|
||||
PointedType * to_raw_pointer() const
|
||||
{
|
||||
#if defined (__GNUC__)
|
||||
//asm(""); //Prevents the function to be optimized-away (provokes an special "side-effect")
|
||||
#endif
|
||||
return static_cast<PointedType *>(
|
||||
static_cast<void*>(
|
||||
(internal.m_offset == 1) ?
|
||||
0 :
|
||||
(const_cast<char*>(reinterpret_cast<const char*>(this)) + internal.m_offset)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void inc_offset(DifferenceType bytes)
|
||||
{ internal.m_offset += bytes; }
|
||||
|
||||
void dec_offset(DifferenceType bytes)
|
||||
{ internal.m_offset -= bytes; }
|
||||
|
||||
union internal_type{
|
||||
OffsetType m_offset; //Distance between this object and pointee address
|
||||
typename ::boost::aligned_storage
|
||||
< sizeof(OffsetType)
|
||||
, (OffsetAlignment == offset_type_alignment) ?
|
||||
::boost::alignment_of<OffsetType>::value : OffsetAlignment
|
||||
>::type alignment_helper;
|
||||
} internal;
|
||||
ipcdetail::offset_ptr_internal<OffsetType, OffsetAlignment> internal;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
//!operator<<
|
||||
//!for offset ptr
|
||||
template<class E, class T, class W, class X, class Y, std::size_t Z>
|
||||
inline std::basic_ostream<E, T> & operator<<
|
||||
template<class E, class T, class W, class X, class Y, std::size_t Z>
|
||||
inline std::basic_ostream<E, T> & operator<<
|
||||
(std::basic_ostream<E, T> & os, offset_ptr<W, X, Y, Z> const & p)
|
||||
{ return os << p.get_offset(); }
|
||||
|
||||
//!operator>>
|
||||
//!operator>>
|
||||
//!for offset ptr
|
||||
template<class E, class T, class W, class X, class Y, std::size_t Z>
|
||||
inline std::basic_istream<E, T> & operator>>
|
||||
template<class E, class T, class W, class X, class Y, std::size_t Z>
|
||||
inline std::basic_istream<E, T> & operator>>
|
||||
(std::basic_istream<E, T> & is, offset_ptr<W, X, Y, Z> & p)
|
||||
{ return is >> p.get_offset(); }
|
||||
|
||||
//!Simulation of static_cast between pointers. Never throws.
|
||||
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
|
||||
inline boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
inline boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
static_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r)
|
||||
{
|
||||
{
|
||||
return boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
(r, boost::interprocess::ipcdetail::static_cast_tag());
|
||||
(r, boost::interprocess::ipcdetail::static_cast_tag());
|
||||
}
|
||||
|
||||
//!Simulation of const_cast between pointers. Never throws.
|
||||
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
|
||||
inline boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
const_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r)
|
||||
{
|
||||
{
|
||||
return boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
(r, boost::interprocess::ipcdetail::const_cast_tag());
|
||||
(r, boost::interprocess::ipcdetail::const_cast_tag());
|
||||
}
|
||||
|
||||
//!Simulation of dynamic_cast between pointers. Never throws.
|
||||
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
|
||||
inline boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
inline boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
dynamic_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r)
|
||||
{
|
||||
{
|
||||
return boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
(r, boost::interprocess::ipcdetail::dynamic_cast_tag());
|
||||
(r, boost::interprocess::ipcdetail::dynamic_cast_tag());
|
||||
}
|
||||
|
||||
//!Simulation of reinterpret_cast between pointers. Never throws.
|
||||
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
|
||||
inline boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
reinterpret_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r)
|
||||
{
|
||||
{
|
||||
return boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
(r, boost::interprocess::ipcdetail::reinterpret_cast_tag());
|
||||
(r, boost::interprocess::ipcdetail::reinterpret_cast_tag());
|
||||
}
|
||||
|
||||
} //namespace interprocess {
|
||||
@@ -425,29 +623,29 @@ inline boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
|
||||
//!has_trivial_constructor<> == true_type specialization for optimizations
|
||||
template <class T, class P, class O, std::size_t A>
|
||||
struct has_trivial_constructor< boost::interprocess::offset_ptr<T, P, O, A> >
|
||||
struct has_trivial_constructor< boost::interprocess::offset_ptr<T, P, O, A> >
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
///has_trivial_destructor<> == true_type specialization for optimizations
|
||||
template <class T, class P, class O, std::size_t A>
|
||||
struct has_trivial_destructor< boost::interprocess::offset_ptr<T, P, O, A> >
|
||||
struct has_trivial_destructor< boost::interprocess::offset_ptr<T, P, O, A> >
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
//#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
|
||||
|
||||
namespace interprocess {
|
||||
//#endif
|
||||
//!to_raw_pointer() enables boost::mem_fn to recognize offset_ptr.
|
||||
|
||||
//!to_raw_pointer() enables boost::mem_fn to recognize offset_ptr.
|
||||
//!Never throws.
|
||||
template <class T, class P, class O, std::size_t A>
|
||||
inline T * to_raw_pointer(boost::interprocess::offset_ptr<T, P, O, A> const & p)
|
||||
{ return p.get(); }
|
||||
//#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
|
||||
{ return ipcdetail::to_raw_pointer(p); }
|
||||
|
||||
} //namespace interprocess
|
||||
//#endif
|
||||
|
||||
|
||||
/// @endcond
|
||||
} //namespace boost {
|
||||
@@ -479,28 +677,34 @@ struct pointer_plus_bits;
|
||||
template<class T, class P, class O, std::size_t A, std::size_t NumBits>
|
||||
struct pointer_plus_bits<boost::interprocess::offset_ptr<T, P, O, A>, NumBits>
|
||||
{
|
||||
typedef boost::interprocess::offset_ptr<T, P, O, A> pointer;
|
||||
typedef boost::interprocess::offset_ptr<T, P, O, A> pointer;
|
||||
typedef ::boost::interprocess::pointer_size_t_caster<T*> caster_t;
|
||||
//Bits are stored in the lower bits of the pointer except the LSB,
|
||||
//because this bit is used to represent the null pointer.
|
||||
static const std::size_t Mask = ((std::size_t(1) << NumBits)-1)<<1u;
|
||||
static const std::size_t Mask = ((std::size_t(1) << NumBits) - 1) << 1u;
|
||||
|
||||
static pointer get_pointer(const pointer &n)
|
||||
{ return reinterpret_cast<T*>(std::size_t(n.get()) & ~std::size_t(Mask)); }
|
||||
|
||||
static void set_pointer(pointer &n, pointer p)
|
||||
{
|
||||
std::size_t pint = std::size_t(p.get());
|
||||
BOOST_ASSERT(0 == (std::size_t(pint) & Mask));
|
||||
n = reinterpret_cast<T*>(pint | (std::size_t(n.get()) & std::size_t(Mask)));
|
||||
caster_t caster(n.get());
|
||||
return pointer(caster_t(caster.size() & ~Mask).pointer());
|
||||
}
|
||||
|
||||
static void set_pointer(pointer &n, const pointer &p)
|
||||
{
|
||||
caster_t n_caster(n.get());
|
||||
caster_t p_caster(p.get());
|
||||
BOOST_ASSERT(0 == (p_caster.size() & Mask));
|
||||
n = caster_t(p_caster.size() | (n_caster.size() & Mask)).pointer();
|
||||
}
|
||||
|
||||
static std::size_t get_bits(const pointer &n)
|
||||
{ return(std::size_t(n.get()) & std::size_t(Mask)) >> 1u; }
|
||||
{ return (caster_t(n.get()).size() & Mask) >> 1u; }
|
||||
|
||||
static void set_bits(pointer &n, std::size_t b)
|
||||
{
|
||||
BOOST_ASSERT(b < (std::size_t(1) << NumBits));
|
||||
n = reinterpret_cast<T*>(std::size_t(get_pointer(n).get()) | (b << 1u));
|
||||
caster_t n_caster(n.get());
|
||||
n = caster_t((n_caster.size() & ~Mask) | (b << 1u)).pointer();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -510,8 +714,6 @@ struct pointer_plus_bits<boost::interprocess::offset_ptr<T, P, O, A>, NumBits>
|
||||
template<class T, class U>
|
||||
struct pointer_to_other;
|
||||
|
||||
|
||||
|
||||
//Backwards compatibility with pointer_to_other
|
||||
template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment, class U>
|
||||
struct pointer_to_other
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -69,9 +69,9 @@ class segment_manager_base
|
||||
typedef typename MemoryAlgorithm::void_pointer void_pointer;
|
||||
typedef typename MemoryAlgorithm::mutex_family mutex_family;
|
||||
typedef MemoryAlgorithm memory_algorithm;
|
||||
|
||||
|
||||
/// @cond
|
||||
|
||||
|
||||
//Experimental. Don't use
|
||||
typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain;
|
||||
typedef typename MemoryAlgorithm::difference_type difference_type;
|
||||
@@ -88,14 +88,14 @@ class segment_manager_base
|
||||
//!"size" is the size of the memory segment where
|
||||
//!the basic segment manager is being constructed.
|
||||
//!
|
||||
//!"reserved_bytes" is the number of bytes
|
||||
//!"reserved_bytes" is the number of bytes
|
||||
//!after the end of the memory algorithm object itself
|
||||
//!that the memory algorithm will exclude from
|
||||
//!dynamic allocation
|
||||
//!
|
||||
//!Can throw
|
||||
segment_manager_base(size_type size, size_type reserved_bytes)
|
||||
: MemoryAlgorithm(size, reserved_bytes)
|
||||
segment_manager_base(size_type sz, size_type reserved_bytes)
|
||||
: MemoryAlgorithm(sz, reserved_bytes)
|
||||
{
|
||||
BOOST_ASSERT((sizeof(segment_manager_base<MemoryAlgorithm>) == sizeof(MemoryAlgorithm)));
|
||||
}
|
||||
@@ -115,7 +115,7 @@ class segment_manager_base
|
||||
static size_type get_min_size (size_type size)
|
||||
{ return MemoryAlgorithm::get_min_size(size); }
|
||||
|
||||
//!Allocates nbytes bytes. This function is only used in
|
||||
//!Allocates nbytes bytes. This function is only used in
|
||||
//!single-segment management. Never throws
|
||||
void * allocate (size_type nbytes, std::nothrow_t)
|
||||
{ return MemoryAlgorithm::allocate(nbytes); }
|
||||
@@ -123,64 +123,65 @@ class segment_manager_base
|
||||
/// @cond
|
||||
|
||||
//Experimental. Dont' use.
|
||||
//!Allocates n_elements of
|
||||
//!elem_size bytes. Throws bad_alloc on failure.
|
||||
multiallocation_chain allocate_many(size_type elem_bytes, size_type num_elements)
|
||||
//!Allocates n_elements of elem_bytes bytes.
|
||||
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
|
||||
void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
|
||||
{
|
||||
multiallocation_chain mem(MemoryAlgorithm::allocate_many(elem_bytes, num_elements));
|
||||
if(mem.empty()) throw bad_alloc();
|
||||
return boost::move(mem);
|
||||
size_type prev_size = chain.size();
|
||||
MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain);
|
||||
if(!elem_bytes || chain.size() == prev_size){
|
||||
throw bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
//!Allocates n_elements, each one of
|
||||
//!element_lenghts[i]*sizeof_element bytes. Throws bad_alloc on failure.
|
||||
multiallocation_chain allocate_many
|
||||
(const size_type *element_lenghts, size_type n_elements, size_type sizeof_element = 1)
|
||||
//!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
|
||||
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
|
||||
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
|
||||
{
|
||||
multiallocation_chain mem(MemoryAlgorithm::allocate_many(element_lenghts, n_elements, sizeof_element));
|
||||
if(mem.empty()) throw bad_alloc();
|
||||
return boost::move(mem);
|
||||
size_type prev_size = chain.size();
|
||||
MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain);
|
||||
if(!sizeof_element || chain.size() == prev_size){
|
||||
throw bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
//!Allocates n_elements of
|
||||
//!elem_size bytes. Returns a default constructed iterator on failure.
|
||||
multiallocation_chain allocate_many
|
||||
(size_type elem_bytes, size_type num_elements, std::nothrow_t)
|
||||
{ return MemoryAlgorithm::allocate_many(elem_bytes, num_elements); }
|
||||
//!Allocates n_elements of elem_bytes bytes.
|
||||
//!Non-throwing version. chain.size() is not increased on failure.
|
||||
void allocate_many(std::nothrow_t, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
|
||||
{ MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); }
|
||||
|
||||
//!Allocates n_elements, each one of
|
||||
//!element_lenghts[i]*sizeof_element bytes.
|
||||
//!Returns a default constructed iterator on failure.
|
||||
multiallocation_chain allocate_many
|
||||
(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, std::nothrow_t)
|
||||
{ return MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element); }
|
||||
//!element_lengths[i]*sizeof_element bytes.
|
||||
//!Non-throwing version. chain.size() is not increased on failure.
|
||||
void allocate_many(std::nothrow_t, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
|
||||
{ MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); }
|
||||
|
||||
//!Deallocates elements pointed by the
|
||||
//!multiallocation iterator range.
|
||||
void deallocate_many(multiallocation_chain chain)
|
||||
{ MemoryAlgorithm::deallocate_many(boost::move(chain)); }
|
||||
//!Deallocates all elements contained in chain.
|
||||
//!Never throws.
|
||||
void deallocate_many(multiallocation_chain &chain)
|
||||
{ MemoryAlgorithm::deallocate_many(chain); }
|
||||
|
||||
/// @endcond
|
||||
|
||||
//!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
|
||||
//!on failure
|
||||
void * allocate(size_type nbytes)
|
||||
{
|
||||
{
|
||||
void * ret = MemoryAlgorithm::allocate(nbytes);
|
||||
if(!ret)
|
||||
throw bad_alloc();
|
||||
return ret;
|
||||
}
|
||||
|
||||
//!Allocates nbytes bytes. This function is only used in
|
||||
//!Allocates nbytes bytes. This function is only used in
|
||||
//!single-segment management. Never throws
|
||||
void * allocate_aligned (size_type nbytes, size_type alignment, std::nothrow_t)
|
||||
{ return MemoryAlgorithm::allocate_aligned(nbytes, alignment); }
|
||||
|
||||
//!Allocates nbytes bytes. This function is only used in
|
||||
//!Allocates nbytes bytes. This function is only used in
|
||||
//!single-segment management. Throws bad_alloc when fails
|
||||
void * allocate_aligned(size_type nbytes, size_type alignment)
|
||||
{
|
||||
{
|
||||
void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment);
|
||||
if(!ret)
|
||||
throw bad_alloc();
|
||||
@@ -269,7 +270,7 @@ class segment_manager_base
|
||||
throw bad_alloc();
|
||||
}
|
||||
else{
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +294,7 @@ class segment_manager_base
|
||||
void prot_anonymous_destroy(const void *object, ipcdetail::in_place_interface &table)
|
||||
{
|
||||
|
||||
//Get control data from associated with this object
|
||||
//Get control data from associated with this object
|
||||
typedef ipcdetail::block_header<size_type> block_header_t;
|
||||
block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment);
|
||||
|
||||
@@ -318,9 +319,9 @@ class segment_manager_base
|
||||
//!This object is placed in the beginning of memory segment and
|
||||
//!implements the allocation (named or anonymous) of portions
|
||||
//!of the segment. This object contains two indexes that
|
||||
//!maintain an association between a name and a portion of the segment.
|
||||
//!maintain an association between a name and a portion of the segment.
|
||||
//!
|
||||
//!The first index contains the mappings for normal named objects using the
|
||||
//!The first index contains the mappings for normal named objects using the
|
||||
//!char type specified in the template parameter.
|
||||
//!
|
||||
//!The second index contains the association for unique instances. The key will
|
||||
@@ -336,7 +337,7 @@ template<class CharType
|
||||
,template<class IndexConfig> class IndexType>
|
||||
class segment_manager
|
||||
: public segment_manager_base<MemoryAlgorithm>
|
||||
{
|
||||
{
|
||||
/// @cond
|
||||
//Non-copyable
|
||||
segment_manager();
|
||||
@@ -407,8 +408,8 @@ class segment_manager
|
||||
//!"size" is the size of the memory segment where
|
||||
//!the segment manager is being constructed.
|
||||
//!Can throw
|
||||
segment_manager(size_type size)
|
||||
: Base(size, priv_get_reserved_bytes())
|
||||
explicit segment_manager(size_type segment_size)
|
||||
: Base(segment_size, priv_get_reserved_bytes())
|
||||
, m_header(static_cast<Base*>(get_this_pointer()))
|
||||
{
|
||||
(void) anonymous_instance; (void) unique_instance;
|
||||
@@ -446,7 +447,7 @@ class segment_manager
|
||||
//!Returns throwing "construct" proxy
|
||||
//!object
|
||||
template <class T>
|
||||
typename construct_proxy<T>::type
|
||||
typename construct_proxy<T>::type
|
||||
construct(char_ptr_holder_t name)
|
||||
{ return typename construct_proxy<T>::type (this, name, false, true); }
|
||||
|
||||
@@ -466,39 +467,39 @@ class segment_manager
|
||||
//!Returns no throwing "search or construct"
|
||||
//!proxy object
|
||||
template <class T>
|
||||
typename construct_proxy<T>::type
|
||||
typename construct_proxy<T>::type
|
||||
find_or_construct(char_ptr_holder_t name, std::nothrow_t)
|
||||
{ return typename construct_proxy<T>::type (this, name, true, false); }
|
||||
|
||||
//!Returns throwing "construct from iterators" proxy object
|
||||
template <class T>
|
||||
typename construct_iter_proxy<T>::type
|
||||
typename construct_iter_proxy<T>::type
|
||||
construct_it(char_ptr_holder_t name)
|
||||
{ return typename construct_iter_proxy<T>::type (this, name, false, true); }
|
||||
|
||||
//!Returns throwing "search or construct from iterators"
|
||||
//!proxy object
|
||||
template <class T>
|
||||
typename construct_iter_proxy<T>::type
|
||||
typename construct_iter_proxy<T>::type
|
||||
find_or_construct_it(char_ptr_holder_t name)
|
||||
{ return typename construct_iter_proxy<T>::type (this, name, true, true); }
|
||||
|
||||
//!Returns no throwing "construct from iterators"
|
||||
//!proxy object
|
||||
template <class T>
|
||||
typename construct_iter_proxy<T>::type
|
||||
typename construct_iter_proxy<T>::type
|
||||
construct_it(char_ptr_holder_t name, std::nothrow_t)
|
||||
{ return typename construct_iter_proxy<T>::type (this, name, false, false); }
|
||||
|
||||
//!Returns no throwing "search or construct from iterators"
|
||||
//!proxy object
|
||||
template <class T>
|
||||
typename construct_iter_proxy<T>::type
|
||||
typename construct_iter_proxy<T>::type
|
||||
find_or_construct_it(char_ptr_holder_t name, std::nothrow_t)
|
||||
{ return typename construct_iter_proxy<T>::type (this, name, true, false); }
|
||||
|
||||
//!Calls object function blocking recursive interprocess_mutex and guarantees that
|
||||
//!no new named_alloc or destroy will be executed by any process while
|
||||
//!Calls object function blocking recursive interprocess_mutex and guarantees that
|
||||
//!no new named_alloc or destroy will be executed by any process while
|
||||
//!executing the object function call*/
|
||||
template <class Func>
|
||||
void atomic_func(Func &f)
|
||||
@@ -571,22 +572,22 @@ class segment_manager
|
||||
static instance_type get_instance_type(const T *ptr)
|
||||
{ return priv_get_instance_type(block_header_t::block_header_from_value(ptr)); }
|
||||
|
||||
//!Preallocates needed index resources to optimize the
|
||||
//!Preallocates needed index resources to optimize the
|
||||
//!creation of "num" named objects in the managed memory segment.
|
||||
//!Can throw boost::interprocess::bad_alloc if there is no enough memory.
|
||||
void reserve_named_objects(size_type num)
|
||||
{
|
||||
{
|
||||
//-------------------------------
|
||||
scoped_lock<rmutex> guard(m_header);
|
||||
//-------------------------------
|
||||
m_header.m_named_index.reserve(num);
|
||||
m_header.m_named_index.reserve(num);
|
||||
}
|
||||
|
||||
//!Preallocates needed index resources to optimize the
|
||||
//!Preallocates needed index resources to optimize the
|
||||
//!creation of "num" unique objects in the managed memory segment.
|
||||
//!Can throw boost::interprocess::bad_alloc if there is no enough memory.
|
||||
void reserve_unique_objects(size_type num)
|
||||
{
|
||||
{
|
||||
//-------------------------------
|
||||
scoped_lock<rmutex> guard(m_header);
|
||||
//-------------------------------
|
||||
@@ -596,32 +597,32 @@ class segment_manager
|
||||
//!Calls shrink_to_fit in both named and unique object indexes
|
||||
//!to try to free unused memory from those indexes.
|
||||
void shrink_to_fit_indexes()
|
||||
{
|
||||
{
|
||||
//-------------------------------
|
||||
scoped_lock<rmutex> guard(m_header);
|
||||
//-------------------------------
|
||||
m_header.m_named_index.shrink_to_fit();
|
||||
m_header.m_unique_index.shrink_to_fit();
|
||||
m_header.m_named_index.shrink_to_fit();
|
||||
m_header.m_unique_index.shrink_to_fit();
|
||||
}
|
||||
|
||||
//!Returns the number of named objects stored in
|
||||
//!the segment.
|
||||
size_type get_num_named_objects()
|
||||
{
|
||||
{
|
||||
//-------------------------------
|
||||
scoped_lock<rmutex> guard(m_header);
|
||||
//-------------------------------
|
||||
return m_header.m_named_index.size();
|
||||
return m_header.m_named_index.size();
|
||||
}
|
||||
|
||||
//!Returns the number of unique objects stored in
|
||||
//!the segment.
|
||||
size_type get_num_unique_objects()
|
||||
{
|
||||
{
|
||||
//-------------------------------
|
||||
scoped_lock<rmutex> guard(m_header);
|
||||
//-------------------------------
|
||||
return m_header.m_unique_index.size();
|
||||
return m_header.m_unique_index.size();
|
||||
}
|
||||
|
||||
//!Obtains the minimum size needed by the
|
||||
@@ -693,13 +694,13 @@ class segment_manager
|
||||
|
||||
/// @cond
|
||||
|
||||
//!Generic named/anonymous new function. Offers all the possibilities,
|
||||
//!such as throwing, search before creating, and the constructor is
|
||||
//!Generic named/anonymous new function. Offers all the possibilities,
|
||||
//!such as throwing, search before creating, and the constructor is
|
||||
//!encapsulated in an object function.
|
||||
template<class T>
|
||||
T *generic_construct(const CharType *name,
|
||||
size_type num,
|
||||
bool try2find,
|
||||
T *generic_construct(const CharType *name,
|
||||
size_type num,
|
||||
bool try2find,
|
||||
bool dothrow,
|
||||
ipcdetail::in_place_interface &table)
|
||||
{
|
||||
@@ -713,20 +714,20 @@ class segment_manager
|
||||
//!returned pair is 0.
|
||||
template <class T>
|
||||
std::pair<T*, size_type> priv_find_impl (const CharType* name, bool lock)
|
||||
{
|
||||
{
|
||||
//The name can't be null, no anonymous object can be found by name
|
||||
BOOST_ASSERT(name != 0);
|
||||
ipcdetail::placement_destroy<T> table;
|
||||
size_type size;
|
||||
size_type sz;
|
||||
void *ret;
|
||||
|
||||
if(name == reinterpret_cast<const CharType*>(-1)){
|
||||
ret = priv_generic_find<char> (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), lock);
|
||||
ret = priv_generic_find<char> (typeid(T).name(), m_header.m_unique_index, table, sz, is_intrusive_t(), lock);
|
||||
}
|
||||
else{
|
||||
ret = priv_generic_find<CharType> (name, m_header.m_named_index, table, size, is_intrusive_t(), lock);
|
||||
ret = priv_generic_find<CharType> (name, m_header.m_named_index, table, sz, is_intrusive_t(), lock);
|
||||
}
|
||||
return std::pair<T*, size_type>(static_cast<T*>(ret), size);
|
||||
return std::pair<T*, size_type>(static_cast<T*>(ret), sz);
|
||||
}
|
||||
|
||||
//!Tries to find a previous unique allocation. Returns the address
|
||||
@@ -737,13 +738,13 @@ class segment_manager
|
||||
{
|
||||
ipcdetail::placement_destroy<T> table;
|
||||
size_type size;
|
||||
void *ret = priv_generic_find<char>(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock);
|
||||
void *ret = priv_generic_find<char>(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock);
|
||||
return std::pair<T*, size_type>(static_cast<T*>(ret), size);
|
||||
}
|
||||
|
||||
void *priv_generic_construct(const CharType *name,
|
||||
size_type num,
|
||||
bool try2find,
|
||||
void *priv_generic_construct(const CharType *name,
|
||||
size_type num,
|
||||
bool try2find,
|
||||
bool dothrow,
|
||||
ipcdetail::in_place_interface &table)
|
||||
{
|
||||
@@ -805,7 +806,7 @@ class segment_manager
|
||||
return 0;
|
||||
}
|
||||
CharType *name = static_cast<CharType*>(ctrl_data->template name<CharType>());
|
||||
|
||||
|
||||
//Sanity checks
|
||||
BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharType));
|
||||
BOOST_ASSERT(ctrl_data->m_num_char == std::char_traits<CharType>::length(name));
|
||||
@@ -837,7 +838,7 @@ class segment_manager
|
||||
|
||||
template <class CharT>
|
||||
void *priv_generic_find
|
||||
(const CharT* name,
|
||||
(const CharT* name,
|
||||
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
||||
ipcdetail::in_place_interface &table,
|
||||
size_type &length,
|
||||
@@ -877,7 +878,7 @@ class segment_manager
|
||||
|
||||
template <class CharT>
|
||||
void *priv_generic_find
|
||||
(const CharT* name,
|
||||
(const CharT* name,
|
||||
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
||||
ipcdetail::in_place_interface &table,
|
||||
size_type &length,
|
||||
@@ -941,7 +942,7 @@ class segment_manager
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
bool priv_generic_named_destroy(const CharT *name,
|
||||
bool priv_generic_named_destroy(const CharT *name,
|
||||
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
||||
ipcdetail::in_place_interface &table,
|
||||
ipcdetail::true_ is_intrusive_index)
|
||||
@@ -951,7 +952,7 @@ class segment_manager
|
||||
typedef ipcdetail::index_key<CharT, void_pointer> index_key_t;
|
||||
typedef typename index_type::iterator index_it;
|
||||
typedef typename index_type::value_type intrusive_value_type;
|
||||
|
||||
|
||||
//-------------------------------
|
||||
scoped_lock<rmutex> guard(m_header);
|
||||
//-------------------------------
|
||||
@@ -972,7 +973,7 @@ class segment_manager
|
||||
void *memory = iv;
|
||||
void *values = ctrl_data->value();
|
||||
std::size_t num = ctrl_data->m_value_bytes/table.size;
|
||||
|
||||
|
||||
//Sanity check
|
||||
BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0);
|
||||
BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char());
|
||||
@@ -992,7 +993,7 @@ class segment_manager
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
bool priv_generic_named_destroy(const CharT *name,
|
||||
bool priv_generic_named_destroy(const CharT *name,
|
||||
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
||||
ipcdetail::in_place_interface &table,
|
||||
ipcdetail::false_ is_intrusive_index)
|
||||
@@ -1006,7 +1007,7 @@ class segment_manager
|
||||
scoped_lock<rmutex> guard(m_header);
|
||||
//-------------------------------
|
||||
//Try to find the name in the index
|
||||
index_it it = index.find(key_type (name,
|
||||
index_it it = index.find(key_type (name,
|
||||
std::char_traits<CharT>::length(name)));
|
||||
|
||||
//If not found, return false
|
||||
@@ -1033,7 +1034,7 @@ class segment_manager
|
||||
char *stored_name = static_cast<char*>(static_cast<void*>(const_cast<CharT*>(it->first.name())));
|
||||
(void)stored_name;
|
||||
|
||||
//Check if the distance between the name pointer and the memory pointer
|
||||
//Check if the distance between the name pointer and the memory pointer
|
||||
//is correct (this can detect incorrect type in destruction)
|
||||
std::size_t num = ctrl_data->m_value_bytes/table.size;
|
||||
void *values = ctrl_data->value();
|
||||
@@ -1070,8 +1071,8 @@ class segment_manager
|
||||
template<class CharT>
|
||||
void * priv_generic_named_construct(unsigned char type,
|
||||
const CharT *name,
|
||||
size_type num,
|
||||
bool try2find,
|
||||
size_type num,
|
||||
bool try2find,
|
||||
bool dothrow,
|
||||
ipcdetail::in_place_interface &table,
|
||||
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
||||
@@ -1095,12 +1096,12 @@ class segment_manager
|
||||
//-------------------------------
|
||||
//Insert the node. This can throw.
|
||||
//First, we want to know if the key is already present before
|
||||
//we allocate any memory, and if the key is not present, we
|
||||
//we allocate any memory, and if the key is not present, we
|
||||
//want to allocate all memory in a single buffer that will
|
||||
//contain the name and the user buffer.
|
||||
//
|
||||
//Since equal_range(key) + insert(hint, value) approach is
|
||||
//quite inefficient in container implementations
|
||||
//quite inefficient in container implementations
|
||||
//(they re-test if the position is correct), I've chosen
|
||||
//to insert the node, do an ugly un-const cast and modify
|
||||
//the key (which is a smart pointer) to an equivalent one
|
||||
@@ -1138,7 +1139,7 @@ class segment_manager
|
||||
}
|
||||
|
||||
//Allocates buffer for name + data, this can throw (it hurts)
|
||||
void *buffer_ptr;
|
||||
void *buffer_ptr;
|
||||
|
||||
//Check if there is enough memory
|
||||
if(dothrow){
|
||||
@@ -1149,7 +1150,7 @@ class segment_manager
|
||||
buffer_ptr = this->allocate
|
||||
(block_info.template total_size_with_header<intrusive_value_type>(), std::nothrow_t());
|
||||
if(!buffer_ptr)
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Now construct the intrusive hook plus the header
|
||||
@@ -1184,7 +1185,7 @@ class segment_manager
|
||||
//the memory allocation as the intrusive value is built in that
|
||||
//memory
|
||||
value_eraser<index_type> v_eraser(index, it);
|
||||
|
||||
|
||||
//Construct array, this can throw
|
||||
ipcdetail::array_construct(ptr, num, table);
|
||||
|
||||
@@ -1197,10 +1198,10 @@ class segment_manager
|
||||
//!Generic named new function for
|
||||
//!named functions
|
||||
template<class CharT>
|
||||
void * priv_generic_named_construct(unsigned char type,
|
||||
void * priv_generic_named_construct(unsigned char type,
|
||||
const CharT *name,
|
||||
size_type num,
|
||||
bool try2find,
|
||||
size_type num,
|
||||
bool try2find,
|
||||
bool dothrow,
|
||||
ipcdetail::in_place_interface &table,
|
||||
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
|
||||
@@ -1227,12 +1228,12 @@ class segment_manager
|
||||
//-------------------------------
|
||||
//Insert the node. This can throw.
|
||||
//First, we want to know if the key is already present before
|
||||
//we allocate any memory, and if the key is not present, we
|
||||
//we allocate any memory, and if the key is not present, we
|
||||
//want to allocate all memory in a single buffer that will
|
||||
//contain the name and the user buffer.
|
||||
//
|
||||
//Since equal_range(key) + insert(hint, value) approach is
|
||||
//quite inefficient in container implementations
|
||||
//quite inefficient in container implementations
|
||||
//(they re-test if the position is correct), I've chosen
|
||||
//to insert the node, do an ugly un-const cast and modify
|
||||
//the key (which is a smart pointer) to an equivalent one
|
||||
@@ -1265,7 +1266,7 @@ class segment_manager
|
||||
value_eraser<index_type> v_eraser(index, it);
|
||||
|
||||
//Allocates buffer for name + data, this can throw (it hurts)
|
||||
void *buffer_ptr;
|
||||
void *buffer_ptr;
|
||||
block_header_t * hdr;
|
||||
|
||||
//Allocate and construct the headers
|
||||
@@ -1277,7 +1278,7 @@ class segment_manager
|
||||
else{
|
||||
buffer_ptr = this->allocate(total_size, std::nothrow_t());
|
||||
if(!buffer_ptr)
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
index_it *idr = new(buffer_ptr) index_it(it);
|
||||
hdr = block_header_t::template from_first_header<index_it>(idr);
|
||||
@@ -1289,7 +1290,7 @@ class segment_manager
|
||||
else{
|
||||
buffer_ptr = this->allocate(block_info.total_size(), std::nothrow_t());
|
||||
if(!buffer_ptr)
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
hdr = static_cast<block_header_t*>(buffer_ptr);
|
||||
}
|
||||
@@ -1303,7 +1304,7 @@ class segment_manager
|
||||
std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
|
||||
|
||||
//Do the ugly cast, please mama, forgive me!
|
||||
//This new key points to an identical string, so it must have the
|
||||
//This new key points to an identical string, so it must have the
|
||||
//same position than the overwritten key according to the predicate
|
||||
const_cast<key_type &>(it->first).name(name_ptr);
|
||||
it->second.m_ptr = hdr;
|
||||
@@ -1346,7 +1347,7 @@ class segment_manager
|
||||
{
|
||||
named_index_t m_named_index;
|
||||
unique_index_t m_unique_index;
|
||||
|
||||
|
||||
header_t(Base *restricted_segment_mngr)
|
||||
: m_named_index (restricted_segment_mngr)
|
||||
, m_unique_index(restricted_segment_mngr)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. 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)
|
||||
//
|
||||
@@ -28,7 +28,7 @@
|
||||
#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS_ONLY)
|
||||
# include <sys/shm.h> //System V shared memory...
|
||||
#elif defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
|
||||
# include <fcntl.h> //O_CREAT, O_*...
|
||||
# include <fcntl.h> //O_CREAT, O_*...
|
||||
# include <sys/mman.h> //shm_xxx
|
||||
# include <unistd.h> //ftruncate, close
|
||||
# include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
|
||||
@@ -71,26 +71,26 @@ class shared_memory_object
|
||||
shared_memory_object(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions())
|
||||
{ this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm); }
|
||||
|
||||
//!Tries to open a shared memory object with name "name", with the access mode "mode".
|
||||
//!Tries to open a shared memory object with name "name", with the access mode "mode".
|
||||
//!If the file does not previously exist, it throws an error.
|
||||
shared_memory_object(open_only_t, const char *name, mode_t mode)
|
||||
{ this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); }
|
||||
|
||||
//!Moves the ownership of "moved"'s shared memory object to *this.
|
||||
//!After the call, "moved" does not represent any shared memory object.
|
||||
//!Moves the ownership of "moved"'s shared memory object to *this.
|
||||
//!After the call, "moved" does not represent any shared memory object.
|
||||
//!Does not throw
|
||||
shared_memory_object(BOOST_RV_REF(shared_memory_object) moved)
|
||||
: m_handle(file_handle_t(ipcdetail::invalid_file()))
|
||||
{ this->swap(moved); }
|
||||
|
||||
//!Moves the ownership of "moved"'s shared memory to *this.
|
||||
//!After the call, "moved" does not represent any shared memory.
|
||||
//!After the call, "moved" does not represent any shared memory.
|
||||
//!Does not throw
|
||||
shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved)
|
||||
{
|
||||
{
|
||||
shared_memory_object tmp(boost::move(moved));
|
||||
this->swap(tmp);
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Swaps the shared_memory_objects. Does not throw
|
||||
@@ -99,7 +99,7 @@ class shared_memory_object
|
||||
//!Erases a shared memory object from the system.
|
||||
//!Returns false on error. Never throws
|
||||
static bool remove(const char *name);
|
||||
|
||||
|
||||
//!Sets the size of the shared memory mapping
|
||||
void truncate(offset_t length);
|
||||
|
||||
@@ -142,11 +142,11 @@ class shared_memory_object
|
||||
|
||||
/// @cond
|
||||
|
||||
inline shared_memory_object::shared_memory_object()
|
||||
inline shared_memory_object::shared_memory_object()
|
||||
: m_handle(file_handle_t(ipcdetail::invalid_file()))
|
||||
{}
|
||||
|
||||
inline shared_memory_object::~shared_memory_object()
|
||||
inline shared_memory_object::~shared_memory_object()
|
||||
{ this->priv_close(); }
|
||||
|
||||
|
||||
@@ -157,10 +157,10 @@ inline bool shared_memory_object::get_size(offset_t &size) const
|
||||
{ return ipcdetail::get_file_size((file_handle_t)m_handle, size); }
|
||||
|
||||
inline void shared_memory_object::swap(shared_memory_object &other)
|
||||
{
|
||||
{
|
||||
std::swap(m_handle, other.m_handle);
|
||||
std::swap(m_mode, other.m_mode);
|
||||
m_filename.swap(other.m_filename);
|
||||
m_filename.swap(other.m_filename);
|
||||
}
|
||||
|
||||
inline mapping_handle_t shared_memory_object::get_mapping_handle() const
|
||||
@@ -268,7 +268,7 @@ inline bool use_filesystem_based_posix()
|
||||
} //shared_memory_object_detail
|
||||
|
||||
inline bool shared_memory_object::priv_open_or_create
|
||||
(ipcdetail::create_enum_t type,
|
||||
(ipcdetail::create_enum_t type,
|
||||
const char *filename,
|
||||
mode_t mode, const permissions &perm)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2007-2011.
|
||||
// (C) Copyright Ion Gaztanaga 2007-2012.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -26,9 +26,9 @@
|
||||
//!Describes the functor to delete objects from the segment.
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace interprocess {
|
||||
|
||||
//!A deleter that uses the segment manager's destroy_ptr
|
||||
//!A deleter that uses the segment manager's destroy_ptr
|
||||
//!function to destroy the passed pointer resource.
|
||||
//!
|
||||
//!This deleter is used
|
||||
@@ -56,7 +56,7 @@ class deleter
|
||||
{ mp_mngr->destroy_ptr(ipcdetail::to_raw_pointer(p)); }
|
||||
};
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//
|
||||
// (C) Copyright Peter Dimov and Multi Media Ltd. 2001, 2002, 2003
|
||||
// (C) Copyright Peter Dimov 2004-2005
|
||||
// (C) Copyright Ion Gaztanaga 2006-2011. Distributed under the Boost
|
||||
// (C) Copyright Ion Gaztanaga 2006-2012. 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)
|
||||
//
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp>
|
||||
#include <boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/container/allocator/allocator_traits.hpp>
|
||||
#include <boost/container/allocator_traits.hpp>
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
#include <functional> // std::less
|
||||
|
||||
@@ -99,7 +99,7 @@ class shared_count
|
||||
counted_impl_allocator alloc(a);
|
||||
m_pi = alloc.allocate(1);
|
||||
//Anti-exception deallocator
|
||||
scoped_ptr<counted_impl,
|
||||
scoped_ptr<counted_impl,
|
||||
scoped_ptr_dealloc_functor<counted_impl_allocator> >
|
||||
deallocator(m_pi, alloc);
|
||||
//It's more correct to use VoidAllocator::construct but
|
||||
@@ -116,7 +116,7 @@ class shared_count
|
||||
}
|
||||
|
||||
~shared_count() // nothrow
|
||||
{
|
||||
{
|
||||
if(m_pi)
|
||||
m_pi->release();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2007-2011.
|
||||
// (C) Copyright Ion Gaztanaga 2007-2012.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
|
||||
// Copyright 2004-2005 Peter Dimov
|
||||
// Copyright 2007-2011 Ion Gaztanaga
|
||||
// Copyright 2007-2012 Ion Gaztanaga
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <boost/interprocess/smart_ptr/detail/sp_counted_base.hpp>
|
||||
#include <boost/interprocess/smart_ptr/scoped_ptr.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/container/allocator/allocator_traits.hpp>
|
||||
#include <boost/container/allocator_traits.hpp>
|
||||
#include <boost/intrusive/pointer_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
@@ -63,10 +63,10 @@ struct scoped_ptr_dealloc_functor
|
||||
{ if (ptr) priv_deallocate(ptr, alloc_version()); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<class A, class D>
|
||||
class sp_counted_impl_pd
|
||||
class sp_counted_impl_pd
|
||||
: public sp_counted_base
|
||||
, boost::container::allocator_traits<A>::template
|
||||
portable_rebind_alloc< sp_counted_impl_pd<A, D> >::type
|
||||
@@ -122,7 +122,7 @@ class sp_counted_impl_pd
|
||||
this_pointer this_ptr (this);
|
||||
//Do it now!
|
||||
scoped_ptr< this_type, scoped_ptr_dealloc_functor<this_allocator> >
|
||||
deleter(this_ptr, a_copy);
|
||||
deleter_ptr(this_ptr, a_copy);
|
||||
typedef typename this_allocator::value_type value_type;
|
||||
ipcdetail::to_raw_pointer(this_ptr)->~value_type();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user