Added boost header

This commit is contained in:
Christophe Riccio
2012-01-08 01:26:07 +00:00
parent 9c3faaca40
commit c7d752cdf8
8946 changed files with 1732316 additions and 0 deletions

View File

@@ -0,0 +1,466 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP
#define BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/container/detail/multiallocation_chain.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes adaptive_pool pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail{
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class adaptive_pool_base
: public node_pool_allocation_impl
< adaptive_pool_base
< Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
, Version
, T
, SegmentManager
>
{
public:
typedef typename SegmentManager::void_pointer void_pointer;
typedef SegmentManager segment_manager;
typedef adaptive_pool_base
<Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> self_t;
/// @cond
template <int dummy>
struct node_pool
{
typedef ipcdetail::shared_adaptive_node_pool
< SegmentManager, sizeof_value<T>::value, NodesPerBlock, MaxFreeBlocks, OverheadPercent> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
/// @endcond
BOOST_STATIC_ASSERT((Version <=2));
public:
//-------
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
typedef boost::interprocess::version_type<adaptive_pool_base, Version> version;
typedef boost::container::containers_detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains adaptive_pool_base from
//!adaptive_pool_base
template<class T2>
struct rebind
{
typedef adaptive_pool_base<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
/// @cond
private:
//!Not assignable from related adaptive_pool_base
template<unsigned int Version2, class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char O2>
adaptive_pool_base& operator=
(const adaptive_pool_base<Version2, T2, SegmentManager2, N2, F2, O2>&);
/// @endcond
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
adaptive_pool_base(segment_manager *segment_mngr)
: mp_node_pool(ipcdetail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { }
//!Copy constructor from other adaptive_pool_base. Increments the reference
//!count of the associated node pool. Never throws
adaptive_pool_base(const adaptive_pool_base &other)
: mp_node_pool(other.get_node_pool())
{
node_pool<0>::get(ipcdetail::get_pointer(mp_node_pool))->inc_ref_count();
}
//!Assignment from other adaptive_pool_base
adaptive_pool_base& operator=(const adaptive_pool_base &other)
{
adaptive_pool_base c(other);
swap(*this, c);
return *this;
}
//!Copy constructor from related adaptive_pool_base. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
adaptive_pool_base
(const adaptive_pool_base<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: mp_node_pool(ipcdetail::get_or_create_node_pool<typename node_pool<0>::type>(other.get_segment_manager())) { }
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~adaptive_pool_base()
{ ipcdetail::destroy_node_pool_if_last_link(node_pool<0>::get(ipcdetail::get_pointer(mp_node_pool))); }
//!Returns a pointer to the node pool.
//!Never throws
void* get_node_pool() const
{ return ipcdetail::get_pointer(mp_node_pool); }
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return node_pool<0>::get(ipcdetail::get_pointer(mp_node_pool))->get_segment_manager(); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2)
{ ipcdetail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); }
/// @cond
private:
void_pointer mp_node_pool;
/// @endcond
};
//!Equality test for same type
//!of adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NPC, std::size_t F, unsigned char OP> inline
bool operator==(const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc1,
const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
//!Inequality test for same type
//!of adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NPC, std::size_t F, unsigned char OP> inline
bool operator!=(const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc1,
const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class adaptive_pool_v1
: public adaptive_pool_base
< 1
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
{
public:
typedef ipcdetail::adaptive_pool_base
< 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
template<class T2>
struct rebind
{
typedef adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
adaptive_pool_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
adaptive_pool_v1
(const adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
};
} //namespace ipcdetail{
/// @endcond
//!An STL node allocator that uses a segment manager as memory
//!source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
//!
//!This node allocator shares a segregated storage between all instances
//!of adaptive_pool with equal sizeof(T) placed in the same segment
//!group. NodesPerBlock is the number of nodes allocated at once when the allocator
//!needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
//!deallocated with the segment manager.
//!
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
//!(memory usable for nodes / total memory allocated from the segment manager)
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class adaptive_pool
/// @cond
: public ipcdetail::adaptive_pool_base
< 2
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef ipcdetail::adaptive_pool_base
< 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
public:
typedef boost::interprocess::version_type<adaptive_pool, 2> version;
template<class T2>
struct rebind
{
typedef adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
adaptive_pool(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
adaptive_pool
(const adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
#else //BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
//!Obtains adaptive_pool from
//!adaptive_pool
template<class T2>
struct rebind
{
typedef adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private:
//!Not assignable from
//!related adaptive_pool
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
adaptive_pool& operator=
(const adaptive_pool<T2, SegmentManager2, N2, F2, OP2>&);
//!Not assignable from
//!other adaptive_pool
//adaptive_pool& operator=(const adaptive_pool&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
adaptive_pool(segment_manager *segment_mngr);
//!Copy constructor from other adaptive_pool. Increments the reference
//!count of the associated node pool. Never throws
adaptive_pool(const adaptive_pool &other);
//!Copy constructor from related adaptive_pool. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
adaptive_pool
(const adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~adaptive_pool();
//!Returns a pointer to the node pool.
//!Never throws
void* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, size_type num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(size_type num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain it);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP

View File

@@ -0,0 +1,305 @@
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/containers/allocation_type.hpp>
#include <boost/container/detail/multiallocation_chain.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
#include <stdexcept>
//!\file
//!Describes an allocator that allocates portions of fixed size
//!memory buffer (shared memory, mapped file...)
namespace boost {
namespace interprocess {
//!An STL compatible allocator that uses a segment manager as
//!memory source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
template<class T, class SegmentManager>
class allocator
{
public:
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
/// @cond
private:
//Self type
typedef allocator<T, SegmentManager> self_t;
//Pointer to void
typedef typename segment_manager::void_pointer aux_pointer_t;
//Typedef to const void pointer
typedef typename
boost::pointer_to_other
<aux_pointer_t, const void>::type cvoid_ptr;
//Pointer to the allocator
typedef typename boost::pointer_to_other
<cvoid_ptr, segment_manager>::type alloc_ptr_t;
//Not assignable from related allocator
template<class T2, class SegmentManager2>
allocator& operator=(const allocator<T2, SegmentManager2>&);
//Not assignable from other allocator
allocator& operator=(const allocator&);
//Pointer to the allocator
alloc_ptr_t mp_mngr;
/// @endcond
public:
typedef T value_type;
typedef typename boost::pointer_to_other
<cvoid_ptr, T>::type pointer;
typedef typename boost::
pointer_to_other<pointer, const T>::type const_pointer;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
typedef boost::interprocess::version_type<allocator, 2> version;
/// @cond
//Experimental. Don't use.
typedef boost::container::containers_detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
/// @endcond
//!Obtains an allocator that allocates
//!objects of type T2
template<class T2>
struct rebind
{
typedef allocator<T2, SegmentManager> other;
};
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return ipcdetail::get_pointer(mp_mngr); }
//!Constructor from the segment manager.
//!Never throws
allocator(segment_manager *segment_mngr)
: mp_mngr(segment_mngr) { }
//!Constructor from other allocator.
//!Never throws
allocator(const allocator &other)
: mp_mngr(other.get_segment_manager()){ }
//!Constructor from related allocator.
//!Never throws
template<class T2>
allocator(const allocator<T2, SegmentManager> &other)
: mp_mngr(other.get_segment_manager()){}
//!Allocates memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_ptr hint = 0)
{
(void)hint;
if(count > this->max_size())
throw bad_alloc();
return pointer(static_cast<value_type*>(mp_mngr->allocate(count*sizeof(T))));
}
//!Deallocates memory previously allocated.
//!Never throws
void deallocate(const pointer &ptr, size_type)
{ mp_mngr->deallocate((void*)ipcdetail::get_pointer(ptr)); }
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const
{ return mp_mngr->get_size()/sizeof(T); }
//!Swap segment manager. Does not throw. If each allocator is placed in
//!different memory segments, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2)
{ ipcdetail::do_swap(alloc1.mp_mngr, alloc2.mp_mngr); }
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const
{
return (size_type)mp_mngr->size(ipcdetail::get_pointer(p))/sizeof(T);
}
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0)
{
return mp_mngr->allocation_command
(command, limit_size, preferred_size, received_size, ipcdetail::get_pointer(reuse));
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many
(size_type elem_size, size_type num_elements)
{
return multiallocation_chain(mp_mngr->allocate_many(sizeof(T)*elem_size, num_elements));
}
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many
(const size_type *elem_sizes, size_type n_elements)
{
multiallocation_chain(mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T)));
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain)
{
return mp_mngr->deallocate_many(chain.extract_multiallocation_chain());
}
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one()
{ return this->allocate(1); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual
(size_type num_elements)
{ return this->allocate_many(1, num_elements); }
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p)
{ return this->deallocate(p, 1); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain)
{ return this->deallocate_many(boost::interprocess::move(chain)); }
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const
{ return pointer(boost::addressof(value)); }
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const
{ return const_pointer(boost::addressof(value)); }
//!Copy construct an object
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v)
{ new((void*)ipcdetail::get_pointer(ptr)) value_type(v); }
//!Default construct an object.
//!Throws if T's default constructor throws
void construct(const pointer &ptr)
{ new((void*)ipcdetail::get_pointer(ptr)) value_type; }
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
};
//!Equality test for same type
//!of allocator
template<class T, class SegmentManager> inline
bool operator==(const allocator<T , SegmentManager> &alloc1,
const allocator<T, SegmentManager> &alloc2)
{ return alloc1.get_segment_manager() == alloc2.get_segment_manager(); }
//!Inequality test for same type
//!of allocator
template<class T, class SegmentManager> inline
bool operator!=(const allocator<T, SegmentManager> &alloc1,
const allocator<T, SegmentManager> &alloc2)
{ return alloc1.get_segment_manager() != alloc2.get_segment_manager(); }
} //namespace interprocess {
/// @cond
template<class T>
struct has_trivial_destructor;
template<class T, class SegmentManager>
struct has_trivial_destructor
<boost::interprocess::allocator <T, SegmentManager> >
{
enum { value = true };
};
/// @endcond
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP

View File

@@ -0,0 +1,356 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP
#define BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <cstddef>
//!\file
//!Describes cached_adaptive_pool pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail {
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class cached_adaptive_pool_v1
: public ipcdetail::cached_allocator_impl
< T
, ipcdetail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 1>
{
public:
typedef ipcdetail::cached_allocator_impl
< T
, ipcdetail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 1> base_t;
template<class T2>
struct rebind
{
typedef cached_adaptive_pool_v1
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
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)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_adaptive_pool_v1
(const cached_adaptive_pool_v1
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
};
} //namespace ipcdetail{
/// @endcond
//!An STL node allocator that uses a segment manager as memory
//!source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
//!
//!This node allocator shares a segregated storage between all instances of
//!cached_adaptive_pool with equal sizeof(T) placed in the same
//!memory segment. But also caches some nodes privately to
//!avoid some synchronization overhead.
//!
//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when
//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
//!deallocated with the segment manager.
//!
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
//!(memory usable for nodes / total memory allocated from the segment manager)
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class cached_adaptive_pool
/// @cond
: public ipcdetail::cached_allocator_impl
< T
, ipcdetail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 2>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef ipcdetail::cached_allocator_impl
< T
, ipcdetail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 2> base_t;
public:
typedef boost::interprocess::version_type<cached_adaptive_pool, 2> version;
template<class T2>
struct rebind
{
typedef cached_adaptive_pool
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
cached_adaptive_pool(SegmentManager *segment_mngr,
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_adaptive_pool
(const cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
//!Obtains cached_adaptive_pool from
//!cached_adaptive_pool
template<class T2>
struct rebind
{
typedef cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private:
//!Not assignable from
//!related cached_adaptive_pool
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
cached_adaptive_pool& operator=
(const cached_adaptive_pool<T2, SegmentManager2, N2, F2, OP2>&);
//!Not assignable from
//!other cached_adaptive_pool
cached_adaptive_pool& operator=(const cached_adaptive_pool&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
cached_adaptive_pool(segment_manager *segment_mngr);
//!Copy constructor from other cached_adaptive_pool. Increments the reference
//!count of the associated node pool. Never throws
cached_adaptive_pool(const cached_adaptive_pool &other);
//!Copy constructor from related cached_adaptive_pool. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
cached_adaptive_pool
(const cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~cached_adaptive_pool();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, size_type num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(size_type num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
//!Sets the new max cached nodes value. This can provoke deallocations
//!if "newmax" is less than current cached nodes. Never throws
void set_max_cached_nodes(size_type newmax);
//!Returns the max cached nodes parameter.
//!Never throws
size_type get_max_cached_nodes() const;
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of cached_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, std::size_t OP> inline
bool operator==(const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of cached_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, std::size_t OP> inline
bool operator!=(const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP

View File

@@ -0,0 +1,327 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <cstddef>
//!\file
//!Describes cached_cached_node_allocator pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail {
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
>
class cached_node_allocator_v1
: public ipcdetail::cached_allocator_impl
< T
, ipcdetail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 1>
{
public:
typedef ipcdetail::cached_allocator_impl
< T
, ipcdetail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 1> base_t;
template<class T2>
struct rebind
{
typedef cached_node_allocator_v1
<T2, SegmentManager, NodesPerBlock> other;
};
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)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_node_allocator_v1
(const cached_node_allocator_v1
<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
};
} //namespace ipcdetail{
/// @endcond
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class cached_node_allocator
/// @cond
: public ipcdetail::cached_allocator_impl
< T
, ipcdetail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 2>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef ipcdetail::cached_allocator_impl
< T
, ipcdetail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 2> base_t;
public:
typedef boost::interprocess::version_type<cached_node_allocator, 2> version;
typedef typename base_t::size_type size_type;
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)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_node_allocator
(const cached_node_allocator<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename SegmentManager::size_type size_type;
typedef typename SegmentManager::difference_type difference_type;
//!Obtains cached_node_allocator from
//!cached_node_allocator
template<class T2>
struct rebind
{
typedef cached_node_allocator<T2, SegmentManager> other;
};
private:
//!Not assignable from
//!related cached_node_allocator
template<class T2, class SegmentManager2, std::size_t N2>
cached_node_allocator& operator=
(const cached_node_allocator<T2, SegmentManager2, N2>&);
//!Not assignable from
//!other cached_node_allocator
cached_node_allocator& operator=(const cached_node_allocator&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
cached_node_allocator(segment_manager *segment_mngr);
//!Copy constructor from other cached_node_allocator. Increments the reference
//!count of the associated node pool. Never throws
cached_node_allocator(const cached_node_allocator &other);
//!Copy constructor from related cached_node_allocator. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
cached_node_allocator
(const cached_node_allocator<T2, SegmentManager, NodesPerBlock> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~cached_node_allocator();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Default construct an object.
//!Throws if T's default constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, size_type num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(size_type num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain it);
//!Sets the new max cached nodes value. This can provoke deallocations
//!if "newmax" is less than current cached nodes. Never throws
void set_max_cached_nodes(size_type newmax);
//!Returns the max cached nodes parameter.
//!Never throws
size_type get_max_cached_nodes() const;
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of cached_node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator==(const cached_node_allocator<T, S, NPC> &alloc1,
const cached_node_allocator<T, S, NPC> &alloc2);
//!Inequality test for same type
//!of cached_node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator!=(const cached_node_allocator<T, S, NPC> &alloc1,
const cached_node_allocator<T, S, NPC> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,109 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP
#define BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/math_functions.hpp>
#include <boost/intrusive/set.hpp>
#include <boost/intrusive/slist.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <cstddef>
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/container/detail/adaptive_node_pool_impl.hpp>
#include <boost/assert.hpp>
//!\file
//!Describes the real adaptive pool shared by many Interprocess pool allocators
namespace boost {
namespace interprocess {
namespace ipcdetail {
template< class SegmentManager
, std::size_t NodeSize
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class private_adaptive_node_pool
: public boost::container::containers_detail::private_adaptive_node_pool_impl
<typename SegmentManager::segment_manager_base_type>
{
typedef boost::container::containers_detail::private_adaptive_node_pool_impl
<typename SegmentManager::segment_manager_base_type> base_t;
//Non-copyable
private_adaptive_node_pool();
private_adaptive_node_pool(const private_adaptive_node_pool &);
private_adaptive_node_pool &operator=(const private_adaptive_node_pool &);
public:
typedef SegmentManager segment_manager;
typedef typename base_t::size_type size_type;
static const size_type nodes_per_block = NodesPerBlock;
//Deprecated, use node_per_block
static const size_type nodes_per_chunk = NodesPerBlock;
//!Constructor from a segment manager. Never throws
private_adaptive_node_pool(segment_manager *segment_mngr)
: base_t(segment_mngr, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent)
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager() const
{ return static_cast<segment_manager*>(base_t::get_segment_manager_base()); }
};
//!Pooled shared memory allocator using adaptive pool. Includes
//!a reference count but the class does not delete itself, this is
//!responsibility of user classes. Node size (NodeSize) and the number of
//!nodes allocated per block (NodesPerBlock) are known at compile time
template< class SegmentManager
, std::size_t NodeSize
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class shared_adaptive_node_pool
: public ipcdetail::shared_pool_impl
< private_adaptive_node_pool
<SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
>
{
typedef ipcdetail::shared_pool_impl
< private_adaptive_node_pool
<SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
> base_t;
public:
shared_adaptive_node_pool(SegmentManager *segment_mgnr)
: base_t(segment_mgnr)
{}
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP

View File

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

View File

@@ -0,0 +1,110 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP
#define BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/intrusive/slist.hpp>
#include <boost/math/common_factor_ct.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/container/detail/node_pool_impl.hpp>
#include <cstddef>
//!\file
//!Describes the real adaptive pool shared by many Interprocess adaptive pool allocators
namespace boost {
namespace interprocess {
namespace ipcdetail {
//!Pooled shared memory allocator using single segregated storage. Includes
//!a reference count but the class does not delete itself, this is
//!responsibility of user classes. Node size (NodeSize) and the number of
//!nodes allocated per block (NodesPerBlock) are known at compile time
template< class SegmentManager, std::size_t NodeSize, std::size_t NodesPerBlock >
class private_node_pool
//Inherit from the implementation to avoid template bloat
: public boost::container::containers_detail::
private_node_pool_impl<typename SegmentManager::segment_manager_base_type>
{
typedef boost::container::containers_detail::private_node_pool_impl
<typename SegmentManager::segment_manager_base_type> base_t;
//Non-copyable
private_node_pool();
private_node_pool(const private_node_pool &);
private_node_pool &operator=(const private_node_pool &);
public:
typedef SegmentManager segment_manager;
typedef typename base_t::size_type size_type;
static const size_type nodes_per_block = NodesPerBlock;
//Deprecated, use nodes_per_block
static const size_type nodes_per_chunk = NodesPerBlock;
//!Constructor from a segment manager. Never throws
private_node_pool(segment_manager *segment_mngr)
: base_t(segment_mngr, NodeSize, NodesPerBlock)
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager() const
{ return static_cast<segment_manager*>(base_t::get_segment_manager_base()); }
};
//!Pooled shared memory allocator using single segregated storage. Includes
//!a reference count but the class does not delete itself, this is
//!responsibility of user classes. Node size (NodeSize) and the number of
//!nodes allocated per block (NodesPerBlock) are known at compile time
//!Pooled shared memory allocator using adaptive pool. Includes
//!a reference count but the class does not delete itself, this is
//!responsibility of user classes. Node size (NodeSize) and the number of
//!nodes allocated per block (NodesPerBlock) are known at compile time
template< class SegmentManager
, std::size_t NodeSize
, std::size_t NodesPerBlock
>
class shared_node_pool
: public ipcdetail::shared_pool_impl
< private_node_pool
<SegmentManager, NodeSize, NodesPerBlock>
>
{
typedef ipcdetail::shared_pool_impl
< private_node_pool
<SegmentManager, NodeSize, NodesPerBlock>
> base_t;
public:
shared_node_pool(SegmentManager *segment_mgnr)
: base_t(segment_mgnr)
{}
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP

View File

@@ -0,0 +1,50 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP
#define BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/intrusive/slist.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class VoidPointer>
struct node_slist
{
//This hook will be used to chain the individual nodes
typedef typename bi::make_slist_base_hook
<bi::void_pointer<VoidPointer>, bi::link_mode<bi::normal_link> >::type slist_hook_t;
//A node object will hold node_t when it's not allocated
struct node_t
: public slist_hook_t
{};
typedef typename bi::make_slist
<node_t, bi::linear<true>, bi::base_hook<slist_hook_t> >::type node_slist_t;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP

View File

@@ -0,0 +1,450 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/container/detail/multiallocation_chain.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes node_allocator pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail{
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class node_allocator_base
: public node_pool_allocation_impl
< node_allocator_base
< Version, T, SegmentManager, NodesPerBlock>
, Version
, T
, SegmentManager
>
{
public:
typedef typename SegmentManager::void_pointer void_pointer;
typedef SegmentManager segment_manager;
typedef node_allocator_base
<Version, T, SegmentManager, NodesPerBlock> self_t;
/// @cond
template <int dummy>
struct node_pool
{
typedef ipcdetail::shared_node_pool
< SegmentManager, sizeof_value<T>::value, NodesPerBlock> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
/// @endcond
BOOST_STATIC_ASSERT((Version <=2));
public:
//-------
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
typedef boost::interprocess::version_type<node_allocator_base, Version> version;
typedef boost::container::containers_detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains node_allocator_base from
//!node_allocator_base
template<class T2>
struct rebind
{
typedef node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> other;
};
/// @cond
private:
//!Not assignable from related node_allocator_base
template<unsigned int Version2, class T2, class SegmentManager2, std::size_t N2>
node_allocator_base& operator=
(const node_allocator_base<Version2, T2, SegmentManager2, N2>&);
//!Not assignable from other node_allocator_base
//node_allocator_base& operator=(const node_allocator_base&);
/// @endcond
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
node_allocator_base(segment_manager *segment_mngr)
: mp_node_pool(ipcdetail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { }
//!Copy constructor from other node_allocator_base. Increments the reference
//!count of the associated node pool. Never throws
node_allocator_base(const node_allocator_base &other)
: mp_node_pool(other.get_node_pool())
{
node_pool<0>::get(ipcdetail::get_pointer(mp_node_pool))->inc_ref_count();
}
//!Copy constructor from related node_allocator_base. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
node_allocator_base
(const node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> &other)
: mp_node_pool(ipcdetail::get_or_create_node_pool<typename node_pool<0>::type>(other.get_segment_manager())) { }
//!Assignment from other node_allocator_base
node_allocator_base& operator=(const node_allocator_base &other)
{
node_allocator_base c(other);
swap(*this, c);
return *this;
}
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~node_allocator_base()
{ ipcdetail::destroy_node_pool_if_last_link(node_pool<0>::get(ipcdetail::get_pointer(mp_node_pool))); }
//!Returns a pointer to the node pool.
//!Never throws
void* get_node_pool() const
{ return ipcdetail::get_pointer(mp_node_pool); }
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return node_pool<0>::get(ipcdetail::get_pointer(mp_node_pool))->get_segment_manager(); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2)
{ ipcdetail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); }
/// @cond
private:
void_pointer mp_node_pool;
/// @endcond
};
//!Equality test for same type
//!of node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator==(const node_allocator_base<V, T, S, NPC> &alloc1,
const node_allocator_base<V, T, S, NPC> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
//!Inequality test for same type
//!of node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator!=(const node_allocator_base<V, T, S, NPC> &alloc1,
const node_allocator_base<V, T, S, NPC> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
>
class node_allocator_v1
: public node_allocator_base
< 1
, T
, SegmentManager
, NodesPerBlock
>
{
public:
typedef ipcdetail::node_allocator_base
< 1, T, SegmentManager, NodesPerBlock> base_t;
template<class T2>
struct rebind
{
typedef node_allocator_v1<T2, SegmentManager, NodesPerBlock> other;
};
node_allocator_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
node_allocator_v1
(const node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
};
} //namespace ipcdetail{
/// @endcond
//!An STL node allocator that uses a segment manager as memory
//!source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
//!This node allocator shares a segregated storage between all instances
//!of node_allocator with equal sizeof(T) placed in the same segment
//!group. NodesPerBlock is the number of nodes allocated at once when the allocator
//!needs runs out of nodes
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class node_allocator
/// @cond
: public ipcdetail::node_allocator_base
< 2
, T
, SegmentManager
, NodesPerBlock
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef ipcdetail::node_allocator_base
< 2, T, SegmentManager, NodesPerBlock> base_t;
public:
typedef boost::interprocess::version_type<node_allocator, 2> version;
template<class T2>
struct rebind
{
typedef node_allocator<T2, SegmentManager, NodesPerBlock> other;
};
node_allocator(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
node_allocator
(const node_allocator<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
#else //BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
//!Obtains node_allocator from
//!node_allocator
template<class T2>
struct rebind
{
typedef node_allocator<T2, SegmentManager, NodesPerBlock> other;
};
private:
//!Not assignable from
//!related node_allocator
template<class T2, class SegmentManager2, std::size_t N2>
node_allocator& operator=
(const node_allocator<T2, SegmentManager2, N2>&);
//!Not assignable from
//!other node_allocator
//node_allocator& operator=(const node_allocator&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
node_allocator(segment_manager *segment_mngr);
//!Copy constructor from other node_allocator. Increments the reference
//!count of the associated node pool. Never throws
node_allocator(const node_allocator &other);
//!Copy constructor from related node_allocator. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
node_allocator
(const node_allocator<T2, SegmentManager, NodesPerBlock> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~node_allocator();
//!Returns a pointer to the node pool.
//!Never throws
void* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, size_type num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(size_type num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator==(const node_allocator<T, S, NPC> &alloc1,
const node_allocator<T, S, NPC> &alloc2);
//!Inequality test for same type
//!of node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator!=(const node_allocator<T, S, NPC> &alloc1,
const node_allocator<T, S, NPC> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,466 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP
#define BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
#include <boost/container/detail/multiallocation_chain.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes private_adaptive_pool_base pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail {
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class private_adaptive_pool_base
: public node_pool_allocation_impl
< private_adaptive_pool_base < Version, T, SegmentManager, NodesPerBlock
, MaxFreeBlocks, OverheadPercent>
, Version
, T
, SegmentManager
>
{
public:
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
/// @cond
private:
typedef private_adaptive_pool_base
< Version, T, SegmentManager, NodesPerBlock
, MaxFreeBlocks, OverheadPercent> self_t;
typedef ipcdetail::private_adaptive_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
> node_pool_t;
BOOST_STATIC_ASSERT((Version <=2));
/// @endcond
public:
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::size_type difference_type;
typedef boost::interprocess::version_type
<private_adaptive_pool_base, Version> version;
typedef boost::container::containers_detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains node_allocator from other node_allocator
template<class T2>
struct rebind
{
typedef private_adaptive_pool_base
<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
/// @cond
template <int dummy>
struct node_pool
{
typedef ipcdetail::private_adaptive_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
private:
//!Not assignable from related private_adaptive_pool_base
template<unsigned int Version2, class T2, class MemoryAlgorithm2, std::size_t N2, std::size_t F2, unsigned char OP2>
private_adaptive_pool_base& operator=
(const private_adaptive_pool_base<Version2, T2, MemoryAlgorithm2, N2, F2, OP2>&);
//!Not assignable from other private_adaptive_pool_base
private_adaptive_pool_base& operator=(const private_adaptive_pool_base&);
/// @endcond
public:
//!Constructor from a segment manager
private_adaptive_pool_base(segment_manager *segment_mngr)
: m_node_pool(segment_mngr)
{}
//!Copy constructor from other private_adaptive_pool_base. Never throws
private_adaptive_pool_base(const private_adaptive_pool_base &other)
: m_node_pool(other.get_segment_manager())
{}
//!Copy constructor from related private_adaptive_pool_base. Never throws.
template<class T2>
private_adaptive_pool_base
(const private_adaptive_pool_base
<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: m_node_pool(other.get_segment_manager())
{}
//!Destructor, frees all used memory. Never throws
~private_adaptive_pool_base()
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager()const
{ return m_node_pool.get_segment_manager(); }
//!Returns the internal node pool. Never throws
node_pool_t* get_node_pool() const
{ return const_cast<node_pool_t*>(&m_node_pool); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different shared memory segments, the result is undefined.
friend void swap(self_t &alloc1,self_t &alloc2)
{ alloc1.m_node_pool.swap(alloc2.m_node_pool); }
/// @cond
private:
node_pool_t m_node_pool;
/// @endcond
};
//!Equality test for same type of private_adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc2)
{ return &alloc1 == &alloc2; }
//!Inequality test for same type of private_adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc2)
{ return &alloc1 != &alloc2; }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class private_adaptive_pool_v1
: public private_adaptive_pool_base
< 1
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
{
public:
typedef ipcdetail::private_adaptive_pool_base
< 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
template<class T2>
struct rebind
{
typedef private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private_adaptive_pool_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_adaptive_pool_v1
(const private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
};
} //namespace ipcdetail {
/// @endcond
//!An STL node allocator that uses a segment manager as memory
//!source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
//!This allocator has its own node pool.
//!
//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when
//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
//!deallocated with the segment manager.
//!
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
//!(memory usable for nodes / total memory allocated from the segment manager)
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class private_adaptive_pool
/// @cond
: public ipcdetail::private_adaptive_pool_base
< 2
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef ipcdetail::private_adaptive_pool_base
< 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
public:
typedef boost::interprocess::version_type<private_adaptive_pool, 2> version;
template<class T2>
struct rebind
{
typedef private_adaptive_pool
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private_adaptive_pool(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_adaptive_pool
(const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
//!Obtains private_adaptive_pool from
//!private_adaptive_pool
template<class T2>
struct rebind
{
typedef private_adaptive_pool
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private:
//!Not assignable from
//!related private_adaptive_pool
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
private_adaptive_pool& operator=
(const private_adaptive_pool<T2, SegmentManager2, N2, F2>&);
//!Not assignable from
//!other private_adaptive_pool
private_adaptive_pool& operator=(const private_adaptive_pool&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
private_adaptive_pool(segment_manager *segment_mngr);
//!Copy constructor from other private_adaptive_pool. Increments the reference
//!count of the associated node pool. Never throws
private_adaptive_pool(const private_adaptive_pool &other);
//!Copy constructor from related private_adaptive_pool. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
private_adaptive_pool
(const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~private_adaptive_pool();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, size_type num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(size_type num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of private_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of private_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP

View File

@@ -0,0 +1,442 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/container/detail/multiallocation_chain.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes private_node_allocator_base pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail {
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class private_node_allocator_base
: public node_pool_allocation_impl
< private_node_allocator_base < Version, T, SegmentManager, NodesPerBlock>
, Version
, T
, SegmentManager
>
{
public:
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
/// @cond
private:
typedef private_node_allocator_base
< Version, T, SegmentManager, NodesPerBlock> self_t;
typedef ipcdetail::private_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
> node_pool_t;
BOOST_STATIC_ASSERT((Version <=2));
/// @endcond
public:
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
typedef boost::interprocess::version_type
<private_node_allocator_base, Version> version;
typedef boost::container::containers_detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains node_allocator from other node_allocator
template<class T2>
struct rebind
{
typedef private_node_allocator_base
<Version, T2, SegmentManager, NodesPerBlock> other;
};
/// @cond
template <int dummy>
struct node_pool
{
typedef ipcdetail::private_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
private:
//!Not assignable from related private_node_allocator_base
template<unsigned int Version2, class T2, class MemoryAlgorithm2, std::size_t N2>
private_node_allocator_base& operator=
(const private_node_allocator_base<Version2, T2, MemoryAlgorithm2, N2>&);
//!Not assignable from other private_node_allocator_base
private_node_allocator_base& operator=(const private_node_allocator_base&);
/// @endcond
public:
//!Constructor from a segment manager
private_node_allocator_base(segment_manager *segment_mngr)
: m_node_pool(segment_mngr)
{}
//!Copy constructor from other private_node_allocator_base. Never throws
private_node_allocator_base(const private_node_allocator_base &other)
: m_node_pool(other.get_segment_manager())
{}
//!Copy constructor from related private_node_allocator_base. Never throws.
template<class T2>
private_node_allocator_base
(const private_node_allocator_base
<Version, T2, SegmentManager, NodesPerBlock> &other)
: m_node_pool(other.get_segment_manager())
{}
//!Destructor, frees all used memory. Never throws
~private_node_allocator_base()
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager()const
{ return m_node_pool.get_segment_manager(); }
//!Returns the internal node pool. Never throws
node_pool_t* get_node_pool() const
{ return const_cast<node_pool_t*>(&m_node_pool); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different shared memory segments, the result is undefined.
friend void swap(self_t &alloc1,self_t &alloc2)
{ alloc1.m_node_pool.swap(alloc2.m_node_pool); }
/// @cond
private:
node_pool_t m_node_pool;
/// @endcond
};
//!Equality test for same type of private_node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator==(const private_node_allocator_base<V, T, S, NPC> &alloc1,
const private_node_allocator_base<V, T, S, NPC> &alloc2)
{ return &alloc1 == &alloc2; }
//!Inequality test for same type of private_node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator!=(const private_node_allocator_base<V, T, S, NPC> &alloc1,
const private_node_allocator_base<V, T, S, NPC> &alloc2)
{ return &alloc1 != &alloc2; }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
>
class private_node_allocator_v1
: public private_node_allocator_base
< 1
, T
, SegmentManager
, NodesPerBlock
>
{
public:
typedef ipcdetail::private_node_allocator_base
< 1, T, SegmentManager, NodesPerBlock> base_t;
template<class T2>
struct rebind
{
typedef private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> other;
};
private_node_allocator_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_node_allocator_v1
(const private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
};
} //namespace ipcdetail {
/// @endcond
//!An STL node allocator that uses a segment manager as memory
//!source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
//!This allocator has its own node pool. NodesPerBlock is the number of nodes allocated
//!at once when the allocator needs runs out of nodes
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class private_node_allocator
/// @cond
: public ipcdetail::private_node_allocator_base
< 2
, T
, SegmentManager
, NodesPerBlock
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef ipcdetail::private_node_allocator_base
< 2, T, SegmentManager, NodesPerBlock> base_t;
public:
typedef boost::interprocess::version_type<private_node_allocator, 2> version;
template<class T2>
struct rebind
{
typedef private_node_allocator
<T2, SegmentManager, NodesPerBlock> other;
};
private_node_allocator(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_node_allocator
(const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manage::difference_type difference_type;
//!Obtains private_node_allocator from
//!private_node_allocator
template<class T2>
struct rebind
{
typedef private_node_allocator
<T2, SegmentManager, NodesPerBlock> other;
};
private:
//!Not assignable from
//!related private_node_allocator
template<class T2, class SegmentManager2, std::size_t N2>
private_node_allocator& operator=
(const private_node_allocator<T2, SegmentManager2, N2>&);
//!Not assignable from
//!other private_node_allocator
private_node_allocator& operator=(const private_node_allocator&);
public:
//!Constructor from a segment manager. If not present, constructs a node
//!pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
private_node_allocator(segment_manager *segment_mngr);
//!Copy constructor from other private_node_allocator. Increments the reference
//!count of the associated node pool. Never throws
private_node_allocator(const private_node_allocator &other);
//!Copy constructor from related private_node_allocator. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
private_node_allocator
(const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~private_node_allocator();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different memory segment, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, size_type num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(size_type num_elements);
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of private_node_allocator
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1,
const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of private_node_allocator
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1,
const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,119 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_ANONYMOUS_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <cstddef>
#if (!defined(BOOST_INTERPROCESS_WINDOWS))
# 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
#include <boost/interprocess/windows_shared_memory.hpp>
#endif
//!\file
//!Describes a function that creates anonymous shared memory that can be
//!shared between forked processes
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail{
class raw_mapped_region_creator
{
public:
static mapped_region
create_posix_mapped_region(void *address, offset_t offset, 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;
}
};
}
/// @endcond
//!A function that creates an anonymous shared memory segment of size "size".
//!If "address" is passed the function will try to map the segment in that address.
//!Otherwise the operating system will choose the mapping address.
//!The function returns a mapped_region holding that segment or throws
//!interprocess_exception if the function fails.
//static mapped_region
static mapped_region
anonymous_shared_memory(std::size_t size, void *address = 0)
#if (!defined(BOOST_INTERPROCESS_WINDOWS))
{
int flags;
int fd = -1;
#if defined(MAP_ANONYMOUS) //Use MAP_ANONYMOUS
flags = MAP_ANONYMOUS | MAP_SHARED;
#elif !defined(MAP_ANONYMOUS) && defined(MAP_ANON) //use MAP_ANON
flags = MAP_ANON | MAP_SHARED;
#else // Use "/dev/zero"
fd = open("/dev/zero", O_RDWR);
flags = MAP_SHARED;
if(fd == -1){
error_info err = system_error_code();
throw interprocess_exception(err);
}
#endif
address = mmap( address
, size
, PROT_READ|PROT_WRITE
, flags
, fd
, 0);
if(address == MAP_FAILED){
if(fd != -1)
close(fd);
error_info err = system_error_code();
throw interprocess_exception(err);
}
if(fd != -1)
close(fd);
return ipcdetail::raw_mapped_region_creator::create_posix_mapped_region(address, 0, size);
}
#else
{
windows_shared_memory anonymous_mapping(create_only, 0, read_write, size);
return mapped_region(anonymous_mapping, read_write, 0, size, address);
}
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP

View File

@@ -0,0 +1,40 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_ALLOCATION_TYPE_HPP
#define BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/detail/allocation_type.hpp>
namespace boost {
namespace interprocess {
/// @cond
typedef int allocation_type;
/// @endcond
static const allocation_type allocate_new = boost::container::allocate_new;
static const allocation_type expand_fwd = boost::container::expand_fwd;
static const allocation_type expand_bwd = boost::container::expand_bwd;
static const allocation_type shrink_in_place = boost::container::shrink_in_place;
static const allocation_type try_shrink_in_place= boost::container::try_shrink_in_place;
static const allocation_type nothrow_allocation = boost::container::nothrow_allocation;
static const allocation_type zero_memory = boost::container::zero_memory;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP

View File

@@ -0,0 +1,40 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2009. 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_CONTAINERS_CONTAINERS_FWD_HPP
#define BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP
/// @cond
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
//////////////////////////////////////////////////////////////////////////////
// Standard predeclarations
//////////////////////////////////////////////////////////////////////////////
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/container_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::ordered_range;
using boost::container::ordered_unique_range;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
/// @endcond
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_DEQUE_HPP
#define BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/deque.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::deque;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_FLAT_MAP_HPP
#define BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::flat_map;
using boost::container::flat_multimap;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_FLAT_SET_HPP
#define BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/flat_set.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::flat_set;
using boost::container::flat_multiset;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_LIST_HPP
#define BOOST_INTERPROCESS_CONTAINERS_LIST_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/list.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::list;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_MAP_HPP
#define BOOST_INTERPROCESS_CONTAINERS_MAP_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/map.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::map;
using boost::container::multimap;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP

View File

@@ -0,0 +1,34 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_PAIR_HPP
#define BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/detail/pair.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::containers_detail::pair;
using boost::container::containers_detail::piecewise_construct;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_SET_HPP
#define BOOST_INTERPROCESS_CONTAINERS_SET_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/set.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::set;
using boost::container::multiset;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_SLIST_HPP
#define BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/slist.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::slist;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_STABLE_VECTOR_HPP
#define BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/stable_vector.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::stable_vector;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_STRING_HPP
#define BOOST_INTERPROCESS_CONTAINERS_STRING_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/string.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::basic_string;
using boost::container::string;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_VECTOR_HPP
#define BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/vector.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::vector;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_VERSION_TYPE_HPP
#define BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/detail/version_type.hpp>
namespace boost {
namespace interprocess {
using boost::container::containers_detail::version_type;
using boost::container::containers_detail::version;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP

View File

@@ -0,0 +1,77 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_CREATION_TAGS_HPP
#define BOOST_INTERPROCESS_CREATION_TAGS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost {
namespace interprocess {
//!Tag to indicate that the resource must
//!be only created
struct create_only_t {};
//!Tag to indicate that the resource must
//!be only opened
struct open_only_t {};
//!Tag to indicate that the resource must
//!be only opened for reading
struct open_read_only_t {};
//!Tag to indicate that the resource must
//!be only opened privately for reading
struct open_read_private_t {};
//!Tag to indicate that the resource must
//!be only opened for reading
struct open_copy_on_write_t {};
//!Tag to indicate that the resource must
//!be created. If already created, it must be opened.
struct open_or_create_t {};
//!Value to indicate that the resource must
//!be only created
static const create_only_t create_only = create_only_t();
//!Value to indicate that the resource must
//!be only opened
static const open_only_t open_only = open_only_t();
//!Value to indicate that the resource must
//!be only opened for reading
static const open_read_only_t open_read_only = open_read_only_t();
//!Value to indicate that the resource must
//!be created. If already created, it must be opened.
static const open_or_create_t open_or_create = open_or_create_t();
//!Value to indicate that the resource must
//!be only opened for reading
static const open_copy_on_write_t open_copy_on_write = open_copy_on_write_t();
namespace ipcdetail {
enum create_enum_t
{ DoCreate, DoOpen, DoOpenOrCreate };
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CREATION_TAGS_HPP

View File

@@ -0,0 +1,593 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2009
// (C) Copyright Markus Schoepflin 2007
// (C) Copyright Bryce Lelbach 2010
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP
#define BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/cstdint.hpp>
namespace boost{
namespace interprocess{
namespace ipcdetail{
//! Atomically increment an boost::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);
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem);
//! 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);
//! 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);
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#if (defined BOOST_INTERPROCESS_WINDOWS)
#include <boost/interprocess/detail/win32_api.hpp>
namespace boost{
namespace interprocess{
namespace ipcdetail{
//! 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 winapi::interlocked_decrement(reinterpret_cast<volatile long*>(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 winapi::interlocked_increment(reinterpret_cast<volatile long*>(mem))-1; }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ return *mem; }
//! 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)
{ winapi::interlocked_exchange(reinterpret_cast<volatile long*>(mem), val); }
//! 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 winapi::interlocked_compare_exchange(reinterpret_cast<volatile long*>(mem), with, cmp); }
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
namespace boost {
namespace interprocess {
namespace ipcdetail{
//! 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 prev = cmp;
// This version by Mans Rullgard of Pathscale
__asm__ __volatile__ ( "lock\n\t"
"cmpxchg %2,%0"
: "+m"(*mem), "+a"(prev)
: "r"(with)
: "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
//! "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)
{
// int r = *pw;
// *mem += val;
// return r;
int r;
asm volatile
(
"lock\n\t"
"xadd %1, %0":
"+m"( *mem ), "=r"( r ): // outputs (%0, %1)
"1"( val ): // inputs (%2 == %1)
"memory", "cc" // clobbers
);
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
//! "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; }
//! 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(__GNUC__) && (defined(__PPC__) || defined(__ppc__))
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)
{
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
return prev;
}
//! 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 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
return prev;
}
//! 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(-1u)); }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ return *mem; }
//! 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(__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>
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 atomic_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), (int32_t)val) - val; }
//! 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 atomic_cas_32(reinterpret_cast<volatile ::uint32_t*>(mem), cmp, with); }
//! 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_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), 1) - 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_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), (boost::uint32_t)-1) + 1; }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ return *mem; }
//! 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(__osf__) && defined(__DECCXX)
#include <machine/builtins.h>
#include <c_asm.h>
namespace boost{
namespace interprocess{
namespace ipcdetail{
//! Atomically decrement a uint32_t by 1
//! "mem": pointer to the atomic value
//! Returns the old value pointed to by mem
//! Acquire, memory barrier after decrement.
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
{ boost::uint32_t old_val = __ATOMIC_DECREMENT_LONG(mem); __MB(); return old_val; }
//! Atomically increment a uint32_t by 1
//! "mem": pointer to the object
//! Returns the old value pointed to by mem
//! Release, memory barrier before increment.
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
{ __MB(); return __ATOMIC_INCREMENT_LONG(mem); }
// Rational for the implementation of the atomic read and write functions.
//
// 1. The Alpha Architecture Handbook requires that access to a byte,
// an aligned word, an aligned longword, or an aligned quadword is
// atomic. (See 'Alpha Architecture Handbook', version 4, chapter 5.2.2.)
//
// 2. The CXX User's Guide states that volatile quantities are accessed
// with single assembler instructions, and that a compilation error
// occurs when declaring a quantity as volatile which is not properly
// aligned.
//! Atomically read an boost::uint32_t from memory
//! Acquire, memory barrier after load.
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ boost::uint32_t old_val = *mem; __MB(); return old_val; }
//! Atomically set an boost::uint32_t in memory
//! "mem": pointer to the object
//! "param": val value that the object will assume
//! Release, memory barrier before store.
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
{ __MB(); *mem = val; }
//! 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
//! Memory barrier between load and store.
inline boost::uint32_t atomic_cas32(
volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
{
// Note:
//
// Branch prediction prefers backward branches, and the Alpha Architecture
// Handbook explicitely states that the loop should not be implemented like
// it is below. (See chapter 4.2.5.) Therefore the code should probably look
// like this:
//
// return asm(
// "10: ldl_l %v0,(%a0) ;"
// " cmpeq %v0,%a2,%t0 ;"
// " beq %t0,20f ;"
// " mb ;"
// " mov %a1,%t0 ;"
// " stl_c %t0,(%a0) ;"
// " beq %t0,30f ;"
// "20: ret ;"
// "30: br 10b;",
// mem, with, cmp);
//
// But as the compiler always transforms this into the form where a backward
// branch is taken on failure, we can as well implement it in the straight
// forward form, as this is what it will end up in anyway.
return asm(
"10: ldl_l %v0,(%a0) ;" // load prev value from mem and lock mem
" cmpeq %v0,%a2,%t0 ;" // compare with given value
" beq %t0,20f ;" // if not equal, we're done
" mb ;" // memory barrier
" mov %a1,%t0 ;" // load new value into scratch register
" stl_c %t0,(%a0) ;" // store new value to locked mem (overwriting scratch)
" beq %t0,10b ;" // store failed because lock has been stolen, retry
"20: ",
mem, with, cmp);
}
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#elif defined(__IBMCPP__) && (__IBMCPP__ >= 800) && defined(_AIX)
#include <builtins.h>
namespace boost {
namespace interprocess {
namespace ipcdetail{
//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)));
}
//! "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;
}
//! 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)
{
boost::uint32_t oldValue;
boost::uint32_t valueToStore;
do
{
oldValue = lwarxu(mem);
} while (!stwcxu(mem, (oldValue == with) ? cmp : 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; }
} //namespace ipcdetail
} //namespace interprocess
} //namespace boost
#else
#error No atomic operations implemented for this platform, sorry!
#endif
namespace boost{
namespace interprocess{
namespace ipcdetail{
inline bool atomic_add_unless32
(volatile boost::uint32_t *mem, boost::uint32_t value, boost::uint32_t unless_this)
{
boost::uint32_t old, c(atomic_read32(mem));
while(c != unless_this && (old = atomic_cas32(mem, c + value, c)) != c){
c = old;
}
return c != unless_this;
}
} //namespace ipcdetail
} //namespace interprocess
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP

View File

@@ -0,0 +1,29 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_CAST_TAGS_HPP
#define BOOST_INTERPROCESS_CAST_TAGS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost { namespace interprocess { namespace ipcdetail {
struct static_cast_tag {};
struct const_cast_tag {};
struct dynamic_cast_tag {};
struct reinterpret_cast_tag {};
}}} //namespace boost { namespace interprocess { namespace ipcdetail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CAST_TAGS_HPP

View File

@@ -0,0 +1,47 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_CONFIG_INCLUDED
#define BOOST_INTERPROCESS_CONFIG_INCLUDED
#include <boost/config.hpp>
#endif
#ifdef BOOST_MSVC
#ifndef _CRT_SECURE_NO_DEPRECATE
#define BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
#endif
#pragma warning (push)
#pragma warning (disable : 4702) // unreachable code
#pragma warning (disable : 4706) // assignment within conditional expression
#pragma warning (disable : 4127) // conditional expression is constant
#pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
#pragma warning (disable : 4284) // odd return type for operator->
#pragma warning (disable : 4244) // possible loss of data
#pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2"
#pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data
#pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier"
#pragma warning (disable : 4355) // "this" : used in base member initializer list
#pragma warning (disable : 4503) // "identifier" : decorated name length exceeded, name was truncated
#pragma warning (disable : 4511) // copy constructor could not be generated
#pragma warning (disable : 4512) // assignment operator could not be generated
#pragma warning (disable : 4514) // unreferenced inline removed
#pragma warning (disable : 4521) // Disable "multiple copy constructors specified"
#pragma warning (disable : 4522) // "class" : multiple assignment operators specified
#pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter
#pragma warning (disable : 4710) // function not inlined
#pragma warning (disable : 4711) // function selected for automatic inline expansion
#pragma warning (disable : 4786) // identifier truncated in debug info
#pragma warning (disable : 4996) // "function": was declared deprecated
#pragma warning (disable : 4197) // top-level volatile in cast is ignored
#pragma warning (disable : 4541) // 'typeid' used on polymorphic type 'boost::exception'
// 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
#endif

View File

@@ -0,0 +1,17 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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 BOOST_MSVC
#pragma warning (pop)
#ifdef BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE
#undef BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE
#undef _CRT_SECURE_NO_DEPRECATE
#endif
#endif

View File

@@ -0,0 +1,202 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP
#define BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/creation_tags.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail{
class file_wrapper
{
/// @cond
BOOST_MOVABLE_BUT_NOT_COPYABLE(file_wrapper)
/// @endcond
public:
//!Default constructor.
//!Represents an empty file_wrapper.
file_wrapper();
//!Creates a file object with name "name" and mode "mode", with the access mode "mode"
//!If the file previously exists, throws an error.
file_wrapper(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions())
{ this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm); }
//!Tries to create a file with name "name" and mode "mode", with the
//!access mode "mode". If the file previously exists, it tries to open it with mode "mode".
//!Otherwise throws an error.
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".
//!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.
//!Does not throw
file_wrapper(BOOST_RV_REF(file_wrapper) moved)
: m_handle(file_handle_t(ipcdetail::invalid_file()))
{ this->swap(moved); }
//!Moves the ownership of "moved"'s file to *this.
//!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::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps to file_wrappers.
//!Does not throw
void swap(file_wrapper &other);
//!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);
//!Closes the
//!file
~file_wrapper();
//!Returns the name of the file
//!used in the constructor
const char *get_name() const;
//!Returns the name of the file
//!used in the constructor
bool get_size(offset_t &size) const;
//!Returns access mode
//!used in the constructor
mode_t get_mode() const;
//!Get mapping handle
//!to use with mapped_region
mapping_handle_t get_mapping_handle() const;
private:
//!Closes a previously opened file mapping. Never throws.
void priv_close();
//!Closes a previously opened file mapping. Never throws.
bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm);
file_handle_t m_handle;
mode_t m_mode;
std::string m_filename;
};
inline file_wrapper::file_wrapper()
: m_handle(file_handle_t(ipcdetail::invalid_file()))
{}
inline file_wrapper::~file_wrapper()
{ this->priv_close(); }
inline const char *file_wrapper::get_name() const
{ return m_filename.c_str(); }
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);
}
inline mapping_handle_t file_wrapper::get_mapping_handle() const
{ return mapping_handle_from_file_handle(m_handle); }
inline mode_t file_wrapper::get_mode() const
{ return m_mode; }
inline bool file_wrapper::priv_open_or_create
(ipcdetail::create_enum_t type,
const char *filename,
mode_t mode,
const permissions &perm = permissions())
{
m_filename = filename;
if(mode != read_only && mode != read_write){
error_info err(mode_error);
throw interprocess_exception(err);
}
//Open file existing native API to obtain the handle
switch(type){
case ipcdetail::DoOpen:
m_handle = open_existing_file(filename, mode);
break;
case ipcdetail::DoCreate:
m_handle = create_new_file(filename, mode, perm);
break;
case ipcdetail::DoOpenOrCreate:
m_handle = create_or_open_file(filename, mode, perm);
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Check for error
if(m_handle == invalid_file()){
throw interprocess_exception(error_info(system_error_code()));
}
m_mode = mode;
return true;
}
inline bool file_wrapper::remove(const char *filename)
{ return delete_file(filename); }
inline void file_wrapper::truncate(offset_t length)
{
if(!truncate_file(m_handle, length)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline void file_wrapper::priv_close()
{
if(m_handle != invalid_file()){
close_file(m_handle);
m_handle = invalid_file();
}
}
} //namespace ipcdetail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP

View File

@@ -0,0 +1,73 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_IN_PLACE_INTERFACE_HPP
#define BOOST_INTERPROCESS_IN_PLACE_INTERFACE_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/type_traits.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <typeinfo> //typeid
//!\file
//!Describes an abstract interface for placement construction and destruction.
namespace boost {
namespace interprocess {
namespace ipcdetail {
struct in_place_interface
{
in_place_interface(std::size_t alignm, std::size_t sz, const char *tname)
: alignment(alignm), size(sz), type_name(tname)
{}
std::size_t alignment;
std::size_t size;
const char *type_name;
virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) = 0;
virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed) = 0;
virtual ~in_place_interface(){}
};
template<class T>
struct placement_destroy : public in_place_interface
{
placement_destroy()
: in_place_interface(::boost::alignment_of<T>::value, sizeof(T), typeid(T).name())
{}
virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed)
{
T* memory = static_cast<T*>(mem);
for(destroyed = 0; destroyed < num; ++destroyed)
(memory++)->~T();
}
virtual void construct_n(void *, std::size_t, std::size_t &) {}
private:
void destroy(void *mem)
{ static_cast<T*>(mem)->~T(); }
};
}
}
} //namespace boost { namespace interprocess { namespace ipcdetail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP
#define BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP
namespace boost{
namespace interprocess{
namespace ipcdetail{
class interprocess_tester
{
public:
template<class T>
static void dont_close_on_destruction(T &t)
{ t.dont_close_on_destruction(); }
};
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,754 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP
#define BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
#include <boost/interprocess/sync/mutex_family.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/segment_manager.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
//
#include <boost/detail/no_exceptions_support.hpp>
//
#include <utility>
#include <fstream>
#include <new>
#include <boost/assert.hpp>
//!\file
//!Describes a named shared memory allocation user class.
//!
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class BasicManagedMemoryImpl>
class create_open_func;
template<
class CharType,
class MemoryAlgorithm,
template<class IndexConfig> class IndexType
>
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
//!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
, class MemoryAlgorithm
, template<class IndexConfig> class IndexType
, std::size_t Offset = 0
>
class basic_managed_memory_impl
{
//Non-copyable
basic_managed_memory_impl(const basic_managed_memory_impl &);
basic_managed_memory_impl &operator=(const basic_managed_memory_impl &);
template<class BasicManagedMemoryImpl>
friend class create_open_func;
public:
typedef typename segment_manager_type
<CharType, MemoryAlgorithm, IndexType>::type segment_manager;
typedef CharType char_type;
typedef MemoryAlgorithm memory_algorithm;
typedef typename MemoryAlgorithm::mutex_family mutex_family;
typedef CharType char_t;
typedef typename MemoryAlgorithm::size_type size_type;
typedef typename MemoryAlgorithm::difference_type difference_type;
typedef difference_type handle_t;
typedef typename segment_manager::
const_named_iterator const_named_iterator;
typedef typename segment_manager::
const_unique_iterator const_unique_iterator;
/// @cond
typedef typename
segment_manager::char_ptr_holder_t char_ptr_holder_t;
//Experimental. Don't use.
typedef typename segment_manager::multiallocation_chain multiallocation_chain;
/// @endcond
static const size_type PayloadPerAllocation = segment_manager::PayloadPerAllocation;
private:
typedef basic_managed_memory_impl
<CharType, MemoryAlgorithm, IndexType, Offset> self_t;
protected:
template<class ManagedMemory>
static bool grow(const char *filename, size_type extra_bytes)
{
typedef typename ManagedMemory::device_type device_type;
//Increase file size
try{
offset_t old_size;
{
device_type f(open_or_create, filename, read_write);
if(!f.get_size(old_size))
return false;
f.truncate(old_size + extra_bytes);
}
ManagedMemory managed_memory(open_only, filename);
//Grow always works
managed_memory.self_t::grow(extra_bytes);
}
catch(...){
return false;
}
return true;
}
template<class ManagedMemory>
static bool shrink_to_fit(const char *filename)
{
typedef typename ManagedMemory::device_type device_type;
size_type new_size, old_size;
try{
ManagedMemory managed_memory(open_only, filename);
old_size = managed_memory.get_size();
managed_memory.self_t::shrink_to_fit();
new_size = managed_memory.get_size();
}
catch(...){
return false;
}
//Decrease file size
{
device_type f(open_or_create, filename, read_write);
f.truncate(new_size);
}
return true;
}
//!Constructor. Allocates basic resources. Never throws.
basic_managed_memory_impl()
: mp_header(0){}
//!Destructor. Calls close. Never throws.
~basic_managed_memory_impl()
{ this->close_impl(); }
//!Places segment manager in the reserved space. This can throw.
bool create_impl (void *addr, size_type size)
{
if(mp_header) return false;
//Check if there is enough space
if(size < segment_manager::get_min_size())
return false;
//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
mp_header = new(addr) segment_manager(size);
}
BOOST_CATCH(...){
return false;
}
BOOST_CATCH_END
return true;
}
//!Connects to a segment manager in the reserved buffer. Never throws.
bool open_impl (void *addr, size_type)
{
if(mp_header) return false;
mp_header = static_cast<segment_manager*>(addr);
return true;
}
//!Frees resources. Never throws.
bool close_impl()
{
bool ret = mp_header != 0;
mp_header = 0;
return ret;
}
//!Frees resources and destroys common resources. Never throws.
bool destroy_impl()
{
if(mp_header == 0)
return false;
mp_header->~segment_manager();
this->close_impl();
return true;
}
//!
void grow(size_type extra_bytes)
{ mp_header->grow(extra_bytes); }
void shrink_to_fit()
{ mp_header->shrink_to_fit(); }
public:
//!Returns segment manager. Never throws.
segment_manager *get_segment_manager() const
{ return mp_header; }
//!Returns the base address of the memory in this process. Never throws.
void * get_address () const
{ return reinterpret_cast<char*>(mp_header) - Offset; }
//!Returns the size of memory segment. Never throws.
size_type get_size () const
{ return mp_header->get_size() + Offset; }
//!Returns the number of free bytes of the memory
//!segment
size_type get_free_memory() const
{ return mp_header->get_free_memory(); }
//!Returns the result of "all_memory_deallocated()" function
//!of the used memory algorithm
bool all_memory_deallocated()
{ return mp_header->all_memory_deallocated(); }
//!Returns the result of "check_sanity()" function
//!of the used memory algorithm
bool check_sanity()
{ return mp_header->check_sanity(); }
//!Writes to zero free memory (memory not yet allocated) of
//!the memory algorithm
void zero_free_memory()
{ mp_header->zero_free_memory(); }
//!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()));
}
//!Returns true if the address belongs to the managed memory segment
bool belongs_to_segment (const void *ptr) const
{
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
//!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 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
//!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
//!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); }
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,
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
//!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); }
/// @cond
//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, 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 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, 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 elem_sizes[i] bytes.
void deallocate_many(multiallocation_chain chain)
{ return mp_header->deallocate_many(boost::interprocess::move(chain)); }
/// @endcond
//!Marks previously allocated memory as free. Never throws.
void deallocate (void *addr)
{ if (mp_header) mp_header->deallocate(addr); }
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find (char_ptr_holder_t name)
{ return mp_header->template find<T>(name); }
//!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
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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>
typename segment_manager::template construct_proxy<T>::type
construct(char_ptr_holder_t name)
{ return mp_header->template construct<T>(name); }
//!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
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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>
typename segment_manager::template construct_proxy<T>::type
find_or_construct(char_ptr_holder_t name)
{ return mp_header->template find_or_construct<T>(name); }
//!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
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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>
typename segment_manager::template construct_proxy<T>::type
construct(char_ptr_holder_t name, std::nothrow_t nothrow)
{ return mp_header->template construct<T>(name, nothrow); }
//!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
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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>
typename segment_manager::template construct_proxy<T>::type
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
//!
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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
//!
//!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
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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
//!
//!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.
//!
//!-> If there is no available memory, returns 0.
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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
//!
//!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.
//!
//!-> If there is no available memory, returns 0.
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!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, std::nothrow_t nothrow)
{ return mp_header->template find_or_construct_it<T>(name, nothrow); }
//!Calls a functor and guarantees that no new construction, search or
//!destruction will be executed by any process while executing the object
//!function call. If the functor throws, this function throws.
template <class Func>
void atomic_func(Func &f)
{ mp_header->atomic_func(f); }
//!Tries to call a functor guaranteeing that no new construction, search or
//!destruction will be executed by any process while executing the object
//!function call. If the atomic function can't be immediatelly executed
//!because the internal mutex is already locked, returns false.
//!If the functor throws, this function throws.
template <class Func>
bool try_atomic_func(Func &f)
{ return mp_header->try_atomic_func(f); }
//!Destroys a named memory object or array.
//!
//!Finds the object with the given name, calls its destructors,
//!frees used memory and returns true.
//!
//!-> If the object is not found, it returns false.
//!
//!Exception Handling:
//!
//!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.
//!
//!Destroying an object:
//!
//!If the destructor throws, the memory will be freed and that exception
//!will be thrown.
//!
//!Destroying an array:
//!
//!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
//!recommended.
template <class T>
bool destroy(const CharType *name)
{ return mp_header->template destroy<T>(name); }
//!Destroys the unique instance of type T
//!
//!Calls the destructor, frees used memory and returns true.
//!
//!Exception Handling:
//!
//!When deleting a dynamically object, the Standard does not
//!guarantee that dynamically allocated memory will be released.
//!
//!Destroying an object:
//!
//!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
//!recommended for memory.
template <class T>
bool destroy(const ipcdetail::unique_instance_t *const )
{ return mp_header->template destroy<T>(unique_instance); }
//!Destroys the object (named, unique, or anonymous)
//!
//!Calls the destructor, frees used memory and returns true.
//!
//!Exception Handling:
//!
//!When deleting a dynamically object, the Standard does not
//!guarantee that dynamically allocated memory will be released.
//!
//!Destroying an object:
//!
//!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
//!recommended for memory.
template <class T>
void destroy_ptr(const T *ptr)
{ mp_header->template destroy_ptr<T>(ptr); }
//!Returns the name of an object created with construct/find_or_construct
//!functions. Does not throw
template<class T>
static const char_type *get_instance_name(const T *ptr)
{ return segment_manager::get_instance_name(ptr); }
//!Returns is the type an object created with construct/find_or_construct
//!functions. Does not throw.
template<class T>
static instance_type get_instance_type(const T *ptr)
{ return segment_manager::get_instance_type(ptr); }
//!Returns the length of an object created with construct/find_or_construct
//!functions (1 if is a single element, >=1 if it's an array). Does not throw.
template<class T>
static size_type get_instance_length(const T *ptr)
{ return segment_manager::get_instance_length(ptr); }
//!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
//!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)
{ mp_header->reserve_unique_objects(num); }
//!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()
{ mp_header->shrink_to_fit_indexes(); }
//!Returns the number of named objects stored
//!in the managed segment.
size_type get_num_named_objects()
{ return mp_header->get_num_named_objects(); }
//!Returns the number of unique objects stored
//!in the managed segment.
size_type get_num_unique_objects()
{ return mp_header->get_num_unique_objects(); }
//!Returns a constant iterator to the index storing the
//!named allocations. NOT thread-safe. Never throws.
const_named_iterator named_begin() const
{ return mp_header->named_begin(); }
//!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(); }
//!Returns a constant iterator to the index storing the
//!unique allocations. NOT thread-safe. Never throws.
const_unique_iterator unique_begin() const
{ return mp_header->unique_begin(); }
//!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(); }
//!This is the default allocator to allocate types T
//!from this managed segment
template<class T>
struct allocator
{
typedef typename segment_manager::template allocator<T>::type type;
};
//!Returns an instance of the default allocator for type T
//!initialized that allocates memory from this segment manager.
template<class T>
typename allocator<T>::type
get_allocator()
{ return mp_header->template get_allocator<T>(); }
//!This is the default deleter to delete types T
//!from this managed segment.
template<class T>
struct deleter
{
typedef typename segment_manager::template deleter<T>::type type;
};
//!Returns an instance of the default allocator for type T
//!initialized that allocates memory from this segment manager.
template<class T>
typename deleter<T>::type
get_deleter()
{ return mp_header->template get_deleter<T>(); }
/// @cond
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find_no_lock (char_ptr_holder_t name)
{ return mp_header->template find_no_lock<T>(name); }
/// @endcond
protected:
//!Swaps the segment manager's managed by this managed memory segment.
//!NOT thread-safe. Never throws.
void swap(basic_managed_memory_impl &other)
{ std::swap(mp_header, other.mp_header); }
private:
segment_manager *mp_header;
};
template<class BasicManagedMemoryImpl>
class create_open_func
{
public:
create_open_func(BasicManagedMemoryImpl * const frontend, ipcdetail::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 == ipcdetail::DoOpen) && created) ||
((m_type == ipcdetail::DoCreate) && !created))
return false;
if(created)
return m_frontend->create_impl(addr, size);
else
return m_frontend->open_impl (addr, size);
}
private:
BasicManagedMemoryImpl *m_frontend;
ipcdetail::create_enum_t m_type;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP

View File

@@ -0,0 +1,402 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MANAGED_MULTI_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_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/detail/managed_memory_impl.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/interprocess/detail/multi_segment_services.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/containers/list.hpp>//list
#include <boost/interprocess/mapped_region.hpp> //mapped_region
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp> //managed_open_or_create_impl
#include <new>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/streams/vectorstream.hpp>
#include <memory>
#include <boost/assert.hpp>
//!\file
//!Describes a named shared memory object allocation user class.
namespace boost {
namespace interprocess {
//TODO: We must somehow obtain the permissions of the first segment
//to apply them to subsequent segments
//-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
//!basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType>
template
<
class CharType,
class MemoryAlgorithm,
template<class IndexConfig> class IndexType
>
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
<CharType, MemoryAlgorithm, IndexType> base_t;
typedef typename MemoryAlgorithm::void_pointer void_pointer;
typedef typename ipcdetail::
managed_open_or_create_impl<shared_memory_object> managed_impl;
typedef typename void_pointer::segment_group_id segment_group_id;
typedef typename base_t::size_type size_type;
////////////////////////////////////////////////////////////////////////
//
// Some internal helper structs/functors
//
////////////////////////////////////////////////////////////////////////
//!This class defines an operator() that creates a shared memory
//!of the requested size. The rest of the parameters are
//!passed in the constructor. The class a template parameter
//!to be used with create_from_file/create_from_istream functions
//!of basic_named_object classes
// class segment_creator
// {
// public:
// segment_creator(shared_memory &shmem,
// const char *mem_name,
// const void *addr)
// : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
//
// void *operator()(size_type size)
// {
// if(!m_shmem.create(m_mem_name, size, m_addr))
// return 0;
// return m_shmem.get_address();
// }
// private:
// shared_memory &m_shmem;
// const char *m_mem_name;
// const void *m_addr;
// };
class group_services
: public multi_segment_services
{
public:
typedef std::pair<void *, size_type> result_type;
typedef basic_managed_multi_shared_memory frontend_t;
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)
: mp_frontend(frontend), m_group(0), m_min_segment_size(0){}
virtual std::pair<void *, size_type> create_new_segment(size_type alloc_size)
{
//We should allocate an extra byte so that the
//[base_addr + alloc_size] byte belongs to this segment
alloc_size += 1;
//If requested size is less than minimum, update that
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())){
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);
}
virtual bool update_segments ()
{ return true; }
virtual ~group_services(){}
void set_group(segment_group_id group)
{ m_group = group; }
segment_group_id get_group() const
{ return m_group; }
void set_min_segment_size(size_type min_segment_size)
{ m_min_segment_size = min_segment_size; }
size_type get_min_segment_size() const
{ return m_min_segment_size; }
private:
frontend_t * const mp_frontend;
segment_group_id m_group;
size_type m_min_segment_size;
};
//!Functor to execute atomically when opening or creating a shared memory
//!segment.
struct create_open_func
{
enum type_t { DoCreate, DoOpen, DoOpenOrCreate };
typedef typename
basic_managed_multi_shared_memory::void_pointer void_pointer;
create_open_func(self_t * const frontend,
type_t type, size_type segment_number)
: 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) ||
((m_type == DoCreate) && !created))
return false;
segment_group_id group = mp_frontend->m_group_services.get_group();
bool mapped = false;
bool impl_done = false;
//Associate this newly created segment as the
//segment id = 0 of this group
void_pointer::insert_mapping
( group
, static_cast<char*>(addr) - managed_impl::ManagedOpenOrCreateUserOffset
, size + managed_impl::ManagedOpenOrCreateUserOffset);
//Check if this is the master segment
if(!m_segment_number){
//Create or open the Interprocess machinery
if((impl_done = created ?
mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){
return true;
}
}
else{
return true;
}
//This is the cleanup part
//---------------
if(impl_done){
mp_frontend->close_impl();
}
if(mapped){
bool ret = void_pointer::erase_last_mapping(group);
BOOST_ASSERT(ret);(void)ret;
}
return false;
}
self_t * const mp_frontend;
type_t m_type;
size_type m_segment_number;
};
//!Functor to execute atomically when closing a shared memory segment.
struct close_func
{
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();
}
self_t * const mp_frontend;
};
//Friend declarations
friend struct basic_managed_multi_shared_memory::create_open_func;
friend struct basic_managed_multi_shared_memory::close_func;
friend class basic_managed_multi_shared_memory::group_services;
typedef list<managed_impl> shmem_list_t;
basic_managed_multi_shared_memory *get_this_pointer()
{ return this; }
public:
basic_managed_multi_shared_memory(create_only_t,
const char *name,
size_type size,
const permissions &perm = permissions())
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoCreate,name, size, perm);
}
basic_managed_multi_shared_memory(open_or_create_t,
const char *name,
size_type size,
const permissions &perm = permissions())
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoOpenOrCreate, name, size, perm);
}
basic_managed_multi_shared_memory(open_only_t, const char *name)
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoOpen, name, 0, permissions());
}
~basic_managed_multi_shared_memory()
{ this->priv_close(); }
private:
bool priv_open_or_create(typename create_open_func::type_t type,
const char *name,
size_type size,
const permissions &perm)
{
if(!m_shmem_list.empty())
return false;
typename void_pointer::segment_group_id group = 0;
BOOST_TRY{
m_root_name = name;
//Insert multi segment services and get a group identifier
group = void_pointer::new_segment_group(&m_group_services);
size = void_pointer::round_size(size);
m_group_services.set_group(group);
m_group_services.set_min_segment_size(size);
if(group){
if(this->priv_new_segment(type, size, 0, perm)){
return true;
}
}
}
BOOST_CATCH(const std::bad_alloc&){
}
BOOST_CATCH_END
if(group){
void_pointer::delete_group(group);
}
return false;
}
bool priv_new_segment(typename create_open_func::type_t type,
size_type size,
const void *addr,
const permissions &perm)
{
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.
boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter;
//Pre-reserve string size
size_type str_size = m_root_name.length()+10;
if(formatter.vector().size() < str_size){
//This can throw.
formatter.reserve(str_size);
}
//Format segment's name
formatter << m_root_name
<< static_cast<unsigned int>(segment_id) << std::ends;
//This functor will be executed when constructing
create_open_func func(this, type, segment_id);
const char *name = formatter.vector().c_str();
//This can throw.
managed_impl mshm;
switch(type){
case create_open_func::DoCreate:
{
managed_impl shm(create_only, name, size, read_write, addr, func, perm);
mshm = boost::interprocess::move(shm);
}
break;
case create_open_func::DoOpen:
{
managed_impl shm(open_only, name,read_write, addr, func);
mshm = boost::interprocess::move(shm);
}
break;
case create_open_func::DoOpenOrCreate:
{
managed_impl shm(open_or_create, name, size, read_write, addr, func, perm);
mshm = boost::interprocess::move(shm);
}
break;
default:
return false;
break;
}
//This can throw.
m_shmem_list.push_back(boost::interprocess::move(mshm));
return true;
}
BOOST_CATCH(const std::bad_alloc&){
}
BOOST_CATCH_END
return false;
}
//!Frees resources. Never throws.
void priv_close()
{
if(!m_shmem_list.empty()){
bool ret;
//Obtain group identifier
segment_group_id group = m_group_services.get_group();
//Erase main segment and its resources
shmem_list_t::iterator itbeg = m_shmem_list.begin(),
itend = m_shmem_list.end(),
it = itbeg;
//(*itbeg)->close_with_func(close_func(this));
//Delete group. All mappings are erased too.
ret = void_pointer::delete_group(group);
BOOST_ASSERT(ret);
m_shmem_list.clear();
}
}
private:
shmem_list_t m_shmem_list;
group_services m_group_services;
std::string m_root_name;
};
typedef basic_managed_multi_shared_memory
< char
, rbtree_best_fit<mutex_family, intersegment_ptr<void> >
, iset_index>
managed_multi_shared_memory;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP

View File

@@ -0,0 +1,473 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006. 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_MANAGED_OPEN_OR_CREATE_IMPL
#define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/interprocess/detail/interprocess_tester.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/type_with_alignment.hpp>
#include <boost/cstdint.hpp>
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail{ class interprocess_tester; }
template<class DeviceAbstraction>
struct managed_open_or_create_impl_device_id_t
{
typedef const char *type;
};
#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
class xsi_shared_memory_file_wrapper;
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 {
template <bool StoreDevice, class DeviceAbstraction>
class managed_open_or_create_impl_device_holder
{
public:
DeviceAbstraction &get_device()
{ static DeviceAbstraction dev; return dev; }
const DeviceAbstraction &get_device() const
{ static DeviceAbstraction dev; return dev; }
};
template <class DeviceAbstraction>
class managed_open_or_create_impl_device_holder<true, DeviceAbstraction>
{
public:
DeviceAbstraction &get_device()
{ return dev; }
const DeviceAbstraction &get_device() const
{ return dev; }
private:
DeviceAbstraction dev;
};
template<class DeviceAbstraction, bool FileBased = true, bool StoreDevice = true>
class managed_open_or_create_impl
: public managed_open_or_create_impl_device_holder<StoreDevice, DeviceAbstraction>
{
//Non-copyable
BOOST_MOVABLE_BUT_NOT_COPYABLE(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,
InitializedSegment,
CorruptedSegment
};
public:
static const std::size_t
ManagedOpenOrCreateUserOffset =
ipcdetail::ct_rounded_size
< sizeof(boost::uint32_t)
, ::boost::alignment_of< ::boost::detail::max_align >::value >::value;
managed_open_or_create_impl()
{}
managed_open_or_create_impl(create_only_t,
const device_id_t & id,
std::size_t size,
mode_t mode,
const void *addr,
const permissions &perm)
{
priv_open_or_create
( ipcdetail::DoCreate
, id
, size
, mode
, addr
, perm
, null_mapped_region_function());
}
managed_open_or_create_impl(open_only_t,
const device_id_t & id,
mode_t mode,
const void *addr)
{
priv_open_or_create
( ipcdetail::DoOpen
, id
, 0
, mode
, addr
, permissions()
, null_mapped_region_function());
}
managed_open_or_create_impl(open_or_create_t,
const device_id_t & id,
std::size_t size,
mode_t mode,
const void *addr,
const permissions &perm)
{
priv_open_or_create
( ipcdetail::DoOpenOrCreate
, id
, size
, mode
, addr
, perm
, null_mapped_region_function());
}
template <class ConstructFunc>
managed_open_or_create_impl(create_only_t,
const device_id_t & id,
std::size_t size,
mode_t mode,
const void *addr,
const ConstructFunc &construct_func,
const permissions &perm)
{
priv_open_or_create
(ipcdetail::DoCreate
, id
, size
, mode
, addr
, perm
, construct_func);
}
template <class ConstructFunc>
managed_open_or_create_impl(open_only_t,
const device_id_t & id,
mode_t mode,
const void *addr,
const ConstructFunc &construct_func)
{
priv_open_or_create
( ipcdetail::DoOpen
, id
, 0
, mode
, addr
, permissions()
, construct_func);
}
template <class ConstructFunc>
managed_open_or_create_impl(open_or_create_t,
const device_id_t & id,
std::size_t size,
mode_t mode,
const void *addr,
const ConstructFunc &construct_func,
const permissions &perm)
{
priv_open_or_create
( ipcdetail::DoOpenOrCreate
, id
, size
, mode
, addr
, perm
, construct_func);
}
managed_open_or_create_impl(BOOST_RV_REF(managed_open_or_create_impl) moved)
{ 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::interprocess::move(moved));
this->swap(tmp);
return *this;
}
~managed_open_or_create_impl()
{}
std::size_t get_user_size() const
{ return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
void *get_user_address() const
{ return static_cast<char*>(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; }
std::size_t get_real_size() const
{ return m_mapped_region.get_size(); }
void *get_real_address() const
{ return m_mapped_region.get_address(); }
void swap(managed_open_or_create_impl &other)
{
this->m_mapped_region.swap(other.m_mapped_region);
}
bool flush()
{ return m_mapped_region.flush(); }
const mapped_region &get_mapped_region() const
{ return m_mapped_region; }
DeviceAbstraction &get_device()
{ return this->DevHolder::get_device(); }
const DeviceAbstraction &get_device() const
{ return this->DevHolder::get_device(); }
private:
//These are templatized to allow explicit instantiations
template<bool dummy>
static void truncate_device(DeviceAbstraction &, offset_t, ipcdetail::false_)
{} //Empty
template<bool dummy>
static void truncate_device(DeviceAbstraction &dev, offset_t size, ipcdetail::true_)
{ dev.truncate(size); }
template<bool dummy>
static bool check_offset_t_size(std::size_t , ipcdetail::false_)
{ return true; } //Empty
template<bool dummy>
static bool check_offset_t_size(std::size_t size, ipcdetail::true_)
{ return size == std::size_t(offset_t(size)); }
//These are templatized to allow explicit instantiations
template<bool dummy>
static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t size, const permissions &perm, ipcdetail::false_)
{
DeviceAbstraction tmp(create_only, id, read_write, size, perm);
tmp.swap(dev);
}
template<bool dummy>
static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t, const permissions &perm, ipcdetail::true_)
{
DeviceAbstraction tmp(create_only, id, read_write, perm);
tmp.swap(dev);
}
template <class ConstructFunc> inline
void priv_open_or_create
(ipcdetail::create_enum_t type,
const device_id_t & id,
std::size_t size,
mode_t mode, const void *addr,
const permissions &perm,
ConstructFunc construct_func)
{
typedef ipcdetail::bool_<FileBased> file_like_t;
(void)mode;
error_info err;
bool created = false;
bool ronly = false;
bool cow = false;
DeviceAbstraction dev;
if(type != ipcdetail::DoOpen && size < ManagedOpenOrCreateUserOffset){
throw interprocess_exception(error_info(size_error));
}
//Check size can be represented by offset_t (used by truncate)
if(type != ipcdetail::DoOpen && !check_offset_t_size<FileBased>(size, file_like_t())){
throw interprocess_exception(error_info(size_error));
}
if(type == ipcdetail::DoOpen && mode == read_write){
DeviceAbstraction tmp(open_only, id, read_write);
tmp.swap(dev);
created = false;
}
else if(type == ipcdetail::DoOpen && mode == read_only){
DeviceAbstraction tmp(open_only, id, read_only);
tmp.swap(dev);
created = false;
ronly = true;
}
else if(type == ipcdetail::DoOpen && mode == copy_on_write){
DeviceAbstraction tmp(open_only, id, read_only);
tmp.swap(dev);
created = false;
cow = true;
}
else if(type == ipcdetail::DoCreate){
create_device<FileBased>(dev, id, size, perm, file_like_t());
created = true;
}
else if(type == ipcdetail::DoOpenOrCreate){
//This loop is very ugly, but brute force is sometimes better
//than diplomacy. If someone knows how to open or create a
//file and know if we have really created it or just open it
//drop me a e-mail!
bool completed = false;
while(!completed){
try{
create_device<FileBased>(dev, id, size, perm, file_like_t());
created = true;
completed = true;
}
catch(interprocess_exception &ex){
if(ex.get_error_code() != already_exists_error){
throw;
}
else{
try{
DeviceAbstraction tmp(open_only, id, read_write);
dev.swap(tmp);
created = false;
completed = true;
}
catch(interprocess_exception &ex){
if(ex.get_error_code() != not_found_error){
throw;
}
}
}
}
ipcdetail::thread_yield();
}
}
if(created){
try{
//If this throws, we are lost
truncate_device<FileBased>(dev, size, file_like_t());
//If the following throws, we will truncate the file to 1
mapped_region region(dev, read_write, 0, 0, addr);
boost::uint32_t *patomic_word = 0; //avoid gcc warning
patomic_word = static_cast<boost::uint32_t*>(region.get_address());
boost::uint32_t previous = ipcdetail::atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
if(previous == UninitializedSegment){
try{
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);
}
catch(...){
ipcdetail::atomic_write32(patomic_word, CorruptedSegment);
throw;
}
ipcdetail::atomic_write32(patomic_word, InitializedSegment);
}
else if(previous == InitializingSegment || previous == InitializedSegment){
throw interprocess_exception(error_info(already_exists_error));
}
else{
throw interprocess_exception(error_info(corrupted_error));
}
}
catch(...){
try{
truncate_device<FileBased>(dev, 1u, file_like_t());
}
catch(...){
}
throw;
}
}
else{
if(FileBased){
offset_t filesize = 0;
while(filesize == 0){
if(!ipcdetail::get_file_size(ipcdetail::file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){
throw interprocess_exception(error_info(system_error_code()));
}
ipcdetail::thread_yield();
}
if(filesize == 1){
throw interprocess_exception(error_info(corrupted_error));
}
}
mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());
boost::uint32_t value = ipcdetail::atomic_read32(patomic_word);
while(value == InitializingSegment || value == UninitializedSegment){
ipcdetail::thread_yield();
value = ipcdetail::atomic_read32(patomic_word);
}
if(value != InitializedSegment)
throw interprocess_exception(error_info(corrupted_error));
construct_func( static_cast<char*>(region.get_address()) + ManagedOpenOrCreateUserOffset
, region.get_size() - ManagedOpenOrCreateUserOffset
, false);
//All ok, just move resources to the external mapped region
m_mapped_region.swap(region);
}
if(StoreDevice){
this->DevHolder::get_device() = boost::interprocess::move(dev);
}
}
private:
friend class ipcdetail::interprocess_tester;
void dont_close_on_destruction()
{ ipcdetail::interprocess_tester::dont_close_on_destruction(m_mapped_region); }
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 {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL

View File

@@ -0,0 +1,110 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Stephen Cleary 2000.
// (C) Copyright Ion Gaztanaga 2007-2009.
//
// 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.
//
// This file is a slightly modified file from Boost.Pool
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP
#define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP
#include <climits>
#include <boost/static_assert.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
// Greatest common divisor and least common multiple
//
// gcd is an algorithm that calculates the greatest common divisor of two
// integers, using Euclid's algorithm.
//
// Pre: A > 0 && B > 0
// Recommended: A > B
template <typename Integer>
inline Integer gcd(Integer A, Integer B)
{
do
{
const Integer tmp(B);
B = A % B;
A = tmp;
} while (B != 0);
return A;
}
//
// lcm is an algorithm that calculates the least common multiple of two
// integers.
//
// Pre: A > 0 && B > 0
// Recommended: A > B
template <typename Integer>
inline Integer lcm(const Integer & A, const Integer & B)
{
Integer ret = A;
ret /= gcd(A, B);
ret *= B;
return ret;
}
template <typename Integer>
inline Integer log2_ceil(const Integer & A)
{
Integer i = 0;
Integer power_of_2 = 1;
while(power_of_2 < A){
power_of_2 <<= 1;
++i;
}
return i;
}
template <typename Integer>
inline Integer upper_power_of_2(const Integer & A)
{
Integer power_of_2 = 1;
while(power_of_2 < A){
power_of_2 <<= 1;
}
return power_of_2;
}
//This function uses binary search to discover the
//highest set bit of the integer
inline std::size_t floor_log2 (std::size_t x)
{
const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT;
const bool Size_t_Bits_Power_2= !(Bits & (Bits-1));
BOOST_STATIC_ASSERT(((Size_t_Bits_Power_2)== true));
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)
log2 += shift, n = tmp;
}
return log2;
}
} // namespace ipcdetail
} // namespace interprocess
} // namespace boost
#endif

View File

@@ -0,0 +1,40 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP
#define BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost {
namespace interprocess {
template<class T>
const T &max_value(const T &a, const T &b)
{ return a > b ? a : b; }
template<class T>
const T &min_value(const T &a, const T &b)
{ return a < b ? a : b; }
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP

View File

@@ -0,0 +1,28 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2010-2011.
// 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/move for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//! \file
#ifndef BOOST_INTERPROCESS_DETAIL_MOVE_HPP
#define BOOST_INTERPROCESS_DETAIL_MOVE_HPP
#include <boost/move/move.hpp>
namespace boost {
namespace interprocess {
using ::boost::move;
using ::boost::forward;
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MOVE_HPP

View File

@@ -0,0 +1,152 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MPL_HPP
#define BOOST_INTERPROCESS_DETAIL_MPL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <cstddef>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template <class T, T val>
struct integral_constant
{
static const T value = val;
typedef integral_constant<T,val> type;
};
template< bool C_ >
struct bool_ : integral_constant<bool, C_>
{
static const bool value = C_;
};
typedef bool_<true> true_;
typedef bool_<false> false_;
typedef true_ true_type;
typedef false_ false_type;
typedef char yes_type;
struct no_type
{
char padding[8];
};
template <bool B, class T = void>
struct enable_if_c {
typedef T type;
};
template <class T>
struct enable_if_c<false, T> {};
template <class Cond, class T = void>
struct enable_if : public enable_if_c<Cond::value, T> {};
template <class Cond, class T = void>
struct disable_if : public enable_if_c<!Cond::value, T> {};
template <class T, class U>
class is_convertible
{
typedef char true_t;
class false_t { char dummy[2]; };
static true_t dispatch(U);
static false_t dispatch(...);
static T trigger();
public:
enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) };
};
template<
bool C
, typename T1
, typename T2
>
struct if_c
{
typedef T1 type;
};
template<
typename T1
, typename T2
>
struct if_c<false,T1,T2>
{
typedef T2 type;
};
template<
typename T1
, typename T2
, typename T3
>
struct if_
{
typedef typename if_c<0 != T1::value, T2, T3>::type type;
};
template <class Pair>
struct select1st
// : public std::unary_function<Pair, typename Pair::first_type>
{
template<class OtherPair>
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
{ return x; }
};
// identity is an extension: it is not part of the standard.
template <class T>
struct identity
// : public std::unary_function<T,T>
{
typedef T type;
const T& operator()(const T& x) const
{ return x; }
};
template<std::size_t S>
struct ls_zeros
{
static const std::size_t value = (S & std::size_t(1)) ? 0 : (1u + ls_zeros<(S >> 1u)>::value);
};
template<>
struct ls_zeros<0>
{
static const std::size_t value = 0;
};
template<>
struct ls_zeros<1>
{
static const std::size_t value = 0;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MPL_HPP

View File

@@ -0,0 +1,46 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MULTI_SEGMENT_SERVICES_HPP
#define BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
/*!\file
Describes a named shared memory allocation user class.
*/
namespace boost {
namespace interprocess {
class multi_segment_services
{
public:
virtual std::pair<void *, std::size_t> create_new_segment(std::size_t mem) = 0;
virtual bool update_segments () = 0;
virtual ~multi_segment_services() = 0;
};
inline multi_segment_services::~multi_segment_services()
{}
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifdef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP

View File

@@ -0,0 +1,349 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_NAMED_PROXY_HPP
#define BOOST_INTERPROCESS_NAMED_PROXY_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 <new>
#include <iterator>
#include <boost/interprocess/detail/in_place_interface.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
#include <boost/interprocess/detail/preprocessor.hpp>
#else
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/detail/variadic_templates_tools.hpp>
#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
//!\file
//!Describes a proxy class that implements named allocation syntax.
namespace boost {
namespace interprocess {
namespace ipcdetail {
#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
template<class T, bool is_iterator, class ...Args>
struct CtorNArg : public placement_destroy<T>
{
typedef ipcdetail::bool_<is_iterator> IsIterator;
typedef CtorNArg<T, is_iterator, Args...> self_t;
typedef typename build_number_seq<sizeof...(Args)>::type index_tuple_t;
self_t& operator++()
{
this->do_increment(IsIterator(), index_tuple_t());
return *this;
}
self_t operator++(int) { return ++*this; *this; }
CtorNArg(Args && ...args)
: args_(args...)
{}
virtual void construct_n(void *mem
, std::size_t num
, std::size_t &constructed)
{
T* memory = static_cast<T*>(mem);
for(constructed = 0; constructed < num; ++constructed){
this->construct(memory++, IsIterator(), index_tuple_t());
this->do_increment(IsIterator(), index_tuple_t());
}
}
private:
template<int ...IdxPack>
void construct(void *mem, ipcdetail::true_, const index_tuple<IdxPack...>&)
{ new((void*)mem)T(*boost::interprocess::forward<Args>(get<IdxPack>(args_))...); }
template<int ...IdxPack>
void construct(void *mem, ipcdetail::false_, const index_tuple<IdxPack...>&)
{ new((void*)mem)T(boost::interprocess::forward<Args>(get<IdxPack>(args_))...); }
template<int ...IdxPack>
void do_increment(ipcdetail::true_, const index_tuple<IdxPack...>&)
{
this->expansion_helper(++get<IdxPack>(args_)...);
}
template<class ...ExpansionArgs>
void expansion_helper(ExpansionArgs &&...)
{}
template<int ...IdxPack>
void do_increment(ipcdetail::false_, const index_tuple<IdxPack...>&)
{}
tuple<Args&...> args_;
};
//!Describes a proxy class that implements named
//!allocation syntax.
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?
>
class named_proxy
{
typedef typename SegmentManager::char_type char_type;
const char_type * mp_name;
SegmentManager * mp_mngr;
mutable std::size_t m_num;
const bool m_find;
const bool m_dothrow;
public:
named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow)
: mp_name(name), mp_mngr(mngr), m_num(1)
, m_find(find), m_dothrow(dothrow)
{}
template<class ...Args>
T *operator()(Args &&...args) const
{
CtorNArg<T, is_iterator, Args...> &&ctor_obj = CtorNArg<T, is_iterator, Args...>
(boost::interprocess::forward<Args>(args)...);
return mp_mngr->template
generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj);
}
//This operator allows --> named_new("Name")[3]; <-- syntax
const named_proxy &operator[](std::size_t num) const
{ m_num *= num; return *this; }
};
#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
//!Function object that makes placement new
//!without arguments
template<class T>
struct Ctor0Arg : public placement_destroy<T>
{
typedef Ctor0Arg self_t;
Ctor0Arg(){}
self_t& operator++() { return *this; }
self_t operator++(int) { return *this; }
void construct(void *mem)
{ new((void*)mem)T; }
virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed)
{
T* memory = static_cast<T*>(mem);
for(constructed = 0; constructed < num; ++constructed)
new((void*)memory++)T;
}
};
////////////////////////////////////////////////////////////////
// What the macro should generate (n == 2):
//
// template<class T, bool is_iterator, class P1, class P2>
// struct Ctor2Arg
// : public placement_destroy<T>
// {
// typedef ipcdetail::bool_<is_iterator> IsIterator;
// typedef Ctor2Arg self_t;
//
// void do_increment(ipcdetail::false_)
// { ++m_p1; ++m_p2; }
//
// void do_increment(ipcdetail::true_){}
//
// self_t& operator++()
// {
// this->do_increment(IsIterator());
// return *this;
// }
//
// self_t operator++(int) { return ++*this; *this; }
//
// Ctor2Arg(const P1 &p1, const P2 &p2)
// : p1((P1 &)p_1), p2((P2 &)p_2) {}
//
// void construct(void *mem)
// { new((void*)object)T(m_p1, m_p2); }
//
// virtual void construct_n(void *mem
// , std::size_t num
// , std::size_t &constructed)
// {
// T* memory = static_cast<T*>(mem);
// for(constructed = 0; constructed < num; ++constructed){
// this->construct(memory++, IsIterator());
// this->do_increment(IsIterator());
// }
// }
//
// private:
// void construct(void *mem, ipcdetail::true_)
// { new((void*)mem)T(*m_p1, *m_p2); }
//
// void construct(void *mem, ipcdetail::false_)
// { new((void*)mem)T(m_p1, m_p2); }
//
// P1 &m_p1; P2 &m_p2;
// };
////////////////////////////////////////////////////////////////
//Note:
//We define template parameters as const references to
//be able to bind temporaries. After that we will un-const them.
//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 lvalues with non-const references, we have to be ugly
#define BOOST_PP_LOCAL_MACRO(n) \
template<class T, bool is_iterator, BOOST_PP_ENUM_PARAMS(n, class P) > \
struct BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \
: public placement_destroy<T> \
{ \
typedef ipcdetail::bool_<is_iterator> IsIterator; \
typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) self_t; \
\
void do_increment(ipcdetail::true_) \
{ BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_INC, _); } \
\
void do_increment(ipcdetail::false_){} \
\
self_t& operator++() \
{ \
this->do_increment(IsIterator()); \
return *this; \
} \
\
self_t operator++(int) { return ++*this; *this; } \
\
BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \
( BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _) ) \
: BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_INIT, _) {} \
\
virtual void construct_n(void *mem \
, std::size_t num \
, std::size_t &constructed) \
{ \
T* memory = static_cast<T*>(mem); \
for(constructed = 0; constructed < num; ++constructed){ \
this->construct(memory++, IsIterator()); \
this->do_increment(IsIterator()); \
} \
} \
\
private: \
void construct(void *mem, ipcdetail::true_) \
{ \
new((void*)mem) T \
(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD, _)); \
} \
\
void construct(void *mem, ipcdetail::false_) \
{ \
new((void*)mem) T \
(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \
} \
\
BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_AUX_PARAM_DEFINE, _) \
}; \
//!
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
#include BOOST_PP_LOCAL_ITERATE()
//!Describes a proxy class that implements named
//!allocation syntax.
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?
>
class named_proxy
{
typedef typename SegmentManager::char_type char_type;
const char_type * mp_name;
SegmentManager * mp_mngr;
mutable std::size_t m_num;
const bool m_find;
const bool m_dothrow;
public:
named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow)
: mp_name(name), mp_mngr(mngr), m_num(1)
, m_find(find), m_dothrow(dothrow)
{}
//!makes a named allocation and calls the
//!default constructor
T *operator()() const
{
Ctor0Arg<T> ctor_obj;
return mp_mngr->template
generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj);
}
//!
#define BOOST_PP_LOCAL_MACRO(n) \
template<BOOST_PP_ENUM_PARAMS(n, class P)> \
T *operator()(BOOST_PP_ENUM (n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) const\
{ \
typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \
<T, is_iterator, BOOST_PP_ENUM_PARAMS(n, P)> \
ctor_obj_t; \
ctor_obj_t ctor_obj \
(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
return mp_mngr->template generic_construct<T> \
(mp_name, m_num, m_find, m_dothrow, ctor_obj); \
} \
//!
#define BOOST_PP_LOCAL_LIMITS ( 1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS )
#include BOOST_PP_LOCAL_ITERATE()
////////////////////////////////////////////////////////////////////////
// What the macro should generate (n == 2)
////////////////////////////////////////////////////////////////////////
//
// template <class P1, class P2>
// T *operator()(P1 &p1, P2 &p2) const
// {
// typedef Ctor2Arg
// <T, is_iterator, P1, P2>
// ctor_obj_t;
// ctor_obj_t ctor_obj(p1, p2);
//
// return mp_mngr->template generic_construct<T>
// (mp_name, m_num, m_find, m_dothrow, ctor_obj);
// }
//
//////////////////////////////////////////////////////////////////////////
//This operator allows --> named_new("Name")[3]; <-- syntax
const named_proxy &operator[](std::size_t num) const
{ m_num *= num; return *this; }
};
#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
}}} //namespace boost { namespace interprocess { namespace ipcdetail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP

View File

@@ -0,0 +1,690 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP
#define BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/permissions.hpp>
#include <string>
#include <limits>
#if (defined BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <fcntl.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <errno.h>
# include <cstdio>
# include <dirent.h>
# if 0
# include <sys/file.h>
# endif
# else
# error Unknown platform
# endif
#endif
#include <cstring>
#include <cstdlib>
namespace boost {
namespace interprocess {
#if (defined BOOST_INTERPROCESS_WINDOWS)
typedef void * file_handle_t;
typedef long long offset_t;
typedef struct mapping_handle_impl_t{
void * handle;
bool is_shm;
} mapping_handle_t;
typedef enum { read_only = winapi::generic_read
, read_write = winapi::generic_read | winapi::generic_write
, copy_on_write
, read_private
, invalid_mode = 0xffff
} mode_t;
typedef enum { file_begin = winapi::file_begin
, file_end = winapi::file_end
, file_current = winapi::file_current
} file_pos_t;
namespace ipcdetail{
inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd)
{
mapping_handle_t ret;
ret.handle = hnd;
ret.is_shm = false;
return ret;
}
inline mapping_handle_t mapping_handle_from_shm_handle(file_handle_t hnd)
{
mapping_handle_t ret;
ret.handle = hnd;
ret.is_shm = true;
return ret;
}
inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd)
{ return hnd.handle; }
inline bool create_directory(const char *path)
{ return winapi::create_directory(path); }
inline const char *get_temporary_path()
{ return std::getenv("TMP"); }
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());
}
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());
}
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);
}
inline bool delete_file(const char *name)
{ return winapi::unlink_file(name); }
inline bool truncate_file (file_handle_t hnd, std::size_t size)
{
offset_t filesize;
if(!winapi::get_file_size(hnd, filesize))
return false;
if(size > (std::numeric_limits<offset_t>::max)()){
winapi::set_last_error(winapi::error_file_too_large);
return false;
}
if(size > (unsigned long long)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
;remaining > 0
;remaining -= write_size){
const std::size_t DataSize = 512;
static char data [DataSize];
write_size = DataSize < remaining ? DataSize : remaining;
unsigned long written;
winapi::write_file(hnd, data, (unsigned long)write_size, &written, 0);
if(written != write_size){
return false;
}
}
}
else{
if(!winapi::set_file_pointer_ex(hnd, size, 0, winapi::file_begin)){
return false;
}
if(!winapi::set_end_of_file(hnd)){
return false;
}
}
return true;
}
inline bool get_file_size(file_handle_t hnd, offset_t &size)
{ return winapi::get_file_size(hnd, size); }
inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos)
{ return winapi::set_file_pointer_ex(hnd, off, 0, (unsigned long) pos); }
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);
}
inline file_handle_t invalid_file()
{ return winapi::invalid_handle_value; }
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;
// winapi::interprocess_overlapped overlapped;
// std::memset(&overlapped, 0, sizeof(overlapped));
return winapi::lock_file_ex
(hnd, winapi::lockfile_exclusive_lock, 0, len, len, &overlapped);
}
inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired)
{
const unsigned long len = 0xffffffff;
winapi::interprocess_overlapped overlapped;
std::memset(&overlapped, 0, sizeof(overlapped));
if(!winapi::lock_file_ex
(hnd, winapi::lockfile_exclusive_lock | winapi::lockfile_fail_immediately,
0, len, len, &overlapped)){
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;
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;
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;
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 ?
acquired = false, true : false;
}
return (acquired = true);
}
inline bool release_file_lock_sharable(file_handle_t hnd)
{ return release_file_lock(hnd); }
inline bool delete_subdirectories_recursive
(const std::string &refcstrRootDirectory, const char *dont_delete_this, unsigned int count)
{
bool bSubdirectory = false; // Flag, indicating whether
// subdirectories have been found
void * hFile; // Handle to directory
std::string strFilePath; // Filepath
std::string strPattern; // Pattern
winapi::win32_find_data_t FileInformation; // File information
//Find all files and directories
strPattern = refcstrRootDirectory + "\\*.*";
hFile = winapi::find_first_file(strPattern.c_str(), &FileInformation);
if(hFile != winapi::invalid_handle_value){
do{
//If it's not "." or ".." or the pointed root_level dont_delete_this erase it
if(FileInformation.cFileName[0] != '.' &&
!(dont_delete_this && count == 0 && std::strcmp(dont_delete_this, FileInformation.cFileName) == 0)){
strFilePath.erase();
strFilePath = refcstrRootDirectory + "\\" + FileInformation.cFileName;
//If it's a directory, go recursive
if(FileInformation.dwFileAttributes & winapi::file_attribute_directory){
// Delete subdirectory
if(!delete_subdirectories_recursive(strFilePath, dont_delete_this, count+1))
return false;
}
//If it's a file, just delete it
else{
// Set file attributes
//if(::SetFileAttributes(strFilePath.c_str(), winapi::file_attribute_normal) == 0)
//return winapi::get_last_error();
// Delete file
winapi::delete_file(strFilePath.c_str());
}
}
//Go to the next file
} while(winapi::find_next_file(hFile, &FileInformation) == 1);
// Close handle
winapi::find_close(hFile);
//See if the loop has ended with an error or just because we've traversed all the files
if(winapi::get_last_error() != winapi::error_no_more_files){
return false;
}
else
{
//Erase empty subdirectories or original refcstrRootDirectory
if(!bSubdirectory && count)
{
// Set directory attributes
//if(::SetFileAttributes(refcstrRootDirectory.c_str(), FILE_ATTRIBUTE_NORMAL) == 0)
//return ::GetLastError();
// Delete directory
if(winapi::remove_directory(refcstrRootDirectory.c_str()) == 0)
return false;
}
}
}
return true;
}
//This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this"
inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this)
{
return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this, 0u);
}
template<class Function>
inline bool for_each_file_in_dir(const char *dir, Function f)
{
void * hFile; // Handle to directory
winapi::win32_find_data_t FileInformation; // File information
//Get base directory
std::string str(dir);
const std::size_t base_root_dir_len = str.size();
//Find all files and directories
str += "\\*.*";
hFile = winapi::find_first_file(str.c_str(), &FileInformation);
if(hFile != winapi::invalid_handle_value){
do{ //Now loop every file
str.erase(base_root_dir_len);
//If it's not "." or ".." skip it
if(FileInformation.cFileName[0] != '.'){
str += "\\"; str += FileInformation.cFileName;
//If it's a file, apply erase logic
if(!(FileInformation.dwFileAttributes & winapi::file_attribute_directory)){
f(str.c_str(), FileInformation.cFileName);
}
}
//Go to the next file
} while(winapi::find_next_file(hFile, &FileInformation) == 1);
// Close handle and see if the loop has ended with an error
winapi::find_close(hFile);
if(winapi::get_last_error() != winapi::error_no_more_files){
return false;
}
}
return true;
}
#else //#if (defined BOOST_INTERPROCESS_WINDOWS)
typedef int file_handle_t;
typedef off_t offset_t;
typedef struct mapping_handle_impl_t
{
file_handle_t handle;
bool is_xsi;
} mapping_handle_t;
typedef enum { read_only = O_RDONLY
, read_write = O_RDWR
, copy_on_write
, read_private
, invalid_mode = 0xffff
} mode_t;
typedef enum { file_begin = SEEK_SET
, file_end = SEEK_END
, file_current = SEEK_CUR
} file_pos_t;
namespace ipcdetail{
inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd)
{
mapping_handle_t ret;
ret.handle = hnd;
ret.is_xsi = false;
return ret;
}
inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd)
{ return hnd.handle; }
inline bool create_directory(const char *path)
{ return ::mkdir(path, 0777) == 0 && ::chmod(path, 0777) == 0; }
inline const char *get_temporary_path()
{
const char *names[] = {"/tmp", "TMPDIR", "TMP", "TEMP" };
const int names_size = sizeof(names)/sizeof(names[0]);
struct stat data;
for(int i = 0; i != names_size; ++i){
if(::stat(names[i], &data) == 0){
return names[i];
}
}
return "/tmp";
}
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){
::fchmod(ret, perm.get_permissions());
}
return ret;
}
inline file_handle_t create_or_open_file
(const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false)
{
(void)temporary;
int ret = -1;
//We need a loop to change permissions correctly using fchmod, since
//with "O_CREAT only" ::open we don't know if we've created or opened the file.
while(1){
ret = ::open(name, ((int)mode) | O_EXCL | O_CREAT, perm.get_permissions());
if(ret >= 0){
::fchmod(ret, perm.get_permissions());
break;
}
else if(errno == EEXIST){
if((ret = ::open(name, (int)mode)) >= 0 || errno != ENOENT){
break;
}
}
}
return ret;
}
inline file_handle_t open_existing_file
(const char *name, mode_t mode, bool temporary = false)
{
(void)temporary;
return ::open(name, (int)mode);
}
inline bool delete_file(const char *name)
{ return ::unlink(name) == 0; }
inline bool truncate_file (file_handle_t hnd, std::size_t size)
{
if(off_t(size) < 0){
errno = EINVAL;
return false;
}
return 0 == ::ftruncate(hnd, size);
}
inline bool get_file_size(file_handle_t hnd, offset_t &size)
{
struct stat data;
bool ret = 0 == ::fstat(hnd, &data);
if(ret){
size = data.st_size;
}
return ret;
}
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);
}
inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata)
{ return (ssize_t(numdata)) == ::write(hnd, data, numdata); }
inline file_handle_t invalid_file()
{ return -1; }
inline bool close_file(file_handle_t hnd)
{ return ::close(hnd) == 0; }
inline bool acquire_file_lock(file_handle_t hnd)
{
struct ::flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
return -1 != ::fcntl(hnd, F_SETLKW, &lock);
}
inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired)
{
struct ::flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
int ret = ::fcntl(hnd, F_SETLK, &lock);
if(ret == -1){
return (errno == EAGAIN || errno == EACCES) ?
acquired = false, true : false;
}
return (acquired = true);
}
inline bool release_file_lock(file_handle_t hnd)
{
struct ::flock lock;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
return -1 != ::fcntl(hnd, F_SETLK, &lock);
}
inline bool acquire_file_lock_sharable(file_handle_t hnd)
{
struct ::flock lock;
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
return -1 != ::fcntl(hnd, F_SETLKW, &lock);
}
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;
lock.l_start = 0;
lock.l_len = 0;
int ret = ::fcntl(hnd, F_SETLK, &lock);
if(ret == -1){
return (errno == EAGAIN || errno == EACCES) ?
acquired = false, true : false;
}
return (acquired = true);
}
inline bool release_file_lock_sharable(file_handle_t hnd)
{ return release_file_lock(hnd); }
#if 0
inline bool acquire_file_lock(file_handle_t hnd)
{ return 0 == ::flock(hnd, LOCK_EX); }
inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired)
{
int ret = ::flock(hnd, LOCK_EX | LOCK_NB);
acquired = ret == 0;
return (acquired || errno == EWOULDBLOCK);
}
inline bool release_file_lock(file_handle_t hnd)
{ return 0 == ::flock(hnd, LOCK_UN); }
inline bool acquire_file_lock_sharable(file_handle_t hnd)
{ return 0 == ::flock(hnd, LOCK_SH); }
inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired)
{
int ret = ::flock(hnd, LOCK_SH | LOCK_NB);
acquired = ret == 0;
return (acquired || errno == EWOULDBLOCK);
}
inline bool release_file_lock_sharable(file_handle_t hnd)
{ return 0 == ::flock(hnd, LOCK_UN); }
#endif
inline bool delete_subdirectories_recursive
(const std::string &refcstrRootDirectory, const char *dont_delete_this)
{
DIR *d = opendir(refcstrRootDirectory.c_str());
if(!d) {
return false;
}
struct dir_close
{
DIR *d_;
dir_close(DIR *d) : d_(d) {}
~dir_close() { ::closedir(d_); }
} dc(d); (void)dc;
struct ::dirent *de;
struct ::stat st;
std::string fn;
while((de=::readdir(d))) {
if( de->d_name[0] == '.' && ( de->d_name[1] == '\0'
|| (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){
continue;
}
if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){
continue;
}
fn = refcstrRootDirectory;
fn += '/';
fn += de->d_name;
if(std::remove(fn.c_str())) {
if(::stat(fn.c_str(), & st)) {
return false;
}
if(S_ISDIR(st.st_mode)) {
if(!delete_subdirectories_recursive(fn, 0) ){
return false;
}
} else {
return false;
}
}
}
return std::remove(refcstrRootDirectory.c_str()) ? false : true;
}
template<class Function>
inline bool for_each_file_in_dir(const char *dir, Function f)
{
std::string refcstrRootDirectory(dir);
DIR *d = opendir(refcstrRootDirectory.c_str());
if(!d) {
return false;
}
struct dir_close
{
DIR *d_;
dir_close(DIR *d) : d_(d) {}
~dir_close() { ::closedir(d_); }
} dc(d); (void)dc;
struct ::dirent *de;
struct ::stat st;
std::string fn;
while((de=::readdir(d))) {
if( de->d_name[0] == '.' && ( de->d_name[1] == '\0'
|| (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){
continue;
}
fn = refcstrRootDirectory;
fn += '/';
fn += de->d_name;
if(::stat(fn.c_str(), & st)) {
return false;
}
//If it's a file, apply erase logic
if(!S_ISDIR(st.st_mode)) {
f(fn.c_str(), de->d_name);
}
}
return true;
}
//This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this"
inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this)
{
return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this );
}
#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
inline bool open_or_create_directory(const char *dir_name)
{
//If fails, check that it's because it already exists
if(!create_directory(dir_name)){
error_info info(system_error_code());
if(info.get_error_code() != already_exists_error){
return false;
}
}
return true;
}
} //namespace ipcdetail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP

View File

@@ -0,0 +1,201 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP
#define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#if (defined BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <pthread.h>
# include <unistd.h>
# include <sched.h>
# else
# error Unknown platform
# endif
#endif
namespace boost {
namespace interprocess {
namespace ipcdetail{
#if (defined BOOST_INTERPROCESS_WINDOWS)
typedef unsigned long OS_process_id_t;
typedef unsigned long OS_thread_id_t;
typedef OS_thread_id_t OS_systemwide_thread_id_t;
//process
inline OS_process_id_t get_current_process_id()
{ return winapi::get_current_process_id(); }
inline OS_process_id_t get_invalid_process_id()
{ return OS_process_id_t(0); }
//thread
inline OS_thread_id_t get_current_thread_id()
{ return winapi::get_current_thread_id(); }
inline OS_thread_id_t get_invalid_thread_id()
{ return OS_thread_id_t(0xffffffff); }
inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2)
{ return id1 == id2; }
inline void thread_yield()
{ winapi::sched_yield(); }
//systemwide thread
inline OS_systemwide_thread_id_t get_current_systemwide_thread_id()
{
return get_current_thread_id();
}
inline void systemwide_thread_id_copy
(const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to)
{
to = from;
}
inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2)
{
return equal_thread_id(id1, id2);
}
inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id()
{
return get_invalid_thread_id();
}
inline long double get_current_process_creation_time()
{
winapi::interprocess_filetime CreationTime, ExitTime, KernelTime, UserTime;
get_process_times
( winapi::get_current_process(), &CreationTime, &ExitTime, &KernelTime, &UserTime);
typedef long double ldouble_t;
const ldouble_t resolution = (100.0l/1000000000.0l);
return CreationTime.dwHighDateTime*(ldouble_t(1u<<31u)*2.0l*resolution) +
CreationTime.dwLowDateTime*resolution;
}
#else //#if (defined BOOST_INTERPROCESS_WINDOWS)
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()
{}
OS_systemwide_thread_id_t(pid_t p, pthread_t t)
: pid(p), tid(t)
{}
OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x)
: pid(x.pid), tid(x.tid)
{}
OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x)
: pid(x.pid), tid(x.tid)
{}
OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x)
{ pid = x.pid; tid = x.tid; return *this; }
OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x)
{ pid = x.pid; tid = x.tid; return *this; }
void operator=(const OS_systemwide_thread_id_t &x) volatile
{ pid = x.pid; tid = x.tid; }
pid_t pid;
pthread_t tid;
};
inline void systemwide_thread_id_copy
(const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to)
{
to.pid = from.pid;
to.tid = from.tid;
}
//process
inline OS_process_id_t get_current_process_id()
{ return ::getpid(); }
inline OS_process_id_t get_invalid_process_id()
{ return pid_t(0); }
//thread
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;
}
inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2)
{ return 0 != pthread_equal(id1, id2); }
inline void thread_yield()
{ ::sched_yield(); }
//systemwide thread
inline OS_systemwide_thread_id_t get_current_systemwide_thread_id()
{
return OS_systemwide_thread_id_t(::getpid(), ::pthread_self());
}
inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2)
{
return (0 != pthread_equal(id1.tid, id2.tid)) && (id1.pid == id2.pid);
}
inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id()
{
return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id());
}
inline long double get_current_process_creation_time()
{ return 0.0L; }
#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
typedef char pid_str_t[sizeof(OS_process_id_t)*3+1];
inline void get_pid_str(pid_str_t &pid_str, OS_process_id_t pid)
{
bufferstream bstream(pid_str, sizeof(pid_str));
bstream << pid << std::ends;
}
inline void get_pid_str(pid_str_t &pid_str)
{ get_pid_str(pid_str, get_current_process_id()); }
} //namespace ipcdetail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP

View File

@@ -0,0 +1,74 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009.
// (C) Copyright Gennaro Prota 2003 - 2004.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP
#define BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_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/type_traits.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
struct two {char _[2];};
namespace pointer_type_imp {
template <class U> static two test(...);
template <class U> static char test(typename U::pointer* = 0);
} //namespace pointer_type_imp {
template <class T>
struct has_pointer_type
{
static const bool value = sizeof(pointer_type_imp::test<T>(0)) == 1;
};
namespace pointer_type_imp {
template <class T, class D, bool = has_pointer_type<D>::value>
struct pointer_type
{
typedef typename D::pointer type;
};
template <class T, class D>
struct pointer_type<T, D, false>
{
typedef T* type;
};
} //namespace pointer_type_imp {
template <class T, class D>
struct pointer_type
{
typedef typename pointer_type_imp::pointer_type<T,
typename ipcdetail::remove_reference<D>::type>::type type;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP

View File

@@ -0,0 +1,42 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_POSIX_TIMES_WRK_HPP
#define BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP
//workaround to avoid winsock redefines when using date-time
#ifdef _WIN32
#ifndef 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
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
namespace boost {
namespace interprocess {
typedef boost::date_time::microsec_clock<boost::posix_time::ptime> microsec_clock;
}
}
#ifdef _WIN32
#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#undef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef _WIN32
#endif //#ifndef BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP

View File

@@ -0,0 +1,137 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_PREPROCESSOR_HPP
#define BOOST_INTERPROCESS_DETAIL_PREPROCESSOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include "config_begin.hpp"
#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
#error "This file is not needed when perfect forwarding is available"
#endif
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#define BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS 10
//Note:
//We define template parameters as const references to
//be able to bind temporaries. After that we will un-const them.
//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
#define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \
BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \
//!
#else
#define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \
const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \
//!
#endif
#ifndef BOOST_NO_RVALUE_REFERENCES
#define BOOST_INTERPROCESS_PARAM(U, u) \
U && u \
//!
#else
#define BOOST_INTERPROCESS_PARAM(U, u) \
const U & u \
//!
#endif
#ifndef BOOST_NO_RVALUE_REFERENCES
#ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES
#define BOOST_INTERPROCESS_AUX_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_AUX_PARAM_INIT(z, n, data) \
BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \
//!
#endif
#else
#define BOOST_INTERPROCESS_AUX_PARAM_INIT(z, n, data) \
BOOST_PP_CAT(m_p, n) (const_cast<BOOST_PP_CAT(P, n) &>(BOOST_PP_CAT(p, n))) \
//!
#endif
#define BOOST_INTERPROCESS_AUX_PARAM_INC(z, n, data) \
BOOST_PP_CAT(++m_p, n) \
//!
#ifndef BOOST_NO_RVALUE_REFERENCES
#if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG)
#define BOOST_INTERPROCESS_AUX_PARAM_DEFINE(z, n, data) \
BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \
//!
#else
#define BOOST_INTERPROCESS_AUX_PARAM_DEFINE(z, n, data) \
BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \
//!
#endif //defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG)
#else
#define BOOST_INTERPROCESS_AUX_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::interprocess::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)
#include <boost/container/detail/stored_ref.hpp>
#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \
::boost::container::containers_detail::stored_ref< BOOST_PP_CAT(P, n) >::forward( BOOST_PP_CAT(m_p, n) ) \
//!
#else
#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \
::boost::interprocess::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) \
//!
#include <boost/interprocess/detail/config_end.hpp>
#else
#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
#error "This file is not needed when perfect forwarding is available"
#endif
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_PREPROCESSOR_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006. 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_PTIME_WRK_HPP
#define BOOST_INTERPROCESS_PTIME_WRK_HPP
//workaround to avoid winsock redefines when using date-time
#ifdef _WIN32
#ifndef 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
#include <boost/date_time/posix_time/ptime.hpp>
#ifdef _WIN32
#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#undef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef _WIN32
#endif //#ifndef BOOST_INTERPROCESS_PTIME_WRK_HPP

View File

@@ -0,0 +1,439 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2010-2010. 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_ROBUST_EMULATION_HPP
#define BOOST_INTERPROCESS_ROBUST_EMULATION_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/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/tmp_dir_helpers.hpp>
#include <boost/interprocess/detail/intermodule_singleton.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <string>
namespace boost{
namespace interprocess{
namespace ipcdetail{
namespace robust_emulation_helpers {
template<class T>
class mutex_traits
{
public:
static void take_ownership(T &t)
{ t.take_ownership(); }
};
inline void remove_if_can_lock_file(const char *file_path)
{
file_handle_t fhnd = open_existing_file(file_path, read_write);
if(fhnd != invalid_file()){
bool acquired;
if(try_acquire_file_lock(fhnd, acquired) && acquired){
delete_file(file_path);
}
close_file(fhnd);
}
}
inline const char *robust_lock_subdir_path()
{ return "robust"; }
inline const char *robust_lock_prefix()
{ return "lck"; }
inline void robust_lock_path(std::string &s)
{
tmp_folder(s);
s += "/";
s += robust_lock_subdir_path();
}
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
(robust_lock_subdir_path(), robust_lock_prefix(), pid, s);
}
//This class will be a intermodule_singleton. The constructor will create
//a lock file, the destructor will erase it.
//
//We should take in care that another process might be erasing unlocked
//files while creating this one, so there are some race conditions we must
//take in care to guarantee some robustness.
class robust_mutex_lock_file
{
file_handle_t fd;
std::string fname;
public:
robust_mutex_lock_file()
{
permissions p;
p.set_unrestricted();
//Remove old lock files of other processes
remove_old_robust_lock_files();
//Create path and obtain lock file path for this process
create_and_get_robust_lock_file_path(fname, get_current_process_id());
//Now try to open or create the lock file
fd = create_or_open_file(fname.c_str(), read_write, p);
//If we can't open or create it, then something unrecoverable has happened
if(fd == invalid_file()){
throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: could not open or create file");
}
//Now we must take in care a race condition with another process
//calling "remove_old_robust_lock_files()". No other threads from this
//process will be creating the lock file because intermodule_singleton
//guarantees this. So let's loop acquiring the lock and checking if we
//can't exclusively create the file (if the file is erased by another process
//then this exclusive open would fail). If the file can't be exclusively created
//then we have correctly open/create and lock the file. If the file can
//be exclusively created, then close previous locked file and try again.
while(1){
bool acquired;
if(!try_acquire_file_lock(fd, acquired) || !acquired ){
throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: try_acquire_file_lock");
}
//Creating exclusively must fail with already_exists_error
//to make sure we've locked the file and no one has
//deleted it between creation and locking
file_handle_t fd2 = create_new_file(fname.c_str(), read_write, p);
if(fd2 != invalid_file()){
close_file(fd);
fd = fd2;
continue;
}
//If exclusive creation fails with expected error go ahead
else if(error_info(system_error_code()).get_error_code() == already_exists_error){ //must already exist
//Leak descriptor to mantain the file locked until the process dies
break;
}
//If exclusive creation fails with unexpected error throw an unrecoverable error
else{
close_file(fd);
throw interprocess_exception(other_error, "Robust emulation robust_mutex_lock_file constructor failed: create_file filed with unexpected error");
}
}
}
~robust_mutex_lock_file()
{
//The destructor is guaranteed by intermodule_singleton to be
//executed serialized between all threads from current process,
//so we just need to close and unlink the file.
close_file(fd);
//If some other process deletes the file before us after
//closing it there should not be any problem.
delete_file(fname.c_str());
}
private:
//This functor is execute for all files in the lock file directory
class other_process_lock_remover
{
public:
void operator()(const char *filepath, const char *filename)
{
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
(filename, robust_lock_prefix(), get_current_process_id(), pid_str)){
remove_if_can_lock_file(filepath);
}
}
};
bool remove_old_robust_lock_files()
{
std::string refcstrRootDirectory;
robust_lock_path(refcstrRootDirectory);
return for_each_file_in_dir(refcstrRootDirectory.c_str(), other_process_lock_remover());
}
};
} //namespace robust_emulation_helpers {
//This is the mutex class. Mutex should follow mutex concept
//with an additonal "take_ownership()" function to take ownership of the
//mutex when robust_emulation_mutex determines the previous owner was dead.
template<class Mutex>
class robust_emulation_mutex
{
public:
static const boost::uint32_t correct_state = 0;
static const boost::uint32_t fixing_state = 1;
static const boost::uint32_t broken_state = 2;
typedef robust_emulation_helpers::mutex_traits<Mutex> mutex_traits_t;
robust_emulation_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
void consistent();
bool previous_owner_dead();
private:
static const unsigned int spin_threshold = 100u;
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);
//The real mutex
Mutex mtx;
//The pid of the owner
volatile boost::uint32_t owner;
//The state of the mutex (correct, fixing, broken)
volatile boost::uint32_t state;
};
template<class Mutex>
inline robust_emulation_mutex<Mutex>::robust_emulation_mutex()
: mtx(), owner(get_invalid_process_id()), state(correct_state)
{}
template<class Mutex>
inline void robust_emulation_mutex<Mutex>::lock()
{
//If the mutex is broken (recovery didn't call consistent()),
//then throw an exception
if(atomic_read32(&this->state) == broken_state){
throw interprocess_exception(lock_error, "Broken id");
}
//This function provokes intermodule_singleton instantiation
if(!this->lock_own_unique_file()){
throw interprocess_exception(lock_error, "Broken id");
}
//Now the logic. Try to lock, if successful mark the owner
//if it fails, start recovery logic
unsigned int spin_count = 0;
while(1){
if (mtx.try_lock()){
atomic_write32(&this->owner, get_current_process_id());
break;
}
else{
//Do the dead owner checking each spin_threshold lock tries
ipcdetail::thread_yield();
++spin_count;
if(spin_count > spin_threshold){
//Check if owner dead and take ownership if possible
if(!this->robust_check()){
spin_count = 0;
}
else{
break;
}
}
}
}
}
template<class Mutex>
inline bool robust_emulation_mutex<Mutex>::try_lock()
{
//Same as lock() but without spinning
if(atomic_read32(&this->state) == broken_state){
throw interprocess_exception(lock_error, "Broken id");
}
if(!this->lock_own_unique_file()){
throw interprocess_exception(lock_error, "Broken id");
}
if (mtx.try_lock()){
atomic_write32(&this->owner, get_current_process_id());
return true;
}
else{
if(!this->robust_check()){
return false;
}
else{
return true;
}
}
}
template<class Mutex>
inline bool robust_emulation_mutex<Mutex>::timed_lock
(const boost::posix_time::ptime &abs_time)
{
//Same as lock() but with an additional timeout
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
//Obtain current count and target time
boost::posix_time::ptime now = microsec_clock::universal_time();
if(now >= abs_time)
return this->try_lock();
do{
if(this->try_lock()){
break;
}
now = microsec_clock::universal_time();
if(now >= abs_time){
return this->try_lock();
}
// relinquish current time slice
ipcdetail::thread_yield();
}while (true);
return true;
}
template<class Mutex>
inline void robust_emulation_mutex<Mutex>::owner_to_filename(boost::uint32_t owner, std::string &s)
{
robust_emulation_helpers::create_and_get_robust_lock_file_path(s, owner);
}
template<class Mutex>
inline bool robust_emulation_mutex<Mutex>::robust_check()
{
//If the old owner was dead, and we've acquired ownership, mark
//the mutex as 'fixing'. This means that a "consistent()" is needed
//to avoid marking the mutex as "broken" when the mutex is unlocked.
if(!this->check_if_owner_dead_and_take_ownership_atomically()){
return false;
}
atomic_write32(&this->state, fixing_state);
return true;
}
template<class Mutex>
inline bool robust_emulation_mutex<Mutex>::check_if_owner_dead_and_take_ownership_atomically()
{
boost::uint32_t cur_owner = get_current_process_id();
boost::uint32_t old_owner = atomic_read32(&this->owner), old_owner2;
//The cas loop guarantees that only one thread from this or another process
//will succeed taking ownership
do{
//Check if owner is dead
if(!this->is_owner_dead(old_owner)){
return false;
}
//If it's dead, try to mark this process as the owner in the owner field
old_owner2 = old_owner;
old_owner = atomic_cas32(&this->owner, cur_owner, old_owner);
}while(old_owner2 != old_owner);
//If success, we fix mutex internals to assure our ownership
mutex_traits_t::take_ownership(mtx);
return true;
}
template<class Mutex>
inline bool robust_emulation_mutex<Mutex>::is_owner_dead(boost::uint32_t owner)
{
//If owner is an invalid id, then it's clear it's dead
if(owner == (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);
//Now the logic is to open and lock it
file_handle_t fhnd = open_existing_file(file.c_str(), read_write);
if(fhnd != invalid_file()){
//If we can open the file, lock it.
bool acquired;
if(try_acquire_file_lock(fhnd, acquired) && acquired){
//If locked, just delete the file
delete_file(file.c_str());
close_file(fhnd);
return true;
}
//If not locked, the owner is suppossed to be still alive
close_file(fhnd);
}
else{
//If the lock file does not exist then the owner is dead (a previous cleanup)
//function has deleted the file. If there is another reason, then this is
//an unrecoverable error
if(error_info(system_error_code()).get_error_code() == not_found_error){
return true;
}
}
return false;
}
template<class Mutex>
inline void robust_emulation_mutex<Mutex>::consistent()
{
//This function supposes the previous state was "fixing"
//and the current process holds the mutex
if(atomic_read32(&this->state) != fixing_state &&
atomic_read32(&this->owner) != (boost::uint32_t)get_current_process_id()){
throw interprocess_exception(lock_error, "Broken id");
}
//If that's the case, just update mutex state
atomic_write32(&this->state, correct_state);
}
template<class Mutex>
inline bool robust_emulation_mutex<Mutex>::previous_owner_dead()
{
//Notifies if a owner recovery has been performed in the last lock()
return atomic_read32(&this->state) == fixing_state;
};
template<class Mutex>
inline void robust_emulation_mutex<Mutex>::unlock()
{
//If in "fixing" state, unlock and mark the mutex as unrecoverable
//so next locks will fail and all threads will be notified that the
//data protected by the mutex was not recoverable.
if(atomic_read32(&this->state) == fixing_state){
atomic_write32(&this->state, broken_state);
}
//Write an invalid owner to minimize pid reuse possibility
atomic_write32(&this->owner, get_invalid_process_id());
mtx.unlock();
}
template<class Mutex>
inline bool robust_emulation_mutex<Mutex>::lock_own_unique_file()
{
//This function forces instantiation of the singleton
robust_emulation_helpers::robust_mutex_lock_file* dummy =
&ipcdetail::intermodule_singleton
<robust_emulation_helpers::robust_mutex_lock_file>::get();
return dummy != 0;
}
} //namespace ipcdetail{
} //namespace interprocess{
} //namespace boost{
#include <boost/interprocess/detail/config_end.hpp>
#endif

View File

@@ -0,0 +1,511 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_SEGMENT_MANAGER_BASE_HPP
#define BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/in_place_interface.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <cstddef> //std::size_t
#include <string> //char_traits
#include <new> //std::nothrow
#include <utility> //std::pair
#include <boost/assert.hpp> //BOOST_ASSERT
#include <functional> //unary_function
#ifndef BOOST_NO_EXCEPTIONS
#include <exception>
#endif
//!\file
//!Describes the object placed in a memory segment that provides
//!named object allocation capabilities.
namespace boost{
namespace interprocess{
template<class MemoryManager>
class segment_manager_base;
//!An integer that describes the type of the
//!instance constructed in memory
enum instance_type { anonymous_type, named_type, unique_type, max_allocation_type };
namespace ipcdetail{
template<class MemoryAlgorithm>
class mem_algo_deallocator
{
void * m_ptr;
MemoryAlgorithm & m_algo;
public:
mem_algo_deallocator(void *ptr, MemoryAlgorithm &algo)
: m_ptr(ptr), m_algo(algo)
{}
void release()
{ m_ptr = 0; }
~mem_algo_deallocator()
{ if(m_ptr) m_algo.deallocate(m_ptr); }
};
/// @cond
template<class size_type>
struct block_header
{
size_type m_value_bytes;
unsigned short m_num_char;
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
,std::size_t num_char
)
: m_value_bytes(value_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) )
{};
template<class T>
block_header &operator= (const T& )
{ return *this; }
size_type total_size() const
{
if(alloc_type() != anonymous_type){
return name_offset() + (m_num_char+1)*sizeof_char();
}
else{
return this->value_offset() + m_value_bytes;
}
}
size_type value_bytes() const
{ return m_value_bytes; }
template<class Header>
size_type total_size_with_header() const
{
return get_rounded_size
( size_type(sizeof(Header))
, size_type(::boost::alignment_of<block_header<size_type> >::value))
+ total_size();
}
unsigned char alloc_type() const
{ return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; }
unsigned char sizeof_char() const
{ return m_alloc_type_sizeof_char & (unsigned char)0x1F; }
template<class CharType>
CharType *name() const
{
return const_cast<CharType*>(reinterpret_cast<const CharType*>
(reinterpret_cast<const char*>(this) + name_offset()));
}
unsigned short name_length() const
{ 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()));
}
void *value() const
{
return const_cast<char*>((reinterpret_cast<const char*>(this) + this->value_offset()));
}
size_type value_offset() const
{
return get_rounded_size(size_type(sizeof(block_header<size_type>)), size_type(m_value_alignment));
}
template<class CharType>
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 &&
std::char_traits<CharType>::compare
(name<CharType>(), b.name<CharType>(), m_num_char) < 0);
}
template<class CharType>
bool equal_comp(const block_header<size_type> &b) const
{
return m_num_char == b.m_num_char &&
std::char_traits<CharType>::compare
(name<CharType>(), b.name<CharType>(), m_num_char) == 0;
}
template<class T>
static block_header<size_type> *block_header_from_value(T *value)
{ 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 =
const_cast<block_header*>
(reinterpret_cast<const block_header*>(reinterpret_cast<const char*>(value) -
get_rounded_size(sizeof(block_header), algn)));
(void)sz;
//Some sanity checks
BOOST_ASSERT(hdr->m_value_alignment == algn);
BOOST_ASSERT(hdr->m_value_bytes % sz == 0);
return hdr;
}
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) +
get_rounded_size(size_type(sizeof(Header)), size_type(::boost::alignment_of<block_header<size_type> >::value)));
//Some sanity checks
return hdr;
}
template<class Header>
static Header *to_first_header(block_header<size_type> *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;
}
};
inline void array_construct(void *mem, std::size_t num, ipcdetail::in_place_interface &table)
{
//Try constructors
std::size_t constructed = 0;
BOOST_TRY{
table.construct_n(mem, num, constructed);
}
//If there is an exception call destructors and erase index node
BOOST_CATCH(...){
std::size_t destroyed = 0;
table.destroy_n(mem, constructed, destroyed);
BOOST_RETHROW
}
BOOST_CATCH_END
}
template<class CharT>
struct intrusive_compare_key
{
typedef CharT char_type;
intrusive_compare_key(const CharT *str, std::size_t len)
: mp_str(str), m_len(len)
{}
const CharT * mp_str;
std::size_t m_len;
};
//!This struct indicates an anonymous object creation
//!allocation
template<instance_type type>
class instance_t
{
instance_t(){}
};
template<class T>
struct char_if_void
{
typedef T type;
};
template<>
struct char_if_void<void>
{
typedef char type;
};
typedef instance_t<anonymous_type> anonymous_instance_t;
typedef instance_t<unique_type> unique_instance_t;
template<class Hook, class CharType, class SizeType>
struct intrusive_value_type_impl
: public Hook
{
private:
//Non-copyable
intrusive_value_type_impl(const intrusive_value_type_impl &);
intrusive_value_type_impl& operator=(const intrusive_value_type_impl &);
public:
typedef CharType char_type;
typedef SizeType size_type;
intrusive_value_type_impl(){}
enum { BlockHdrAlignment = ::boost::alignment_of<block_header<size_type> >::value };
block_header<size_type> *get_block_header() const
{
return const_cast<block_header<size_type>*>
(reinterpret_cast<const block_header<size_type> *>(reinterpret_cast<const char*>(this) +
::boost::interprocess::ipcdetail::get_rounded_size(size_type(sizeof(*this)), size_type(BlockHdrAlignment))));
}
bool operator <(const intrusive_value_type_impl<Hook, CharType, SizeType> & other) const
{ return (this->get_block_header())->template less_comp<CharType>(*other.get_block_header()); }
bool operator ==(const intrusive_value_type_impl<Hook, CharType, SizeType> & other) const
{ return (this->get_block_header())->template equal_comp<CharType>(*other.get_block_header()); }
static intrusive_value_type_impl *get_intrusive_value_type(block_header<size_type> *hdr)
{
return reinterpret_cast<intrusive_value_type_impl *>(reinterpret_cast<char*>(hdr) -
get_rounded_size(size_type(sizeof(intrusive_value_type_impl)), size_type(BlockHdrAlignment)));
}
CharType *name() const
{ return get_block_header()->template name<CharType>(); }
unsigned short name_length() const
{ return get_block_header()->name_length(); }
void *value() const
{ return get_block_header()->value(); }
};
template<class CharType>
class char_ptr_holder
{
public:
char_ptr_holder(const CharType *name)
: m_name(name)
{}
char_ptr_holder(const ipcdetail::anonymous_instance_t *)
: m_name(static_cast<CharType*>(0))
{}
char_ptr_holder(const ipcdetail::unique_instance_t *)
: m_name(reinterpret_cast<CharType*>(-1))
{}
operator const CharType *()
{ return m_name; }
private:
const CharType *m_name;
};
//!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
{
typedef typename boost::
pointer_to_other<VoidPointer, const CharT>::type const_char_ptr_t;
typedef CharT char_type;
typedef typename std::iterator_traits<const_char_ptr_t>::difference_type difference_type;
typedef typename boost::make_unsigned<difference_type>::type size_type;
private:
//Offset pointer to the object's name
const_char_ptr_t mp_str;
//Length of the name buffer (null NOT included)
size_type m_len;
public:
//!Constructor of the key
index_key (const char_type *name, size_type length)
: mp_str(name), 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
(ipcdetail::get_pointer(mp_str)
,ipcdetail::get_pointer(right.mp_str), m_len) < 0);
}
//!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
(ipcdetail::get_pointer(mp_str),
ipcdetail::get_pointer(right.mp_str), m_len) == 0;
}
void name(const CharT *name)
{ mp_str = name; }
void name_length(size_type len)
{ m_len = len; }
const CharT *name() const
{ return ipcdetail::get_pointer(mp_str); }
size_type name_length() const
{ return m_len; }
};
//!The index_data stores a pointer to a buffer and the element count needed
//!to know how many destructors must be called when calling destroy
template<class VoidPointer>
struct index_data
{
typedef VoidPointer void_pointer;
void_pointer m_ptr;
index_data(void *ptr) : m_ptr(ptr){}
void *value() const
{ return static_cast<void*>(ipcdetail::get_pointer(m_ptr)); }
};
template<class MemoryAlgorithm>
struct segment_manager_base_type
{ typedef segment_manager_base<MemoryAlgorithm> type; };
template<class CharT, class MemoryAlgorithm>
struct index_config
{
typedef typename MemoryAlgorithm::void_pointer void_pointer;
typedef CharT char_type;
typedef ipcdetail::index_key<CharT, void_pointer> key_type;
typedef ipcdetail::index_data<void_pointer> mapped_type;
typedef typename segment_manager_base_type
<MemoryAlgorithm>::type segment_manager_base;
template<class HeaderBase>
struct intrusive_value_type
{ typedef ipcdetail::intrusive_value_type_impl<HeaderBase, CharT, typename segment_manager_base::size_type> type; };
typedef intrusive_compare_key<CharT> intrusive_compare_key_type;
};
template<class Iterator, bool intrusive>
class segment_manager_iterator_value_adaptor
{
typedef typename Iterator::value_type iterator_val_t;
typedef typename iterator_val_t::char_type char_type;
public:
segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val)
: m_val(&val)
{}
const char_type *name() const
{ return m_val->name(); }
unsigned short name_length() const
{ return m_val->name_length(); }
const void *value() const
{ return m_val->value(); }
const typename Iterator::value_type *m_val;
};
template<class Iterator>
class segment_manager_iterator_value_adaptor<Iterator, false>
{
typedef typename Iterator::value_type iterator_val_t;
typedef typename iterator_val_t::first_type first_type;
typedef typename iterator_val_t::second_type second_type;
typedef typename first_type::char_type char_type;
typedef typename first_type::size_type size_type;
public:
segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val)
: m_val(&val)
{}
const char_type *name() const
{ return m_val->first.name(); }
size_type name_length() const
{ return m_val->first.name_length(); }
const void *value() const
{
return reinterpret_cast<block_header<size_type>*>
(ipcdetail::get_pointer(m_val->second.m_ptr))->value();
}
const typename Iterator::value_type *m_val;
};
template<class Iterator, bool intrusive>
struct segment_manager_iterator_transform
: std::unary_function< typename Iterator::value_type
, 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
//indicate previous allocation types
static const ipcdetail::anonymous_instance_t * anonymous_instance = 0;
static const ipcdetail::unique_instance_t * unique_instance = 0;
namespace ipcdetail_really_deep_namespace {
//Otherwise, gcc issues a warning of previously defined
//anonymous_instance and unique_instance
struct dummy
{
dummy()
{
(void)anonymous_instance;
(void)unique_instance;
}
};
} //detail_really_deep_namespace
}} //namespace boost { namespace interprocess
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP

View File

@@ -0,0 +1,173 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP
#define BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/errors.hpp>
#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
#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 = 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 (::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;
long long fields[2] = { result.tv_sec, result.tv_usec };
for(std::size_t field = 0; field != 2; ++field){
for(std::size_t i = 0; i != sizeof(long long); ++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;
}
}
#endif
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();
}
#else
tmp_name = get_temporary_path();
#endif
if(tmp_name.empty()){
error_info err = system_error_code();
throw interprocess_exception(err);
}
//Remove final null.
tmp_name += "/boost_interprocess";
}
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);
#endif
}
inline void tmp_filename(const char *filename, std::string &tmp_name)
{
tmp_folder(tmp_name);
tmp_name += "/";
tmp_name += filename;
}
inline void create_tmp_and_clean_old(std::string &tmp_name)
{
//First get the temp directory
std::string root_tmp_name;
get_tmp_base_dir(root_tmp_name);
//If fails, check that it's because already exists
if(!create_directory(root_tmp_name.c_str())){
error_info info(system_error_code());
if(info.get_error_code() != already_exists_error){
throw interprocess_exception(info);
}
}
#ifdef 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);
}
}
//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;
#endif
}
inline void create_tmp_and_clean_old_and_get_filename(const char *filename, std::string &tmp_name)
{
create_tmp_and_clean_old(tmp_name);
tmp_name += "/";
tmp_name += filename;
}
inline void add_leading_slash(const char *name, std::string &new_name)
{
if(name[0] != '/'){
new_name = '/';
}
new_name += name;
}
} //namespace boost{
} //namespace interprocess {
} //namespace ipcdetail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //ifndef BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP

View File

@@ -0,0 +1,195 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009.
// (C) Copyright Gennaro Prota 2003 - 2004.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP
#define BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <iterator>
#include <boost/interprocess/detail/type_traits.hpp>
namespace boost {
namespace interprocess {
template <class PseudoReference>
struct operator_arrow_proxy
{
operator_arrow_proxy(const PseudoReference &px)
: m_value(px)
{}
PseudoReference* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
mutable PseudoReference m_value;
};
template <class T>
struct operator_arrow_proxy<T&>
{
operator_arrow_proxy(T &px)
: m_value(px)
{}
T* operator->() const { return const_cast<T*>(&m_value); }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
T &m_value;
};
template <class Iterator, class UnaryFunction>
class transform_iterator
: public UnaryFunction
, public std::iterator
< typename Iterator::iterator_category
, typename ipcdetail::remove_reference<typename UnaryFunction::result_type>::type
, typename Iterator::difference_type
, operator_arrow_proxy<typename UnaryFunction::result_type>
, typename UnaryFunction::result_type>
{
public:
explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction())
: UnaryFunction(f), m_it(it)
{}
explicit transform_iterator()
: UnaryFunction(), m_it()
{}
//Constructors
transform_iterator& operator++()
{ increment(); return *this; }
transform_iterator operator++(int)
{
transform_iterator result (*this);
increment();
return result;
}
transform_iterator& operator--()
{ decrement(); return *this; }
transform_iterator operator--(int)
{
transform_iterator result (*this);
decrement();
return result;
}
friend bool operator== (const transform_iterator& i, const transform_iterator& i2)
{ return i.equal(i2); }
friend bool operator!= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i == i2); }
friend bool operator< (const transform_iterator& i, const transform_iterator& i2)
{ return i < i2; }
friend bool operator> (const transform_iterator& i, const transform_iterator& i2)
{ return i2 < i; }
friend bool operator<= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i > i2); }
friend bool operator>= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i < i2); }
friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2)
{ return i2.distance_to(i); }
//Arithmetic
transform_iterator& operator+=(typename Iterator::difference_type off)
{ this->advance(off); return *this; }
transform_iterator operator+(typename Iterator::difference_type off) const
{
transform_iterator other(*this);
other.advance(off);
return other;
}
friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right)
{ return right + off; }
transform_iterator& operator-=(typename Iterator::difference_type off)
{ this->advance(-off); return *this; }
transform_iterator operator-(typename Iterator::difference_type off) const
{ return *this + (-off); }
typename UnaryFunction::result_type operator*() const
{ return dereference(); }
typename UnaryFunction::result_type operator[](typename Iterator::difference_type off) const
{ return UnaryFunction::operator()(m_it[off]); }
operator_arrow_proxy<typename UnaryFunction::result_type>
operator->() const
{ return operator_arrow_proxy<typename UnaryFunction::result_type>(dereference()); }
Iterator & base()
{ return m_it; }
const Iterator & base() const
{ return m_it; }
private:
Iterator m_it;
void increment()
{ ++m_it; }
void decrement()
{ --m_it; }
bool equal(const transform_iterator &other) const
{ return m_it == other.m_it; }
bool less(const transform_iterator &other) const
{ return other.m_it < m_it; }
typename UnaryFunction::result_type dereference() const
{ return UnaryFunction::operator()(*m_it); }
void advance(typename Iterator::difference_type n)
{ std::advance(m_it, n); }
typename Iterator::difference_type distance_to(const transform_iterator &other)const
{ return std::distance(other.m_it, m_it); }
};
template <class Iterator, class UnaryFunc>
transform_iterator<Iterator, UnaryFunc>
make_transform_iterator(Iterator it, UnaryFunc fun)
{
return transform_iterator<Iterator, UnaryFunc>(it, fun);
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP

View File

@@ -0,0 +1,122 @@
//////////////////////////////////////////////////////////////////////////////
// (C) Copyright John Maddock 2000.
// (C) Copyright Ion Gaztanaga 2005-2009.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP
#define BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
struct nat{};
template<class T>
struct remove_reference
{
typedef T type;
};
template<class T>
struct remove_reference<T&>
{
typedef T type;
};
template<class T>
struct is_reference
{
enum { value = false };
};
template<class T>
struct is_reference<T&>
{
enum { value = true };
};
template<class T>
struct is_pointer
{
enum { value = false };
};
template<class T>
struct is_pointer<T*>
{
enum { value = true };
};
template <typename T>
struct add_reference
{
typedef T& type;
};
template<class T>
struct add_reference<T&>
{
typedef T& type;
};
template<>
struct add_reference<void>
{
typedef nat &type;
};
template<>
struct add_reference<const void>
{
typedef const nat &type;
};
template <class T>
struct add_const_reference
{ typedef const T &type; };
template <class T>
struct add_const_reference<T&>
{ typedef T& type; };
template <typename T, typename U>
struct is_same
{
typedef char yes_type;
struct no_type
{
char padding[8];
};
template <typename V>
static yes_type is_same_tester(V*, V*);
static no_type is_same_tester(...);
static T *t;
static U *u;
static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u));
};
} // namespace ipcdetail
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP
#include <boost/interprocess/detail/config_end.hpp>

View File

@@ -0,0 +1,174 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009.
// (C) Copyright Gennaro Prota 2003 - 2004.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP
#define BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
#include <boost/interprocess/detail/min_max.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/transform_iterator.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <utility>
#include <algorithm>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class SmartPtr>
struct smart_ptr_type
{
typedef typename SmartPtr::value_type value_type;
typedef value_type *pointer;
static pointer get (const SmartPtr &smartptr)
{ return smartptr.get();}
};
template<class T>
struct smart_ptr_type<T*>
{
typedef T value_type;
typedef value_type *pointer;
static pointer get (pointer ptr)
{ return ptr;}
};
//!Overload for smart pointers to avoid ADL problems with get_pointer
template<class Ptr>
inline typename smart_ptr_type<Ptr>::pointer
get_pointer(const Ptr &ptr)
{ return smart_ptr_type<Ptr>::get(ptr); }
//!To avoid ADL problems with swap
template <class T>
inline void do_swap(T& x, T& y)
{
using std::swap;
swap(x, y);
}
//Rounds "orig_size" by excess to round_to bytes
template<class SizeType>
inline SizeType get_rounded_size(SizeType orig_size, SizeType round_to)
{
return ((orig_size-1)/round_to+1)*round_to;
}
//Truncates "orig_size" to a multiple of "multiple" bytes.
template<class SizeType>
inline SizeType get_truncated_size(SizeType orig_size, SizeType multiple)
{
return orig_size/multiple*multiple;
}
//Rounds "orig_size" by excess to round_to bytes. round_to must be power of two
template<class SizeType>
inline SizeType get_rounded_size_po2(SizeType orig_size, SizeType round_to)
{
return ((orig_size-1)&(~(round_to-1))) + round_to;
}
//Truncates "orig_size" to a multiple of "multiple" bytes. multiple must be power of two
template<class SizeType>
inline SizeType get_truncated_size_po2(SizeType orig_size, SizeType multiple)
{
return (orig_size & (~(multiple-1)));
}
template <std::size_t OrigSize, std::size_t RoundTo>
struct ct_rounded_size
{
enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo };
};
// Gennaro Prota wrote this. Thanks!
template <int p, int n = 4>
struct ct_max_pow2_less
{
enum { c = 2*n < p };
static const std::size_t value =
c ? (ct_max_pow2_less< c*p, 2*c*n>::value) : n;
};
template <>
struct ct_max_pow2_less<0, 0>
{
static const std::size_t value = 0;
};
} //namespace ipcdetail {
//!Trait class to detect if an index is a node
//!index. This allows more efficient operations
//!when deallocating named objects.
template <class Index>
struct is_node_index
{
enum { value = false };
};
//!Trait class to detect if an index is an intrusive
//!index. This will embed the derivation hook in each
//!allocation header, to provide memory for the intrusive
//!container.
template <class Index>
struct is_intrusive_index
{
enum { value = false };
};
template <typename T> T*
addressof(T& v)
{
return reinterpret_cast<T*>(
&const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
}
//Anti-exception node eraser
template<class Cont>
class value_eraser
{
public:
value_eraser(Cont & cont, typename Cont::iterator it)
: m_cont(cont), m_index_it(it), m_erase(true){}
~value_eraser()
{ if(m_erase) m_cont.erase(m_index_it); }
void release() { m_erase = false; }
private:
Cont &m_cont;
typename Cont::iterator m_index_it;
bool m_erase;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP

View File

@@ -0,0 +1,153 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP
#define BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <cstddef> //std::size_t
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<typename... Values>
class tuple;
template<> class tuple<>
{};
template<typename Head, typename... Tail>
class tuple<Head, Tail...>
: private tuple<Tail...>
{
typedef tuple<Tail...> inherited;
public:
tuple() { }
// implicit copy-constructor is okay
// Construct tuple from separate arguments.
tuple(typename add_const_reference<Head>::type v,
typename add_const_reference<Tail>::type... vtail)
: inherited(vtail...), m_head(v)
{}
// Construct tuple from another tuple.
template<typename... VValues>
tuple(const tuple<VValues...>& other)
: m_head(other.head()), inherited(other.tail())
{}
template<typename... VValues>
tuple& operator=(const tuple<VValues...>& other)
{
m_head = other.head();
tail() = other.tail();
return this;
}
typename add_reference<Head>::type head() { return m_head; }
typename add_reference<const Head>::type head() const { return m_head; }
inherited& tail() { return *this; }
const inherited& tail() const { return *this; }
protected:
Head m_head;
};
template<typename... Values>
tuple<Values&&...> tie_forward(Values&&... values)
{ return tuple<Values&&...>(values...); }
template<int I, typename Tuple>
struct tuple_element;
template<int I, typename Head, typename... Tail>
struct tuple_element<I, tuple<Head, Tail...> >
{
typedef typename tuple_element<I-1, tuple<Tail...> >::type type;
};
template<typename Head, typename... Tail>
struct tuple_element<0, tuple<Head, Tail...> >
{
typedef Head type;
};
template<int I, typename Tuple>
class get_impl;
template<int I, typename Head, typename... Values>
class get_impl<I, tuple<Head, Values...> >
{
typedef typename tuple_element<I-1, tuple<Values...> >::type Element;
typedef get_impl<I-1, tuple<Values...> > Next;
public:
typedef typename add_reference<Element>::type type;
typedef typename add_const_reference<Element>::type const_type;
static type get(tuple<Head, Values...>& t) { return Next::get(t.tail()); }
static const_type get(const tuple<Head, Values...>& t) { return Next::get(t.tail()); }
};
template<typename Head, typename... Values>
class get_impl<0, tuple<Head, Values...> >
{
public:
typedef typename add_reference<Head>::type type;
typedef typename add_const_reference<Head>::type const_type;
static type get(tuple<Head, Values...>& t) { return t.head(); }
static const_type get(const tuple<Head, Values...>& t){ return t.head(); }
};
template<int I, typename... Values>
typename get_impl<I, tuple<Values...> >::type get(tuple<Values...>& t)
{ return get_impl<I, tuple<Values...> >::get(t); }
template<int I, typename... Values>
typename get_impl<I, tuple<Values...> >::const_type get(const tuple<Values...>& t)
{ return get_impl<I, tuple<Values...> >::get(t); }
////////////////////////////////////////////////////
// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will
// be used to "unpack" into comma-separated values
// in a function call.
////////////////////////////////////////////////////
template<int... Indexes>
struct index_tuple{};
template<std::size_t Num, typename Tuple = index_tuple<> >
struct build_number_seq;
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)> >
{};
template<int... Indexes>
struct build_number_seq<0, index_tuple<Indexes...> >
{ typedef index_tuple<Indexes...> type; };
}}} //namespace boost { namespace interprocess { namespace ipcdetail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,148 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP
#define BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP
#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)
#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
#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
//Some platforms have a limited (name length) named semaphore support
#elif (defined(__FreeBSD__) && (__FreeBSD__ >= 4)) || defined(__APPLE__)
# 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)) ||\
((defined _V6_LPBIG_OFFBIG) &&(_V6_LPBIG_OFFBIG - 0 > 0)) ||\
((defined _XBS5_ILP32_OFFBIG)&&(_XBS5_ILP32_OFFBIG - 0 > 0)) ||\
((defined _XBS5_LP64_OFF64) &&(_XBS5_LP64_OFF64 - 0 > 0)) ||\
((defined _XBS5_LPBIG_OFFBIG)&&(_XBS5_LPBIG_OFFBIG - 0 > 0)) ||\
((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__)
# define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
#endif
#if ((_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
#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
#endif
#if ((_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
#elif defined(__FreeBSD__)
#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
#endif
#endif
#if ((_POSIX_VERSION + 0)>= 200112L || (_XOPEN_VERSION + 0)>= 500)
#define BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES
#endif
#endif
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)\
&& !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL)
#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
#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
#endif
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP

View File

@@ -0,0 +1,392 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2009-2010. 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_XSI_SHARED_MEMORY_DEVICE_HPP
#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_DEVICE_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/detail/workaround.hpp>
#if defined(BOOST_INTERPROCESS_WINDOWS)
#error "This header can't be used in Windows operating systems"
#endif
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/tmp_dir_helpers.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/xsi_shared_memory.hpp>
#include <boost/interprocess/sync/xsi/xsi_named_mutex.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <cstddef>
#include <boost/cstdint.hpp>
#include <string>
#include <cstring>
//!\file
//!Describes a class representing a native xsi shared memory.
namespace boost {
namespace interprocess {
class xsi_shared_memory_device
{
/// @cond
BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper)
/// @endcond
public:
xsi_shared_memory_device();
xsi_shared_memory_device(create_only_t, const char *name, mode_t mode, std::size_t size)
{ this->priv_open_or_create_name_only(ipcdetail::DoCreate, name, mode, size); }
xsi_shared_memory_device(open_or_create_t, const char *name, mode_t mode, std::size_t size)
{ this->priv_open_or_create_name_only(ipcdetail::DoOpenOrCreate, name, mode, size); }
xsi_shared_memory_device(open_only_t, const char *name, mode_t mode)
{ this->priv_open_or_create_name_only(ipcdetail::DoOpen, name, mode, 0); }
xsi_shared_memory_device(create_only_t, const char *filepath, boost::uint8_t id, mode_t mode, std::size_t size)
{ this->priv_open_or_create_name_id(ipcdetail::DoCreate, name, id, mode, size); }
xsi_shared_memory_device(open_or_create_t, const char *filepath, boost::uint8_t id, mode_t mode, std::size_t size)
{ this->priv_open_or_create_name_id(ipcdetail::DoOpenOrCreate, id, name, mode, size); }
xsi_shared_memory_device(open_only_t, const char *filepath, boost::uint8_t id, mode_t mode)
{ this->priv_open_or_create_name_id(ipcdetail::DoOpen, name, id, mode, 0); }
xsi_shared_memory_device(BOOST_RV_REF(xsi_shared_memory_device) moved)
{ this->swap(moved); }
xsi_shared_memory_device &operator=(BOOST_RV_REF(xsi_shared_memory_device) moved)
{
xsi_shared_memory_device tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps two xsi_shared_memory_device. Does not throw
void swap(xsi_shared_memory_device &other);
//!Destroys *this. The shared memory won't be destroyed, just
//!this connection to it. Use remove() to destroy the shared memory.
~xsi_shared_memory_device();
//!Returns the name of the
//!shared memory.
const char *get_name() const;
//!Returns the shared memory ID that
//!identifies the shared memory
int get_shmid() const;
//!Returns access
//!permissions
mode_t get_mode() const;
//!Returns the mapping handle.
//!Never throws
mapping_handle_t get_mapping_handle() const;
//!Erases a XSI shared memory object identified by shmname
//!from the system.
//!Returns false on error. Never throws
static bool remove(const char *shmname);
//!Erases the XSI shared memory object identified by shmid
//!from the system.
//!Returns false on error. Never throws
static bool remove(int shmid);
/// @cond
private:
template<int Dummy>
struct info_constants_t
{
static const std::size_t MaxName = 32;
static const std::size_t FirstID = 2;
static const std::size_t LastID = 256;
static const std::size_t NumID = LastID - FirstID;
};
struct info_t
{
struct names_t
{
char buf[info_constants_t<0>::MaxName];
} names[info_constants_t<0>::NumID];
};
static void priv_obtain_index(mapped_region &m, xsi_named_mutex &m, std::string &path);
static bool priv_remove_dead_memory(info_t *info, const char *path);
bool priv_open_or_create_name_only( ipcdetail::create_enum_t type
, const char *shmname
, mode_t mode
, std::size_t size);
bool priv_open_or_create_name_id( ipcdetail::create_enum_t type
, const char *shmname
, boost::uint8_t id
, mode_t mode
, std::size_t size);
xsi_shared_memory m_shm;
mode_t m_mode;
std::string m_name;
/// @endcond
};
template<int Dummy>
const std::size_t xsi_shared_memory_device::info_constants_t<Dummy>::MaxName;
template<int Dummy>
const std::size_t xsi_shared_memory_device::info_constants_t<Dummy>::FirstID;
template<int Dummy>
const std::size_t xsi_shared_memory_device::info_constants_t<Dummy>::LastID;
template<int Dummy>
const std::size_t xsi_shared_memory_device::info_constants_t<Dummy>::NumID;
/// @cond
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 const char *xsi_shared_memory_device::get_name() const
{ return m_name.c_str(); }
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);
}
inline mapping_handle_t xsi_shared_memory_device::get_mapping_handle() const
{ return m_shm.get_mapping_handle(); }
inline mode_t xsi_shared_memory_device::get_mode() const
{ return m_mode; }
inline int xsi_shared_memory::get_shmid() const
{ return m_shm.get_shmid(); }
inline void xsi_shared_memory_device::priv_obtain_index
(mapped_region &reg, xsi_named_mutex &mut, std::string &path)
{
const char *const filename = "xsi_shm_emulation_file";
permissions p;
p.set_unrestricted();
std::string xsi_shm_emulation_file_path;
ipcdetail::create_tmp_and_clean_old_and_get_filename(filename, xsi_shm_emulation_file_path);
ipcdetail::create_or_open_file(xsi_shm_emulation_file_path.c_str(), read_write, p);
const std::size_t MemSize = sizeof(info_t);
xsi_shared_memory index_shm(open_or_create, xsi_shm_emulation_file_path.c_str(), 1, MemSize, 0666);
mapped_region r(index_shm, read_write, 0, MemSize, 0);
xsi_named_mutex m(open_or_create, xsi_shm_emulation_file_path.c_str(), 2, 0666);
reg = boost::interprocess::move(r);
mut = boost::interprocess::move(m);
path.swap(xsi_shm_emulation_file_path);
}
inline bool xsi_shared_memory_device::priv_remove_dead_memory
(xsi_shared_memory_device::info_t *info, const char *path)
{
bool removed = false;
for(std::size_t i = 0; i != info_constants_t<0>::NumID; ++i){
if(info->names[i].buf[0]){
try{
xsi_shared_memory temp( open_only, path, i+info_constants_t<0>::FirstID, 0600);
}
catch(interprocess_exception &e){
if(e.get_error_code() == not_found_error){
std::memset(info->names[i].buf, 0, info_constants_t<0>::MaxName);
removed = true;
}
}
}
}
return removed;
}
inline bool xsi_shared_memory_device::priv_open_or_create_name_id
(ipcdetail::create_enum_t type, const char *filepath, mode_t mode, std::size_t size)
{
//Set accesses
if (mode != read_write && mode != read_only){
error_info err = other_error;
throw interprocess_exception(err);
}
int perm = (mode == read_only) ? (0444) : (0666);
if(type == ipcdetail::DoOpen){
if(!found){
error_info err = not_found_error;
throw interprocess_exception(err);
}
xsi_shared_memory temp(open_only, filepath, id, perm);
m_shm = boost::interprocess::move(temp);
}
else if(type == ipcdetail::DoCreate){
//Try to reuse slot
xsi_shared_memory temp(create_only, filepath, id, size, perm);
std::strcpy(info->names[target_entry].buf, shmname);
m_shm = boost::interprocess::move(temp);
}
else{ // if(type == ipcdetail::DoOpenOrCreate){
xsi_shared_memory temp(open_or_create, filepath, id, size, perm);
m_shm = boost::interprocess::move(temp);
}
m_mode = mode;
m_name.clear();
return true;
}
inline bool xsi_shared_memory_device::priv_open_or_create_name_only
(ipcdetail::create_enum_t type, const char *shmname, mode_t mode, std::size_t size)
{
//Set accesses
if (mode != read_write && mode != read_only){
error_info err = other_error;
throw interprocess_exception(err);
}
if (std::strlen(shmname) >= (info_constants_t<0>::MaxName)){
error_info err = other_error;
throw interprocess_exception(err);
}
{
//Obtain index and index lock
mapped_region region;
xsi_named_mutex mut;
std::string xsi_shm_emulation_file_path;
priv_obtain_index(region, mut, xsi_shm_emulation_file_path);
info_t *info = static_cast<info_t *>(region.get_address());
scoped_lock<xsi_named_mutex> lock(mut);
//Find the correct entry or the first empty index
bool found = false;
int target_entry = -1;
int tries = 2;
while(tries--){
for(std::size_t i = 0; i != info_constants_t<0>::NumID; ++i){
if(target_entry < 0 && !info->names[i].buf[0]){
target_entry = static_cast<int>(i);
}
else if(0 == std::strcmp(info->names[i].buf, shmname)){
found = true;
target_entry = static_cast<int>(i);
break;
}
}
if(target_entry < 0){
if(!tries || !priv_remove_dead_memory(info, xsi_shm_emulation_file_path.c_str())){
error_info err = out_of_resource_error;
throw interprocess_exception(err);
}
}
}
//Now handle the result
int perm = (mode == read_only) ? (0444) : (0666);
if(type == ipcdetail::DoOpen){
if(!found){
error_info err = not_found_error;
throw interprocess_exception(err);
}
xsi_shared_memory temp( open_only, xsi_shm_emulation_file_path.c_str()
, target_entry+info_constants_t<0>::FirstID, perm);
m_shm = boost::interprocess::move(temp);
}
else{
if(type == ipcdetail::DoCreate){
//Try to reuse slot
xsi_shared_memory temp( create_only, xsi_shm_emulation_file_path.c_str()
, target_entry+info_constants_t<0>::FirstID, size, perm);
std::strcpy(info->names[target_entry].buf, shmname);
m_shm = boost::interprocess::move(temp);
}
else{ // if(type == ipcdetail::DoOpenOrCreate){
xsi_shared_memory temp( open_or_create, xsi_shm_emulation_file_path.c_str()
, target_entry+info_constants_t<0>::FirstID, size, perm);
if(!found){
std::memset(info->names[target_entry].buf, 0, info_constants_t<0>::MaxName);
std::strcpy(info->names[target_entry].buf, shmname);
}
m_shm = boost::interprocess::move(temp);
}
}
}
m_mode = mode;
m_name = shmname;
return true;
}
inline bool xsi_shared_memory_device::remove(const char *shmname)
{
try{
//Obtain index and index lockss
mapped_region region;
xsi_named_mutex mut;
std::string xsi_shm_emulation_file_path;
priv_obtain_index(region, mut, xsi_shm_emulation_file_path);
scoped_lock<xsi_named_mutex> lock(mut);
info_t *info = static_cast<info_t *>(region.get_address());
//Now check and remove
bool removed = false;
for(std::size_t i = 0; i != info_constants_t<0>::NumID; ++i){
if(0 == std::strcmp(info->names[i].buf, name)){
xsi_shared_memory temp( open_only, xsi_shm_emulation_file_path.c_str()
, i+info_constants_t<0>::FirstID);
if(!xsi_shared_memory::remove(temp.get_shmid()) && (system_error_code() != invalid_argument)){
return false;
}
std::memset(info->names[i].buf, 0, info_constants_t<0>::MaxName);
removed = true;
break;
}
}
return removed;
}
catch(...){
return false;
}
}
inline bool xsi_shared_memory_device::remove(int shmid)
{ return xsi_shared_memory::remove(shmid); }
///@endcond
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_DEVICE_HPP

View File

@@ -0,0 +1,80 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2009-2010. 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_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP
#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/detail/workaround.hpp>
#if !defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS)
#error "This header can't be used in operating systems without XSI (System V) shared memory support"
#endif
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/tmp_dir_helpers.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/xsi_shared_memory.hpp>
//!\file
//!Describes a class representing a pseudo-file implemented on top of xsi shared memory.
namespace boost {
namespace interprocess {
class xsi_shared_memory_file_wrapper
: public xsi_shared_memory
{
/// @cond
BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_shared_memory_file_wrapper)
/// @endcond
public:
xsi_shared_memory_file_wrapper() : xsi_shared_memory() {}
xsi_shared_memory_file_wrapper(create_only_t, const xsi_key &key, mode_t mode, std::size_t size, const permissions& perm = permissions())
: xsi_shared_memory(create_only_t(), key, size, perm.get_permissions())
{}
xsi_shared_memory_file_wrapper(open_or_create_t, const xsi_key &key, mode_t mode, std::size_t size, const permissions& perm = permissions())
: xsi_shared_memory(open_or_create_t(), key, size, perm.get_permissions())
{}
xsi_shared_memory_file_wrapper(open_only_t, const xsi_key &key, mode_t mode, const permissions& perm = permissions())
: xsi_shared_memory(open_only_t(), key)
{}
xsi_shared_memory_file_wrapper(BOOST_RV_REF(xsi_shared_memory_file_wrapper) moved)
{ 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::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps two xsi_shared_memory_file_wrapper. Does not throw
void swap(xsi_shared_memory_file_wrapper &other)
{ this->xsi_shared_memory::swap(other); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_FILE_WRAPPER_HPP

View File

@@ -0,0 +1,235 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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.
//
// Parts of this code are taken from boost::filesystem library
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 Beman Dawes
// 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)
//
// See library home page at http://www.boost.org/libs/filesystem
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ERRORS_HPP
#define BOOST_INTERPROCESS_ERRORS_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 <stdarg.h>
#include <string>
#if (defined BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <errno.h> //Errors
# include <cstring> //strerror
# else //ifdef BOOST_HAS_UNISTD_H
# error Unknown platform
# endif //ifdef BOOST_HAS_UNISTD_H
#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
//!\file
//!Describes the error numbering of interprocess classes
namespace boost {
namespace interprocess {
/// @cond
inline int system_error_code() // artifact of POSIX and WINDOWS error reporting
{
#if (defined BOOST_INTERPROCESS_WINDOWS)
return winapi::get_last_error();
#else
return errno; // GCC 3.1 won't accept ::errno
#endif
}
#if (defined BOOST_INTERPROCESS_WINDOWS)
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_ignore_inserts,
0,
sys_err_code,
winapi::make_lang_id(winapi::lang_neutral, winapi::sublang_default), // Default language
reinterpret_cast<char *>(&lpMsgBuf),
0,
0
);
str += static_cast<const char*>(lpMsgBuf);
winapi::local_free( lpMsgBuf ); // free the buffer
while ( str.size()
&& (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') )
str.erase( str.size()-1 );
}
# else
inline void fill_system_message( int system_error, std::string &str)
{ str = std::strerror(system_error); }
# endif
/// @endcond
enum error_code_t
{
no_error = 0,
system_error, // system generated error; if possible, is translated
// to one of the more specific errors below.
other_error, // library generated error
security_error, // includes access rights, permissions failures
read_only_error,
io_error,
path_error,
not_found_error,
// not_directory_error,
busy_error, // implies trying again might succeed
already_exists_error,
not_empty_error,
is_directory_error,
out_of_space_error,
out_of_memory_error,
out_of_resource_error,
lock_error,
sem_error,
mode_error,
size_error,
corrupted_error,
not_such_file_or_directory,
invalid_argument,
timeout_when_locking_error,
};
typedef int native_error_t;
/// @cond
struct ec_xlate
{
native_error_t sys_ec;
error_code_t ec;
};
static const ec_xlate ec_table[] =
{
#if (defined BOOST_INTERPROCESS_WINDOWS)
{ /*ERROR_ACCESS_DENIED*/5L, security_error },
{ /*ERROR_INVALID_ACCESS*/12L, security_error },
{ /*ERROR_SHARING_VIOLATION*/32L, security_error },
{ /*ERROR_LOCK_VIOLATION*/33L, security_error },
{ /*ERROR_LOCKED*/212L, security_error },
{ /*ERROR_NOACCESS*/998L, security_error },
{ /*ERROR_WRITE_PROTECT*/19L, read_only_error },
{ /*ERROR_NOT_READY*/21L, io_error },
{ /*ERROR_SEEK*/25L, io_error },
{ /*ERROR_READ_FAULT*/30L, io_error },
{ /*ERROR_WRITE_FAULT*/29L, io_error },
{ /*ERROR_CANTOPEN*/1011L, io_error },
{ /*ERROR_CANTREAD*/1012L, io_error },
{ /*ERROR_CANTWRITE*/1013L, io_error },
{ /*ERROR_DIRECTORY*/267L, path_error },
{ /*ERROR_INVALID_NAME*/123L, path_error },
{ /*ERROR_FILE_NOT_FOUND*/2L, not_found_error },
{ /*ERROR_PATH_NOT_FOUND*/3L, not_found_error },
{ /*ERROR_DEV_NOT_EXIST*/55L, not_found_error },
{ /*ERROR_DEVICE_IN_USE*/2404L, busy_error },
{ /*ERROR_OPEN_FILES*/2401L, busy_error },
{ /*ERROR_BUSY_DRIVE*/142L, busy_error },
{ /*ERROR_BUSY*/170L, busy_error },
{ /*ERROR_FILE_EXISTS*/80L, already_exists_error },
{ /*ERROR_ALREADY_EXISTS*/183L, already_exists_error },
{ /*ERROR_DIR_NOT_EMPTY*/145L, not_empty_error },
{ /*ERROR_HANDLE_DISK_FULL*/39L, out_of_space_error },
{ /*ERROR_DISK_FULL*/112L, out_of_space_error },
{ /*ERROR_OUTOFMEMORY*/14L, out_of_memory_error },
{ /*ERROR_NOT_ENOUGH_MEMORY*/8L, out_of_memory_error },
{ /*ERROR_TOO_MANY_OPEN_FILES*/4L, out_of_resource_error },
{ /*ERROR_INVALID_ADDRESS*/487L, busy_error }
#else //#if (defined BOOST_INTERPROCESS_WINDOWS)
{ EACCES, security_error },
{ EROFS, read_only_error },
{ EIO, io_error },
{ ENAMETOOLONG, path_error },
{ ENOENT, not_found_error },
// { ENOTDIR, not_directory_error },
{ EAGAIN, busy_error },
{ EBUSY, busy_error },
{ ETXTBSY, busy_error },
{ EEXIST, already_exists_error },
{ ENOTEMPTY, not_empty_error },
{ EISDIR, is_directory_error },
{ ENOSPC, out_of_space_error },
{ ENOMEM, out_of_memory_error },
{ EMFILE, out_of_resource_error },
{ ENOENT, not_such_file_or_directory },
{ EINVAL, invalid_argument }
#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
};
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);
for (;cur != end; ++cur ){
if ( err == cur->sys_ec ) return cur->ec;
}
return system_error; // general system error code
}
struct error_info
{
error_info(error_code_t ec = other_error )
: m_nat(0), m_ec(ec)
{}
error_info(native_error_t sys_err_code)
: m_nat(sys_err_code), m_ec(lookup_error(sys_err_code))
{}
error_info & operator =(error_code_t ec)
{
m_nat = 0;
m_ec = ec;
return *this;
}
error_info & operator =(native_error_t sys_err_code)
{
m_nat = sys_err_code;
m_ec = lookup_error(sys_err_code);
return *this;
}
native_error_t get_native_error()const
{ return m_nat; }
error_code_t get_error_code()const
{ return m_ec; }
private:
native_error_t m_nat;
error_code_t m_ec;
};
/// @endcond
} // namespace interprocess {
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_ERRORS_HPP

View File

@@ -0,0 +1,150 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_EXCEPTIONS_HPP
#define BOOST_INTERPROCESS_EXCEPTIONS_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/errors.hpp>
#include <stdexcept>
#include <new>
//!\file
//!Describes exceptions thrown by interprocess classes
namespace boost {
namespace interprocess {
//!This class is the base class of all exceptions
//!thrown by boost::interprocess
class interprocess_exception : public std::exception
{
public:
interprocess_exception(const char *err/*error_code_t ec = other_error*/)
: m_err(other_error)
{
// try { m_str = "boost::interprocess_exception::library_error"; }
try { m_str = err; }
catch (...) {}
}
/*
interprocess_exception(native_error_t sys_err_code)
: m_err(sys_err_code)
{
try { fill_system_message(m_err.get_native_error(), m_str); }
catch (...) {}
}*/
interprocess_exception(const error_info &err_info, const char *str = 0)
: m_err(err_info)
{
try{
if(m_err.get_native_error() != 0){
fill_system_message(m_err.get_native_error(), m_str);
}
else if(str){
m_str = str;
}
else{
m_str = "boost::interprocess_exception::library_error";
}
}
catch(...){}
}
virtual ~interprocess_exception() throw(){}
virtual const char * what() const throw()
{ return m_str.c_str(); }
native_error_t get_native_error()const { return m_err.get_native_error(); }
// Note: a value of other_error implies a library (rather than system) error
error_code_t get_error_code() const { return m_err.get_error_code(); }
/// @cond
private:
error_info m_err;
std::string m_str;
/// @endcond
};
//!This is the exception thrown by shared interprocess_mutex family when a deadlock situation
//!is detected or when using a interprocess_condition the interprocess_mutex is not locked
class lock_exception : public interprocess_exception
{
public:
lock_exception()
: interprocess_exception(lock_error)
{}
virtual const char* what() const throw()
{ return "boost::interprocess::lock_exception"; }
};
//!This is the exception thrown by named interprocess_semaphore when a deadlock situation
//!is detected or when an error is detected in the post/wait operation
/*
class sem_exception : public interprocess_exception
{
public:
sem_exception()
: interprocess_exception(lock_error)
{}
virtual const char* what() const throw()
{ return "boost::interprocess::sem_exception"; }
};
*/
//!This is the exception thrown by synchronization objects when there is
//!an error in a wait() function
/*
class wait_exception : public interprocess_exception
{
public:
virtual const char* what() const throw()
{ return "boost::interprocess::wait_exception"; }
};
*/
//!This exception is thrown when a named object is created
//!in "open_only" mode and the resource was not already created
/*
class not_previously_created : public interprocess_exception
{
public:
virtual const char* what() const throw()
{ return "boost::interprocess::not_previously_created"; }
};
*/
//!This exception is thrown when a memory request can't be
//!fulfilled.
class bad_alloc : public interprocess_exception
{
public:
bad_alloc() : interprocess_exception("::boost::interprocess::bad_alloc"){}
virtual const char* what() const throw()
{ return "boost::interprocess::bad_alloc"; }
};
} // namespace interprocess {
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_EXCEPTIONS_HPP

View File

@@ -0,0 +1,184 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MAPPING_HPP
#define BOOST_INTERPROCESS_FILE_MAPPING_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <string> //std::string
//!\file
//!Describes file_mapping and mapped region classes
namespace boost {
namespace interprocess {
//!A class that wraps a file-mapping that can be used to
//!create mapped regions from the mapped files
class file_mapping
{
/// @cond
BOOST_MOVABLE_BUT_NOT_COPYABLE(file_mapping)
/// @endcond
public:
//!Constructs an empty 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
//!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.
//!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.
//!Does not throw
file_mapping &operator=(BOOST_RV_REF(file_mapping) moved)
{
file_mapping tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps to file_mappings.
//!Does not throw.
void swap(file_mapping &other);
//!Returns access mode
//!used in the constructor
mode_t get_mode() const;
//!Obtains the mapping handle
//!to be used with mapped_region
mapping_handle_t get_mapping_handle() const;
//!Destroys the file mapping. All mapped regions created from this are still
//!valid. Does not throw
~file_mapping();
//!Returns the name of the file
//!used in the constructor.
const char *get_name() const;
//!Removes the file named "filename" even if it's been memory mapped.
//!Returns true on success.
//!The function might fail in some operating systems if the file is
//!being used other processes and no deletion permission was shared.
static bool remove(const char *filename);
/// @cond
private:
//!Closes a previously opened file mapping. Never throws.
void priv_close();
file_handle_t m_handle;
mode_t m_mode;
std::string m_filename;
/// @endcond
};
inline file_mapping::file_mapping()
: m_handle(file_handle_t(ipcdetail::invalid_file()))
{}
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);
}
inline mapping_handle_t file_mapping::get_mapping_handle() const
{ return ipcdetail::mapping_handle_from_file_handle(m_handle); }
inline mode_t file_mapping::get_mode() const
{ return m_mode; }
inline file_mapping::file_mapping
(const char *filename, mode_t mode)
: m_filename(filename)
{
//Check accesses
if (mode != read_write && mode != read_only){
error_info err = other_error;
throw interprocess_exception(err);
}
//Open file
m_handle = ipcdetail::open_existing_file(filename, mode);
//Check for error
if(m_handle == ipcdetail::invalid_file()){
error_info err = system_error_code();
this->priv_close();
throw interprocess_exception(err);
}
m_mode = mode;
}
inline bool file_mapping::remove(const char *filename)
{ return ipcdetail::delete_file(filename); }
///@cond
inline void file_mapping::priv_close()
{
if(m_handle != ipcdetail::invalid_file()){
ipcdetail::close_file(m_handle);
m_handle = ipcdetail::invalid_file();
}
}
///@endcond
//!A class that stores the name of a file
//!and tries to remove it in its destructor
//!Useful to remove temporary files in the presence
//!of exceptions
class remove_file_on_destroy
{
const char * m_name;
public:
remove_file_on_destroy(const char *name)
: m_name(name)
{}
~remove_file_on_destroy()
{ ipcdetail::delete_file(m_name); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_FILE_MAPPING_HPP

View File

@@ -0,0 +1,78 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_FLAT_MAP_INDEX_HPP
#define BOOST_INTERPROCESS_FLAT_MAP_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/interprocess/containers/flat_map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
//!\file
//!Describes index adaptor of boost::map container, to use it
//!as name/shared memory index
//[flat_map_index
namespace boost { namespace interprocess {
//!Helper class to define typedefs from IndexTraits
template <class MapConfig>
struct flat_map_index_aux
{
typedef typename MapConfig::key_type key_type;
typedef typename MapConfig::mapped_type mapped_type;
typedef typename MapConfig::
segment_manager_base segment_manager_base;
typedef std::less<key_type> key_less;
typedef std::pair<key_type, mapped_type> value_type;
typedef allocator<value_type
,segment_manager_base> allocator_type;
typedef flat_map<key_type, mapped_type,
key_less, allocator_type> index_t;
};
//!Index type based in flat_map. Just derives from flat_map and
//!defines the interface needed by managed memory segments.
template <class MapConfig>
class flat_map_index
//Derive class from flat_map specialization
: public flat_map_index_aux<MapConfig>::index_t
{
/// @cond
typedef flat_map_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t base_type;
typedef typename index_aux::
segment_manager_base segment_manager_base;
/// @endcond
public:
//!Constructor. Takes a pointer to the segment manager. Can throw
flat_map_index(segment_manager_base *segment_mngr)
: base_type(typename index_aux::key_less(),
typename index_aux::allocator_type(segment_mngr))
{}
//!This reserves memory to optimize the insertion of n elements in the index
void reserve(typename segment_manager_base::size_type n)
{ base_type::reserve(n); }
//!This frees all unnecessary memory
void shrink_to_fit()
{ base_type::shrink_to_fit(); }
};
}} //namespace boost { namespace interprocess
//]
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_FLAT_MAP_INDEX_HPP

View File

@@ -0,0 +1,150 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_ISET_INDEX_HPP
#define BOOST_INTERPROCESS_ISET_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <string>
#include <functional>
#include <utility>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/intrusive/set.hpp>
//!\file
//!Describes index adaptor of boost::intrusive::set container, to use it
//!as name/shared memory index
namespace boost {
namespace interprocess {
/// @cond
//!Helper class to define typedefs from IndexTraits
template <class MapConfig>
struct iset_index_aux
{
typedef typename
MapConfig::segment_manager_base segment_manager_base;
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
intrusive_value_type<derivation_hook>::type value_type;
typedef std::less<value_type> value_compare;
typedef typename bi::make_set
< value_type
, bi::base_hook<derivation_hook>
>::type index_t;
};
/// @endcond
//!Index type based in boost::intrusive::set.
//!Just derives from boost::intrusive::set
//!and defines the interface needed by managed memory segments*/
template <class MapConfig>
class iset_index
//Derive class from map specialization
: public iset_index_aux<MapConfig>::index_t
{
/// @cond
typedef iset_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t index_type;
typedef typename MapConfig::
intrusive_compare_key_type intrusive_compare_key_type;
typedef typename MapConfig::char_type char_type;
/// @endcond
public:
typedef typename index_type::iterator iterator;
typedef typename index_type::const_iterator const_iterator;
typedef typename index_type::insert_commit_data insert_commit_data;
typedef typename index_type::value_type value_type;
/// @cond
private:
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
(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) ||
(blen == i.m_len &&
std::char_traits<char_type>::compare
(b.name(), i.mp_str, i.m_len) < 0);
}
};
/// @endcond
public:
//!Constructor. Takes a pointer to the
//!segment manager. Can throw
iset_index(typename MapConfig::segment_manager_base *)
: index_type(/*typename index_aux::value_compare()*/)
{}
//!This reserves memory to optimize the insertion of n
//!elements in the index
void reserve(typename MapConfig::segment_manager_base::size_type)
{ /*Does nothing, map has not reserve or rehash*/ }
//!This frees all unnecessary memory
void shrink_to_fit()
{ /*Does nothing, this intrusive index does not allocate memory;*/ }
iterator find(const intrusive_compare_key_type &key)
{ return index_type::find(key, intrusive_key_value_less()); }
const_iterator find(const intrusive_compare_key_type &key) const
{ return index_type::find(key, intrusive_key_value_less()); }
std::pair<iterator, bool>insert_check
(const intrusive_compare_key_type &key, insert_commit_data &commit_data)
{ return index_type::insert_check(key, intrusive_key_value_less(), commit_data); }
};
/// @cond
//!Trait class to detect if an index is an intrusive
//!index.
template<class MapConfig>
struct is_intrusive_index
<boost::interprocess::iset_index<MapConfig> >
{
enum{ value = true };
};
/// @endcond
} //namespace interprocess {
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_ISET_INDEX_HPP

View File

@@ -0,0 +1,368 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_IUNORDERED_SET_INDEX_HPP
#define BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/get_pointer.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/intrusive/unordered_set.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
//!\file
//!Describes index adaptor of boost::intrusive::unordered_set container, to use it
//!as name/shared memory index
namespace boost { namespace interprocess {
/// @cond
//!Helper class to define typedefs
//!from IndexTraits
template <class MapConfig>
struct iunordered_set_index_aux
{
typedef typename
MapConfig::segment_manager_base segment_manager_base;
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
intrusive_value_type<derivation_hook>::type value_type;
typedef typename MapConfig::
intrusive_compare_key_type intrusive_compare_key_type;
typedef std::equal_to<value_type> value_equal;
typedef typename MapConfig::char_type char_type;
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
(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
(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
(b1.name(), b2.name(), b1.name_length()) == 0);
}
};
struct hash_function
: std::unary_function<value_type, std::size_t>
{
std::size_t operator()(const value_type &val) const
{
const char_type *beg = ipcdetail::get_pointer(val.name()),
*end = beg + val.name_length();
return boost::hash_range(beg, end);
}
std::size_t operator()(const intrusive_compare_key_type &i) const
{
const char_type *beg = i.mp_str,
*end = beg + i.m_len;
return boost::hash_range(beg, end);
}
};
typedef typename bi::make_unordered_set
< value_type
, bi::hash<hash_function>
, bi::equal<equal_function>
, bi::size_type<typename segment_manager_base::size_type>
>::type index_t;
typedef typename index_t::bucket_type bucket_type;
typedef allocator
<bucket_type, segment_manager_base> allocator_type;
struct allocator_holder
{
allocator_holder(segment_manager_base *mngr)
: alloc(mngr)
{}
allocator_type alloc;
bucket_type init_bucket;
};
};
/// @endcond
//!Index type based in 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
//Derive class from map specialization
: private iunordered_set_index_aux<MapConfig>::allocator_holder
, public iunordered_set_index_aux<MapConfig>::index_t
{
/// @cond
typedef iunordered_set_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t index_type;
typedef typename MapConfig::
intrusive_compare_key_type intrusive_compare_key_type;
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
iunordered_set_index_aux<MapConfig>::allocator_type allocator_type;
typedef typename
iunordered_set_index_aux<MapConfig>::allocator_holder allocator_holder;
/// @endcond
public:
typedef typename index_type::iterator iterator;
typedef typename index_type::const_iterator const_iterator;
typedef typename index_type::insert_commit_data insert_commit_data;
typedef typename index_type::value_type value_type;
typedef typename index_type::bucket_ptr bucket_ptr;
typedef typename index_type::bucket_type bucket_type;
typedef typename index_type::bucket_traits bucket_traits;
typedef typename index_type::size_type size_type;
/// @cond
private:
typedef typename index_aux::
segment_manager_base segment_manager_base;
enum { InitBufferSize = 64};
static bucket_ptr create_buckets(allocator_type &alloc, size_type num)
{
num = index_type::suggested_upper_bucket_count(num);
bucket_ptr buckets = alloc.allocate(num);
bucket_ptr buckets_init = buckets;
for(size_type i = 0; i < num; ++i){
new(get_pointer(buckets_init++))bucket_type();
}
return buckets;
}
static size_type shrink_buckets
( bucket_ptr buckets, size_type old_size
, allocator_type &alloc, size_type new_size)
{
if(old_size <= new_size )
return old_size;
size_type received_size;
if(!alloc.allocation_command
(boost::interprocess::try_shrink_in_place | boost::interprocess::nothrow_allocation, old_size, new_size, received_size, buckets).first){
return old_size;
}
for( bucket_type *p = ipcdetail::get_pointer(buckets) + received_size
, *pend = ipcdetail::get_pointer(buckets) + old_size
; p != pend
; ++p){
p->~bucket_type();
}
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);
bucket_ptr buckets_init = buckets + received_size;
for(size_type i = 0; i < (old_size - received_size); ++i){
get_pointer(buckets_init++)->~bucket_type();
}
return received_size;
}
static bucket_ptr expand_or_create_buckets
( bucket_ptr old_buckets, const size_type old_num
, allocator_type &alloc, const size_type new_num)
{
size_type received_size;
std::pair<bucket_ptr, bool> ret =
alloc.allocation_command
(boost::interprocess::expand_fwd | boost::interprocess::allocate_new, new_num, new_num, received_size, old_buckets);
if(ret.first == old_buckets){
bucket_ptr buckets_init = old_buckets + old_num;
for(size_type i = 0; i < (new_num - old_num); ++i){
new(get_pointer(buckets_init++))bucket_type();
}
}
else{
bucket_ptr buckets_init = ret.first;
for(size_type i = 0; i < new_num; ++i){
new(get_pointer(buckets_init++))bucket_type();
}
}
return ret.first;
}
static void destroy_buckets
(allocator_type &alloc, bucket_ptr buckets, size_type num)
{
bucket_ptr buckets_destroy = buckets;
for(size_type i = 0; i < num; ++i){
get_pointer(buckets_destroy++)->~bucket_type();
}
alloc.deallocate(buckets, num);
}
iunordered_set_index<MapConfig>* get_this_pointer()
{ return this; }
/// @endcond
public:
//!Constructor. Takes a pointer to the
//!segment manager. Can throw
iunordered_set_index(segment_manager_base *mngr)
: allocator_holder(mngr)
, index_type(bucket_traits(&get_this_pointer()->init_bucket, 1))
{}
~iunordered_set_index()
{
index_type::clear();
if(index_type::bucket_pointer() != bucket_ptr(&this->init_bucket)){
destroy_buckets(this->alloc, index_type::bucket_pointer(), index_type::bucket_count());
}
}
//!This reserves memory to optimize the insertion of n
//!elements in the index
void reserve(size_type new_n)
{
//Let's maintain a 1.0f load factor
size_type old_n = this->bucket_count();
if(new_n <= old_n)
return;
bucket_ptr old_p = this->bucket_pointer();
new_n = index_type::suggested_upper_bucket_count(new_n);
bucket_ptr new_p;
//This can throw
try{
if(old_p != bucket_ptr(&this->init_bucket))
new_p = expand_or_create_buckets(old_p, old_n, this->alloc, new_n);
else
new_p = create_buckets(this->alloc, new_n);
}
catch(...){
return;
}
//Rehashing does not throw, since neither the hash nor the
//comparison function can throw
this->rehash(bucket_traits(new_p, new_n));
if(new_p != old_p && old_p != bucket_ptr(&this->init_bucket)){
destroy_buckets(this->alloc, old_p, old_n);
}
}
//!This tries to free unused memory
//!previously allocated.
void shrink_to_fit()
{
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);
}
else{
size_type sug_count = 0; //gcc warning
sug_count = index_type::suggested_upper_bucket_count(cur_size);
if(sug_count >= cur_count)
return;
try{
shrink_buckets(old_p, cur_count, this->alloc, sug_count);
}
catch(...){
return;
}
//Rehashing does not throw, since neither the hash nor the
//comparison function can throw
this->rehash(bucket_traits(old_p, sug_count));
}
}
iterator find(const intrusive_compare_key_type &key)
{ return index_type::find(key, hash_function(), equal_function()); }
const_iterator find(const intrusive_compare_key_type &key) const
{ return index_type::find(key, hash_function(), equal_function()); }
std::pair<iterator, bool>insert_check
(const intrusive_compare_key_type &key, insert_commit_data &commit_data)
{ return index_type::insert_check(key, hash_function(), equal_function(), commit_data); }
iterator insert_commit(value_type &val, insert_commit_data &commit_data)
{
iterator it = index_type::insert_commit(val, commit_data);
size_type cur_size = this->size();
if(cur_size > this->bucket_count()){
try{
this->reserve(cur_size);
}
catch(...){
//Strong guarantee: if something goes wrong
//we should remove the insertion.
//
//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.
index_type::erase(it);
throw;
}
}
return it;
}
};
/// @cond
//!Trait class to detect if an index is an intrusive
//!index
template<class MapConfig>
struct is_intrusive_index
<boost::interprocess::iunordered_set_index<MapConfig> >
{
enum{ value = true };
};
/// @endcond
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP

View File

@@ -0,0 +1,100 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MAP_INDEX_HPP
#define BOOST_INTERPROCESS_MAP_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/private_adaptive_pool.hpp>
//!\file
//!Describes index adaptor of boost::map container, to use it
//!as name/shared memory index
namespace boost {
namespace interprocess {
namespace ipcdetail{
//!Helper class to define typedefs from IndexTraits
template <class MapConfig>
struct map_index_aux
{
typedef typename MapConfig::key_type key_type;
typedef typename MapConfig::mapped_type mapped_type;
typedef std::less<key_type> key_less;
typedef std::pair<const key_type, mapped_type> value_type;
typedef private_adaptive_pool
<value_type,
typename MapConfig::
segment_manager_base> allocator_type;
typedef boost::interprocess::map
<key_type, mapped_type,
key_less, allocator_type> index_t;
};
} //namespace ipcdetail {
//!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
//Derive class from map specialization
: public ipcdetail::map_index_aux<MapConfig>::index_t
{
/// @cond
typedef ipcdetail::map_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t base_type;
typedef typename MapConfig::
segment_manager_base segment_manager_base;
/// @endcond
public:
//!Constructor. Takes a pointer to the
//!segment manager. Can throw
map_index(segment_manager_base *segment_mngr)
: base_type(typename index_aux::key_less(),
segment_mngr){}
//!This reserves memory to optimize the insertion of n
//!elements in the index
void reserve(typename segment_manager_base::size_type)
{ /*Does nothing, map has not reserve or rehash*/ }
//!This tries to free previously allocate
//!unused memory.
void shrink_to_fit()
{ base_type::get_stored_allocator().deallocate_free_blocks(); }
};
/// @cond
//!Trait class to detect if an index is a node
//!index. This allows more efficient operations
//!when deallocating named objects.
template<class MapConfig>
struct is_node_index
<boost::interprocess::map_index<MapConfig> >
{
enum { value = true };
};
/// @endcond
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MAP_INDEX_HPP

View File

@@ -0,0 +1,68 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_NULL_INDEX_HPP
#define BOOST_INTERPROCESS_NULL_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/offset_ptr.hpp>
//!\file
//!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 {
namespace interprocess {
//!Null index type
//!used to save compilation time when
//!named indexes are not needed.
template <class MapConfig>
class null_index
{
/// @cond
typedef typename MapConfig::
segment_manager_base segment_manager_base;
/// @endcond
public:
typedef void * iterator;
typedef const void * const_iterator;
//!begin() is equal
//!to end()
const_iterator begin() const
{ return const_iterator(0); }
//!begin() is equal
//!to end()
iterator begin()
{ return iterator(0); }
//!begin() is equal
//!to end()
const_iterator end() const
{ return const_iterator(0); }
//!begin() is equal
//!to end()
iterator end()
{ return iterator(0); }
//!Empty constructor
null_index(segment_manager_base *){}
};
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NULL_INDEX_HPP

View File

@@ -0,0 +1,113 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_UNORDERED_MAP_INDEX_HPP
#define BOOST_INTERPROCESS_UNORDERED_MAP_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/unordered_map.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/allocators/private_adaptive_pool.hpp>
//!\file
//!Describes index adaptor of boost::unordered_map container, to use it
//!as name/shared memory index
namespace boost {
namespace interprocess {
///@cond
//!Helper class to define typedefs from
//!IndexTraits
template <class MapConfig>
struct unordered_map_index_aux
{
typedef typename MapConfig::key_type key_type;
typedef typename MapConfig::mapped_type mapped_type;
typedef std::equal_to<key_type> key_equal;
typedef std::pair<const key_type, mapped_type> value_type;
typedef private_adaptive_pool
<value_type,
typename MapConfig::
segment_manager_base> allocator_type;
struct hasher
: std::unary_function<key_type, std::size_t>
{
std::size_t operator()(const key_type &val) const
{
typedef typename key_type::char_type char_type;
const char_type *beg = ipcdetail::get_pointer(val.mp_str),
*end = beg + val.m_len;
return boost::hash_range(beg, end);
}
};
typedef unordered_map<key_type, mapped_type, hasher,
key_equal, allocator_type> index_t;
};
///@endcond
//!Index type based in unordered_map. Just derives from unordered_map and
//!defines the interface needed by managed memory segments
template <class MapConfig>
class unordered_map_index
//Derive class from unordered_map specialization
: public unordered_map_index_aux<MapConfig>::index_t
{
/// @cond
typedef unordered_map_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t base_type;
typedef typename
MapConfig::segment_manager_base segment_manager_base;
/// @endcond
public:
//!Constructor. Takes a pointer to the
//!segment manager. Can throw
unordered_map_index(segment_manager_base *segment_mngr)
: base_type(0,
typename index_aux::hasher(),
typename index_aux::key_equal(),
segment_mngr){}
//!This reserves memory to optimize the insertion of n
//!elements in the index
void reserve(typename segment_manager_base::size_type n)
{ base_type::rehash(n); }
//!This tries to free previously allocate
//!unused memory.
void shrink_to_fit()
{ base_type::rehash(base_type::size()); }
};
/// @cond
//!Trait class to detect if an index is a node
//!index. This allows more efficient operations
//!when deallocating named objects.
template<class MapConfig>
struct is_node_index
<boost::interprocess::unordered_map_index<MapConfig> >
{
enum { value = true };
};
/// @endcond
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_UNORDERED_MAP_INDEX_HPP

View File

@@ -0,0 +1,439 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_FWD_HPP
#define BOOST_INTERPROCESS_FWD_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 <cstddef>
//////////////////////////////////////////////////////////////////////////////
// Standard predeclarations
//////////////////////////////////////////////////////////////////////////////
/// @cond
namespace boost{
namespace intrusive{
}}
namespace boost{
namespace interprocess{
namespace bi = boost::intrusive;
}}
#ifndef _LIBCPP_VERSION
namespace std {
template <class T>
class allocator;
template <class T>
struct less;
template <class T1, class T2>
struct pair;
template <class CharType>
struct char_traits;
} //namespace std {
#else
#include <utility>
#include <memory>
#include <functional>
#include <iosfwd>
#endif
/// @endcond
namespace boost { namespace interprocess {
//////////////////////////////////////////////////////////////////////////////
// permissions
//////////////////////////////////////////////////////////////////////////////
class permissions;
//////////////////////////////////////////////////////////////////////////////
// shared_memory
//////////////////////////////////////////////////////////////////////////////
class shared_memory_object;
#if defined (BOOST_INTERPROCESS_WINDOWS) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
class windows_shared_memory;
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
//////////////////////////////////////////////////////////////////////////////
// mapped file/mapped region/mapped_file
//////////////////////////////////////////////////////////////////////////////
class file_mapping;
class mapped_region;
class mapped_file;
//////////////////////////////////////////////////////////////////////////////
// Mutexes
//////////////////////////////////////////////////////////////////////////////
class null_mutex;
class interprocess_mutex;
class interprocess_recursive_mutex;
class named_mutex;
class named_recursive_mutex;
class interprocess_semaphore;
class named_semaphore;
//////////////////////////////////////////////////////////////////////////////
// Mutex families
//////////////////////////////////////////////////////////////////////////////
struct mutex_family;
struct null_mutex_family;
//////////////////////////////////////////////////////////////////////////////
// Other synchronization classes
//////////////////////////////////////////////////////////////////////////////
class barrier;
class interprocess_sharable_mutex;
class interprocess_condition;
//////////////////////////////////////////////////////////////////////////////
// Locks
//////////////////////////////////////////////////////////////////////////////
template <class Mutex>
class scoped_lock;
template <class SharableMutex>
class sharable_lock;
template <class UpgradableMutex>
class upgradable_lock;
//////////////////////////////////////////////////////////////////////////////
// STL compatible allocators
//////////////////////////////////////////////////////////////////////////////
template<class T, class SegmentManager>
class allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64>
class node_allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64>
class private_node_allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64>
class cached_node_allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class adaptive_pool;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class private_adaptive_pool;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class cached_adaptive_pool;
//////////////////////////////////////////////////////////////////////////////
// offset_ptr
//////////////////////////////////////////////////////////////////////////////
static const std::size_t offset_type_alignment = 0;
template <class T, class DifferenceType = std::ptrdiff_t, class OffsetType = std::size_t, std::size_t Alignment = offset_type_alignment>
class offset_ptr;
//////////////////////////////////////////////////////////////////////////////
// Memory allocation algorithms
//////////////////////////////////////////////////////////////////////////////
//Single segment memory allocation algorithms
template<class MutexFamily, class VoidMutex = offset_ptr<void> >
class simple_seq_fit;
template<class MutexFamily, class VoidMutex = offset_ptr<void>, std::size_t MemAlignment = 0>
class rbtree_best_fit;
//////////////////////////////////////////////////////////////////////////////
// Index Types
//////////////////////////////////////////////////////////////////////////////
template<class IndexConfig> class flat_map_index;
template<class IndexConfig> class iset_index;
template<class IndexConfig> class iunordered_set_index;
template<class IndexConfig> class map_index;
template<class IndexConfig> class null_index;
template<class IndexConfig> class unordered_map_index;
//////////////////////////////////////////////////////////////////////////////
// Segment manager
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class segment_manager;
//////////////////////////////////////////////////////////////////////////////
// External buffer managed memory classes
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_external_buffer;
typedef basic_managed_external_buffer
<char
,rbtree_best_fit<null_mutex_family>
,iset_index>
managed_external_buffer;
typedef basic_managed_external_buffer
<wchar_t
,rbtree_best_fit<null_mutex_family>
,iset_index>
wmanaged_external_buffer;
//////////////////////////////////////////////////////////////////////////////
// managed memory classes
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_shared_memory;
typedef basic_managed_shared_memory
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_shared_memory;
typedef basic_managed_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_shared_memory;
//////////////////////////////////////////////////////////////////////////////
// Windows shared memory managed memory classes
//////////////////////////////////////////////////////////////////////////////
#if defined (BOOST_INTERPROCESS_WINDOWS) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_windows_shared_memory;
typedef basic_managed_windows_shared_memory
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_windows_shared_memory;
typedef basic_managed_windows_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_windows_shared_memory;
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_xsi_shared_memory;
typedef basic_managed_xsi_shared_memory
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_xsi_shared_memory;
typedef basic_managed_xsi_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_xsi_shared_memory;
#endif //#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS)
//////////////////////////////////////////////////////////////////////////////
// Fixed address shared memory
//////////////////////////////////////////////////////////////////////////////
typedef basic_managed_shared_memory
<char
,rbtree_best_fit<mutex_family, void*>
,iset_index>
fixed_managed_shared_memory;
typedef basic_managed_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family, void*>
,iset_index>
wfixed_managed_shared_memory;
//////////////////////////////////////////////////////////////////////////////
// Heap memory managed memory classes
//////////////////////////////////////////////////////////////////////////////
template
<class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_heap_memory;
typedef basic_managed_heap_memory
<char
,rbtree_best_fit<null_mutex_family>
,iset_index>
managed_heap_memory;
typedef basic_managed_heap_memory
<wchar_t
,rbtree_best_fit<null_mutex_family>
,iset_index>
wmanaged_heap_memory;
//////////////////////////////////////////////////////////////////////////////
// Mapped file managed memory classes
//////////////////////////////////////////////////////////////////////////////
template
<class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_mapped_file;
typedef basic_managed_mapped_file
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_mapped_file;
typedef basic_managed_mapped_file
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_mapped_file;
//////////////////////////////////////////////////////////////////////////////
// Exceptions
//////////////////////////////////////////////////////////////////////////////
class interprocess_exception;
class lock_exception;
class bad_alloc;
//////////////////////////////////////////////////////////////////////////////
// Bufferstream
//////////////////////////////////////////////////////////////////////////////
//bufferstream
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_bufferbuf;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_ibufferstream;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_obufferstream;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_bufferstream;
//////////////////////////////////////////////////////////////////////////////
// Vectorstream
//////////////////////////////////////////////////////////////////////////////
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_vectorbuf;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_ivectorstream;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_ovectorstream;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_vectorstream;
//////////////////////////////////////////////////////////////////////////////
// Smart pointers
//////////////////////////////////////////////////////////////////////////////
template<class T, class Deleter>
class scoped_ptr;
template<class T, class VoidPointer>
class intrusive_ptr;
template<class T, class VoidAllocator, class Deleter>
class shared_ptr;
template<class T, class VoidAllocator, class Deleter>
class weak_ptr;
//////////////////////////////////////////////////////////////////////////////
// IPC
//////////////////////////////////////////////////////////////////////////////
template<class VoidPointer>
class message_queue_t;
typedef message_queue_t<offset_ptr<void> > message_queue;
}} //namespace boost { namespace interprocess {
//////////////////////////////////////////////////////////////////////////////
// CONTAINERS
//////////////////////////////////////////////////////////////////////////////
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_FWD_HPP

View File

@@ -0,0 +1,693 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MESSAGE_QUEUE_HPP
#define BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <algorithm> //std::lower_bound
#include <cstddef> //std::size_t
#include <cstring> //memcpy
//!\file
//!Describes an inter-process message queue. This class allows sending
//!messages between processes and allows blocking, non-blocking and timed
//!sending and receiving.
namespace boost{ namespace interprocess{
//!A class that allows sending messages
//!between processes.
template<class VoidPointer>
class message_queue_t
{
/// @cond
//Blocking modes
enum block_t { blocking, timed, non_blocking };
message_queue_t();
/// @endcond
public:
typedef VoidPointer void_pointer;
typedef typename boost::pointer_to_other<void_pointer, char>::type char_ptr;
typedef typename std::iterator_traits<char_ptr>::difference_type difference_type;
typedef typename boost::make_unsigned<difference_type>::type size_type;
//!Creates a process shared message queue with name "name". For this message queue,
//!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,
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
//!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,
size_type max_msg_size,
const permissions &perm = permissions());
//!Opens a previously created process shared message queue with name "name".
//!If the was not previously created or there are no free resources,
//!throws an error.
message_queue_t(open_only_t open_only,
const char *name);
//!Destroys *this and indicates that the calling process is finished using
//!the resource. All opened message queues are still
//!valid after destruction. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!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();
//!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,
unsigned int priority);
//!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,
unsigned int priority);
//!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,
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
//!"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,
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
//!"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,
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
//!"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,
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.
//!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.
//!Never throws
size_type get_max_msg_size() const;
//!Returns the number of messages currently stored.
//!Never throws
size_type get_num_msg();
//!Removes the message queue from the system.
//!Returns false on error. Never throws
static bool remove(const char *name);
/// @cond
private:
typedef boost::posix_time::ptime ptime;
bool do_receive(block_t block,
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,
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;
/// @endcond
};
/// @cond
namespace ipcdetail {
//!This header is the prefix of each message in the queue
template<class VoidPointer>
class msg_hdr_t
{
typedef VoidPointer void_pointer;
typedef typename boost::
pointer_to_other<VoidPointer, char>::type char_ptr;
typedef typename std::iterator_traits<char_ptr>::difference_type difference_type;
typedef typename boost::make_unsigned<difference_type>::type size_type;
public:
size_type len; // Message length
unsigned int priority;// Message priority
//!Returns the data buffer associated with this this message
void * data(){ return this+1; } //
};
//!This functor is the predicate to order stored messages by priority
template<class VoidPointer>
class priority_functor
{
typedef typename boost::
pointer_to_other<VoidPointer, msg_hdr_t<VoidPointer> >::type msg_hdr_ptr_t;
public:
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
//!in the following way: in ascending memory address with proper alignment
//!fillings:
//!
//!-> 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
//! reordered in runtime in the following way:
//!
//! 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
//! 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
//! message queue.
//!
//!-> struct message_t
//! {
//! msg_hdr_t header;
//! char[max_msg_size] data;
//! } messages [max_num_msg];
//!
//! An array of buffers of preallocated messages, each one prefixed with the
//! msg_hdr_t structure. Each of this message is pointed by one pointer of
//! the index structure.
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::
pointer_to_other<void_pointer, msg_header>::type msg_hdr_ptr_t;
typedef typename std::iterator_traits<msg_hdr_ptr_t>::difference_type difference_type;
typedef typename boost::make_unsigned<difference_type>::type size_type;
typedef typename boost::
pointer_to_other<void_pointer, msg_hdr_ptr_t>::type msg_hdr_ptr_ptr_t;
public:
//!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.*/
mq_hdr_t(size_type max_num_msg, size_type max_msg_size)
: m_max_num_msg(max_num_msg),
m_max_msg_size(max_msg_size),
m_cur_num_msg(0)
{ 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; }
//!Returns true if the message queue is empty
bool is_empty() const
{ return !m_cur_num_msg; }
//!Frees the top priority message and saves it in the free message list
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(); }
//!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;
}
//!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
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_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;
}
//!Initializes the memory structures to preallocate messages and constructs the
//!message index. Never throws.
void initialize_memory()
{
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_max_msg_size = ipcdetail::get_rounded_size(m_max_msg_size, msg_hdr_align) + sizeof(msg_header);
//Pointer to the index
msg_hdr_ptr_t *index = reinterpret_cast<msg_hdr_ptr_t*>
(reinterpret_cast<char*>(this)+r_hdr_size);
//Pointer to the first message header
msg_header *msg_hdr = reinterpret_cast<msg_header*>
(reinterpret_cast<char*>(this)+r_hdr_size+r_index_size);
//Initialize the pointer to the index
mp_index = index;
//Initialize the index so each slot points to a preallocated message
for(size_type i = 0; i < m_max_num_msg; ++i){
index[i] = msg_hdr;
msg_hdr = reinterpret_cast<msg_header*>
(reinterpret_cast<char*>(msg_hdr)+r_max_msg_size);
}
}
public:
//Pointer to the index
msg_hdr_ptr_ptr_t mp_index;
//Maximum number of messages of the queue
const size_type m_max_num_msg;
//Maximum size of messages of the queue
const size_type m_max_msg_size;
//Current number of messages
size_type m_cur_num_msg;
//Mutex to protect data structures
interprocess_mutex m_mutex;
//Condition block receivers when there are no messages
interprocess_condition m_cond_recv;
//Condition block senders when the queue is full
interprocess_condition m_cond_send;
};
//!This is the atomic functor to be executed when creating or opening
//!shared memory. Never throws
template<class VoidPointer>
class initialization_func_t
{
public:
typedef typename boost::pointer_to_other<VoidPointer, char>::type char_ptr;
typedef typename std::iterator_traits<char_ptr>::difference_type difference_type;
typedef typename boost::make_unsigned<difference_type>::type size_type;
initialization_func_t(size_type maxmsg = 0,
size_type maxmsgsize = 0)
: m_maxmsg (maxmsg), m_maxmsgsize(maxmsgsize) {}
bool operator()(void *address, size_type, bool created)
{
char *mptr;
if(created){
mptr = reinterpret_cast<char*>(address);
//Construct the message queue header at the beginning
BOOST_TRY{
new (mptr) mq_hdr_t<VoidPointer>(m_maxmsg, m_maxmsgsize);
}
BOOST_CATCH(...){
return false;
}
BOOST_CATCH_END
}
return true;
}
const size_type m_maxmsg;
const size_type m_maxmsgsize;
};
} //namespace ipcdetail {
template<class VoidPointer>
inline message_queue_t<VoidPointer>::~message_queue_t()
{}
template<class VoidPointer>
inline typename message_queue_t<VoidPointer>::size_type message_queue_t<VoidPointer>::get_mem_size
(size_type max_msg_size, size_type max_num_msg)
{ 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,
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,
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_only_t open_only,
const char *name)
//Create shared memory and execute functor atomically
: m_shmem(open_only,
name,
read_write,
static_cast<void*>(0),
//Prepare initialization functor
ipcdetail::initialization_func_t<VoidPointer> ())
{}
template<class VoidPointer>
inline void message_queue_t<VoidPointer>::send
(const void *buffer, size_type buffer_size, unsigned int priority)
{ this->do_send(blocking, buffer, buffer_size, priority, ptime()); }
template<class VoidPointer>
inline bool message_queue_t<VoidPointer>::try_send
(const void *buffer, size_type buffer_size, unsigned int priority)
{ return this->do_send(non_blocking, buffer, buffer_size, priority, ptime()); }
template<class VoidPointer>
inline bool message_queue_t<VoidPointer>::timed_send
(const void *buffer, size_type buffer_size
,unsigned int priority, const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->send(buffer, buffer_size, priority);
return true;
}
return this->do_send(timed, buffer, buffer_size, priority, abs_time);
}
template<class VoidPointer>
inline bool message_queue_t<VoidPointer>::do_send(block_t block,
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());
//Check if buffer is smaller than maximum allowed
if (buffer_size > p_hdr->m_max_msg_size) {
throw interprocess_exception(size_error);
}
//---------------------------------------------
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;
break;
case blocking :
do{
p_hdr->m_cond_send.wait(lock);
}
while (p_hdr->is_full());
break;
case timed :
do{
if(!p_hdr->m_cond_send.timed_wait(lock, abs_time)){
if(p_hdr->is_full())
return false;
break;
}
}
while (p_hdr->is_full());
break;
default:
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");
}
//Copy control data to the free message
free_msg->priority = priority;
free_msg->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();
// }
} // Lock end
return true;
}
template<class VoidPointer>
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,
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,
size_type &recvd_size, unsigned int &priority,
const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->receive(buffer, buffer_size, recvd_size, priority);
return true;
}
return this->do_receive(timed, buffer, buffer_size, recvd_size, priority, abs_time);
}
template<class VoidPointer>
inline bool
message_queue_t<VoidPointer>::do_receive(block_t block,
void *buffer, size_type buffer_size,
size_type &recvd_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());
//Check if buffer is big enough for any message
if (buffer_size < p_hdr->m_max_msg_size) {
throw interprocess_exception(size_error);
}
//---------------------------------------------
scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
//---------------------------------------------
{
//If there are no messages execute blocking logic
if (p_hdr->is_empty()) {
switch(block){
case non_blocking :
return false;
break;
case blocking :
do{
p_hdr->m_cond_recv.wait(lock);
}
while (p_hdr->is_empty());
break;
case timed :
do{
if(!p_hdr->m_cond_recv.timed_wait(lock, abs_time)){
if(p_hdr->is_empty())
return false;
break;
}
}
while (p_hdr->is_empty());
break;
//Paranoia check
default:
break;
}
}
//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");
}
//Get data from the message
recvd_size = top_msg->len;
priority = top_msg->priority;
//Copy data to receiver's bufers
std::memcpy(buffer, top_msg->data(), recvd_size);
// bool 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
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;
}
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){
//---------------------------------------------
scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
//---------------------------------------------
return p_hdr->m_cur_num_msg;
}
return 0;
}
template<class VoidPointer>
inline bool message_queue_t<VoidPointer>::remove(const char *name)
{ return shared_memory_object::remove(name); }
/// @endcond
}} //namespace boost{ namespace interprocess{
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP

View File

@@ -0,0 +1,108 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MANAGED_EXTERNAL_BUFFER_HPP
#define BOOST_INTERPROCESS_MANAGED_EXTERNAL_BUFFER_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/creation_tags.hpp>
#include <boost/interprocess/detail/managed_memory_impl.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/assert.hpp>
//!\file
//!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
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
template
<
class CharType,
class AllocationAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_external_buffer
: public ipcdetail::basic_managed_memory_impl <CharType, AllocationAlgorithm, IndexType>
{
/// @cond
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;
//!Default constructor. Does nothing.
//!Useful in combination with move semantics
basic_managed_external_buffer()
{}
//!Creates and places the segment manager. This can throw
basic_managed_external_buffer
(create_only_t, void *addr, size_type size)
{
//Check if alignment is correct
BOOST_ASSERT((0 == (((std::size_t)addr) & (AllocationAlgorithm::Alignment - size_type(1u)))));
if(!base_t::create_impl(addr, size)){
throw interprocess_exception("Could not initialize buffer in basic_managed_external_buffer constructor");
}
}
//!Creates and places the segment manager. This can throw
basic_managed_external_buffer
(open_only_t, void *addr, size_type size)
{
//Check if alignment is correct
BOOST_ASSERT((0 == (((std::size_t)addr) & (AllocationAlgorithm::Alignment - size_type(1u)))));
if(!base_t::open_impl(addr, size)){
throw interprocess_exception("Could not initialize buffer in basic_managed_external_buffer constructor");
}
}
//!Moves the ownership of "moved"'s managed memory to *this. Does not throw
basic_managed_external_buffer(BOOST_RV_REF(basic_managed_external_buffer) moved)
{
this->swap(moved);
}
//!Moves the ownership of "moved"'s managed memory to *this. Does not throw
basic_managed_external_buffer &operator=(BOOST_RV_REF(basic_managed_external_buffer) moved)
{
basic_managed_external_buffer tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
void grow(size_type extra_bytes)
{ base_t::grow(extra_bytes); }
//!Swaps the ownership of the managed heap memories managed by *this and other.
//!Never throws.
void swap(basic_managed_external_buffer &other)
{ base_t::swap(other); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_EXTERNAL_BUFFER_HPP

View File

@@ -0,0 +1,143 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MANAGED_HEAP_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_HEAP_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/creation_tags.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <vector>
#include <boost/interprocess/detail/managed_memory_impl.hpp>
#include <boost/detail/no_exceptions_support.hpp>
//!\file
//!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
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
template
<
class CharType,
class AllocationAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_heap_memory
: public ipcdetail::basic_managed_memory_impl <CharType, AllocationAlgorithm, IndexType>
{
/// @cond
private:
typedef ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType> base_t;
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_heap_memory)
/// @endcond
public: //functions
typedef typename base_t::size_type size_type;
//!Default constructor. Does nothing.
//!Useful in combination with move semantics
basic_managed_heap_memory(){}
//!Destructor. Liberates the heap memory holding the managed data.
//!Never throws.
~basic_managed_heap_memory()
{ this->priv_close(); }
//!Creates heap memory and initializes the segment manager.
//!This can throw.
basic_managed_heap_memory(size_type size)
: m_heapmem(size, char(0))
{
if(!base_t::create_impl(&m_heapmem[0], size)){
this->priv_close();
throw interprocess_exception("Could not initialize heap in basic_managed_heap_memory constructor");
}
}
//!Moves the ownership of "moved"'s managed memory to *this. Does not throw
basic_managed_heap_memory(BOOST_RV_REF(basic_managed_heap_memory) moved)
{ this->swap(moved); }
//!Moves the ownership of "moved"'s managed memory to *this. Does not throw
basic_managed_heap_memory &operator=(BOOST_RV_REF(basic_managed_heap_memory) moved)
{
basic_managed_heap_memory tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Tries to resize internal heap memory so that
//!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
//!false, the heap allocation has failed.
bool grow(size_type extra_bytes)
{
//If memory is reallocated, data will
//be automatically copied
BOOST_TRY{
m_heapmem.resize(m_heapmem.size()+extra_bytes);
}
BOOST_CATCH(...){
return false;
}
BOOST_CATCH_END
//Grow always works
base_t::close_impl();
base_t::open_impl(&m_heapmem[0], m_heapmem.size());
base_t::grow(extra_bytes);
return true;
}
//!Swaps the ownership of the managed heap memories managed by *this and other.
//!Never throws.
void swap(basic_managed_heap_memory &other)
{
base_t::swap(other);
m_heapmem.swap(other.m_heapmem);
}
/// @cond
private:
//!Frees resources. Never throws.
void priv_close()
{
base_t::destroy_impl();
std::vector<char>().swap(m_heapmem);
}
std::vector<char> m_heapmem;
/// @endcond
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_HEAP_MEMORY_HPP

View File

@@ -0,0 +1,207 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MANAGED_MAPPED_FILE_HPP
#define BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_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_open_or_create_impl.hpp>
#include <boost/interprocess/detail/managed_memory_impl.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/file_wrapper.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/permissions.hpp>
namespace boost {
namespace interprocess {
//!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,
template<class IndexConfig> class IndexType
>
class basic_managed_mapped_file
: public ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType
,ipcdetail::managed_open_or_create_impl<ipcdetail::file_wrapper>::ManagedOpenOrCreateUserOffset>
{
/// @cond
public:
typedef ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType,
ipcdetail::managed_open_or_create_impl<ipcdetail::file_wrapper>::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> managed_open_or_create_type;
basic_managed_mapped_file *get_this_pointer()
{ return this; }
private:
typedef typename base_t::char_ptr_holder_t char_ptr_holder_t;
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_mapped_file)
/// @endcond
public: //functions
//!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.
//!This can throw.
basic_managed_mapped_file(create_only_t create_only, const char *name,
size_type size, const void *addr = 0, const permissions &perm = permissions())
: m_mfile(create_only, name, size, read_write, addr,
create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm)
{}
//!Creates mapped file and creates and places the segment manager if
//!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,
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(),
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,
const void *addr = 0)
: m_mfile(open_only, name, read_write, addr,
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,
const void *addr = 0)
: 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,
const void *addr = 0)
: m_mfile(open_only, name, read_only, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpen))
{}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_mapped_file(BOOST_RV_REF(basic_managed_mapped_file) moved)
{
this->swap(moved);
}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_mapped_file &operator=(BOOST_RV_REF(basic_managed_mapped_file) moved)
{
basic_managed_mapped_file tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Destroys *this and indicates that the calling process is finished using
//!the resource. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~basic_managed_mapped_file()
{}
//!Swaps the ownership of the managed mapped memories managed by *this and other.
//!Never throws.
void swap(basic_managed_mapped_file &other)
{
base_t::swap(other);
m_mfile.swap(other.m_mfile);
}
//!Flushes cached data to file.
//!Never throws
bool flush()
{ return m_mfile.flush(); }
//!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
static bool grow(const char *filename, size_type extra_bytes)
{
return base_t::template grow
<basic_managed_mapped_file>(filename, extra_bytes);
}
//!Tries to resize mapped file to minimized the size of the file.
//!
//!This function is not synchronized so no other thread or process should
//!be reading or writing the file
static bool shrink_to_fit(const char *filename)
{
return base_t::template shrink_to_fit
<basic_managed_mapped_file>(filename);
}
/// @cond
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find (char_ptr_holder_t name)
{
if(m_mfile.get_mapped_region().get_mode() == read_only){
return base_t::template find_no_lock<T>(name);
}
else{
return base_t::template find<T>(name);
}
}
private:
managed_open_or_create_type m_mfile;
/// @endcond
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP

View File

@@ -0,0 +1,215 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MANAGED_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_SHARED_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/detail/managed_memory_impl.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/permissions.hpp>
namespace boost {
namespace interprocess {
//!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,
template<class IndexConfig> class IndexType
>
class basic_managed_shared_memory
: public ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType
,ipcdetail::managed_open_or_create_impl<shared_memory_object>::ManagedOpenOrCreateUserOffset>
, private ipcdetail::managed_open_or_create_impl<shared_memory_object>
{
/// @cond
typedef ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType,
ipcdetail::managed_open_or_create_impl<shared_memory_object>::ManagedOpenOrCreateUserOffset> base_t;
typedef ipcdetail::managed_open_or_create_impl
<shared_memory_object> base2_t;
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
basic_managed_shared_memory *get_this_pointer()
{ return this; }
public:
typedef shared_memory_object device_type;
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_shared_memory)
/// @endcond
public: //functions
//!Destroys *this and indicates that the calling process is finished using
//!the resource. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~basic_managed_shared_memory()
{}
//!Default constructor. Does nothing.
//!Useful in combination with move semantics
basic_managed_shared_memory()
{}
//!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,
size_type size, const void *addr = 0, const permissions& perm = permissions())
: base_t()
, base2_t(create_only, name, size, read_write, addr,
create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm)
{}
//!Creates shared memory and creates and places the segment manager if
//!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,
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(),
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,
const void *addr = 0)
: base_t()
, 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,
const void *addr = 0)
: base_t()
, 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,
const void *addr = 0)
: base_t()
, base2_t(open_only, name, read_write, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpen))
{}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_shared_memory(BOOST_RV_REF(basic_managed_shared_memory) moved)
{
basic_managed_shared_memory tmp;
this->swap(moved);
tmp.swap(moved);
}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_shared_memory &operator=(BOOST_RV_REF(basic_managed_shared_memory) moved)
{
basic_managed_shared_memory tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps the ownership of the managed shared memories managed by *this and other.
//!Never throws.
void swap(basic_managed_shared_memory &other)
{
base_t::swap(other);
base2_t::swap(other);
}
//!Tries to resize the managed shared memory object 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
static bool grow(const char *shmname, size_type extra_bytes)
{
return base_t::template grow
<basic_managed_shared_memory>(shmname, extra_bytes);
}
//!Tries to resize the managed shared memory to minimized the size of the file.
//!
//!This function is not synchronized so no other thread or process should
//!be reading or writing the file
static bool shrink_to_fit(const char *shmname)
{
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
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find (char_ptr_holder_t name)
{
if(base2_t::get_mapped_region().get_mode() == read_only){
return base_t::template find_no_lock<T>(name);
}
else{
return base_t::template find<T>(name);
}
}
/// @endcond
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP

View File

@@ -0,0 +1,183 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MANAGED_WINDOWS_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_WINDOWS_SHARED_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/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/detail/managed_memory_impl.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/windows_shared_memory.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/interprocess/detail/move.hpp>
namespace boost {
namespace interprocess {
//!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
//!when all processes destroy all their windows_shared_memory
//!objects and mapped regions for the same shared memory
//!or the processes end/crash.
//!
//!Warning: basic_managed_windows_shared_memory and
//!basic_managed_shared_memory can't communicate between them.
template
<
class CharType,
class AllocationAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_windows_shared_memory
: public ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType
,ipcdetail::managed_open_or_create_impl<windows_shared_memory>::ManagedOpenOrCreateUserOffset>
{
/// @cond
private:
typedef ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType,
ipcdetail::managed_open_or_create_impl<windows_shared_memory>::ManagedOpenOrCreateUserOffset> base_t;
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
basic_managed_windows_shared_memory *get_this_pointer()
{ return this; }
private:
typedef typename base_t::char_ptr_holder_t char_ptr_holder_t;
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_windows_shared_memory)
/// @endcond
public: //functions
typedef typename base_t::size_type size_type;
//!Default constructor. Does nothing.
//!Useful in combination with move semantics
basic_managed_windows_shared_memory()
{}
//!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,
size_type size, const void *addr = 0, const permissions &perm = permissions())
: m_wshm(create_only, name, size, read_write, addr,
create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm)
{}
//!Creates shared memory and creates and places the segment manager if
//!segment was not created. If segment was created it connects to the
//!segment.
//!This can throw.
basic_managed_windows_shared_memory
(open_or_create_t open_or_create,
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(),
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(),
ipcdetail::DoOpen))
{}
//!Connects to a created shared memory and its segment manager
//!in copy_on_write mode.
//!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,
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_windows_shared_memory
(open_read_only_t, const char* name, const void *addr = 0)
: base_t()
, m_wshm(open_only, name, read_only, addr,
create_open_func_t(get_this_pointer(), ipcdetail::DoOpen))
{}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_windows_shared_memory
(BOOST_RV_REF(basic_managed_windows_shared_memory) moved)
{ this->swap(moved); }
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_windows_shared_memory &operator=(BOOST_RV_REF(basic_managed_windows_shared_memory) moved)
{
basic_managed_windows_shared_memory tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Destroys *this and indicates that the calling process is finished using
//!the resource. All mapped regions are still valid after
//!destruction. When all mapped regions and basic_managed_windows_shared_memory
//!objects referring the shared memory are destroyed, the
//!operating system will destroy the shared memory.
~basic_managed_windows_shared_memory()
{}
//!Swaps the ownership of the managed mapped memories managed by *this and other.
//!Never throws.
void swap(basic_managed_windows_shared_memory &other)
{
base_t::swap(other);
m_wshm.swap(other.m_wshm);
}
/// @cond
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find (char_ptr_holder_t name)
{
if(m_wshm.get_mapped_region().get_mode() == read_only){
return base_t::template find_no_lock<T>(name);
}
else{
return base_t::template find<T>(name);
}
}
private:
ipcdetail::managed_open_or_create_impl<windows_shared_memory, false> m_wshm;
/// @endcond
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_WINDOWS_SHARED_MEMORY_HPP

View File

@@ -0,0 +1,190 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. 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_MANAGED_XSI_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_XSI_SHARED_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>
#if !defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS)
#error "This header can't be used in operating systems without XSI (System V) shared memory support"
#endif
#include <boost/interprocess/detail/managed_memory_impl.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/detail/xsi_shared_memory_file_wrapper.hpp>
#include <boost/interprocess/creation_tags.hpp>
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>*/
template
<
class CharType,
class AllocationAlgorithm,
template<class IndexConfig> class IndexType
>
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, false, true>::ManagedOpenOrCreateUserOffset>
, private ipcdetail::managed_open_or_create_impl<xsi_shared_memory_file_wrapper, false, true>
{
/// @cond
public:
typedef xsi_shared_memory_file_wrapper device_type;
public:
typedef ipcdetail::managed_open_or_create_impl
<xsi_shared_memory_file_wrapper, false, true> base2_t;
typedef ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType,
base2_t::ManagedOpenOrCreateUserOffset> base_t;
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
basic_managed_xsi_shared_memory *get_this_pointer()
{ return this; }
private:
typedef typename base_t::char_ptr_holder_t char_ptr_holder_t;
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_xsi_shared_memory)
/// @endcond
public: //functions
typedef typename base_t::size_type size_type;
//!Destroys *this and indicates that the calling process is finished using
//!the resource. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~basic_managed_xsi_shared_memory()
{}
//!Default constructor. Does nothing.
//!Useful in combination with move semantics
basic_managed_xsi_shared_memory()
{}
//!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,
std::size_t size, const void *addr = 0, const permissions& perm = permissions())
: base_t()
, base2_t(create_only, key, size, read_write, addr,
create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm)
{}
//!Creates shared memory and creates and places the segment manager if
//!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,
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(),
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,
const void *addr = 0)
: base_t()
, 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,
const void *addr = 0)
: base_t()
, base2_t(open_only, key, read_write, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpen))
{}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_xsi_shared_memory(BOOST_RV_REF(basic_managed_xsi_shared_memory) moved)
{
basic_managed_xsi_shared_memory tmp;
this->swap(moved);
tmp.swap(moved);
}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_xsi_shared_memory &operator=(BOOST_RV_REF(basic_managed_xsi_shared_memory) moved)
{
basic_managed_xsi_shared_memory tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps the ownership of the managed shared memories managed by *this and other.
//!Never throws.
void swap(basic_managed_xsi_shared_memory &other)
{
base_t::swap(other);
base2_t::swap(other);
}
//!Erases a XSI shared memory object identified by shmid
//!from the system.
//!Returns false on error. Never throws
static bool remove(int shmid)
{ return device_type::remove(shmid); }
int get_shmid() const
{ return base2_t::get_device().get_shmid(); }
/// @cond
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, std::size_t> find (char_ptr_holder_t name)
{
if(base2_t::get_mapped_region().get_mode() == read_only){
return base_t::template find_no_lock<T>(name);
}
else{
return base_t::template find<T>(name);
}
}
/// @endcond
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_XSI_SHARED_MEMORY_HPP

View File

@@ -0,0 +1,609 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MAPPED_REGION_HPP
#define BOOST_INTERPROCESS_MAPPED_REGION_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <string>
#include <limits>
#if (defined BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <fcntl.h>
# include <sys/mman.h> //mmap
# include <unistd.h>
# include <sys/stat.h>
# include <sys/types.h>
# if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS)
# include <sys/shm.h> //System V shared memory...
# endif
# include <boost/assert.hpp>
# else
# error Unknown platform
# endif
#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
//!\file
//!Describes mapped region class
namespace boost {
namespace interprocess {
/// @cond
namespace ipcdetail{ class interprocess_tester; }
namespace ipcdetail{ class raw_mapped_region_creator; }
/// @endcond
//!The mapped_region class represents a portion or region created from a
//!memory_mappable object.
class mapped_region
{
/// @cond
//Non-copyable
BOOST_MOVABLE_BUT_NOT_COPYABLE(mapped_region)
/// @endcond
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.
template<class MemoryMappable>
mapped_region(const MemoryMappable& mapping
,mode_t mode
,offset_t offset = 0
,std::size_t size = 0
,const void *address = 0);
//!Default constructor. Address and size and offset will be 0.
//!Does not throw
mapped_region();
//!Move constructor. *this will be constructed taking ownership of "other"'s
//!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_mode(read_only)
, m_file_mapping_hnd(ipcdetail::invalid_file())
#else
: m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only), m_is_xsi(false)
#endif
{ this->swap(other); }
//!Destroys the mapped region.
//!Does not throw
~mapped_region();
//!Move assignment. If *this owns a memory mapped region, it will be
//!destroyed and it will take ownership of "other"'s memory mapped region.
mapped_region &operator=(BOOST_RV_REF(mapped_region) other)
{
mapped_region tmp(boost::interprocess::move(other));
this->swap(tmp);
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.
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.
//!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);
//!Swaps the mapped_region with another
//!mapped region
void swap(mapped_region &other);
//!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.
static std::size_t get_page_size();
/// @cond
private:
//!Closes a previously opened memory mapping. Never throws
void priv_close();
template<int dummy>
struct page_size_holder
{
static const std::size_t PageSize;
static std::size_t get_page_size();
};
void* m_base;
std::size_t m_size;
offset_t m_offset;
offset_t m_extra_offset;
mode_t m_mode;
#if (defined BOOST_INTERPROCESS_WINDOWS)
file_handle_t m_file_mapping_hnd;
#else
bool m_is_xsi;
#endif
friend class ipcdetail::interprocess_tester;
friend class ipcdetail::raw_mapped_region_creator;
void dont_close_on_destruction();
/// @endcond
};
///@cond
inline void swap(mapped_region &x, mapped_region &y)
{ x.swap(y); }
inline mapped_region::~mapped_region()
{ this->priv_close(); }
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; }
#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())
{}
template<int dummy>
inline std::size_t mapped_region::page_size_holder<dummy>::get_page_size()
{
winapi::system_info info;
get_system_info(&info);
return std::size_t(info.dwAllocationGranularity);
}
template<class MemoryMappable>
inline mapped_region::mapped_region
(const MemoryMappable &mapping
,mode_t mode
,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())
{
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);
throw interprocess_exception(err);
}
break;
}
if(!mhandle.is_shm){
//Update mapping size if the user does not specify it
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());
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);
}
//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){
error_info err = winapi::get_last_error();
this->priv_close();
throw interprocess_exception(err);
}
}
//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){
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)
{
//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(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));
}
inline void mapped_region::priv_close()
{
if(m_base){
winapi::unmap_view_of_file(static_cast<char*>(m_base) - m_extra_offset);
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
}
inline void mapped_region::dont_close_on_destruction()
{}
#else //#if (defined BOOST_INTERPROCESS_WINDOWS)
inline mapped_region::mapped_region()
: m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only), m_is_xsi(false)
{}
template<int dummy>
inline std::size_t mapped_region::page_size_holder<dummy>::get_page_size()
{ return std::size_t(sysconf(_SC_PAGESIZE)); }
template<class MemoryMappable>
inline mapped_region::mapped_region
(const MemoryMappable &mapping,
mode_t mode,
offset_t offset,
std::size_t size,
const void *address)
: m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode), m_is_xsi(false)
{
mapping_handle_t map_hnd = mapping.get_mapping_handle();
//Some systems dont' support XSI shared memory
#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
if(map_hnd.is_xsi){
//Get the size
::shmid_ds xsi_ds;
int ret = ::shmctl(map_hnd.handle, IPC_STAT, &xsi_ds);
if(ret == -1){
error_info err(system_error_code());
throw interprocess_exception(err);
}
//Compare sizess
if(size == 0){
size = (std::size_t)xsi_ds.shm_segsz;
}
else if(size != (std::size_t)xsi_ds.shm_segsz){
error_info err(size_error);
throw interprocess_exception(err);
}
//Calculate flag
int flag = 0;
if(m_mode == read_only){
flag |= SHM_RDONLY;
}
else if(m_mode != read_write){
error_info err(mode_error);
throw interprocess_exception(err);
}
//Attach memory
void *base = ::shmat(map_hnd.handle, (void*)address, flag);
if(base == (void*)-1){
error_info err(system_error_code());
throw interprocess_exception(err);
}
//Update members
m_base = base;
m_offset = offset;
m_size = size;
m_mode = mode;
m_extra_offset = 0;
m_is_xsi = true;
return;
}
#endif //ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
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;
}
//Create new mapping
int prot = 0;
int flags = 0;
switch(mode)
{
case read_only:
prot |= PROT_READ;
flags |= MAP_SHARED;
break;
case read_private:
prot |= (PROT_READ);
flags |= MAP_PRIVATE;
break;
case read_write:
prot |= (PROT_WRITE | PROT_READ);
flags |= MAP_SHARED;
break;
case copy_on_write:
prot |= (PROT_WRITE | PROT_READ);
flags |= MAP_PRIVATE;
break;
default:
{
error_info err(mode_error);
throw interprocess_exception(err);
}
break;
}
//We calculate the difference between demanded and valid offset
std::size_t page_size = this->get_page_size();
m_extra_offset = (offset - (offset / page_size) * page_size);
//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;
}
//Map it to the address space
m_base = mmap ( const_cast<void*>(address)
, static_cast<std::size_t>(m_extra_offset + m_size)
, prot
, flags
, mapping.get_mapping_handle().handle
, offset - m_extra_offset);
//Check if mapping was successful
if(m_base == MAP_FAILED){
error_info err = system_error_code();
this->priv_close();
throw interprocess_exception(err);
}
//Calculate new base for the user
const void *old_base = m_base;
m_base = static_cast<char*>(m_base) + m_extra_offset;
m_offset = offset;
m_size = size;
//Check for fixed mapping error
if(address && (old_base != address)){
error_info err(busy_error);
this->priv_close();
throw interprocess_exception(err);
}
}
inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes)
{
if(mapping_offset >= m_size || (mapping_offset+numbytes)> m_size){
return false;
}
if(numbytes == 0){
numbytes = m_size - mapping_offset;
}
//Flush it all
return msync(static_cast<char*>(m_base)+mapping_offset,
numbytes, MS_ASYNC) == 0;
}
inline void mapped_region::priv_close()
{
if(m_base != MAP_FAILED){
#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
if(m_is_xsi){
int ret = ::shmdt(m_base);
BOOST_ASSERT(ret == 0);
(void)ret;
return;
}
#endif //#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS
munmap(static_cast<char*>(m_base) - m_extra_offset, m_size + m_extra_offset);
m_base = MAP_FAILED;
}
}
inline void mapped_region::dont_close_on_destruction()
{ m_base = MAP_FAILED; }
#endif //##if (defined BOOST_INTERPROCESS_WINDOWS)
template<int dummy>
const std::size_t mapped_region::page_size_holder<dummy>::PageSize
= mapped_region::page_size_holder<dummy>::get_page_size();
inline std::size_t mapped_region::get_page_size()
{
if(!page_size_holder<0>::PageSize)
return page_size_holder<0>::get_page_size();
else
return page_size_holder<0>::PageSize;
}
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_mode, other.m_mode);
#if (defined BOOST_INTERPROCESS_WINDOWS)
ipcdetail::do_swap(this->m_file_mapping_hnd, other.m_file_mapping_hnd);
#else
ipcdetail::do_swap(this->m_is_xsi, other.m_is_xsi);
#endif
}
//!No-op functor
struct null_mapped_region_function
{
bool operator()(void *, std::size_t , bool) const
{ return true; }
};
/// @endcond
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MAPPED_REGION_HPP

View File

@@ -0,0 +1,554 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP
#define BOOST_INTERPROCESS_DETAIL_MEM_ALGO_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/interprocess_fwd.hpp>
#include <boost/interprocess/containers/allocation_type.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/math_functions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/detail/min_max.hpp>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <algorithm>
#include <utility>
#include <iterator>
#include <boost/assert.hpp>
//!\file
//!Implements common operations for memory algorithms.
namespace boost {
namespace interprocess {
namespace ipcdetail {
//!This class implements several allocation functions shared by different algorithms
//!(aligned allocation, multiple allocation...).
template<class MemoryAlgorithm>
class memory_algorithm_common
{
public:
typedef typename MemoryAlgorithm::void_pointer void_pointer;
typedef typename MemoryAlgorithm::block_ctrl block_ctrl;
typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain;
typedef memory_algorithm_common<MemoryAlgorithm> this_type;
typedef typename MemoryAlgorithm::size_type size_type;
static const size_type Alignment = MemoryAlgorithm::Alignment;
static const size_type MinBlockUnits = MemoryAlgorithm::MinBlockUnits;
static const size_type AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes;
static const size_type AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits;
static const size_type BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes;
static const size_type BlockCtrlUnits = MemoryAlgorithm::BlockCtrlUnits;
static const size_type UsableByPreviousChunk = MemoryAlgorithm::UsableByPreviousChunk;
static void assert_alignment(const void *ptr)
{ assert_alignment((std::size_t)ptr); }
static void assert_alignment(size_type uint_ptr)
{
(void)uint_ptr;
BOOST_ASSERT(uint_ptr % Alignment == 0);
}
static bool check_alignment(const void *ptr)
{ return (((std::size_t)ptr) % Alignment == 0); }
static size_type ceil_units(size_type size)
{ return ipcdetail::get_rounded_size(size, Alignment)/Alignment; }
static size_type floor_units(size_type size)
{ return size/Alignment; }
static size_type multiple_of_units(size_type size)
{ return ipcdetail::get_rounded_size(size, Alignment); }
static multiallocation_chain allocate_many
(MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements)
{
return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0);
}
static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain)
{
return this_type::priv_deallocate_many(memory_algo, boost::interprocess::move(chain));
}
static bool calculate_lcm_and_needs_backwards_lcmed
(size_type backwards_multiple, size_type received_size, size_type size_to_achieve,
size_type &lcm_out, size_type &needs_backwards_lcmed_out)
{
// Now calculate lcm
size_type max = backwards_multiple;
size_type min = Alignment;
size_type needs_backwards;
size_type needs_backwards_lcmed;
size_type lcm;
size_type current_forward;
//Swap if necessary
if(max < min){
size_type tmp = min;
min = max;
max = tmp;
}
//Check if it's power of two
if((backwards_multiple & (backwards_multiple-1)) == 0){
if(0 != (size_to_achieve & ((backwards_multiple-1)))){
return false;
}
lcm = max;
//If we want to use minbytes data to get a buffer between maxbytes
//and minbytes if maxbytes can't be achieved, calculate the
//biggest of all possibilities
current_forward = ipcdetail::get_truncated_size_po2(received_size, backwards_multiple);
needs_backwards = size_to_achieve - current_forward;
BOOST_ASSERT((needs_backwards % backwards_multiple) == 0);
needs_backwards_lcmed = ipcdetail::get_rounded_size_po2(needs_backwards, lcm);
lcm_out = lcm;
needs_backwards_lcmed_out = needs_backwards_lcmed;
return true;
}
//Check if it's multiple of alignment
else if((backwards_multiple & (Alignment - 1u)) == 0){
lcm = backwards_multiple;
current_forward = ipcdetail::get_truncated_size(received_size, backwards_multiple);
//No need to round needs_backwards because backwards_multiple == lcm
needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
BOOST_ASSERT((needs_backwards_lcmed & (Alignment - 1u)) == 0);
lcm_out = lcm;
needs_backwards_lcmed_out = needs_backwards_lcmed;
return true;
}
//Check if it's multiple of the half of the alignmment
else if((backwards_multiple & ((Alignment/2u) - 1u)) == 0){
lcm = backwards_multiple*2u;
current_forward = ipcdetail::get_truncated_size(received_size, backwards_multiple);
needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
if(0 != (needs_backwards_lcmed & (Alignment-1)))
//while(0 != (needs_backwards_lcmed & (Alignment-1)))
needs_backwards_lcmed += backwards_multiple;
BOOST_ASSERT((needs_backwards_lcmed % lcm) == 0);
lcm_out = lcm;
needs_backwards_lcmed_out = needs_backwards_lcmed;
return true;
}
//Check if it's multiple of the half of the alignmment
else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){
size_type remainder;
lcm = backwards_multiple*4u;
current_forward = ipcdetail::get_truncated_size(received_size, backwards_multiple);
needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
//while(0 != (needs_backwards_lcmed & (Alignment-1)))
//needs_backwards_lcmed += backwards_multiple;
if(0 != (remainder = ((needs_backwards_lcmed & (Alignment-1))>>(Alignment/8u)))){
if(backwards_multiple & Alignment/2u){
needs_backwards_lcmed += (remainder)*backwards_multiple;
}
else{
needs_backwards_lcmed += (4-remainder)*backwards_multiple;
}
}
BOOST_ASSERT((needs_backwards_lcmed % lcm) == 0);
lcm_out = lcm;
needs_backwards_lcmed_out = needs_backwards_lcmed;
return true;
}
else{
lcm = ipcdetail::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
//biggest of all possibilities
current_forward = ipcdetail::get_truncated_size(received_size, backwards_multiple);
needs_backwards = size_to_achieve - current_forward;
BOOST_ASSERT((needs_backwards % backwards_multiple) == 0);
needs_backwards_lcmed = ipcdetail::get_rounded_size(needs_backwards, lcm);
lcm_out = lcm;
needs_backwards_lcmed_out = needs_backwards_lcmed;
return true;
}
static multiallocation_chain allocate_many
( MemoryAlgorithm *memory_algo
, const size_type *elem_sizes
, size_type n_elements
, size_type sizeof_element)
{
return this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element);
}
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
BOOST_ASSERT((alignment & (alignment - size_type(1u))) == 0);
return 0;
}
size_type real_size;
if(alignment <= Alignment){
return memory_algo->priv_allocate
(boost::interprocess::allocate_new, nbytes, nbytes, real_size).first;
}
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
(nbytes + alignment, size_type(MinBlockUnits*Alignment));
//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 |
// -----------------------------------------------------
size_type request =
minimum_allocation + (2*MinBlockUnits*Alignment - AllocatedCtrlBytes
//prevsize - UsableByPreviousChunk
);
//Now allocate the buffer
void *buffer = memory_algo->priv_allocate
(boost::interprocess::allocate_new, request, request, real_size).first;
if(!buffer){
return 0;
}
else if ((((std::size_t)(buffer)) % alignment) == 0){
//If we are lucky and the buffer is aligned, just split it and
//return the high part
block_ctrl *first = memory_algo->priv_get_block(buffer);
size_type old_size = first->m_size;
const size_type first_min_units =
max_value(ceil_units(nbytes) + AllocatedCtrlUnits, size_type(MinBlockUnits));
//We can create a new block in the end of the segment
if(old_size >= (first_min_units + MinBlockUnits)){
block_ctrl *second = reinterpret_cast<block_ctrl *>
(reinterpret_cast<char*>(first) + Alignment*first_min_units);
first->m_size = first_min_units;
second->m_size = old_size - first->m_size;
BOOST_ASSERT(second->m_size >= MinBlockUnits);
memory_algo->priv_mark_new_allocated_block(first);
//memory_algo->priv_tail_size(first, first->m_size);
memory_algo->priv_mark_new_allocated_block(second);
memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(second));
}
return buffer;
}
//Buffer not aligned, find the aligned part.
//
// ____ Aligned here
// |
// -----------------------------------------------------
// | MBU +more | ACB |
// -----------------------------------------------------
char *pos = reinterpret_cast<char*>
(reinterpret_cast<std::size_t>(static_cast<char*>(buffer) +
//This is the minimum size of (2)
(MinBlockUnits*Alignment - AllocatedCtrlBytes) +
//This is the next MBU for the aligned memory
AllocatedCtrlBytes +
//This is the alignment trick
alignment - 1) & -alignment);
//Now obtain the address of the blocks
block_ctrl *first = memory_algo->priv_get_block(buffer);
block_ctrl *second = memory_algo->priv_get_block(pos);
BOOST_ASSERT(pos <= (reinterpret_cast<char*>(first) + first->m_size*Alignment));
BOOST_ASSERT(first->m_size >= 2*MinBlockUnits);
BOOST_ASSERT((pos + MinBlockUnits*Alignment - AllocatedCtrlBytes + nbytes*Alignment/Alignment) <=
(reinterpret_cast<char*>(first) + first->m_size*Alignment));
//Set the new size of the first block
size_type old_size = first->m_size;
first->m_size = (size_type)(reinterpret_cast<char*>(second) - reinterpret_cast<char*>(first))/Alignment;
memory_algo->priv_mark_new_allocated_block(first);
//Now check if we can create a new buffer in the end
//
// __"second" block
// | __Aligned here
// | | __"third" block
// -----------|-----|-----|------------------------------
// | MBU +more | ACB | (3) | BCU |
// -----------------------------------------------------
//This size will be the minimum size to be able to create a
//new block in the end.
const size_type second_min_units = max_value(size_type(MinBlockUnits),
ceil_units(nbytes) + AllocatedCtrlUnits );
//Check if we can create a new block (of size MinBlockUnits) in the end of the segment
if((old_size - first->m_size) >= (second_min_units + MinBlockUnits)){
//Now obtain the address of the end block
block_ctrl *third = new (reinterpret_cast<char*>(second) + Alignment*second_min_units)block_ctrl;
second->m_size = second_min_units;
third->m_size = old_size - first->m_size - second->m_size;
BOOST_ASSERT(third->m_size >= MinBlockUnits);
memory_algo->priv_mark_new_allocated_block(second);
memory_algo->priv_mark_new_allocated_block(third);
memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(third));
}
else{
second->m_size = old_size - first->m_size;
BOOST_ASSERT(second->m_size >= MinBlockUnits);
memory_algo->priv_mark_new_allocated_block(second);
}
memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(first));
return memory_algo->priv_get_user_buffer(second);
}
static bool try_shrink
(MemoryAlgorithm *memory_algo, void *ptr
,const size_type max_size, const size_type preferred_size
,size_type &received_size)
{
(void)memory_algo;
//Obtain the real block
block_ctrl *block = memory_algo->priv_get_block(ptr);
size_type old_block_units = (size_type)block->m_size;
//The block must be marked as allocated
BOOST_ASSERT(memory_algo->priv_is_allocated_block(block));
//Check if alignment and block size are right
assert_alignment(ptr);
//Put this to a safe value
received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
//Now translate it to Alignment units
const size_type max_user_units = floor_units(max_size - UsableByPreviousChunk);
const size_type preferred_user_units = ceil_units(preferred_size - UsableByPreviousChunk);
//Check if rounded max and preferred are possible correct
if(max_user_units < preferred_user_units)
return false;
//Check if the block is smaller than the requested minimum
size_type old_user_units = old_block_units - AllocatedCtrlUnits;
if(old_user_units < preferred_user_units)
return false;
//If the block is smaller than the requested minimum
if(old_user_units == preferred_user_units)
return true;
size_type shrunk_user_units =
((BlockCtrlUnits - AllocatedCtrlUnits) > preferred_user_units)
? (BlockCtrlUnits - AllocatedCtrlUnits)
: preferred_user_units;
//Some parameter checks
if(max_user_units < shrunk_user_units)
return false;
//We must be able to create at least a new empty block
if((old_user_units - shrunk_user_units) < BlockCtrlUnits ){
return false;
}
//Update new size
received_size = shrunk_user_units*Alignment + UsableByPreviousChunk;
return true;
}
static bool shrink
(MemoryAlgorithm *memory_algo, void *ptr
,const size_type max_size, const size_type preferred_size
,size_type &received_size)
{
//Obtain the real block
block_ctrl *block = memory_algo->priv_get_block(ptr);
size_type old_block_units = (size_type)block->m_size;
if(!try_shrink
(memory_algo, ptr, max_size, preferred_size, received_size)){
return false;
}
//Check if the old size was just the shrunk size (no splitting)
if((old_block_units - AllocatedCtrlUnits) == ceil_units(preferred_size - UsableByPreviousChunk))
return true;
//Now we can just rewrite the size of the old buffer
block->m_size = (received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits;
BOOST_ASSERT(block->m_size >= BlockCtrlUnits);
//We create the new block
block_ctrl *new_block = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(block) + block->m_size*Alignment);
//Write control data to simulate this new block was previously allocated
//and deallocate it
new_block->m_size = old_block_units - block->m_size;
BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits);
memory_algo->priv_mark_new_allocated_block(block);
memory_algo->priv_mark_new_allocated_block(new_block);
memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(new_block));
return true;
}
private:
static multiallocation_chain priv_allocate_many
( MemoryAlgorithm *memory_algo
, const size_type *elem_sizes
, size_type n_elements
, size_type sizeof_element)
{
//Note: sizeof_element == 0 indicates that we want to
//allocate n_elements of the same size "*elem_sizes"
//Calculate the total size of all requests
size_type total_request_units = 0;
size_type elem_units = 0;
const size_type ptr_size_units = memory_algo->priv_get_total_units(sizeof(void_pointer));
if(!sizeof_element){
elem_units = memory_algo->priv_get_total_units(*elem_sizes);
elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
total_request_units = n_elements*elem_units;
}
else{
for(size_type i = 0; i < n_elements; ++i){
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;
total_request_units += elem_units;
}
}
multiallocation_chain chain;
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)
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);
//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;
//prev_block = new_block;
}
//Sanity check
BOOST_ASSERT(total_used_units == received_units);
}
if(low_idx != n_elements){
priv_deallocate_many(memory_algo, boost::interprocess::move(chain));
}
return boost::interprocess::move(chain);
}
static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain)
{
while(!chain.empty()){
void *addr = ipcdetail::get_pointer(chain.front());
chain.pop_front();
memory_algo->priv_deallocate(addr);
}
}
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP

View File

@@ -0,0 +1,61 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MULTI_SIMPLE_SEQ_FIT_HPP
#define BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp>
#include <boost/interprocess/intersegment_ptr.hpp>
/*!\file
Describes sequential fit algorithm used to allocate objects in shared memory.
*/
namespace boost {
namespace interprocess {
/*!This class implements the simple sequential fit algorithm with a simply
linked list of free buffers.*/
template<class MutexFamily, class VoidPtr>
class multi_simple_seq_fit
: public ipcdetail::simple_seq_fit_impl<MutexFamily, VoidPtr>
{
typedef ipcdetail::simple_seq_fit_impl<MutexFamily, VoidPtr> base_t;
public:
/*!Constructor. "size" is the total size of the managed memory segment,
"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(multi_simple_seq_fit)
offset that the allocator should not use at all.*/
multi_simple_seq_fit (size_type size, size_type extra_hdr_bytes)
: base_t(size, extra_hdr_bytes){}
/*!Allocates bytes from existing segments. If there is no memory, it uses
the growing functor associated with the group to allocate a new segment.
If this fails, returns 0.*/
void* allocate (size_type nbytes)
{ return base_t::multi_allocate(nbytes); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP

View File

@@ -0,0 +1,981 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP
#define BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/containers/allocation_type.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/multi_segment_services.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/type_with_alignment.hpp>
#include <boost/interprocess/detail/min_max.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <algorithm>
#include <utility>
#include <cstring>
#include <boost/assert.hpp>
#include <new>
/*!\file
Describes sequential fit algorithm used to allocate objects in shared memory.
This class is intended as a base class for single segment and multi-segment
implementations.
*/
namespace boost {
namespace interprocess {
namespace ipcdetail {
/*!This class implements the simple sequential fit algorithm with a simply
linked list of free buffers.
This class is intended as a base class for single segment and multi-segment
implementations.*/
template<class MutexFamily, class VoidPointer>
class simple_seq_fit_impl
{
//Non-copyable
simple_seq_fit_impl();
simple_seq_fit_impl(const simple_seq_fit_impl &);
simple_seq_fit_impl &operator=(const simple_seq_fit_impl &);
public:
/*!Shared interprocess_mutex family used for the rest of the Interprocess framework*/
typedef MutexFamily mutex_family;
/*!Pointer type to be used with the rest of the Interprocess framework*/
typedef VoidPointer void_pointer;
typedef typename std::iterator_traits<char_ptr>::difference_type difference_type;
typedef typename boost::make_unsigned<difference_type>::type size_type;
private:
struct block_ctrl;
typedef typename boost::
pointer_to_other<void_pointer, block_ctrl>::type block_ctrl_ptr;
/*!Block control structure*/
struct block_ctrl
{
/*!Offset pointer to the next block.*/
block_ctrl_ptr m_next;
/*!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; }
size_type get_total_bytes() const
{ return this->m_size*Alignment; }
static block_ctrl *get_block_from_addr(void *addr)
{
return reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(addr) - BlockCtrlBytes);
}
void *get_addr() const
{
return reinterpret_cast<block_ctrl*>
(reinterpret_cast<const char*>(this) + BlockCtrlBytes);
}
};
/*!Shared interprocess_mutex to protect memory allocate/deallocate*/
typedef typename MutexFamily::mutex_type interprocess_mutex;
/*!This struct includes needed data and derives from
interprocess_mutex to allow EBO when using null interprocess_mutex*/
struct header_t : public interprocess_mutex
{
/*!Pointer to the first free block*/
block_ctrl m_root;
/*!Allocated bytes for internal checking*/
size_type m_allocated;
/*!The size of the memory segment*/
size_type m_size;
} m_header;
public:
/*!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);
/*!Destructor.*/
~simple_seq_fit_impl();
/*!Obtains the minimum size needed by the algorithm*/
static size_type get_min_size (size_type extra_hdr_bytes);
//Functions for single segment management
/*!Allocates bytes, returns 0 if there is not more memory*/
void* allocate (size_type nbytes);
/*!Deallocates previously allocated bytes*/
void deallocate (void *addr);
/*!Returns the size of the memory segment*/
size_type get_size() const;
/*!Increases managed memory in extra_size bytes more*/
void grow(size_type extra_size);
/*!Returns true if all allocated memory has been deallocated*/
bool all_memory_deallocated();
/*!Makes an internal sanity check and returns true if success*/
bool check_sanity();
//!Initializes to zero all the memory that's not in use.
//!This function is normally used for security reasons.
void clear_free_memory();
std::pair<void *, bool>
allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
size_type preferred_size,size_type &received_size,
void *reuse_ptr = 0, size_type backwards_multiple = 1);
/*!Returns the size of the buffer previously allocated pointed by ptr*/
size_type size(void *ptr) const;
/*!Allocates aligned bytes, returns 0 if there is not more memory.
Alignment must be power of 2*/
void* allocate_aligned (size_type nbytes, size_type alignment);
/*!Allocates bytes, if there is no more memory, it executes functor
f(size_type) to allocate a new segment to manage. The functor returns
std::pair<void*, size_type> indicating the base address and size of
the new segment. If the new segment can't be allocated, allocate
it will return 0.*/
void* multi_allocate(size_type nbytes);
private:
/*!Real allocation algorithm with min allocation option*/
std::pair<void *, bool> priv_allocate(boost::interprocess::allocation_type command
,size_type min_size
,size_type preferred_size
,size_type &received_size
,void *reuse_ptr = 0);
/*!Returns next block if it's free.
Returns 0 if next block is not free.*/
block_ctrl *priv_next_block_if_free(block_ctrl *ptr);
/*!Returns previous block's if it's free.
Returns 0 if previous block is not free.*/
std::pair<block_ctrl*, block_ctrl*>priv_prev_block_if_free(block_ctrl *ptr);
/*!Real expand function implementation*/
bool priv_expand(void *ptr
,size_type min_size, size_type preferred_size
,size_type &received_size);
/*!Real expand to both sides implementation*/
void* priv_expand_both_sides(boost::interprocess::allocation_type command
,size_type min_size
,size_type preferred_size
,size_type &received_size
,void *reuse_ptr
,bool only_preferred_backwards);
/*!Real shrink function implementation*/
bool priv_shrink(void *ptr
,size_type max_size, size_type preferred_size
,size_type &received_size);
//!Real private aligned allocation function
void* priv_allocate_aligned (size_type nbytes, size_type alignment);
/*!Checks if block has enough memory and splits/unlinks the block
returning the address to the users*/
void* priv_check_and_allocate(size_type units
,block_ctrl* prev
,block_ctrl* block
,size_type &received_size);
/*!Real deallocation algorithm*/
void priv_deallocate(void *addr);
/*!Makes a new memory portion available for allocation*/
void priv_add_segment(void *addr, size_type size);
enum { Alignment = ::boost::alignment_of<boost::ipcdetail::max_align>::value };
enum { BlockCtrlBytes = ipcdetail::ct_rounded_size<sizeof(block_ctrl), Alignment>::value };
enum { BlockCtrlSize = BlockCtrlBytes/Alignment };
enum { MinBlockSize = BlockCtrlSize + Alignment };
public:
enum { PayloadPerAllocation = BlockCtrlBytes };
};
template<class MutexFamily, class VoidPointer>
inline simple_seq_fit_impl<MutexFamily, VoidPointer>::
simple_seq_fit_impl(size_type size, size_type extra_hdr_bytes)
{
//Initialize sizes and counters
m_header.m_allocated = 0;
m_header.m_size = size;
//Initialize pointers
size_type block1_off = ipcdetail::get_rounded_size(sizeof(*this)+extra_hdr_bytes, Alignment);
m_header.m_root.m_next = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(this) + block1_off);
m_header.m_root.m_next->m_size = (size - block1_off)/Alignment;
m_header.m_root.m_next->m_next = &m_header.m_root;
}
template<class MutexFamily, class VoidPointer>
inline simple_seq_fit_impl<MutexFamily, VoidPointer>::~simple_seq_fit_impl()
{
//There is a memory leak!
// BOOST_ASSERT(m_header.m_allocated == 0);
// BOOST_ASSERT(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root));
}
template<class MutexFamily, class VoidPointer>
inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::grow(size_type extra_size)
{
//Old highest address block's end offset
size_type old_end = m_header.m_size/Alignment*Alignment;
//Update managed buffer's size
m_header.m_size += extra_size;
//We need at least MinBlockSize blocks to create a new block
if((m_header.m_size - old_end) < MinBlockSize){
return;
}
//We'll create a new free block with extra_size bytes
block_ctrl *new_block = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(this) + old_end);
new_block->m_next = 0;
new_block->m_size = (m_header.m_size - old_end)/Alignment;
m_header.m_allocated += new_block->m_size*Alignment;
this->priv_deallocate(reinterpret_cast<char*>(new_block) + BlockCtrlBytes);
}
template<class MutexFamily, class VoidPointer>
inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_add_segment(void *addr, size_type size)
{
//Check size
BOOST_ASSERT(!(size < MinBlockSize));
if(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_next = 0;
//Simulate this block was previously allocated
m_header.m_allocated += new_block->m_size*Alignment;
//Return block and insert it in the free block list
this->priv_deallocate(reinterpret_cast<char*>(new_block) + BlockCtrlBytes);
}
template<class MutexFamily, class VoidPointer>
inline typename simple_seq_fit_impl<MutexFamily, VoidPointer>::size_type
simple_seq_fit_impl<MutexFamily, VoidPointer>::get_size() const
{ return m_header.m_size; }
template<class MutexFamily, class VoidPointer>
inline typename simple_seq_fit_impl<MutexFamily, VoidPointer>::size_type
simple_seq_fit_impl<MutexFamily, VoidPointer>::
get_min_size (size_type extra_hdr_bytes)
{
return ipcdetail::get_rounded_size(sizeof(simple_seq_fit_impl)+extra_hdr_bytes
,Alignment)
+ MinBlockSize;
}
template<class MutexFamily, class VoidPointer>
inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
all_memory_deallocated()
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
return m_header.m_allocated == 0 &&
ipcdetail::get_pointer(m_header.m_root.m_next->m_next) == &m_header.m_root;
}
template<class MutexFamily, class VoidPointer>
inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::clear_free_memory()
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
block_ctrl *block = ipcdetail::get_pointer(m_header.m_root.m_next);
//Iterate through all free portions
do{
//Just clear user the memory part reserved for the user
std::memset( reinterpret_cast<char*>(block) + BlockCtrlBytes
, 0
, block->m_size*Alignment - BlockCtrlBytes);
block = ipcdetail::get_pointer(block->m_next);
}
while(block != &m_header.m_root);
}
template<class MutexFamily, class VoidPointer>
inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
check_sanity()
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
block_ctrl *block = ipcdetail::get_pointer(m_header.m_root.m_next);
size_type free_memory = 0;
//Iterate through all blocks obtaining their size
do{
//Free blocks's next must be always valid
block_ctrl *next = ipcdetail::get_pointer(block->m_next);
if(!next){
return false;
}
free_memory += block->m_size*Alignment;
block = next;
}
while(block != &m_header.m_root);
//Check allocated bytes are less than size
if(m_header.m_allocated > m_header.m_size){
return false;
}
//Check free bytes are less than size
if(free_memory > m_header.m_size){
return false;
}
return true;
}
template<class MutexFamily, class VoidPointer>
inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
allocate(size_type nbytes)
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
size_type ignore;
return priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first;
}
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 priv_allocate_aligned(nbytes, alignment);
}
template<class MutexFamily, class VoidPointer>
inline std::pair<void *, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
allocation_command (boost::interprocess::allocation_type command, size_type min_size,
size_type preferred_size,size_type &received_size,
void *reuse_ptr, size_type backwards_multiple)
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
(void)backwards_multiple;
command &= ~boost::interprocess::expand_bwd;
if(!command)
return std::pair<void *, bool>(0, false);
return priv_allocate(command, min_size, preferred_size, received_size, reuse_ptr);
}
template<class MutexFamily, class VoidPointer>
inline typename simple_seq_fit_impl<MutexFamily, VoidPointer>::size_type
simple_seq_fit_impl<MutexFamily, VoidPointer>::
size(void *ptr) const
{
//We need no synchronization since this block is not going
//to be modified
//Obtain the real size of the block
block_ctrl *block = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(ptr) - BlockCtrlBytes);
return block->m_size*Alignment - BlockCtrlBytes;
}
template<class MutexFamily, class VoidPointer>
inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
multi_allocate(size_type nbytes)
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
//Multisegment pointer. Let's try first the normal allocation
//since it's faster.
size_type ignore;
void *addr = this->priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first;
if(!addr){
//If this fails we will try the allocation through the segment
//creator.
size_type group, id;
//Obtain the segment group of this segment
void_pointer::get_group_and_id(this, group, id);
if(group == 0){
//Ooops, group 0 is not valid.
return 0;
}
//Now obtain the polymorphic functor that creates
//new segments and try to allocate again.
boost::interprocess::multi_segment_services *p_services =
static_cast<boost::interprocess::multi_segment_services*>
(void_pointer::find_group_data(group));
BOOST_ASSERT(p_services);
std::pair<void *, std::size_t> ret =
p_services->create_new_segment(MinBlockSize > nbytes ? MinBlockSize : nbytes);
if(ret.first){
priv_add_segment(ret.first, ret.second);
addr = this->priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first;
}
}
return addr;
}
template<class MutexFamily, class VoidPointer>
void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_expand_both_sides(boost::interprocess::allocation_type command
,size_type min_size
,size_type preferred_size
,size_type &received_size
,void *reuse_ptr
,bool only_preferred_backwards)
{
typedef std::pair<block_ctrl *, block_ctrl *> prev_block_t;
block_ctrl *reuse = block_ctrl::get_block_from_addr(reuse_ptr);
received_size = 0;
if(this->size(reuse_ptr) > min_size){
received_size = this->size(reuse_ptr);
return reuse_ptr;
}
if(command & boost::interprocess::expand_fwd){
if(priv_expand(reuse_ptr, min_size, preferred_size, received_size))
return reuse_ptr;
}
else{
received_size = this->size(reuse_ptr);
}
if(command & boost::interprocess::expand_bwd){
size_type extra_forward = !received_size ? 0 : received_size + BlockCtrlBytes;
prev_block_t prev_pair = priv_prev_block_if_free(reuse);
block_ctrl *prev = prev_pair.second;
if(!prev){
return 0;
}
size_type needs_backwards =
ipcdetail::get_rounded_size(preferred_size - extra_forward, Alignment);
if(!only_preferred_backwards){
needs_backwards =
max_value(ipcdetail::get_rounded_size(min_size - extra_forward, Alignment)
,min_value(prev->get_user_bytes(), needs_backwards));
}
//Check if previous block has enough size
if((prev->get_user_bytes()) >= needs_backwards){
//Now take all next space. This will succeed
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 =
BlockCtrlSize + (needs_backwards + extra_forward)/Alignment;
prev->m_size =
(prev->get_total_bytes() - needs_backwards)/Alignment - BlockCtrlSize;
received_size = needs_backwards + extra_forward;
m_header.m_allocated += needs_backwards + BlockCtrlBytes;
return new_block->get_addr();
}
else{
//Just merge the whole previous block
block_ctrl *prev_2_block = prev_pair.first;
//Update received size and allocation
received_size = extra_forward + prev->get_user_bytes();
m_header.m_allocated += prev->get_total_bytes();
//Now unlink it from previous block
prev_2_block->m_next = prev->m_next;
prev->m_size = reuse->m_size + prev->m_size;
prev->m_next = 0;
return prev->get_addr();
}
}
}
return 0;
}
template<class MutexFamily, class VoidPointer>
std::pair<void *, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_allocate(boost::interprocess::allocation_type command
,size_type limit_size
,size_type preferred_size
,size_type &received_size
,void *reuse_ptr)
{
if(command & boost::interprocess::shrink_in_place){
bool success =
this->priv_shrink(reuse_ptr, limit_size, preferred_size, received_size);
return std::pair<void *, bool> ((success ? reuse_ptr : 0), true);
}
typedef std::pair<void *, bool> return_type;
received_size = 0;
if(limit_size > preferred_size)
return return_type(0, false);
//Number of units to request (including block_ctrl header)
size_type nunits = ipcdetail::get_rounded_size(preferred_size, Alignment)/Alignment + BlockCtrlSize;
//Get the root and the first memory block
block_ctrl *prev = &m_header.m_root;
block_ctrl *block = ipcdetail::get_pointer(prev->m_next);
block_ctrl *root = &m_header.m_root;
block_ctrl *biggest_block = 0;
block_ctrl *prev_biggest_block = 0;
size_type biggest_size = limit_size;
//Expand in place
//reuse_ptr, limit_size, preferred_size, received_size
//
if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){
void *ret = priv_expand_both_sides
(command, limit_size, preferred_size, received_size, reuse_ptr, true);
if(ret)
return return_type(ret, true);
}
if(command & boost::interprocess::allocate_new){
received_size = 0;
while(block != root){
//Update biggest block pointers
if(block->m_size > biggest_size){
prev_biggest_block = prev;
biggest_size = block->m_size;
biggest_block = block;
}
void *addr = this->priv_check_and_allocate(nunits, prev, block, received_size);
if(addr) return return_type(addr, false);
//Bad luck, let's check next block
prev = block;
block = ipcdetail::get_pointer(block->m_next);
}
//Bad luck finding preferred_size, now if we have any biggest_block
//try with this block
if(biggest_block){
received_size = biggest_block->m_size*Alignment - BlockCtrlSize;
nunits = ipcdetail::get_rounded_size(limit_size, Alignment)/Alignment + BlockCtrlSize;
void *ret = this->priv_check_and_allocate
(nunits, prev_biggest_block, biggest_block, received_size);
if(ret)
return return_type(ret, false);
}
}
//Now try to expand both sides with min size
if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){
return return_type(priv_expand_both_sides
(command, limit_size, preferred_size, received_size, reuse_ptr, false), true);
}
return return_type(0, false);
}
template<class MutexFamily, class VoidPointer>
inline typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *
simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_next_block_if_free
(typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *ptr)
{
//Take the address where the next block should go
block_ctrl *next_block = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(ptr) + ptr->m_size*Alignment);
//Check if the adjacent block is in the managed segment
size_type distance = (reinterpret_cast<char*>(next_block) - reinterpret_cast<char*>(this))/Alignment;
if(distance >= (m_header.m_size/Alignment)){
//"next_block" does not exist so we can't expand "block"
return 0;
}
if(!next_block->m_next)
return 0;
return next_block;
}
template<class MutexFamily, class VoidPointer>
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>::
priv_prev_block_if_free
(typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *ptr)
{
typedef std::pair<block_ctrl *, block_ctrl *> prev_pair_t;
//Take the address where the previous block should go
block_ctrl *root = &m_header.m_root;
block_ctrl *prev_2_block = root;
block_ctrl *prev_block = ipcdetail::get_pointer(root->m_next);
while((reinterpret_cast<char*>(prev_block) + prev_block->m_size*Alignment)
!= (reinterpret_cast<char*>(ptr))
&& prev_block != root){
prev_2_block = prev_block;
prev_block = ipcdetail::get_pointer(prev_block->m_next);
}
if(prev_block == root || !prev_block->m_next)
return prev_pair_t(0, 0);
//Check if the previous block is in the managed segment
size_type distance = (reinterpret_cast<char*>(prev_block) - reinterpret_cast<char*>(this))/Alignment;
if(distance >= (m_header.m_size/Alignment)){
//"previous_block" does not exist so we can't expand "block"
return prev_pair_t(0, 0);
}
return prev_pair_t(prev_2_block, prev_block);
}
template<class MutexFamily, class VoidPointer>
inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_expand (void *ptr
,size_type min_size
,size_type preferred_size
,size_type &received_size)
{
//Obtain the real size of the block
block_ctrl *block = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(ptr) - BlockCtrlBytes);
size_type old_block_size = block->m_size;
//All used blocks' next is marked with 0 so check it
BOOST_ASSERT(block->m_next == 0);
//Put this to a safe value
received_size = old_block_size*Alignment - BlockCtrlBytes;
//Now translate it to Alignment units
min_size = ipcdetail::get_rounded_size(min_size, Alignment)/Alignment;
preferred_size = ipcdetail::get_rounded_size(preferred_size, Alignment)/Alignment;
//Some parameter checks
if(min_size > preferred_size)
return false;
size_type data_size = old_block_size - BlockCtrlSize;
if(data_size >= min_size)
return true;
block_ctrl *next_block = priv_next_block_if_free(block);
if(!next_block){
return false;
}
//Is "block" + "next_block" big enough?
size_type merged_size = old_block_size + next_block->m_size;
//Now we can expand this block further than before
received_size = merged_size*Alignment - BlockCtrlBytes;
if(merged_size < (min_size + BlockCtrlSize)){
return false;
}
//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::get_pointer(prev->m_next) != next_block){
prev = ipcdetail::get_pointer(prev->m_next);
}
//Now insert merged block in the free list
//This allows reusing allocation logic in this function
m_header.m_allocated -= old_block_size*Alignment;
prev->m_next = block;
//Now use check and allocate to do the allocation logic
preferred_size += BlockCtrlSize;
size_type nunits = preferred_size < merged_size ? preferred_size : merged_size;
//This must success since nunits is less than merged_size!
if(!this->priv_check_and_allocate (nunits, prev, block, received_size)){
//Something very ugly is happening here. This is a bug
//or there is memory corruption
BOOST_ASSERT(0);
return false;
}
return true;
}
template<class MutexFamily, class VoidPointer>
inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_shrink (void *ptr
,size_type max_size
,size_type preferred_size
,size_type &received_size)
{
//Obtain the real size of the block
block_ctrl *block = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(ptr) - BlockCtrlBytes);
size_type block_size = block->m_size;
//All used blocks' next is marked with 0 so check it
BOOST_ASSERT(block->m_next == 0);
//Put this to a safe value
received_size = block_size*Alignment - BlockCtrlBytes;
//Now translate it to Alignment units
max_size = max_size/Alignment;
preferred_size = ipcdetail::get_rounded_size(preferred_size, Alignment)/Alignment;
//Some parameter checks
if(max_size < preferred_size)
return false;
size_type data_size = block_size - BlockCtrlSize;
if(data_size < preferred_size)
return false;
if(data_size == preferred_size)
return true;
//We must be able to create at least a new empty block
if((data_size - preferred_size) < BlockCtrlSize){
return false;
}
//Now we can just rewrite the size of the old buffer
block->m_size = preferred_size + BlockCtrlSize;
//Update new size
received_size = preferred_size*Alignment;
//We create the new block
block = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(block) + block->m_size*Alignment);
//Write control data to simulate this new block was previously allocated
block->m_next = 0;
block->m_size = data_size - preferred_size;
//Now deallocate the new block to insert it in the free list
this->priv_deallocate(reinterpret_cast<char*>(block)+BlockCtrlBytes);
return true;
}
template<class MutexFamily, class VoidPointer>
inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_allocate_aligned(size_type nbytes, size_type alignment)
{
//Ensure power of 2
if ((alignment & (alignment - size_type(1u))) != 0){
//Alignment is not power of two
BOOST_ASSERT((alignment & (alignment - size_type(1u))) != 0);
return 0;
}
size_type ignore;
if(alignment <= Alignment){
return priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first;
}
size_type request =
nbytes + alignment + MinBlockSize*Alignment - BlockCtrlBytes;
void *buffer = priv_allocate(boost::interprocess::allocate_new, request, request, ignore).first;
if(!buffer)
return 0;
else if ((((std::size_t)(buffer)) % alignment) == 0)
return buffer;
char *aligned_portion = reinterpret_cast<char*>
(reinterpret_cast<size_type>(static_cast<char*>(buffer) + alignment - 1) & -alignment);
char *pos = ((aligned_portion - reinterpret_cast<char*>(buffer)) >= (MinBlockSize*Alignment)) ?
aligned_portion : (aligned_portion + alignment);
block_ctrl *first = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(buffer) - BlockCtrlBytes);
block_ctrl *second = reinterpret_cast<block_ctrl*>(pos - BlockCtrlBytes);
size_type old_size = first->m_size;
first->m_size = (reinterpret_cast<char*>(second) - reinterpret_cast<char*>(first))/Alignment;
second->m_size = old_size - first->m_size;
//Write control data to simulate this new block was previously allocated
second->m_next = 0;
//Now deallocate the new block to insert it in the free list
this->priv_deallocate(reinterpret_cast<char*>(first) + BlockCtrlBytes);
return reinterpret_cast<char*>(second) + BlockCtrlBytes;
}
template<class MutexFamily, class VoidPointer> inline
void* simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_check_and_allocate
(size_type nunits
,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl* prev
,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl* block
,size_type &received_size)
{
size_type upper_nunits = nunits + BlockCtrlSize;
bool found = false;
if (block->m_size > upper_nunits){
//This block is bigger than needed, split it in
//two blocks, the first's size will be (block->m_size-units)
//the second's size (units)
size_type total_size = block->m_size;
block->m_size = nunits;
block_ctrl *new_block = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(block) + Alignment*nunits);
new_block->m_size = total_size - nunits;
new_block->m_next = block->m_next;
prev->m_next = new_block;
found = true;
}
else if (block->m_size >= nunits){
//This block has exactly the right size with an extra
//unusable extra bytes.
prev->m_next = block->m_next;
found = true;
}
if(found){
//We need block_ctrl for deallocation stuff, so
//return memory user can overwrite
m_header.m_allocated += block->m_size*Alignment;
received_size = block->m_size*Alignment - BlockCtrlBytes;
//Mark the block as allocated
block->m_next = 0;
//Check alignment
BOOST_ASSERT(((reinterpret_cast<char*>(block) - reinterpret_cast<char*>(this))
% Alignment) == 0 );
return reinterpret_cast<char*>(block) + BlockCtrlBytes;
}
return 0;
}
template<class MutexFamily, class VoidPointer>
void simple_seq_fit_impl<MutexFamily, VoidPointer>::deallocate(void* addr)
{
if(!addr) return;
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
return this->priv_deallocate(addr);
}
template<class MutexFamily, class VoidPointer>
void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_deallocate(void* addr)
{
if(!addr) return;
//Let's get free block list. List is always sorted
//by memory address to allow block merging.
//Pointer next always points to the first
//(lower address) block
block_ctrl_ptr prev = &m_header.m_root;
block_ctrl_ptr pos = m_header.m_root.m_next;
block_ctrl_ptr block = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(addr) - BlockCtrlBytes);
//All used blocks' next is marked with 0 so check it
BOOST_ASSERT(block->m_next == 0);
//Check if alignment and block size are right
BOOST_ASSERT((reinterpret_cast<char*>(addr) - reinterpret_cast<char*>(this))
% Alignment == 0 );
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;
//Let's find the previous and the next block of the block to deallocate
//This ordering comparison must be done with original pointers
//types since their mapping to raw pointers can be different
//in each process
while((ipcdetail::get_pointer(pos) != &m_header.m_root) && (block > pos)){
prev = pos;
pos = pos->m_next;
}
//Try to combine with upper block
if ((reinterpret_cast<char*>(ipcdetail::get_pointer(block))
+ Alignment*block->m_size) ==
reinterpret_cast<char*>(ipcdetail::get_pointer(pos))){
block->m_size += pos->m_size;
block->m_next = pos->m_next;
}
else{
block->m_next = pos;
}
//Try to combine with lower block
if ((reinterpret_cast<char*>(ipcdetail::get_pointer(prev))
+ Alignment*prev->m_size) ==
reinterpret_cast<char*>(ipcdetail::get_pointer(block))){
prev->m_size += block->m_size;
prev->m_next = block->m_next;
}
else{
prev->m_next = block;
}
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_SIMPLE_SEQ_FIT_HPP
#define BOOST_INTERPROCESS_SIMPLE_SEQ_FIT_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp>
#include <boost/interprocess/offset_ptr.hpp>
//!\file
//!Describes sequential fit algorithm used to allocate objects in shared memory.
namespace boost {
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
: public ipcdetail::simple_seq_fit_impl<MutexFamily, VoidPointer>
{
/// @cond
typedef ipcdetail::simple_seq_fit_impl<MutexFamily, VoidPointer> base_t;
/// @endcond
public:
typedef typename base_t::size_type size_type;
//!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){}
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_SIMPLE_SEQ_FIT_HPP

View File

@@ -0,0 +1,500 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_OFFSET_PTR_HPP
#define BOOST_OFFSET_PTR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/cast_tags.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/pointer_cast.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/assert.hpp>
#include <ostream>
#include <istream>
#include <iterator>
#include <boost/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
//!\file
//!Describes a smart pointer that stores the offset between this pointer and
//!target pointee, called offset_ptr.
namespace boost {
//Predeclarations
template <class T>
struct has_trivial_constructor;
template <class T>
struct has_trivial_destructor;
namespace interprocess {
//!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
//!pointer and the pointee are still separated by the same offset. This feature
//!converts offset_ptr in a smart pointer that can be placed in shared memory and
//!memory mapped files mapped in different addresses in every process.
template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment>
class offset_ptr
{
/// @cond
typedef offset_ptr<PointedType, DifferenceType, OffsetType, OffsetAlignment> self_t;
void unspecified_bool_type_func() const {}
typedef void (self_t::*unspecified_bool_type)() const;
//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) && (_MSC_VER >= 1400)
__declspec(noinline) //this workaround is needed for msvc-8.0 and msvc-9.0
#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 * get_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 pointed address
typename ::boost::aligned_storage
< sizeof(OffsetType)
, (OffsetAlignment == offset_type_alignment) ?
::boost::alignment_of<OffsetType>::value : OffsetAlignment
>::type alignment_helper;
} internal;
/// @endcond
public:
typedef PointedType * pointer;
typedef typename ipcdetail::
add_reference<PointedType>::type reference;
typedef PointedType value_type;
typedef DifferenceType difference_type;
typedef std::random_access_iterator_tag iterator_category;
typedef OffsetType offset_type;
public: //Public Functions
//!Constructor from raw pointer (allows "0" pointer conversion).
//!Never throws.
offset_ptr(pointer ptr = 0) { this->set_offset(ptr); }
//!Constructor from other pointer.
//!Never throws.
template <class T>
offset_ptr(T *ptr)
{ pointer p (ptr); (void)p; this->set_offset(p); }
//!Constructor from other offset_ptr
//!Never throws.
offset_ptr(const offset_ptr& ptr)
{ this->set_offset(ptr.get()); }
//!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)
{ pointer p(ptr.get()); (void)p; this->set_offset(p); }
//!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())); }
//!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())); }
//!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())); }
//!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())); }
//!Obtains raw pointer from offset.
//!Never throws.
pointer get()const
{ return this->get_pointer(); }
offset_type get_offset() const
{ return internal.m_offset; }
//!Pointer-like -> operator. It can return 0 pointer.
//!Never throws.
pointer operator->() const
{ return this->get(); }
//!Dereferencing operator, if it is a null offset_ptr behavior
//! is undefined. Never throws.
reference operator* () const
{
pointer p = this->get();
reference r = *p;
return r;
}
//!Indexing operator.
//!Never throws.
template<class T>
reference operator[](T 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; }
//!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; }
//!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>
offset_ptr& operator= (const offset_ptr<T2, P2, O2, A2> & pt)
{ pointer p(pt.get()); this->set_offset(p); return *this; }
//!offset_ptr + difference_type.
//!Never throws.
template<class T>
offset_ptr operator+ (T offset) const
{ return offset_ptr(this->get()+offset); }
//!offset_ptr - difference_type.
//!Never throws.
template<class T>
offset_ptr operator- (T offset) const
{ return offset_ptr(this->get()-offset); }
//!offset_ptr += difference_type.
//!Never throws.
template<class T>
offset_ptr &operator+= (T offset)
{ this->inc_offset(offset * sizeof (PointedType)); return *this; }
//!offset_ptr -= difference_type.
//!Never throws.
template<class T>
offset_ptr &operator-= (T offset)
{ this->dec_offset(offset * sizeof (PointedType)); return *this; }
//!++offset_ptr.
//!Never throws.
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.
//!Never throws.
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; }
//!safe bool conversion operator.
//!Never throws.
operator unspecified_bool_type() const
{ return this->get()? &self_t::unspecified_bool_type_func : 0; }
//!Not operator. Not needed in theory, but improves portability.
//!Never throws
bool operator! () const
{ return this->get() == 0; }
/*
friend void swap (offset_ptr &pt, offset_ptr &pt2)
{
value_type *ptr = pt.get();
pt = pt2;
pt2 = ptr;
}
*/
};
//!offset_ptr<T1, P1, O1, A1> == offset_ptr<T2, P2, O2, A2>.
//!Never throws.
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
inline bool operator== (const offset_ptr<T1, P1, O1, A1> &pt1,
const offset_ptr<T2, P2, O2, A2> &pt2)
{ return pt1.get() == pt2.get(); }
//!offset_ptr<T1, P1, O1, A1> != offset_ptr<T2, P2, O2, A2>.
//!Never throws.
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
inline bool operator!= (const offset_ptr<T1, P1, O1, A1> &pt1,
const offset_ptr<T2, P2, O2, A2> &pt2)
{ return pt1.get() != pt2.get(); }
//!offset_ptr<T1, P1, O1, A1> < offset_ptr<T2, P2, O2, A2>.
//!Never throws.
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
inline bool operator< (const offset_ptr<T1, P1, O1, A1> &pt1,
const offset_ptr<T2, P2, O2, A2> &pt2)
{ return pt1.get() < pt2.get(); }
//!offset_ptr<T1, P1, O1, A1> <= offset_ptr<T2, P2, O2, A2>.
//!Never throws.
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
inline bool operator<= (const offset_ptr<T1, P1, O1, A1> &pt1,
const offset_ptr<T2, P2, O2, A2> &pt2)
{ return pt1.get() <= pt2.get(); }
//!offset_ptr<T1, P1, O1, A1> > offset_ptr<T2, P2, O2, A2>.
//!Never throws.
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
inline bool operator> (const offset_ptr<T1, P1, O1, A1> &pt1,
const offset_ptr<T2, P2, O2, A2> &pt2)
{ return pt1.get() > pt2.get(); }
//!offset_ptr<T1, P1, O1, A1> >= offset_ptr<T2, P2, O2, A2>.
//!Never throws.
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
inline bool operator>= (const offset_ptr<T1, P1, O1, A1> &pt1,
const offset_ptr<T2, P2, O2, A2> &pt2)
{ return pt1.get() >= pt2.get(); }
//!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<<
(std::basic_ostream<E, T> & os, offset_ptr<W, X, Y, Z> const & p)
{ return os << p.get_offset(); }
//!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>>
(std::basic_istream<E, T> & is, offset_ptr<W, X, Y, Z> & p)
{ return is >> p.get_offset(); }
//!difference_type + offset_ptr
//!operation
template<class T, class P, class O, std::size_t A, class D>
inline offset_ptr<T, P, O, A> operator+(D diff, const offset_ptr<T, P, O, A>& right)
{ return right + diff; }
//!offset_ptr - offset_ptr
//!operation
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
inline typename offset_ptr<T1, P1, O1, A1>::difference_type operator-
(const offset_ptr<T1, P1, O1, A1> &pt, const offset_ptr<T2, P2, O2, A2> &pt2)
{ return typename offset_ptr<T1, P1, O1, A1>::difference_type(pt.get()- pt2.get()); }
//!swap specialization
//!for offset_ptr
template<class T, class P, class O, std::size_t A>
inline void swap (boost::interprocess::offset_ptr<T, P, O, A> &pt,
boost::interprocess::offset_ptr<T, P, O, A> &pt2)
{
typename offset_ptr<T, P, O, A>::value_type *ptr = pt.get();
pt = pt2;
pt2 = ptr;
}
//!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>
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());
}
//!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());
}
//!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>
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());
}
//!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());
}
} //namespace interprocess {
/// @cond
//!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> >
{
enum { 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> >
{
enum { value = true };
};
//#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
namespace interprocess {
//#endif
//!get_pointer() enables boost::mem_fn to recognize offset_ptr.
//!Never throws.
template <class T, class P, class O, std::size_t A>
inline T * get_pointer(boost::interprocess::offset_ptr<T, P, O, A> const & p)
{ return p.get(); }
//#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
} //namespace interprocess
//#endif
/// @endcond
} //namespace boost {
/// @cond
namespace boost{
//This is to support embedding a bit in the pointer
//for intrusive containers, saving space
namespace intrusive {
//Predeclaration to avoid including header
template<class VoidPointer, std::size_t N>
struct max_pointer_plus_bits;
template<std::size_t OffsetAlignment, class P, class O, std::size_t A>
struct max_pointer_plus_bits<boost::interprocess::offset_ptr<void, P, O, A>, OffsetAlignment>
{
//The offset ptr can embed one bit less than the alignment since it
//uses offset == 1 to store the null pointer.
static const std::size_t value = ::boost::interprocess::ipcdetail::ls_zeros<OffsetAlignment>::value - 1;
};
//Predeclaration
template<class Pointer, std::size_t NumBits>
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;
//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 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)));
}
static std::size_t get_bits(const pointer &n)
{ return(std::size_t(n.get()) & std::size_t(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));
}
};
} //namespace intrusive
template<class T, class T2, class T3, std::size_t A, class U>
struct pointer_to_other< ::boost::interprocess::offset_ptr<T, T2, T3, A>, U >
{
typedef ::boost::interprocess::offset_ptr<U, T2, T3, A> type;
};
} //namespace boost{
/// @endcond
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_OFFSET_PTR_HPP

View File

@@ -0,0 +1,132 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_PERMISSIONS_HPP
#define BOOST_INTERPROCESS_PERMISSIONS_HPP
/// @cond
#if defined (_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#if defined(BOOST_INTERPROCESS_WINDOWS)
#include <boost/interprocess/detail/win32_api.hpp>
#endif
/// @endcond
//!\file
//!Describes permissions class
namespace boost {
namespace interprocess {
/// @cond
#if defined(BOOST_INTERPROCESS_WINDOWS)
namespace ipcdetail {
template <int Dummy>
struct unrestricted_permissions_holder
{
static winapi::interprocess_all_access_security unrestricted;
};
template<int Dummy>
winapi::interprocess_all_access_security unrestricted_permissions_holder<Dummy>::unrestricted;
} //namespace ipcdetail {
#endif //defined BOOST_INTERPROCESS_WINDOWS
/// @endcond
//!The permissions class represents permissions to be set to shared memory or
//!files, that can be constructed form usual permission representations:
//!a SECURITY_ATTRIBUTES pointer in windows or ORed rwx chmod integer in UNIX.
class permissions
{
/// @cond
#if defined(BOOST_INTERPROCESS_WINDOWS)
typedef void* os_permissions_type;
#else
typedef int os_permissions_type;
#endif
os_permissions_type m_perm;
/// @endcond
public:
//!Constructs a permissions object from a user provided os-dependent
//!permissions.
permissions(os_permissions_type type)
: m_perm(type)
{}
//!Constructs a default permissions object:
//!A null security attributes pointer for windows or 0644
//!for UNIX.
permissions()
{ set_default(); }
//!Sets permissions to default values:
//!A null security attributes pointer for windows or 0644
//!for UNIX.
void set_default()
{
/// @cond
#if defined (BOOST_INTERPROCESS_WINDOWS)
m_perm = 0;
#else
m_perm = 0644;
#endif
/// @endcond
}
//!Sets permissions to unrestricted access:
//!A null DACL for windows or 0666 for UNIX.
void set_unrestricted()
{
/// @cond
#if defined (BOOST_INTERPROCESS_WINDOWS)
m_perm = &ipcdetail::unrestricted_permissions_holder<0>::unrestricted;
#else
m_perm = 0666;
#endif
/// @endcond
}
//!Sets permissions from a user provided os-dependent
//!permissions.
void set_permissions(os_permissions_type perm)
{ m_perm = perm; }
//!Returns stored os-dependent
//!permissions
os_permissions_type get_permissions() const
{ return m_perm; }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_PERMISSIONS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,422 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. 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_SHARED_MEMORY_OBJECT_HPP
#define BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/tmp_dir_helpers.hpp>
#include <boost/interprocess/permissions.hpp>
#include <cstddef>
#include <string>
#include <algorithm>
#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 <sys/mman.h> //shm_xxx
# include <unistd.h> //ftruncate, close
# include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
# if defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
# if defined(__FreeBSD__)
# include <sys/sysctl.h>
# endif
# endif
#else
//
#endif
//!\file
//!Describes a shared memory object management class.
namespace boost {
namespace interprocess {
//!A class that wraps a shared memory mapping that can be used to
//!create mapped regions from the mapped files
class shared_memory_object
{
/// @cond
//Non-copyable and non-assignable
BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_memory_object)
/// @endcond
public:
//!Default constructor. Represents an empty shared_memory_object.
shared_memory_object();
//!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode"
//!If the file previously exists, throws an error.*/
shared_memory_object(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions())
{ this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm); }
//!Tries to create a shared memory object with name "name" and mode "mode", with the
//!access mode "mode". If the file previously exists, it tries to open it with mode "mode".
//!Otherwise throws an error.
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".
//!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.
//!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.
//!Does not throw
shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved)
{
shared_memory_object tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps the shared_memory_objects. Does not throw
void swap(shared_memory_object &moved);
//!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);
//!Destroys *this and indicates that the calling process is finished using
//!the resource. All mapped regions are still
//!valid after destruction. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~shared_memory_object();
//!Returns the name of the shared memory object.
const char *get_name() const;
//!Returns true if the size of the shared memory object
//!can be obtained and writes the size in the passed reference
bool get_size(offset_t &size) const;
//!Returns access mode
mode_t get_mode() const;
//!Returns mapping handle. Never throws.
mapping_handle_t get_mapping_handle() const;
/// @cond
private:
//!Closes a previously opened file mapping. Never throws.
void priv_close();
//!Closes a previously opened file mapping. Never throws.
bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm);
file_handle_t m_handle;
mode_t m_mode;
std::string m_filename;
/// @endcond
};
/// @cond
inline shared_memory_object::shared_memory_object()
: m_handle(file_handle_t(ipcdetail::invalid_file()))
{}
inline shared_memory_object::~shared_memory_object()
{ this->priv_close(); }
inline const char *shared_memory_object::get_name() const
{ return m_filename.c_str(); }
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);
}
inline mapping_handle_t shared_memory_object::get_mapping_handle() const
{
return ipcdetail::mapping_handle_from_file_handle(m_handle);
}
inline mode_t shared_memory_object::get_mode() const
{ return m_mode; }
#if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
inline bool shared_memory_object::priv_open_or_create
(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm)
{
m_filename = filename;
std::string shmfile;
ipcdetail::create_tmp_and_clean_old_and_get_filename(filename, shmfile);
//Set accesses
if (mode != read_write && mode != read_only){
error_info err = other_error;
throw interprocess_exception(err);
}
switch(type){
case ipcdetail::DoOpen:
m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true);
break;
case ipcdetail::DoCreate:
m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true);
break;
case ipcdetail::DoOpenOrCreate:
m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true);
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Check for error
if(m_handle == ipcdetail::invalid_file()){
error_info err = system_error_code();
this->priv_close();
throw interprocess_exception(err);
}
m_mode = mode;
return true;
}
inline bool shared_memory_object::remove(const char *filename)
{
try{
//Make sure a temporary path is created for shared memory
std::string shmfile;
ipcdetail::tmp_filename(filename, shmfile);
return ipcdetail::delete_file(shmfile.c_str());
}
catch(...){
return false;
}
}
inline void shared_memory_object::truncate(offset_t length)
{
if(!ipcdetail::truncate_file(m_handle, length)){
error_info err = system_error_code();
throw interprocess_exception(err);
}
}
inline void shared_memory_object::priv_close()
{
if(m_handle != ipcdetail::invalid_file()){
ipcdetail::close_file(m_handle);
m_handle = ipcdetail::invalid_file();
}
}
#else //!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
namespace shared_memory_object_detail {
#ifdef BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
#if defined(__FreeBSD__)
inline bool use_filesistem_based_posix()
{
int jailed = 0;
std::size_t len = sizeof(jailed);
::sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0);
return jailed != 0;
}
#else
#error "Not supported platform for BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY"
#endif
#endif
} //shared_memory_object_detail
inline bool shared_memory_object::priv_open_or_create
(ipcdetail::create_enum_t type,
const char *filename,
mode_t mode, const permissions &perm)
{
#if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
const bool add_leading_slash = false;
#elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
const bool add_leading_slash = !shared_memory_object_ipcdetail::use_filesistem_based_posix();
#else
const bool add_leading_slash = true;
#endif
if(add_leading_slash){
ipcdetail::add_leading_slash(filename, m_filename);
}
else{
ipcdetail::create_tmp_and_clean_old_and_get_filename(filename, m_filename);
}
//Create new mapping
int oflag = 0;
if(mode == read_only){
oflag |= O_RDONLY;
}
else if(mode == read_write){
oflag |= O_RDWR;
}
else{
error_info err(mode_error);
throw interprocess_exception(err);
}
int unix_perm = perm.get_permissions();
switch(type){
case ipcdetail::DoOpen:
{
//No oflag addition
m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
}
break;
case ipcdetail::DoCreate:
{
oflag |= (O_CREAT | O_EXCL);
m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
if(m_handle >= 0){
::fchmod(m_handle, unix_perm);
}
}
break;
case ipcdetail::DoOpenOrCreate:
{
oflag |= O_CREAT;
//We need a loop to change permissions correctly using fchmod, since
//with "O_CREAT only" shm_open we don't know if we've created or opened the file.
while(1){
m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
if(m_handle >= 0){
::fchmod(m_handle, unix_perm);
break;
}
else if(errno == EEXIST){
if((m_handle = shm_open(m_filename.c_str(), oflag, unix_perm)) >= 0 || errno != ENOENT){
break;
}
}
}
}
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Check for error
if(m_handle == -1){
error_info err = errno;
this->priv_close();
throw interprocess_exception(err);
}
m_filename = filename;
m_mode = mode;
return true;
}
inline bool shared_memory_object::remove(const char *filename)
{
try{
std::string file_str;
#if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
const bool add_leading_slash = false;
#elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
const bool add_leading_slash = !shared_memory_object_ipcdetail::use_filesistem_based_posix();
#else
const bool add_leading_slash = true;
#endif
if(add_leading_slash){
ipcdetail::add_leading_slash(filename, file_str);
}
else{
ipcdetail::tmp_filename(filename, file_str);
}
return 0 == shm_unlink(file_str.c_str());
}
catch(...){
return false;
}
}
inline void shared_memory_object::truncate(offset_t length)
{
if(0 != ftruncate(m_handle, length)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline void shared_memory_object::priv_close()
{
if(m_handle != -1){
::close(m_handle);
m_handle = -1;
}
}
#endif
///@endcond
//!A class that stores the name of a shared memory
//!and calls shared_memory_object::remove(name) in its destructor
//!Useful to remove temporary shared memory objects in the presence
//!of exceptions
class remove_shared_memory_on_destroy
{
const char * m_name;
public:
remove_shared_memory_on_destroy(const char *name)
: m_name(name)
{}
~remove_shared_memory_on_destroy()
{ shared_memory_object::remove(m_name); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP

View File

@@ -0,0 +1,62 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2009.
//
// 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_DELETER_HPP
#define BOOST_INTERPROCESS_DELETER_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/pointer_to_other.hpp>
//!\file
//!Describes the functor to delete objects from the segment.
namespace boost {
namespace interprocess {
//!A deleter that uses the segment manager's destroy_ptr
//!function to destroy the passed pointer resource.
//!
//!This deleter is used
template<class T, class SegmentManager>
class deleter
{
public:
typedef typename boost::pointer_to_other
<typename SegmentManager::void_pointer, T>::type pointer;
private:
typedef typename boost::pointer_to_other
<pointer, SegmentManager>::type segment_manager_pointer;
segment_manager_pointer mp_mngr;
public:
deleter(segment_manager_pointer pmngr)
: mp_mngr(pmngr)
{}
void operator()(const pointer &p)
{ mp_mngr->destroy_ptr(ipcdetail::get_pointer(p)); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DELETER_HPP

View File

@@ -0,0 +1,44 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/detail/bad_weak_ptr.hpp
//
// (C) Copyright Peter Dimov and Multi Media Ltd. 2001, 2002, 2003
// (C) Copyright Ion Gaztanaga 2006. 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_BAD_WEAK_PTR_HPP_INCLUDED
#define BOOST_INTERPROCESS_BAD_WEAK_PTR_HPP_INCLUDED
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#ifndef BOOST_NO_EXCEPTIONS
#include <exception>
#endif
namespace boost{
namespace interprocess{
class bad_weak_ptr
: public std::exception
{
public:
virtual char const * what() const throw()
{ return "boost::interprocess::bad_weak_ptr"; }
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_BAD_WEAK_PTR_HPP_INCLUDED

View File

@@ -0,0 +1,321 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/detail/shared_count.hpp
//
// (C) Copyright Peter Dimov and Multi Media Ltd. 2001, 2002, 2003
// (C) Copyright Peter Dimov 2004-2005
// (C) Copyright Ion Gaztanaga 2006-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/checked_delete.hpp>
#include <boost/pointer_to_other.hpp>
#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/detail/no_exceptions_support.hpp>
#include <functional> // std::less
namespace boost {
namespace interprocess {
namespace ipcdetail{
template<class T, class VoidAllocator, class Deleter>
class weak_count;
template<class T, class VoidAllocator, class Deleter>
class shared_count
{
public:
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, T>::type pointer;
private:
typedef sp_counted_impl_pd<VoidAllocator, Deleter> counted_impl;
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, counted_impl>::type counted_impl_ptr;
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, sp_counted_base>::type counted_base_ptr;
typedef typename VoidAllocator::template rebind
<counted_impl>::other counted_impl_allocator;
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, const Deleter>::type const_deleter_pointer;
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, const VoidAllocator>::type const_allocator_pointer;
pointer m_px;
counted_impl_ptr m_pi;
template <class T2, class VoidAllocator2, class Deleter2>
friend class weak_count;
template <class T2, class VoidAllocator2, class Deleter2>
friend class shared_count;
public:
shared_count()
: m_px(0), m_pi(0) // nothrow
{}
template <class Ptr>
shared_count(const shared_count &other_shared_count, const Ptr &p)
: m_px(p), m_pi(other_shared_count.m_pi)
{}
template <class Ptr>
shared_count(const Ptr &p, const VoidAllocator &a, Deleter d)
: m_px(p), m_pi(0)
{
BOOST_TRY{
if(p){
counted_impl_allocator alloc(a);
m_pi = alloc.allocate(1);
//Anti-exception deallocator
scoped_ptr<counted_impl,
scoped_ptr_dealloc_functor<counted_impl_allocator> >
deallocator(m_pi, alloc);
//It's more correct to use VoidAllocator::construct but
//this needs copy constructor and we don't like it
new(ipcdetail::get_pointer(m_pi))counted_impl(p, a, d);
deallocator.release();
}
}
BOOST_CATCH (...){
d(p); // delete p
BOOST_RETHROW
}
BOOST_CATCH_END
}
~shared_count() // nothrow
{
if( m_pi != 0 )
m_pi->release();
}
shared_count(shared_count const & r)
: m_px(r.m_px), m_pi(r.m_pi) // nothrow
{ if( m_pi != 0 ) m_pi->add_ref_copy(); }
//this is a test
template<class Y>
explicit shared_count(shared_count<Y, VoidAllocator, Deleter> const & r)
: m_px(r.m_px), m_pi(r.m_pi) // nothrow
{ if( m_pi != 0 ) m_pi->add_ref_copy(); }
//this is a test
template<class Y>
explicit shared_count(const pointer & ptr, shared_count<Y, VoidAllocator, Deleter> const & r)
: m_px(ptr), m_pi(r.m_pi) // nothrow
{ if( m_pi != 0 ) m_pi->add_ref_copy(); }
/*
explicit shared_count(weak_count<Y, VoidAllocator, Deleter> const & r)
// throws bad_weak_ptr when r.use_count() == 0
: m_pi( r.m_pi )
{
if( m_pi == 0 || !m_pi->add_ref_lock() ){
boost::throw_exception( boost::interprocess::bad_weak_ptr() );
}
}
*/
template<class Y>
explicit shared_count(weak_count<Y, VoidAllocator, Deleter> const & r)
// throws bad_weak_ptr when r.use_count() == 0
: m_px(r.m_px), m_pi( r.m_pi )
{
if( m_pi == 0 || !m_pi->add_ref_lock() ){
throw( boost::interprocess::bad_weak_ptr() );
}
}
const pointer &get_pointer() const
{ return m_px; }
pointer &get_pointer()
{ return m_px; }
shared_count & operator= (shared_count const & r) // nothrow
{
m_px = r.m_px;
counted_impl_ptr tmp = r.m_pi;
if( tmp != m_pi ){
if(tmp != 0) tmp->add_ref_copy();
if(m_pi != 0) m_pi->release();
m_pi = tmp;
}
return *this;
}
template<class Y>
shared_count & operator= (shared_count<Y, VoidAllocator, Deleter> const & r) // nothrow
{
m_px = r.m_px;
counted_impl_ptr tmp = r.m_pi;
if( tmp != m_pi ){
if(tmp != 0) tmp->add_ref_copy();
if(m_pi != 0) m_pi->release();
m_pi = tmp;
}
return *this;
}
void swap(shared_count & r) // nothrow
{ ipcdetail::do_swap(m_px, r.m_px); ipcdetail::do_swap(m_pi, r.m_pi); }
long use_count() const // nothrow
{ return m_pi != 0? m_pi->use_count(): 0; }
bool unique() const // nothrow
{ return use_count() == 1; }
const_deleter_pointer get_deleter() const
{ return m_pi ? m_pi->get_deleter() : 0; }
// const_allocator_pointer get_allocator() const
// { return m_pi ? m_pi->get_allocator() : 0; }
template<class T2, class VoidAllocator2, class Deleter2>
bool internal_equal (shared_count<T2, VoidAllocator2, Deleter2> const & other) const
{ return this->m_pi == other.m_pi; }
template<class T2, class VoidAllocator2, class Deleter2>
bool internal_less (shared_count<T2, VoidAllocator2, Deleter2> const & other) const
{ return std::less<counted_base_ptr>()(this->m_pi, other.m_pi); }
};
template<class T, class VoidAllocator, class Deleter, class T2, class VoidAllocator2, class Deleter2> inline
bool operator==(shared_count<T, VoidAllocator, Deleter> const & a, shared_count<T2, VoidAllocator2, Deleter2> const & b)
{ return a.internal_equal(b); }
template<class T, class VoidAllocator, class Deleter, class T2, class VoidAllocator2, class Deleter2> inline
bool operator<(shared_count<T, VoidAllocator, Deleter> const & a, shared_count<T2, VoidAllocator2, Deleter2> const & b)
{ return a.internal_less(b); }
template<class T, class VoidAllocator, class Deleter>
class weak_count
{
public:
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, T>::type pointer;
private:
typedef sp_counted_impl_pd<VoidAllocator, Deleter> counted_impl;
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, counted_impl>::type counted_impl_ptr;
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, sp_counted_base>::type counted_base_ptr;
pointer m_px;
counted_impl_ptr m_pi;
template <class T2, class VoidAllocator2, class Deleter2>
friend class weak_count;
template <class T2, class VoidAllocator2, class Deleter2>
friend class shared_count;
public:
weak_count(): m_px(0), m_pi(0) // nothrow
{}
template <class Y>
explicit weak_count(shared_count<Y, VoidAllocator, Deleter> const & r)
: m_px(r.m_px), m_pi(r.m_pi) // nothrow
{ if(m_pi != 0) m_pi->weak_add_ref(); }
weak_count(weak_count const & r)
: m_px(r.m_px), m_pi(r.m_pi) // nothrow
{ if(m_pi != 0) m_pi->weak_add_ref(); }
template<class Y>
weak_count(weak_count<Y, VoidAllocator, Deleter> const & r)
: m_px(r.m_px), m_pi(r.m_pi) // nothrow
{ if(m_pi != 0) m_pi->weak_add_ref(); }
~weak_count() // nothrow
{ if(m_pi != 0) m_pi->weak_release(); }
template<class Y>
weak_count & operator= (shared_count<Y, VoidAllocator, Deleter> const & r) // nothrow
{
m_px = r.m_px;
counted_impl_ptr tmp = r.m_pi;
if(tmp != 0) tmp->weak_add_ref();
if(m_pi != 0) m_pi->weak_release();
m_pi = tmp;
return *this;
}
weak_count & operator= (weak_count const & r) // nothrow
{
counted_impl_ptr tmp = r.m_pi;
if(tmp != 0) tmp->weak_add_ref();
if(m_pi != 0) m_pi->weak_release();
m_pi = tmp;
return *this;
}
void set_pointer(const pointer &ptr)
{ m_px = ptr; }
template<class Y>
weak_count & operator= (weak_count<Y, VoidAllocator, Deleter> const& r) // nothrow
{
counted_impl_ptr tmp = r.m_pi;
if(tmp != 0) tmp->weak_add_ref();
if(m_pi != 0) m_pi->weak_release();
m_pi = tmp;
return *this;
}
void swap(weak_count & r) // nothrow
{ ipcdetail::do_swap(m_px, r.m_px); ipcdetail::do_swap(m_pi, r.m_pi); }
long use_count() const // nothrow
{ return m_pi != 0? m_pi->use_count() : 0; }
template<class T2, class VoidAllocator2, class Deleter2>
bool internal_equal (weak_count<T2, VoidAllocator2, Deleter2> const & other) const
{ return this->m_pi == other.m_pi; }
template<class T2, class VoidAllocator2, class Deleter2>
bool internal_less (weak_count<T2, VoidAllocator2, Deleter2> const & other) const
{ return std::less<counted_base_ptr>()(this->m_pi, other.m_pi); }
};
template<class T, class VoidAllocator, class Deleter, class T2, class VoidAllocator2, class Deleter2> inline
bool operator==(weak_count<T, VoidAllocator, Deleter> const & a, weak_count<T2, VoidAllocator2, Deleter2> const & b)
{ return a.internal_equal(b); }
template<class T, class VoidAllocator, class Deleter, class T2, class VoidAllocator2, class Deleter2> inline
bool operator<(weak_count<T, VoidAllocator, Deleter> const & a, weak_count<T2, VoidAllocator2, Deleter2> const & b)
{ return a.internal_less(b); }
} // namespace ipcdetail
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED

View File

@@ -0,0 +1,18 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2009.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED
# include <boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED

View File

@@ -0,0 +1,92 @@
#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_ATOMIC_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_ATOMIC_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
// Copyright 2004-2005 Peter Dimov
// Copyright 2007-2009 Ion Gaztanaga
//
// 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)
//
//
// Lock-free algorithm by Alexander Terekhov
//
// Thanks to Ben Hitchings for the #weak + (#shared != 0)
// formulation
//
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <typeinfo>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class sp_counted_base
{
private:
sp_counted_base( sp_counted_base const & );
sp_counted_base & operator= ( sp_counted_base const & );
boost::uint32_t use_count_; // #shared
boost::uint32_t weak_count_; // #weak + (#shared != 0)
public:
sp_counted_base(): use_count_( 1 ), weak_count_( 1 )
{}
~sp_counted_base() // nothrow
{}
void add_ref_copy()
{
ipcdetail::atomic_inc32( &use_count_ );
}
bool add_ref_lock() // true on success
{
for( ;; )
{
boost::uint32_t tmp = static_cast< boost::uint32_t const volatile& >( use_count_ );
if( tmp == 0 ) return false;
if( ipcdetail::atomic_cas32( &use_count_, tmp + 1, tmp ) == tmp )
return true;
}
}
bool ref_release() // nothrow
{ return 1 == ipcdetail::atomic_dec32( &use_count_ ); }
void weak_add_ref() // nothrow
{ ipcdetail::atomic_inc32( &weak_count_ ); }
bool weak_release() // nothrow
{ return 1 == ipcdetail::atomic_dec32( &weak_count_ ); }
long use_count() const // nothrow
{ return (long)static_cast<boost::uint32_t const volatile &>( use_count_ ); }
};
} // namespace ipcdetail
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_ATOMIC_HPP_INCLUDED

View File

@@ -0,0 +1,146 @@
#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
//
// This file is the adaptation for shared memory memory mapped
// files of boost/detail/sp_counted_impl.hpp
//
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
// Copyright 2004-2005 Peter Dimov
// Copyright 2006 Ion Gaztanaga
//
// 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)
//
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#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/pointer_to_other.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
//!A deleter for scoped_ptr that deallocates the memory
//!allocated for an object using a STL allocator.
template <class Allocator>
struct scoped_ptr_dealloc_functor
{
typedef typename Allocator::pointer pointer;
typedef ipcdetail::integral_constant<unsigned,
boost::interprocess::version<Allocator>::value> alloc_version;
typedef ipcdetail::integral_constant<unsigned, 1> allocator_v1;
typedef ipcdetail::integral_constant<unsigned, 2> allocator_v2;
private:
void priv_deallocate(const typename Allocator::pointer &p, allocator_v1)
{ m_alloc.deallocate(p, 1); }
void priv_deallocate(const typename Allocator::pointer &p, allocator_v2)
{ m_alloc.deallocate_one(p); }
public:
Allocator& m_alloc;
scoped_ptr_dealloc_functor(Allocator& a)
: m_alloc(a) {}
void operator()(pointer ptr)
{ if (ptr) priv_deallocate(ptr, alloc_version()); }
};
template<class A, class D>
class sp_counted_impl_pd
: public sp_counted_base
, A::template rebind< sp_counted_impl_pd<A, D> >::other
, D // copy constructor must not throw
{
private:
typedef sp_counted_impl_pd<A, D> this_type;
typedef typename A::template rebind
<this_type>::other this_allocator;
typedef typename A::template rebind
<const this_type>::other const_this_allocator;
typedef typename this_allocator::pointer this_pointer;
sp_counted_impl_pd( sp_counted_impl_pd const & );
sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & );
typedef typename boost::pointer_to_other
<typename A::pointer, const D>::type const_deleter_pointer;
typedef typename boost::pointer_to_other
<typename A::pointer, const A>::type const_allocator_pointer;
typedef typename D::pointer pointer;
pointer m_ptr;
public:
// pre: d(p) must not throw
template<class Ptr>
sp_counted_impl_pd(const Ptr & p, const A &a, const D &d )
: this_allocator(a), D(d), m_ptr(p)
{}
const_deleter_pointer get_deleter() const
{ return const_deleter_pointer(&static_cast<const D&>(*this)); }
const_allocator_pointer get_allocator() const
{ return const_allocator_pointer(&static_cast<const A&>(*this)); }
void dispose() // nothrow
{ static_cast<D&>(*this)(m_ptr); }
void destroy() // nothrow
{
//Self destruction, so get a copy of the allocator
//(in the future we could move it)
this_allocator a_copy(*this);
BOOST_ASSERT(a_copy == *this);
this_pointer this_ptr (this);
//Do it now!
scoped_ptr< this_type, scoped_ptr_dealloc_functor<this_allocator> >
deleter(this_ptr, a_copy);
typedef typename this_allocator::value_type value_type;
ipcdetail::get_pointer(this_ptr)->~value_type();
}
void release() // nothrow
{
if(this->ref_release()){
this->dispose();
this->weak_release();
}
}
void weak_release() // nothrow
{
if(sp_counted_base::weak_release()){
this->destroy();
}
}
};
} // namespace ipcdetail
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED

View File

@@ -0,0 +1,79 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/enable_shared_from_this.hpp
//
// (C) Copyright Peter Dimov 2002
// (C) Copyright Ion Gaztanaga 2006. 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_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED
#define BOOST_INTERPROCESS_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/smart_ptr/weak_ptr.hpp>
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
//!\file
//!Describes an utility to form a shared pointer from this
namespace boost{
namespace interprocess{
//!This class is used as a base class that allows a shared_ptr to the current
//!object to be obtained from within a member function.
//!enable_shared_from_this defines two member functions called shared_from_this
//!that return a shared_ptr<T> and shared_ptr<T const>, depending on constness, to this.
template<class T, class A, class D>
class enable_shared_from_this
{
/// @cond
protected:
enable_shared_from_this()
{}
enable_shared_from_this(enable_shared_from_this const &)
{}
enable_shared_from_this & operator=(enable_shared_from_this const &)
{ return *this; }
~enable_shared_from_this()
{}
/// @endcond
public:
shared_ptr<T, A, D> shared_from_this()
{
shared_ptr<T, A, D> p(_internal_weak_this);
BOOST_ASSERT(ipcdetail::get_pointer(p.get()) == this);
return p;
}
shared_ptr<T const, A, D> shared_from_this() const
{
shared_ptr<T const, A, D> p(_internal_weak_this);
BOOST_ASSERT(ipcdetail::get_pointer(p.get()) == this);
return p;
}
/// @cond
typedef T element_type;
mutable weak_ptr<element_type, A, D> _internal_weak_this;
/// @endcond
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED

View File

@@ -0,0 +1,294 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/intrusive_ptr.hpp
//
// (C) Copyright Peter Dimov 2001, 2002
// (C) Copyright Ion Gaztanaga 2006. 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_INTRUSIVE_PTR_HPP_INCLUDED
#define BOOST_INTERPROCESS_INTRUSIVE_PTR_HPP_INCLUDED
//!\file
//!Describes an intrusive ownership pointer.
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/pointer_to_other.hpp>
#include <functional> // for std::less
#include <iosfwd> // for std::basic_ostream
namespace boost {
namespace interprocess {
//!The intrusive_ptr class template stores a pointer to an object
//!with an embedded reference count. intrusive_ptr is parameterized on
//!T (the type of the object pointed to) and VoidPointer(a void pointer type
//!that defines the type of pointer that intrusive_ptr will store).
//!intrusive_ptr<T, void *> defines a class with a T* member whereas
//!intrusive_ptr<T, offset_ptr<void> > defines a class with a offset_ptr<T> member.
//!Relies on unqualified calls to:
//!
//! void intrusive_ptr_add_ref(T * p);
//! void intrusive_ptr_release(T * p);
//!
//! with (p != 0)
//!
//!The object is responsible for destroying itself.
template<class T, class VoidPointer>
class intrusive_ptr
{
public:
//!Provides the type of the internal stored pointer.
typedef typename boost::pointer_to_other<VoidPointer, T>::type pointer;
//!Provides the type of the stored pointer.
typedef T element_type;
/// @cond
private:
typedef VoidPointer VP;
typedef intrusive_ptr this_type;
typedef pointer this_type::*unspecified_bool_type;
/// @endcond
public:
//!Constructor. Initializes internal pointer to 0.
//!Does not throw
intrusive_ptr(): m_ptr(0)
{}
//!Constructor. Copies pointer and if "p" is not zero and
//!"add_ref" is true calls intrusive_ptr_add_ref(get_pointer(p)).
//!Does not throw
intrusive_ptr(const pointer &p, bool add_ref = true): m_ptr(p)
{
if(m_ptr != 0 && add_ref) intrusive_ptr_add_ref(ipcdetail::get_pointer(m_ptr));
}
//!Copy constructor. Copies the internal pointer and if "p" is not
//!zero calls intrusive_ptr_add_ref(get_pointer(p)). Does not throw
intrusive_ptr(intrusive_ptr const & rhs)
: m_ptr(rhs.m_ptr)
{
if(m_ptr != 0) intrusive_ptr_add_ref(ipcdetail::get_pointer(m_ptr));
}
//!Constructor from related. Copies the internal pointer and if "p" is not
//!zero calls intrusive_ptr_add_ref(get_pointer(p)). Does not throw
template<class U> intrusive_ptr
(intrusive_ptr<U, VP> const & rhs)
: m_ptr(rhs.get())
{
if(m_ptr != 0) intrusive_ptr_add_ref(ipcdetail::get_pointer(m_ptr));
}
//!Destructor. If internal pointer is not 0, calls
//!intrusive_ptr_release(get_pointer(m_ptr)). Does not throw
~intrusive_ptr()
{
if(m_ptr != 0) intrusive_ptr_release(ipcdetail::get_pointer(m_ptr));
}
//!Assignment operator. Equivalent to intrusive_ptr(r).swap(*this).
//!Does not throw
intrusive_ptr & operator=(intrusive_ptr const & rhs)
{
this_type(rhs).swap(*this);
return *this;
}
//!Assignment from related. Equivalent to intrusive_ptr(r).swap(*this).
//!Does not throw
template<class U> intrusive_ptr & operator=
(intrusive_ptr<U, VP> const & rhs)
{
this_type(rhs).swap(*this);
return *this;
}
//!Assignment from pointer. Equivalent to intrusive_ptr(r).swap(*this).
//!Does not throw
intrusive_ptr & operator=(pointer rhs)
{
this_type(rhs).swap(*this);
return *this;
}
//!Returns a reference to the internal pointer.
//!Does not throw
pointer &get()
{ return m_ptr; }
//!Returns a reference to the internal pointer.
//!Does not throw
const pointer &get() const
{ return m_ptr; }
//!Returns *get().
//!Does not throw
T & operator*() const
{ return *m_ptr; }
//!Returns *get().
//!Does not throw
const pointer &operator->() const
{ return m_ptr; }
//!Returns get().
//!Does not throw
pointer &operator->()
{ return m_ptr; }
//!Conversion to boolean.
//!Does not throw
operator unspecified_bool_type () const
{ return m_ptr == 0? 0: &this_type::m_ptr; }
//!Not operator.
//!Does not throw
bool operator! () const
{ return m_ptr == 0; }
//!Exchanges the contents of the two smart pointers.
//!Does not throw
void swap(intrusive_ptr & rhs)
{ ipcdetail::do_swap(m_ptr, rhs.m_ptr); }
/// @cond
private:
pointer m_ptr;
/// @endcond
};
//!Returns a.get() == b.get().
//!Does not throw
template<class T, class U, class VP> inline
bool operator==(intrusive_ptr<T, VP> const & a,
intrusive_ptr<U, VP> const & b)
{ return a.get() == b.get(); }
//!Returns a.get() != b.get().
//!Does not throw
template<class T, class U, class VP> inline
bool operator!=(intrusive_ptr<T, VP> const & a,
intrusive_ptr<U, VP> const & b)
{ return a.get() != b.get(); }
//!Returns a.get() == b.
//!Does not throw
template<class T, class VP> inline
bool operator==(intrusive_ptr<T, VP> const & a,
const typename intrusive_ptr<T, VP>::pointer &b)
{ return a.get() == b; }
//!Returns a.get() != b.
//!Does not throw
template<class T, class VP> inline
bool operator!=(intrusive_ptr<T, VP> const & a,
const typename intrusive_ptr<T, VP>::pointer &b)
{ return a.get() != b; }
//!Returns a == b.get().
//!Does not throw
template<class T, class VP> inline
bool operator==(const typename intrusive_ptr<T, VP>::pointer &a,
intrusive_ptr<T, VP> const & b)
{ return a == b.get(); }
//!Returns a != b.get().
//!Does not throw
template<class T, class VP> inline
bool operator!=(const typename intrusive_ptr<T, VP>::pointer &a,
intrusive_ptr<T, VP> const & b)
{ return a != b.get(); }
//!Returns a.get() < b.get().
//!Does not throw
template<class T, class VP> inline
bool operator<(intrusive_ptr<T, VP> const & a,
intrusive_ptr<T, VP> const & b)
{
return std::less<typename intrusive_ptr<T, VP>::pointer>()
(a.get(), b.get());
}
//!Exchanges the contents of the two intrusive_ptrs.
//!Does not throw
template<class T, class VP> inline
void swap(intrusive_ptr<T, VP> & lhs,
intrusive_ptr<T, VP> & rhs)
{ lhs.swap(rhs); }
// operator<<
template<class E, class T, class Y, class VP>
inline std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, intrusive_ptr<Y, VP> const & p)
{ os << p.get(); return os; }
//!Returns p.get().
//!Does not throw
template<class T, class VP>
inline typename boost::interprocess::intrusive_ptr<T, VP>::pointer
get_pointer(intrusive_ptr<T, VP> p)
{ return p.get(); }
/*Emulates static cast operator. Does not throw*/
/*
template<class T, class U, class VP>
inline boost::interprocess::intrusive_ptr<T, VP> static_pointer_cast
(boost::interprocess::intrusive_ptr<U, VP> const & p)
{ return do_static_cast<U>(p.get()); }
*/
/*Emulates const cast operator. Does not throw*/
/*
template<class T, class U, class VP>
inline boost::interprocess::intrusive_ptr<T, VP> const_pointer_cast
(boost::interprocess::intrusive_ptr<U, VP> const & p)
{ return do_const_cast<U>(p.get()); }
*/
/*Emulates dynamic cast operator. Does not throw*/
/*
template<class T, class U, class VP>
inline boost::interprocess::intrusive_ptr<T, VP> dynamic_pointer_cast
(boost::interprocess::intrusive_ptr<U, VP> const & p)
{ return do_dynamic_cast<U>(p.get()); }
*/
/*Emulates reinterpret cast operator. Does not throw*/
/*
template<class T, class U, class VP>
inline boost::interprocess::intrusive_ptr<T, VP>reinterpret_pointer_cast
(boost::interprocess::intrusive_ptr<U, VP> const & p)
{ return do_reinterpret_cast<U>(p.get()); }
*/
} // namespace interprocess
/// @cond
#if defined(_MSC_VER) && (_MSC_VER < 1400)
//!Returns p.get().
//!Does not throw
template<class T, class VP>
inline T *get_pointer(boost::interprocess::intrusive_ptr<T, VP> p)
{ return p.get(); }
#endif
/// @endcond
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_INTRUSIVE_PTR_HPP_INCLUDED

View File

@@ -0,0 +1,168 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/scoped_ptr.hpp
//
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
// (C) Copyright Peter Dimov 2001, 2002
// (C) Copyright Ion Gaztanaga 2006. 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_SCOPED_PTR_HPP_INCLUDED
#define BOOST_INTERPROCESS_SCOPED_PTR_HPP_INCLUDED
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/pointer_type.hpp>
#include <boost/assert.hpp>
#include <boost/pointer_to_other.hpp>
//!\file
//!Describes the smart pointer scoped_ptr
namespace boost {
namespace interprocess {
//!scoped_ptr stores a pointer to a dynamically allocated object.
//!The object pointed to is guaranteed to be deleted, either on destruction
//!of the scoped_ptr, or via an explicit reset. The user can avoid this
//!deletion using release().
//!scoped_ptr is parameterized on T (the type of the object pointed to) and
//!Deleter (the functor to be executed to delete the internal pointer).
//!The internal pointer will be of the same pointer type as typename
//!Deleter::pointer type (that is, if typename Deleter::pointer is
//!offset_ptr<void>, the internal pointer will be offset_ptr<T>).
template<class T, class Deleter>
class scoped_ptr
: private Deleter
{
/// @cond
scoped_ptr(scoped_ptr const &);
scoped_ptr & operator=(scoped_ptr const &);
typedef scoped_ptr<T, Deleter> this_type;
typedef typename ipcdetail::add_reference<T>::type reference;
/// @endcond
public:
typedef T element_type;
typedef Deleter deleter_type;
typedef typename ipcdetail::pointer_type<T, Deleter>::type pointer;
//!Provides the type of the internal stored pointer
// typedef typename boost::pointer_to_other
// <typename Deleter::pointer, T>::type pointer;
//!Constructs a scoped_ptr, storing a copy of p(which can be 0) and d.
//!Does not throw.
explicit scoped_ptr(const pointer &p = 0, const Deleter &d = Deleter())
: Deleter(d), m_ptr(p) // throws if pointer/Deleter copy ctor throws
{}
//!If the stored pointer is not 0, destroys the object pointed to by the stored pointer.
//!calling the operator() of the stored deleter. Never throws
~scoped_ptr()
{
if(m_ptr){
Deleter &del = static_cast<Deleter&>(*this);
del(m_ptr);
}
}
//!Deletes the object pointed to by the stored pointer and then
//!stores a copy of p. Never throws
void reset(const pointer &p = 0) // never throws
{ BOOST_ASSERT(p == 0 || p != m_ptr); this_type(p).swap(*this); }
//!Deletes the object pointed to by the stored pointer and then
//!stores a copy of p and a copy of d.
void reset(const pointer &p, const Deleter &d) // never throws
{ BOOST_ASSERT(p == 0 || p != m_ptr); this_type(p).swap(*this); }
//!Assigns internal pointer as 0 and returns previous pointer. This will
//!avoid deletion on destructor
pointer release()
{ pointer tmp(m_ptr); m_ptr = 0; return tmp; }
//!Returns a reference to the object pointed to by the stored pointer.
//!Never throws.
reference operator*() const
{ BOOST_ASSERT(m_ptr != 0); return *m_ptr; }
//!Returns the internal stored pointer.
//!Never throws.
pointer &operator->()
{ BOOST_ASSERT(m_ptr != 0); return m_ptr; }
//!Returns the internal stored pointer.
//!Never throws.
const pointer &operator->() const
{ BOOST_ASSERT(m_ptr != 0); return m_ptr; }
//!Returns the stored pointer.
//!Never throws.
pointer & get()
{ return m_ptr; }
//!Returns the stored pointer.
//!Never throws.
const pointer & get() const
{ return m_ptr; }
typedef pointer this_type::*unspecified_bool_type;
//!Conversion to bool
//!Never throws
operator unspecified_bool_type() const
{ return m_ptr == 0? 0: &this_type::m_ptr; }
//!Returns true if the stored pointer is 0.
//!Never throws.
bool operator! () const // never throws
{ return m_ptr == 0; }
//!Exchanges the internal pointer and deleter with other scoped_ptr
//!Never throws.
void swap(scoped_ptr & b) // never throws
{ ipcdetail::do_swap<Deleter>(*this, b); ipcdetail::do_swap(m_ptr, b.m_ptr); }
/// @cond
private:
pointer m_ptr;
/// @endcond
};
//!Exchanges the internal pointer and deleter with other scoped_ptr
//!Never throws.
template<class T, class D> inline
void swap(scoped_ptr<T, D> & a, scoped_ptr<T, D> & b)
{ a.swap(b); }
//!Returns a copy of the stored pointer
//!Never throws
template<class T, class D> inline
typename scoped_ptr<T, D>::pointer get_pointer(scoped_ptr<T, D> const & p)
{ return p.get(); }
} // namespace interprocess
/// @cond
#if defined(_MSC_VER) && (_MSC_VER < 1400)
template<class T, class D> inline
T *get_pointer(boost::interprocess::scoped_ptr<T, D> const & p)
{ return p.get(); }
#endif
/// @endcond
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_SCOPED_PTR_HPP_INCLUDED

View File

@@ -0,0 +1,409 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/shared_ptr.hpp
//
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
// (C) Copyright Peter Dimov 2001, 2002, 2003
// (C) Copyright Ion Gaztanaga 2006-2009.
// 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_SHARED_PTR_HPP_INCLUDED
#define BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/cast_tags.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/smart_ptr/detail/shared_count.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/smart_ptr/deleter.hpp>
#include <boost/static_assert.hpp>
#include <boost/pointer_to_other.hpp>
#include <algorithm> // for std::swap
#include <functional> // for std::less
#include <typeinfo> // for std::bad_cast
#include <iosfwd> // for std::basic_ostream
//!\file
//!Describes the smart pointer shared_ptr
namespace boost{
namespace interprocess{
template<class T, class VoidAllocator, class Deleter> class weak_ptr;
template<class T, class VoidAllocator, class Deleter> class enable_shared_from_this;
namespace ipcdetail{
template<class T, class VoidAllocator, class Deleter>
inline void sp_enable_shared_from_this
(shared_count<T, VoidAllocator, Deleter> const & pn
,enable_shared_from_this<T, VoidAllocator, Deleter> *pe
,T *ptr)
{
(void)ptr;
if(pe != 0){
pe->_internal_weak_this._internal_assign(pn);
}
}
template<class T, class VoidAllocator, class Deleter>
inline void sp_enable_shared_from_this(shared_count<T, VoidAllocator, Deleter> const &, ...)
{}
} // namespace ipcdetail
//!shared_ptr stores a pointer to a dynamically allocated object.
//!The object pointed to is guaranteed to be deleted when the last shared_ptr pointing to
//!it is destroyed or reset.
//!
//!shared_ptr is parameterized on
//!T (the type of the object pointed to), VoidAllocator (the void allocator to be used
//!to allocate the auxiliary data) and Deleter (the deleter whose
//!operator() will be used to delete the object.
//!
//!The internal pointer will be of the same pointer type as typename
//!VoidAllocator::pointer type (that is, if typename VoidAllocator::pointer is
//!offset_ptr<void>, the internal pointer will be offset_ptr<T>).
//!
//!Because the implementation uses reference counting, cycles of shared_ptr
//!instances will not be reclaimed. For example, if main() holds a
//!shared_ptr to A, which directly or indirectly holds a shared_ptr back
//!to A, A's use count will be 2. Destruction of the original shared_ptr
//!will leave A dangling with a use count of 1.
//!Use weak_ptr to "break cycles."
template<class T, class VoidAllocator, class Deleter>
class shared_ptr
{
/// @cond
private:
typedef shared_ptr<T, VoidAllocator, Deleter> this_type;
/// @endcond
public:
typedef T element_type;
typedef T value_type;
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, T>::type pointer;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, const Deleter>::type const_deleter_pointer;
typedef typename boost::pointer_to_other
<typename VoidAllocator::pointer, const VoidAllocator>::type const_allocator_pointer;
BOOST_COPYABLE_AND_MOVABLE(shared_ptr)
public:
//!Constructs an empty shared_ptr.
//!Use_count() == 0 && get()== 0.
shared_ptr()
: m_pn() // never throws
{}
//!Constructs a shared_ptr that owns the pointer p. Auxiliary data will be allocated
//!with a copy of a and the object will be deleted with a copy of d.
//!Requirements: Deleter and A's copy constructor must not throw.
explicit shared_ptr(const pointer&p, const VoidAllocator &a = VoidAllocator(), const Deleter &d = Deleter())
: m_pn(p, a, d)
{
//Check that the pointer passed is of the same type that
//the pointer the allocator defines or it's a raw pointer
typedef typename boost::pointer_to_other<pointer, T>::type ParameterPointer;
BOOST_STATIC_ASSERT((ipcdetail::is_same<pointer, ParameterPointer>::value) ||
(ipcdetail::is_pointer<pointer>::value));
ipcdetail::sp_enable_shared_from_this<T, VoidAllocator, Deleter>( m_pn, ipcdetail::get_pointer(p), ipcdetail::get_pointer(p) );
}
//!Constructs a shared_ptr that shares ownership with r and stores p.
//!Postconditions: get() == p && use_count() == r.use_count().
//!Throws: nothing.
shared_ptr(const shared_ptr &other, const pointer &p)
: m_pn(other.m_pn, p)
{}
//!If r is empty, constructs an empty shared_ptr. Otherwise, constructs
//!a shared_ptr that shares ownership with r. Never throws.
template<class Y>
shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r)
: m_pn(r.m_pn) // never throws
{}
//!Constructs a shared_ptr that shares ownership with r and stores
//!a copy of the pointer stored in r.
template<class Y>
explicit shared_ptr(weak_ptr<Y, VoidAllocator, Deleter> const & r)
: m_pn(r.m_pn) // may throw
{}
//!Move-Constructs a shared_ptr that takes ownership of other resource and
//!other is put in default-constructed state.
//!Throws: nothing.
explicit shared_ptr(BOOST_RV_REF(shared_ptr) other)
: m_pn()
{ this->swap(other); }
/// @cond
template<class Y>
shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r, ipcdetail::static_cast_tag)
: m_pn( pointer(static_cast<T*>(ipcdetail::get_pointer(r.m_pn.get_pointer())))
, r.m_pn)
{}
template<class Y>
shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r, ipcdetail::const_cast_tag)
: m_pn( pointer(const_cast<T*>(ipcdetail::get_pointer(r.m_pn.get_pointer())))
, r.m_pn)
{}
template<class Y>
shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r, ipcdetail::dynamic_cast_tag)
: m_pn( pointer(dynamic_cast<T*>(ipcdetail::get_pointer(r.m_pn.get_pointer())))
, r.m_pn)
{
if(!m_pn.get_pointer()){ // need to allocate new counter -- the cast failed
m_pn = ipcdetail::shared_count<T, VoidAllocator, Deleter>();
}
}
/// @endcond
//!Equivalent to shared_ptr(r).swap(*this).
//!Never throws
template<class Y>
shared_ptr & operator=(shared_ptr<Y, VoidAllocator, Deleter> const & r)
{
m_pn = r.m_pn; // shared_count::op= doesn't throw
return *this;
}
//!Equivalent to shared_ptr(r).swap(*this).
//!Never throws
shared_ptr & operator=(BOOST_COPY_ASSIGN_REF(shared_ptr) r)
{
m_pn = r.m_pn; // shared_count::op= doesn't throw
return *this;
}
//!Move-assignment. Equivalent to shared_ptr(other).swap(*this).
//!Never throws
shared_ptr & operator=(BOOST_RV_REF(shared_ptr) other) // never throws
{
this_type(other).swap(*this);
return *this;
}
//!This is equivalent to:
//!this_type().swap(*this);
void reset()
{
this_type().swap(*this);
}
//!This is equivalent to:
//!this_type(p, a, d).swap(*this);
template<class Pointer>
void reset(const Pointer &p, const VoidAllocator &a = VoidAllocator(), const Deleter &d = Deleter())
{
//Check that the pointer passed is of the same type that
//the pointer the allocator defines or it's a raw pointer
typedef typename boost::pointer_to_other<Pointer, T>::type ParameterPointer;
BOOST_STATIC_ASSERT((ipcdetail::is_same<pointer, ParameterPointer>::value) ||
(ipcdetail::is_pointer<Pointer>::value));
this_type(p, a, d).swap(*this);
}
template<class Y>
void reset(shared_ptr<Y, VoidAllocator, Deleter> const & r, const pointer &p)
{
this_type(r, p).swap(*this);
}
//!Returns a reference to the
//!pointed type
reference operator* () const // never throws
{ BOOST_ASSERT(m_pn.get_pointer() != 0); return *m_pn.get_pointer(); }
//!Returns the pointer pointing
//!to the owned object
pointer operator-> () const // never throws
{ BOOST_ASSERT(m_pn.get_pointer() != 0); return m_pn.get_pointer(); }
//!Returns the pointer pointing
//!to the owned object
pointer get() const // never throws
{ return m_pn.get_pointer(); }
/// @cond
// implicit conversion to "bool"
void unspecified_bool_type_func() const {}
typedef void (this_type::*unspecified_bool_type)() const;
operator unspecified_bool_type() const // never throws
{ return !m_pn.get_pointer() ? 0 : &this_type::unspecified_bool_type_func; }
/// @endcond
//!Not operator.
//!Returns true if this->get() != 0, false otherwise
bool operator! () const // never throws
{ return !m_pn.get_pointer(); }
//!Returns use_count() == 1.
//!unique() might be faster than use_count()
bool unique() const // never throws
{ return m_pn.unique(); }
//!Returns the number of shared_ptr objects, *this included,
//!that share ownership with *this, or an unspecified nonnegative
//!value when *this is empty.
//!use_count() is not necessarily efficient. Use only for
//!debugging and testing purposes, not for production code.
long use_count() const // never throws
{ return m_pn.use_count(); }
//!Exchanges the contents of the two
//!smart pointers.
void swap(shared_ptr<T, VoidAllocator, Deleter> & other) // never throws
{ m_pn.swap(other.m_pn); }
/// @cond
template<class T2, class A2, class Deleter2>
bool _internal_less(shared_ptr<T2, A2, Deleter2> const & rhs) const
{ return m_pn < rhs.m_pn; }
const_deleter_pointer get_deleter() const
{ return m_pn.get_deleter(); }
// const_allocator_pointer get_allocator() const
// { return m_pn.get_allocator(); }
private:
template<class T2, class A2, class Deleter2> friend class shared_ptr;
template<class T2, class A2, class Deleter2> friend class weak_ptr;
ipcdetail::shared_count<T, VoidAllocator, Deleter> m_pn; // reference counter
/// @endcond
}; // shared_ptr
template<class T, class VoidAllocator, class Deleter, class U, class VoidAllocator2, class Deleter2> inline
bool operator==(shared_ptr<T, VoidAllocator, Deleter> const & a, shared_ptr<U, VoidAllocator2, Deleter2> const & b)
{ return a.get() == b.get(); }
template<class T, class VoidAllocator, class Deleter, class U, class VoidAllocator2, class Deleter2> inline
bool operator!=(shared_ptr<T, VoidAllocator, Deleter> const & a, shared_ptr<U, VoidAllocator2, Deleter2> const & b)
{ return a.get() != b.get(); }
template<class T, class VoidAllocator, class Deleter, class U, class VoidAllocator2, class Deleter2> inline
bool operator<(shared_ptr<T, VoidAllocator, Deleter> const & a, shared_ptr<U, VoidAllocator2, Deleter2> const & b)
{ return a._internal_less(b); }
template<class T, class VoidAllocator, class Deleter> inline
void swap(shared_ptr<T, VoidAllocator, Deleter> & a, shared_ptr<T, VoidAllocator, Deleter> & b)
{ a.swap(b); }
template<class T, class VoidAllocator, class Deleter, class U> inline
shared_ptr<T, VoidAllocator, Deleter> static_pointer_cast(shared_ptr<U, VoidAllocator, Deleter> const & r)
{ return shared_ptr<T, VoidAllocator, Deleter>(r, ipcdetail::static_cast_tag()); }
template<class T, class VoidAllocator, class Deleter, class U> inline
shared_ptr<T, VoidAllocator, Deleter> const_pointer_cast(shared_ptr<U, VoidAllocator, Deleter> const & r)
{ return shared_ptr<T, VoidAllocator, Deleter>(r, ipcdetail::const_cast_tag()); }
template<class T, class VoidAllocator, class Deleter, class U> inline
shared_ptr<T, VoidAllocator, Deleter> dynamic_pointer_cast(shared_ptr<U, VoidAllocator, Deleter> const & r)
{ return shared_ptr<T, VoidAllocator, Deleter>(r, ipcdetail::dynamic_cast_tag()); }
// get_pointer() enables boost::mem_fn to recognize shared_ptr
template<class T, class VoidAllocator, class Deleter> inline
T * get_pointer(shared_ptr<T, VoidAllocator, Deleter> const & p)
{ return p.get(); }
// operator<<
template<class E, class T, class Y, class VoidAllocator, class Deleter> inline
std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, shared_ptr<Y, VoidAllocator, Deleter> const & p)
{ os << p.get(); return os; }
//!Returns the type of a shared pointer
//!of type T with the allocator boost::interprocess::allocator allocator
//!and boost::interprocess::deleter deleter
//!that can be constructed in the given managed segment type.
template<class T, class ManagedMemory>
struct managed_shared_ptr
{
typedef typename ManagedMemory::template allocator<void>::type void_allocator;
typedef typename ManagedMemory::template deleter<T>::type deleter;
typedef shared_ptr< T, void_allocator, deleter> type;
};
//!Returns an instance of a shared pointer constructed
//!with the default allocator and deleter from a pointer
//!of type T that has been allocated in the passed managed segment
template<class T, class ManagedMemory>
inline typename managed_shared_ptr<T, ManagedMemory>::type
make_managed_shared_ptr(T *constructed_object, ManagedMemory &managed_memory)
{
return typename managed_shared_ptr<T, ManagedMemory>::type
( constructed_object
, managed_memory.template get_allocator<void>()
, managed_memory.template get_deleter<T>()
);
}
//!Returns an instance of a shared pointer constructed
//!with the default allocator and deleter from a pointer
//!of type T that has been allocated in the passed managed segment.
//!Does not throw, return null shared pointer in error.
template<class T, class ManagedMemory>
inline typename managed_shared_ptr<T, ManagedMemory>::type
make_managed_shared_ptr(T *constructed_object, ManagedMemory &managed_memory, std::nothrow_t)
{
try{
return typename managed_shared_ptr<T, ManagedMemory>::type
( constructed_object
, managed_memory.template get_allocator<void>()
, managed_memory.template get_deleter<T>()
);
}
catch(...){
return typename managed_shared_ptr<T, ManagedMemory>::type();
}
}
} // namespace interprocess
/// @cond
#if defined(_MSC_VER) && (_MSC_VER < 1400)
// get_pointer() enables boost::mem_fn to recognize shared_ptr
template<class T, class VoidAllocator, class Deleter> inline
T * get_pointer(boost::interprocess::shared_ptr<T, VoidAllocator, Deleter> const & p)
{ return p.get(); }
#endif
/// @endcond
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED

Some files were not shown because too many files have changed in this diff Show More