Updated Boost libraries

This commit is contained in:
Sergii Pylypenko
2013-06-26 17:31:21 +03:00
parent cb4611925f
commit d62c91a533
2623 changed files with 177228 additions and 61242 deletions

View File

@@ -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

View File

@@ -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(); }

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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)
//

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
{

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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)
//

View File

@@ -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>

View File

@@ -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)
//

View File

@@ -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

View File

@@ -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)
//

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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())

View File

@@ -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

View File

@@ -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

View File

@@ -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)
//

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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 &region, 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;

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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>

View File

@@ -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)

View File

@@ -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

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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)> >
{};

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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)
//

View File

@@ -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

View File

@@ -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)
//

View File

@@ -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>

View File

@@ -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.

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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
};

View File

@@ -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

View File

@@ -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
};

View File

@@ -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))
{}

View File

@@ -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)

View File

@@ -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()));
}
}
};

View File

@@ -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){

View File

@@ -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));

View File

@@ -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 {

View File

@@ -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

View File

@@ -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)
//

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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>

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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

View File

@@ -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