mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2026-07-05 10:03:21 -04:00
Merge commit 'edd0930758f2177025d50dd655514f1ce64bb903' into hotfix-2.0.0-rc4
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_ALLOCATOR_HPP
|
||||
#define BOOST_INTERPROCESS_ALLOCATOR_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <boost/intrusive/pointer_traits.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 <boost/container/detail/placement_new.hpp>
|
||||
|
||||
#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;
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
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::intrusive::
|
||||
pointer_traits<aux_pointer_t>::template
|
||||
rebind_pointer<const void>::type cvoid_ptr;
|
||||
|
||||
//Pointer to the allocator
|
||||
typedef typename boost::intrusive::
|
||||
pointer_traits<cvoid_ptr>::template
|
||||
rebind_pointer<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;
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef typename boost::intrusive::
|
||||
pointer_traits<cvoid_ptr>::template
|
||||
rebind_pointer<T>::type pointer;
|
||||
typedef typename boost::intrusive::
|
||||
pointer_traits<pointer>::template
|
||||
rebind_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;
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
//Experimental. Don't use.
|
||||
typedef boost::container::container_detail::transform_multiallocation_chain
|
||||
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!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::to_raw_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(size_overflows<sizeof(T)>(count)){
|
||||
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::to_raw_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)
|
||||
{ boost::adl_move_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::to_raw_pointer(p))/sizeof(T);
|
||||
}
|
||||
|
||||
pointer allocation_command(boost::interprocess::allocation_type command,
|
||||
size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse)
|
||||
{
|
||||
value_type *reuse_raw = ipcdetail::to_raw_pointer(reuse);
|
||||
pointer const p = mp_mngr->allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse_raw);
|
||||
reuse = reuse_raw;
|
||||
return p;
|
||||
}
|
||||
|
||||
//!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 allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain)
|
||||
{
|
||||
if(size_overflows<sizeof(T)>(elem_size)){
|
||||
throw bad_alloc();
|
||||
}
|
||||
mp_mngr->allocate_many(elem_size*sizeof(T), num_elements, chain);
|
||||
}
|
||||
|
||||
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
|
||||
//!contiguous block
|
||||
//!of memory. The elements must be deallocated
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
|
||||
{
|
||||
mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T), chain);
|
||||
}
|
||||
|
||||
//!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)
|
||||
{ mp_mngr->deallocate_many(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().
|
||||
void allocate_individual(size_type num_elements, multiallocation_chain &chain)
|
||||
{ this->allocate_many(1, num_elements, chain); }
|
||||
|
||||
//!Deallocates memory previously allocated with allocate_one().
|
||||
//!You should never use deallocate_one to deallocate memory allocated
|
||||
//!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)
|
||||
{ this->deallocate_many(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)); }
|
||||
|
||||
//!Constructs an object
|
||||
//!Throws if T's constructor throws
|
||||
//!For backwards compatibility with libraries using C++03 allocators
|
||||
template<class P>
|
||||
void construct(const pointer &ptr, BOOST_FWD_REF(P) p)
|
||||
{ ::new((void*)ipcdetail::to_raw_pointer(ptr), boost_container_new_t()) value_type(::boost::forward<P>(p)); }
|
||||
|
||||
//!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 {
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
template<class T>
|
||||
struct has_trivial_destructor;
|
||||
|
||||
template<class T, class SegmentManager>
|
||||
struct has_trivial_destructor
|
||||
<boost::interprocess::allocator <T, SegmentManager> >
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP
|
||||
|
||||
@@ -0,0 +1,858 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 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
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <boost/intrusive/pointer_traits.hpp>
|
||||
|
||||
#include <boost/interprocess/interprocess_fwd.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp> //to_raw_pointer
|
||||
#include <boost/utility/addressof.hpp> //boost::addressof
|
||||
#include <boost/assert.hpp> //BOOST_ASSERT
|
||||
#include <boost/interprocess/exceptions.hpp> //bad_alloc
|
||||
#include <boost/interprocess/sync/scoped_lock.hpp> //scoped_lock
|
||||
#include <boost/interprocess/containers/allocation_type.hpp> //boost::interprocess::allocation_type
|
||||
#include <boost/container/detail/multiallocation_chain.hpp>
|
||||
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
|
||||
#include <boost/interprocess/detail/segment_manager_helper.hpp>
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/container/detail/placement_new.hpp>
|
||||
#include <boost/move/adl_move_swap.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 boost::intrusive::
|
||||
pointer_traits<void_pointer>::template
|
||||
rebind_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::to_raw_pointer(mp_node_pool));
|
||||
}
|
||||
|
||||
NodePool *get_node_pool() const
|
||||
{ return ipcdetail::to_raw_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()){
|
||||
mp_node_pool->allocate_nodes(m_max_cached_nodes/2, m_cached_nodes);
|
||||
}
|
||||
void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.pop_front());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void 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::to_raw_pointer(m_cached_nodes.pop_front());
|
||||
chain.push_back(ret);
|
||||
++allocated;
|
||||
}
|
||||
|
||||
if(allocated != n){
|
||||
mp_node_pool->allocate_nodes(n - allocated, chain);
|
||||
}
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
this->cached_deallocation(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(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(chain);
|
||||
}
|
||||
|
||||
public:
|
||||
void swap(cache_impl &other)
|
||||
{
|
||||
::boost::adl_move_swap(mp_node_pool, other.mp_node_pool);
|
||||
::boost::adl_move_swap(m_cached_nodes, other.m_cached_nodes);
|
||||
::boost::adl_move_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::intrusive::
|
||||
pointer_traits<void_pointer>::template
|
||||
rebind_pointer<T>::type pointer;
|
||||
typedef typename boost::intrusive::
|
||||
pointer_traits<void_pointer>::template
|
||||
rebind_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::container_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::to_raw_pointer(p))/sizeof(T);
|
||||
}
|
||||
|
||||
pointer allocation_command(boost::interprocess::allocation_type command,
|
||||
size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse)
|
||||
{
|
||||
value_type *reuse_raw = ipcdetail::to_raw_pointer(reuse);
|
||||
pointer const p = this->derived()->get_segment_manager()->allocation_command
|
||||
(command, limit_size, prefer_in_recvd_out_size, reuse_raw);
|
||||
reuse = reuse_raw;
|
||||
return p;
|
||||
}
|
||||
|
||||
//!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 allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain)
|
||||
{
|
||||
if(size_overflows<sizeof(T)>(elem_size)){
|
||||
throw bad_alloc();
|
||||
}
|
||||
this->derived()->get_segment_manager()->allocate_many(elem_size*sizeof(T), num_elements, chain);
|
||||
}
|
||||
|
||||
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
|
||||
//!contiguous block
|
||||
//!of memory. The elements must be deallocated
|
||||
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
|
||||
{
|
||||
this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T), chain);
|
||||
}
|
||||
|
||||
//!Allocates many elements of size elem_size in a contiguous block
|
||||
//!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)
|
||||
{ this->derived()->get_segment_manager()->deallocate_many(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)); }
|
||||
|
||||
//!Constructs an object
|
||||
//!Throws if T's constructor throws
|
||||
//!For backwards compatibility with libraries using C++03 allocators
|
||||
template<class P>
|
||||
void construct(const pointer &ptr, BOOST_FWD_REF(P) p)
|
||||
{ ::new((void*)ipcdetail::to_raw_pointer(ptr), boost_container_new_t()) value_type(::boost::forward<P>(p)); }
|
||||
|
||||
//!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::intrusive::
|
||||
pointer_traits<void_pointer>::template
|
||||
rebind_pointer<const void>::type cvoid_pointer;
|
||||
|
||||
public:
|
||||
typedef typename boost::intrusive::
|
||||
pointer_traits<void_pointer>::template
|
||||
rebind_pointer<T>::type pointer;
|
||||
typedef typename boost::intrusive::
|
||||
pointer_traits<void_pointer>::template
|
||||
rebind_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::container_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(size_overflows<sizeof(T)>(count)){
|
||||
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(count*sizeof(T))));
|
||||
}
|
||||
}
|
||||
|
||||
//!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::to_raw_pointer(ptr));
|
||||
else
|
||||
pool->get_segment_manager()->deallocate((void*)ipcdetail::to_raw_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().
|
||||
void allocate_individual(size_type num_elements, multiallocation_chain &chain)
|
||||
{
|
||||
typedef typename node_pool<0>::type node_pool_t;
|
||||
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
|
||||
pool->allocate_nodes(num_elements, chain);
|
||||
}
|
||||
|
||||
//!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::to_raw_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);
|
||||
}
|
||||
|
||||
//!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::intrusive::
|
||||
pointer_traits<void_pointer>::template
|
||||
rebind_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:
|
||||
static const std::size_t 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(size_overflows<sizeof(T)>(count)){
|
||||
throw bad_alloc();
|
||||
}
|
||||
else if(Version == 1 && count == 1){
|
||||
ret = m_cache.cached_allocation();
|
||||
}
|
||||
else{
|
||||
ret = this->get_segment_manager()->allocate(count*sizeof(T));
|
||||
}
|
||||
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::to_raw_pointer(ptr));
|
||||
}
|
||||
else{
|
||||
this->get_segment_manager()->deallocate((void*)ipcdetail::to_raw_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().
|
||||
void allocate_individual(size_type num_elements, multiallocation_chain &chain)
|
||||
{ this->m_cache.cached_allocation(num_elements, chain); }
|
||||
|
||||
//!Deallocates memory previously allocated with allocate_one().
|
||||
//!You should never use deallocate_one to deallocate memory allocated
|
||||
//!with other functions different from allocate_one(). Never throws
|
||||
void deallocate_one(const pointer &p)
|
||||
{ this->m_cache.cached_deallocation(ipcdetail::to_raw_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)
|
||||
{ m_cache.cached_deallocation(chain); }
|
||||
|
||||
//!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)
|
||||
{ ::boost::adl_move_swap(alloc1.m_cache, 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(); }
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
private:
|
||||
cache_impl<node_pool_t> m_cache;
|
||||
#endif //!defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
};
|
||||
|
||||
//!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 n nodes.
|
||||
//!Can throw boost::interprocess::bad_alloc
|
||||
void allocate_nodes(const size_type n, multiallocation_chain &chain)
|
||||
{
|
||||
//-----------------------
|
||||
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
|
||||
//-----------------------
|
||||
private_node_allocator_t::allocate_nodes(n, chain);
|
||||
}
|
||||
|
||||
//!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(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
|
||||
@@ -0,0 +1,44 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP
|
||||
#define BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/container/detail/allocation_type.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
typedef int allocation_type;
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
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_ALLOCATION_TYPE_HPP
|
||||
@@ -0,0 +1,44 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP
|
||||
#define BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# 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>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP
|
||||
@@ -0,0 +1,37 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP
|
||||
#define BOOST_INTERPROCESS_CONTAINERS_STRING_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# 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
|
||||
@@ -0,0 +1,37 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP
|
||||
#define BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# 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
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP
|
||||
#define BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/container/detail/version_type.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
using boost::container::container_detail::version_type;
|
||||
using boost::container::container_detail::version;
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP
|
||||
#define BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
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 {
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP
|
||||
@@ -0,0 +1,212 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP
|
||||
#define BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#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/move/utility_core.hpp>
|
||||
#include <boost/interprocess/creation_tags.hpp>
|
||||
#include <boost/interprocess/detail/simple_swap.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail{
|
||||
|
||||
class file_wrapper
|
||||
{
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(file_wrapper)
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
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::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)
|
||||
{
|
||||
(simple_swap)(m_handle, other.m_handle);
|
||||
(simple_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()){
|
||||
error_info err = system_error_code();
|
||||
throw interprocess_exception(err);
|
||||
}
|
||||
|
||||
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
|
||||
@@ -0,0 +1,77 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP
|
||||
#define BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# 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/container/detail/type_traits.hpp> //alignment_of, aligned_storage
|
||||
#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::container::container_detail::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
|
||||
@@ -0,0 +1,775 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 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
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# 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/os_file_functions.hpp>
|
||||
#include <boost/interprocess/creation_tags.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/interprocess/segment_manager.hpp>
|
||||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||
#include <boost/interprocess/detail/nothrow.hpp>
|
||||
#include <boost/interprocess/detail/simple_swap.hpp>
|
||||
//
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
//
|
||||
#include <boost/intrusive/detail/minimal_pair_header.hpp>
|
||||
#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;
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
typedef typename
|
||||
segment_manager::char_ptr_holder_t char_ptr_holder_t;
|
||||
//Experimental. Don't use.
|
||||
|
||||
typedef typename segment_manager::multiallocation_chain multiallocation_chain;
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
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;
|
||||
try{
|
||||
ManagedMemory managed_memory(open_only, filename);
|
||||
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, boost_container_new_t()) 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, const std::nothrow_t &tag)
|
||||
{ return mp_header->allocate(nbytes, tag); }
|
||||
|
||||
//!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, const std::nothrow_t &tag)
|
||||
{ return mp_header->allocate_aligned(nbytes, alignment, tag); }
|
||||
|
||||
template<class T>
|
||||
T * allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
|
||||
size_type &prefer_in_recvd_out_size, T *&reuse)
|
||||
{ return mp_header->allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); }
|
||||
|
||||
//!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); }
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
//Experimental. Don't use.
|
||||
|
||||
//!Allocates n_elements of elem_bytes bytes.
|
||||
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
|
||||
void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
|
||||
{ mp_header->allocate_many(elem_bytes, n_elements, chain); }
|
||||
|
||||
//!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
|
||||
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
|
||||
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
|
||||
{ mp_header->allocate_many(element_lengths, n_elements, sizeof_element, chain); }
|
||||
|
||||
//!Allocates n_elements of elem_bytes bytes.
|
||||
//!Non-throwing version. chain.size() is not increased on failure.
|
||||
void allocate_many(const std::nothrow_t &tag, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
|
||||
{ mp_header->allocate_many(tag, elem_bytes, n_elements, chain); }
|
||||
|
||||
//!Allocates n_elements, each one of
|
||||
//!element_lengths[i]*sizeof_element bytes.
|
||||
//!Non-throwing version. chain.size() is not increased on failure.
|
||||
void allocate_many(const std::nothrow_t &tag, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
|
||||
{ mp_header->allocate_many(tag, elem_sizes, n_elements, sizeof_element, chain); }
|
||||
|
||||
//!Deallocates all elements contained in chain.
|
||||
//!Never throws.
|
||||
void deallocate_many(multiallocation_chain &chain)
|
||||
{ mp_header->deallocate_many(chain); }
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!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, const std::nothrow_t &tag)
|
||||
{ return mp_header->template construct<T>(name, tag); }
|
||||
|
||||
//!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, const std::nothrow_t &tag)
|
||||
{ return mp_header->template find_or_construct<T>(name, tag); }
|
||||
|
||||
//!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, const std::nothrow_t &tag)
|
||||
{ return mp_header->template construct_it<T>(name, tag); }
|
||||
|
||||
//!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, const std::nothrow_t &tag)
|
||||
{ return mp_header->template find_or_construct_it<T>(name, tag); }
|
||||
|
||||
//!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 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. If ptr points to an unique instance typeid(T).name() is returned.
|
||||
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>(); }
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
//!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); }
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
protected:
|
||||
//!Swaps the segment manager's managed by this managed memory segment.
|
||||
//!NOT thread-safe. Never throws.
|
||||
void swap(basic_managed_memory_impl &other)
|
||||
{ (simple_swap)(mp_header, other.mp_header); }
|
||||
|
||||
private:
|
||||
segment_manager *mp_header;
|
||||
};
|
||||
|
||||
template<class BasicManagedMemoryImpl>
|
||||
class create_open_func
|
||||
{
|
||||
typedef typename BasicManagedMemoryImpl::size_type size_type;
|
||||
|
||||
public:
|
||||
|
||||
create_open_func(BasicManagedMemoryImpl * const frontend, create_enum_t type)
|
||||
: m_frontend(frontend), m_type(type){}
|
||||
|
||||
bool operator()(void *addr, std::size_t size, bool created) const
|
||||
{
|
||||
if( ((m_type == DoOpen) && created) ||
|
||||
((m_type == DoCreate) && !created) ||
|
||||
//Check for overflow
|
||||
size_type(-1) < size ){
|
||||
return false;
|
||||
}
|
||||
else if(created){
|
||||
return m_frontend->create_impl(addr, static_cast<size_type>(size));
|
||||
}
|
||||
else{
|
||||
return m_frontend->open_impl (addr, static_cast<size_type>(size));
|
||||
}
|
||||
}
|
||||
|
||||
static std::size_t get_min_size()
|
||||
{
|
||||
const size_type sz = BasicManagedMemoryImpl::segment_manager::get_min_size();
|
||||
if(sz > std::size_t(-1)){
|
||||
//The minimum size is not representable by std::size_t
|
||||
BOOST_ASSERT(false);
|
||||
return std::size_t(-1);
|
||||
}
|
||||
else{
|
||||
return static_cast<std::size_t>(sz);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
BasicManagedMemoryImpl *m_frontend;
|
||||
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
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Stephen Cleary 2000.
|
||||
// (C) Copyright Ion Gaztanaga 2007-2012.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 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
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,316 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP
|
||||
#define BOOST_INTERPROCESS_NAMED_PROXY_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
// interprocess/detail
|
||||
#include <boost/interprocess/detail/in_place_interface.hpp>
|
||||
#include <boost/interprocess/detail/mpl.hpp>
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
|
||||
#include <boost/move/detail/fwd_macros.hpp>
|
||||
#else
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/interprocess/detail/variadic_templates_tools.hpp>
|
||||
#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
|
||||
#include <boost/container/detail/placement_new.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
//!\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 CtorArgN : public placement_destroy<T>
|
||||
{
|
||||
typedef bool_<is_iterator> IsIterator;
|
||||
typedef CtorArgN<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; }
|
||||
|
||||
CtorArgN(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<std::size_t ...IdxPack>
|
||||
void construct(void *mem, true_, const index_tuple<IdxPack...>&)
|
||||
{ ::new((void*)mem, boost_container_new_t())T(*boost::forward<Args>(get<IdxPack>(args_))...); }
|
||||
|
||||
template<std::size_t ...IdxPack>
|
||||
void construct(void *mem, false_, const index_tuple<IdxPack...>&)
|
||||
{ ::new((void*)mem, boost_container_new_t())T(boost::forward<Args>(get<IdxPack>(args_))...); }
|
||||
|
||||
template<std::size_t ...IdxPack>
|
||||
void do_increment(true_, const index_tuple<IdxPack...>&)
|
||||
{
|
||||
this->expansion_helper(++get<IdxPack>(args_)...);
|
||||
}
|
||||
|
||||
template<class ...ExpansionArgs>
|
||||
void expansion_helper(ExpansionArgs &&...)
|
||||
{}
|
||||
|
||||
template<std::size_t ...IdxPack>
|
||||
void do_increment(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
|
||||
{
|
||||
CtorArgN<T, is_iterator, Args...> &&ctor_obj = CtorArgN<T, is_iterator, Args...>
|
||||
(boost::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
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// What the macro should generate (n == 2):
|
||||
//
|
||||
// template<class T, bool is_iterator, class P1, class P2>
|
||||
// struct Ctor2Arg
|
||||
// : public placement_destroy<T>
|
||||
// {
|
||||
// typedef bool_<is_iterator> IsIterator;
|
||||
// typedef Ctor2Arg self_t;
|
||||
//
|
||||
// void do_increment(false_)
|
||||
// { ++m_p1; ++m_p2; }
|
||||
//
|
||||
// void do_increment(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, true_)
|
||||
// { new((void*)mem)T(*m_p1, *m_p2); }
|
||||
//
|
||||
// void construct(void *mem, false_)
|
||||
// { new((void*)mem)T(m_p1, m_p2); }
|
||||
//
|
||||
// P1 &m_p1; P2 &m_p2;
|
||||
// };
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN(N)\
|
||||
\
|
||||
template<class T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \
|
||||
struct CtorArg##N : placement_destroy<T>\
|
||||
{\
|
||||
typedef CtorArg##N self_t;\
|
||||
\
|
||||
CtorArg##N ( BOOST_MOVE_UREF##N )\
|
||||
BOOST_MOVE_COLON##N BOOST_MOVE_FWD_INIT##N{}\
|
||||
\
|
||||
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 ( BOOST_MOVE_MFWD##N );\
|
||||
}\
|
||||
}\
|
||||
\
|
||||
private:\
|
||||
BOOST_MOVE_MREF##N\
|
||||
};\
|
||||
//!
|
||||
BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN)
|
||||
#undef BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN
|
||||
|
||||
#define BOOST_INTERPROCESS_NAMED_PROXY_CTORITN(N)\
|
||||
\
|
||||
template<class T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \
|
||||
struct CtorIt##N : public placement_destroy<T>\
|
||||
{\
|
||||
typedef CtorIt##N self_t;\
|
||||
\
|
||||
self_t& operator++()\
|
||||
{ BOOST_MOVE_MINC##N; return *this; }\
|
||||
\
|
||||
self_t operator++(int) { return ++*this; *this; }\
|
||||
\
|
||||
CtorIt##N ( BOOST_MOVE_VAL##N )\
|
||||
BOOST_MOVE_COLON##N BOOST_MOVE_VAL_INIT##N{}\
|
||||
\
|
||||
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( BOOST_MOVE_MITFWD##N );\
|
||||
++(*this);\
|
||||
}\
|
||||
}\
|
||||
\
|
||||
private:\
|
||||
BOOST_MOVE_MEMB##N\
|
||||
};\
|
||||
//!
|
||||
BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CTORITN)
|
||||
#undef BOOST_INTERPROCESS_NAMED_PROXY_CTORITN
|
||||
|
||||
//!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)
|
||||
{}
|
||||
|
||||
#define BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR(N)\
|
||||
\
|
||||
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
|
||||
T *operator()( BOOST_MOVE_UREF##N ) const\
|
||||
{\
|
||||
typedef typename if_c<is_iterator \
|
||||
, CtorIt##N<T BOOST_MOVE_I##N BOOST_MOVE_TARG##N> \
|
||||
, CtorArg##N<T BOOST_MOVE_I##N BOOST_MOVE_TARG##N> \
|
||||
>::type ctor_obj_t;\
|
||||
ctor_obj_t ctor_obj = ctor_obj_t( BOOST_MOVE_FWD##N );\
|
||||
return mp_mngr->template generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj);\
|
||||
}\
|
||||
//
|
||||
BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR)
|
||||
#undef BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// What the macro should generate (n == 2)
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// template <class P1, class P2>
|
||||
// T *operator()(P1 &p1, P2 &p2) const
|
||||
// {
|
||||
// typedef CtorArg2
|
||||
// <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
|
||||
@@ -0,0 +1,42 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2014-2015. Distributed under the 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_NOTHROW_HPP
|
||||
#define BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
namespace std { //no namespace versioning in clang+libc++
|
||||
|
||||
struct nothrow_t;
|
||||
|
||||
} //namespace std {
|
||||
|
||||
namespace boost{ namespace interprocess {
|
||||
|
||||
template <int Dummy = 0>
|
||||
struct nothrow
|
||||
{
|
||||
static const std::nothrow_t &get() { return *pnothrow; }
|
||||
static std::nothrow_t *pnothrow;
|
||||
};
|
||||
|
||||
template <int Dummy>
|
||||
std::nothrow_t *nothrow<Dummy>::pnothrow =
|
||||
reinterpret_cast<std::nothrow_t *>(0x1234); //Avoid sanitizer warnings on references to null
|
||||
|
||||
}} //namespace boost{ namespace interprocess {
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP
|
||||
@@ -0,0 +1,518 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
|
||||
#define BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
// interprocess
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
// interprocess/detail
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/interprocess/detail/in_place_interface.hpp>
|
||||
// container/detail
|
||||
#include <boost/container/detail/type_traits.hpp> //alignment_of
|
||||
#include <boost/container/detail/minimal_char_traits_header.hpp>
|
||||
// intrusive
|
||||
#include <boost/intrusive/pointer_traits.hpp>
|
||||
// move/detail
|
||||
#include <boost/move/detail/type_traits.hpp> //make_unsigned
|
||||
// other boost
|
||||
#include <boost/assert.hpp> //BOOST_ASSERT
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
// std
|
||||
#include <cstddef> //std::size_t
|
||||
|
||||
//!\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); }
|
||||
};
|
||||
|
||||
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 val_bytes
|
||||
,size_type val_alignment
|
||||
,unsigned char al_type
|
||||
,std::size_t szof_char
|
||||
,std::size_t num_char
|
||||
)
|
||||
: m_value_bytes(val_bytes)
|
||||
, m_num_char((unsigned short)num_char)
|
||||
, m_value_alignment((unsigned char)val_alignment)
|
||||
, m_alloc_type_sizeof_char( (al_type << 5u) | ((unsigned char)szof_char & 0x1F) )
|
||||
{};
|
||||
|
||||
template<class T>
|
||||
block_header &operator= (const T& )
|
||||
{ return *this; }
|
||||
|
||||
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::container::container_detail::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::container::container_detail::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::container::container_detail::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::container::container_detail::alignment_of<block_header<size_type> >::value)));
|
||||
//Some sanity checks
|
||||
return hdr;
|
||||
}
|
||||
};
|
||||
|
||||
inline void array_construct(void *mem, std::size_t num, 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::container::container_detail::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) +
|
||||
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 anonymous_instance_t *)
|
||||
: m_name(static_cast<CharType*>(0))
|
||||
{}
|
||||
|
||||
char_ptr_holder(const unique_instance_t *)
|
||||
: m_name(reinterpret_cast<CharType*>(-1))
|
||||
{}
|
||||
|
||||
operator const CharType *()
|
||||
{ return m_name; }
|
||||
|
||||
const CharType *get() const
|
||||
{ return m_name; }
|
||||
|
||||
bool is_unique() const
|
||||
{ return m_name == reinterpret_cast<CharType*>(-1); }
|
||||
|
||||
bool is_anonymous() const
|
||||
{ return m_name == static_cast<CharType*>(0); }
|
||||
|
||||
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::intrusive::
|
||||
pointer_traits<VoidPointer>::template
|
||||
rebind_pointer<const CharT>::type const_char_ptr_t;
|
||||
typedef CharT char_type;
|
||||
typedef typename boost::intrusive::pointer_traits<const_char_ptr_t>::difference_type difference_type;
|
||||
typedef typename boost::move_detail::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 *nm, size_type length)
|
||||
: mp_str(nm), m_len(length)
|
||||
{}
|
||||
|
||||
//!Less than function for index ordering
|
||||
bool operator < (const index_key & right) const
|
||||
{
|
||||
return (m_len < right.m_len) ||
|
||||
(m_len == right.m_len &&
|
||||
std::char_traits<char_type>::compare
|
||||
(to_raw_pointer(mp_str),to_raw_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
|
||||
(to_raw_pointer(mp_str), to_raw_pointer(right.mp_str), m_len) == 0;
|
||||
}
|
||||
|
||||
void name(const CharT *nm)
|
||||
{ mp_str = nm; }
|
||||
|
||||
void name_length(size_type len)
|
||||
{ m_len = len; }
|
||||
|
||||
const CharT *name() const
|
||||
{ return to_raw_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;
|
||||
explicit index_data(void *ptr) : m_ptr(ptr){}
|
||||
|
||||
void *value() const
|
||||
{ return static_cast<void*>(to_raw_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 index_key<CharT, void_pointer> key_type;
|
||||
typedef 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 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>*>
|
||||
(to_raw_pointer(m_val->second.m_ptr))->value();
|
||||
}
|
||||
|
||||
const typename Iterator::value_type *m_val;
|
||||
};
|
||||
|
||||
template<class Iterator, bool intrusive>
|
||||
struct segment_manager_iterator_transform
|
||||
{
|
||||
typedef segment_manager_iterator_value_adaptor<Iterator, intrusive> result_type;
|
||||
|
||||
template <class T> result_type operator()(const T &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
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2015.
|
||||
// (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
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
// interprocess
|
||||
#include <boost/interprocess/interprocess_fwd.hpp>
|
||||
// interprocess/detail
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
// move/detail
|
||||
#include <boost/container/detail/iterator.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:
|
||||
typedef typename ::boost::container::iterator_traits<Iterator>::iterator_category iterator_category;
|
||||
typedef typename ipcdetail::remove_reference<typename UnaryFunction::result_type>::type value_type;
|
||||
typedef typename ::boost::container::iterator_traits<Iterator>::difference_type difference_type;
|
||||
typedef operator_arrow_proxy<typename UnaryFunction::result_type> pointer;
|
||||
typedef typename UnaryFunction::result_type reference;
|
||||
|
||||
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 difference_type operator- (const transform_iterator& i, const transform_iterator& i2)
|
||||
{ return i2.distance_to(i); }
|
||||
|
||||
//Arithmetic
|
||||
transform_iterator& operator+=(difference_type off)
|
||||
{ this->advance(off); return *this; }
|
||||
|
||||
transform_iterator operator+(difference_type off) const
|
||||
{
|
||||
transform_iterator other(*this);
|
||||
other.advance(off);
|
||||
return other;
|
||||
}
|
||||
|
||||
friend transform_iterator operator+(difference_type off, const transform_iterator& right)
|
||||
{ return right + off; }
|
||||
|
||||
transform_iterator& operator-=(difference_type off)
|
||||
{ this->advance(-off); return *this; }
|
||||
|
||||
transform_iterator operator-(difference_type off) const
|
||||
{ return *this + (-off); }
|
||||
|
||||
typename UnaryFunction::result_type operator*() const
|
||||
{ return dereference(); }
|
||||
|
||||
typename UnaryFunction::result_type operator[](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(difference_type n)
|
||||
{ ::boost::container::iterator_advance(m_it, n); }
|
||||
|
||||
difference_type distance_to(const transform_iterator &other)const
|
||||
{ return ::boost::container::iterator_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
|
||||
@@ -0,0 +1,35 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 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
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/container/detail/variadic_templates_tools.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
using boost::container::container_detail::tuple;
|
||||
using boost::container::container_detail::build_number_seq;
|
||||
using boost::container::container_detail::index_tuple;
|
||||
using boost::container::container_detail::get;
|
||||
|
||||
}}} //namespace boost { namespace interprocess { namespace ipcdetail {
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP
|
||||
@@ -0,0 +1,199 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_FILE_MAPPING_HPP
|
||||
#define BOOST_INTERPROCESS_FILE_MAPPING_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_MAPPED_FILES)
|
||||
#error "Boost.Interprocess: This platform does not support memory mapped files!"
|
||||
#endif
|
||||
|
||||
#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/simple_swap.hpp>
|
||||
#include <boost/move/utility_core.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
|
||||
{
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(file_mapping)
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
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()))
|
||||
, m_mode(read_only)
|
||||
{ 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::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);
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
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;
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
};
|
||||
|
||||
inline file_mapping::file_mapping()
|
||||
: m_handle(file_handle_t(ipcdetail::invalid_file()))
|
||||
, m_mode(read_only)
|
||||
{}
|
||||
|
||||
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)
|
||||
{
|
||||
(simple_swap)(m_handle, other.m_handle);
|
||||
(simple_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); }
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
inline void file_mapping::priv_close()
|
||||
{
|
||||
if(m_handle != ipcdetail::invalid_file()){
|
||||
ipcdetail::close_file(m_handle);
|
||||
m_handle = ipcdetail::invalid_file();
|
||||
}
|
||||
}
|
||||
|
||||
//!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); }
|
||||
};
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_FILE_MAPPING_HPP
|
||||
@@ -0,0 +1,158 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_ISET_INDEX_HPP
|
||||
#define BOOST_INTERPROCESS_ISET_INDEX_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <boost/intrusive/detail/minimal_pair_header.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/intrusive/detail/minimal_pair_header.hpp> //std::pair
|
||||
#include <boost/intrusive/detail/minimal_less_equal_header.hpp> //std::less
|
||||
#include <boost/container/detail/minimal_char_traits_header.hpp> //std::char_traits
|
||||
#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 {
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
//!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;
|
||||
};
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!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
|
||||
{
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
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;
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
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;
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
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); }
|
||||
};
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
//!Trait class to detect if an index is an intrusive
|
||||
//!index.
|
||||
template<class MapConfig>
|
||||
struct is_intrusive_index
|
||||
<boost::interprocess::iset_index<MapConfig> >
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_ISET_INDEX_HPP
|
||||
@@ -0,0 +1,250 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP
|
||||
#define BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# 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/move/utility_core.hpp>
|
||||
#include <boost/interprocess/file_mapping.hpp>
|
||||
#include <boost/interprocess/permissions.hpp>
|
||||
//These includes needed to fulfill default template parameters of
|
||||
//predeclarations in interprocess_fwd.hpp
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
#include <boost/interprocess/indexes/iset_index.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
template<class AllocationAlgorithm>
|
||||
struct mfile_open_or_create
|
||||
{
|
||||
typedef ipcdetail::managed_open_or_create_impl
|
||||
< file_wrapper, AllocationAlgorithm::Alignment, true, false> type;
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
|
||||
//!A basic mapped file named object creation class. Initializes the
|
||||
//!mapped file. Inherits all basic functionality from
|
||||
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>
|
||||
template
|
||||
<
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
template<class IndexConfig> class IndexType
|
||||
>
|
||||
class basic_managed_mapped_file
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
: public ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType
|
||||
,ipcdetail::mfile_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset>
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
{
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
public:
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType,
|
||||
ipcdetail::mfile_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset> base_t;
|
||||
typedef ipcdetail::file_wrapper device_type;
|
||||
|
||||
private:
|
||||
|
||||
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
|
||||
|
||||
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)
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
public: //functions
|
||||
|
||||
//!Unsigned integral type enough to represent
|
||||
//!the size of a basic_managed_mapped_file.
|
||||
typedef typename BOOST_INTERPROCESS_IMPDEF(base_t::size_type) size_type;
|
||||
|
||||
//!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, 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,
|
||||
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, 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::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);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
//!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:
|
||||
typename ipcdetail::mfile_open_or_create<AllocationAlgorithm>::type m_mfile;
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
};
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!Typedef for a default basic_managed_mapped_file
|
||||
//!of narrow characters
|
||||
typedef basic_managed_mapped_file
|
||||
<char
|
||||
,rbtree_best_fit<mutex_family>
|
||||
,iset_index>
|
||||
managed_mapped_file;
|
||||
|
||||
//!Typedef for a default basic_managed_mapped_file
|
||||
//!of wide characters
|
||||
typedef basic_managed_mapped_file
|
||||
<wchar_t
|
||||
,rbtree_best_fit<mutex_family>
|
||||
,iset_index>
|
||||
wmanaged_mapped_file;
|
||||
|
||||
#endif //#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP
|
||||
@@ -0,0 +1,262 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP
|
||||
#define BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# 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/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>
|
||||
//These includes needed to fulfill default template parameters of
|
||||
//predeclarations in interprocess_fwd.hpp
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
namespace ipcdetail {
|
||||
|
||||
template<class AllocationAlgorithm>
|
||||
struct shmem_open_or_create
|
||||
{
|
||||
typedef ipcdetail::managed_open_or_create_impl
|
||||
< shared_memory_object, AllocationAlgorithm::Alignment, true, false> type;
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
|
||||
//!A basic shared memory named object creation class. Initializes the
|
||||
//!shared memory segment. Inherits all basic functionality from
|
||||
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
|
||||
template
|
||||
<
|
||||
class CharType,
|
||||
class AllocationAlgorithm,
|
||||
template<class IndexConfig> class IndexType
|
||||
>
|
||||
class basic_managed_shared_memory
|
||||
: public ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType
|
||||
,ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset>
|
||||
, private ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type
|
||||
{
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
typedef ipcdetail::basic_managed_memory_impl
|
||||
<CharType, AllocationAlgorithm, IndexType,
|
||||
ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset> base_t;
|
||||
typedef typename ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type base2_t;
|
||||
|
||||
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
|
||||
|
||||
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)
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
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, 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,
|
||||
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, 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::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);
|
||||
}
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
//!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);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
};
|
||||
|
||||
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!Typedef for a default basic_managed_shared_memory
|
||||
//!of narrow characters
|
||||
typedef basic_managed_shared_memory
|
||||
<char
|
||||
,rbtree_best_fit<mutex_family>
|
||||
,iset_index>
|
||||
managed_shared_memory;
|
||||
|
||||
//!Typedef for a default basic_managed_shared_memory
|
||||
//!of wide characters
|
||||
typedef basic_managed_shared_memory
|
||||
<wchar_t
|
||||
,rbtree_best_fit<mutex_family>
|
||||
,iset_index>
|
||||
wmanaged_shared_memory;
|
||||
|
||||
//!Typedef for a default basic_managed_shared_memory
|
||||
//!of narrow characters to be placed in a fixed address
|
||||
typedef basic_managed_shared_memory
|
||||
<char
|
||||
,rbtree_best_fit<mutex_family, void*>
|
||||
,iset_index>
|
||||
fixed_managed_shared_memory;
|
||||
|
||||
//!Typedef for a default basic_managed_shared_memory
|
||||
//!of narrow characters to be placed in a fixed address
|
||||
typedef basic_managed_shared_memory
|
||||
<wchar_t
|
||||
,rbtree_best_fit<mutex_family, void*>
|
||||
,iset_index>
|
||||
wfixed_managed_shared_memory;
|
||||
|
||||
|
||||
#endif //#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP
|
||||
|
||||
@@ -0,0 +1,596 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 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
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
// interprocess
|
||||
#include <boost/interprocess/interprocess_fwd.hpp>
|
||||
#include <boost/interprocess/containers/allocation_type.hpp>
|
||||
// interprocess/detail
|
||||
#include <boost/interprocess/detail/math_functions.hpp>
|
||||
#include <boost/interprocess/detail/min_max.hpp>
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
// container/detail
|
||||
#include <boost/container/detail/multiallocation_chain.hpp>
|
||||
#include <boost/container/detail/placement_new.hpp>
|
||||
// move
|
||||
#include <boost/move/utility_core.hpp>
|
||||
// other boost
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
//!\file
|
||||
//!Implements common operations for memory algorithms.
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
template<class VoidPointer>
|
||||
class basic_multiallocation_chain
|
||||
: public boost::container::container_detail::
|
||||
basic_multiallocation_chain<VoidPointer>
|
||||
{
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_multiallocation_chain)
|
||||
typedef boost::container::container_detail::
|
||||
basic_multiallocation_chain<VoidPointer> base_t;
|
||||
public:
|
||||
|
||||
basic_multiallocation_chain()
|
||||
: base_t()
|
||||
{}
|
||||
|
||||
basic_multiallocation_chain(BOOST_RV_REF(basic_multiallocation_chain) other)
|
||||
: base_t(::boost::move(static_cast<base_t&>(other)))
|
||||
{}
|
||||
|
||||
basic_multiallocation_chain& operator=(BOOST_RV_REF(basic_multiallocation_chain) other)
|
||||
{
|
||||
this->base_t::operator=(::boost::move(static_cast<base_t&>(other)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void *pop_front()
|
||||
{
|
||||
return boost::interprocess::ipcdetail::to_raw_pointer(this->base_t::pop_front());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//!This class implements several allocation functions shared by different algorithms
|
||||
//!(aligned allocation, multiple allocation...).
|
||||
template<class MemoryAlgorithm>
|
||||
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 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 get_rounded_size(size, Alignment); }
|
||||
|
||||
static void allocate_many
|
||||
(MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
|
||||
{
|
||||
return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0, chain);
|
||||
}
|
||||
|
||||
static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain)
|
||||
{
|
||||
return this_type::priv_deallocate_many(memory_algo, 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_val
|
||||
size_type max = backwards_multiple;
|
||||
size_type min = Alignment;
|
||||
size_type needs_backwards;
|
||||
size_type needs_backwards_lcmed;
|
||||
size_type lcm_val;
|
||||
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_val = max;
|
||||
//If we want to use minbytes data to get a buffer between maxbytes
|
||||
//and minbytes if maxbytes can't be achieved, calculate the
|
||||
//biggest of all possibilities
|
||||
current_forward = 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 = get_rounded_size_po2(needs_backwards, lcm_val);
|
||||
lcm_out = lcm_val;
|
||||
needs_backwards_lcmed_out = needs_backwards_lcmed;
|
||||
return true;
|
||||
}
|
||||
//Check if it's multiple of alignment
|
||||
else if((backwards_multiple & (Alignment - 1u)) == 0){
|
||||
lcm_val = backwards_multiple;
|
||||
current_forward = get_truncated_size(received_size, backwards_multiple);
|
||||
//No need to round needs_backwards because backwards_multiple == lcm_val
|
||||
needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
|
||||
BOOST_ASSERT((needs_backwards_lcmed & (Alignment - 1u)) == 0);
|
||||
lcm_out = lcm_val;
|
||||
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_val = backwards_multiple*2u;
|
||||
current_forward = 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_val) == 0);
|
||||
lcm_out = lcm_val;
|
||||
needs_backwards_lcmed_out = needs_backwards_lcmed;
|
||||
return true;
|
||||
}
|
||||
//Check if it's multiple of the quarter of the alignmment
|
||||
else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){
|
||||
size_type remainder;
|
||||
lcm_val = backwards_multiple*4u;
|
||||
current_forward = 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_val) == 0);
|
||||
lcm_out = lcm_val;
|
||||
needs_backwards_lcmed_out = needs_backwards_lcmed;
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
lcm_val = lcm(max, min);
|
||||
}
|
||||
//If we want to use minbytes data to get a buffer between maxbytes
|
||||
//and minbytes if maxbytes can't be achieved, calculate the
|
||||
//biggest of all possibilities
|
||||
current_forward = get_truncated_size(received_size, backwards_multiple);
|
||||
needs_backwards = size_to_achieve - current_forward;
|
||||
BOOST_ASSERT((needs_backwards % backwards_multiple) == 0);
|
||||
needs_backwards_lcmed = get_rounded_size(needs_backwards, lcm_val);
|
||||
lcm_out = lcm_val;
|
||||
needs_backwards_lcmed_out = needs_backwards_lcmed;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void allocate_many
|
||||
( MemoryAlgorithm *memory_algo
|
||||
, const size_type *elem_sizes
|
||||
, size_type n_elements
|
||||
, size_type sizeof_element
|
||||
, multiallocation_chain &chain)
|
||||
{
|
||||
this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, chain);
|
||||
}
|
||||
|
||||
static void* allocate_aligned
|
||||
(MemoryAlgorithm *memory_algo, size_type nbytes, size_type alignment)
|
||||
{
|
||||
|
||||
//Ensure power of 2
|
||||
if ((alignment & (alignment - size_type(1u))) != 0){
|
||||
//Alignment is not power of two
|
||||
BOOST_ASSERT((alignment & (alignment - size_type(1u))) == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_type real_size = nbytes;
|
||||
if(alignment <= Alignment){
|
||||
void *ignore_reuse = 0;
|
||||
return memory_algo->priv_allocate
|
||||
(boost::interprocess::allocate_new, nbytes, real_size, ignore_reuse);
|
||||
}
|
||||
|
||||
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
|
||||
real_size = request;
|
||||
void *ignore_reuse = 0;
|
||||
void *buffer = memory_algo->priv_allocate(boost::interprocess::allocate_new, request, real_size, ignore_reuse);
|
||||
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_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, size_type &received_size)
|
||||
{
|
||||
size_type const preferred_size = 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, size_type &received_size)
|
||||
{
|
||||
size_type const preferred_size = 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, 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 void priv_allocate_many
|
||||
( MemoryAlgorithm *memory_algo
|
||||
, const size_type *elem_sizes
|
||||
, size_type n_elements
|
||||
, size_type sizeof_element
|
||||
, multiallocation_chain &chain)
|
||||
{
|
||||
//Note: sizeof_element == 0 indicates that we want to
|
||||
//allocate n_elements of the same size "*elem_sizes"
|
||||
|
||||
//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){
|
||||
if(multiplication_overflows(elem_sizes[i], sizeof_element)){
|
||||
total_request_units = 0;
|
||||
break;
|
||||
}
|
||||
elem_units = memory_algo->priv_get_total_units(elem_sizes[i]*sizeof_element);
|
||||
elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
|
||||
if(sum_overflows(total_request_units, elem_units)){
|
||||
total_request_units = 0;
|
||||
break;
|
||||
}
|
||||
total_request_units += elem_units;
|
||||
}
|
||||
}
|
||||
|
||||
if(total_request_units && !multiplication_overflows(total_request_units, Alignment)){
|
||||
size_type low_idx = 0;
|
||||
while(low_idx < n_elements){
|
||||
size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
|
||||
size_type min_allocation = (!sizeof_element)
|
||||
? elem_units
|
||||
: memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
|
||||
min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
|
||||
|
||||
size_type received_size = total_bytes;
|
||||
void *ignore_reuse = 0;
|
||||
void *ret = memory_algo->priv_allocate
|
||||
(boost::interprocess::allocate_new, min_allocation, received_size, ignore_reuse);
|
||||
if(!ret){
|
||||
break;
|
||||
}
|
||||
|
||||
block_ctrl *block = memory_algo->priv_get_block(ret);
|
||||
size_type received_units = (size_type)block->m_size;
|
||||
char *block_address = reinterpret_cast<char*>(block);
|
||||
|
||||
size_type total_used_units = 0;
|
||||
while(total_used_units < received_units){
|
||||
if(sizeof_element){
|
||||
elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
|
||||
elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
|
||||
}
|
||||
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
|
||||
: max_value(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_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
|
||||
size_type shrunk_received = shrunk_request;
|
||||
bool shrink_ok = shrink
|
||||
(memory_algo
|
||||
,memory_algo->priv_get_user_buffer(new_block)
|
||||
,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), boost_container_new_t())void_pointer(0);
|
||||
chain.push_back(p);
|
||||
++low_idx;
|
||||
}
|
||||
//Sanity check
|
||||
BOOST_ASSERT(total_used_units == received_units);
|
||||
}
|
||||
|
||||
if(low_idx != n_elements){
|
||||
priv_deallocate_many(memory_algo, chain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain)
|
||||
{
|
||||
while(!chain.empty()){
|
||||
memory_algo->priv_deallocate(to_raw_pointer(chain.pop_front()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,751 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the 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_OFFSET_PTR_HPP
|
||||
#define BOOST_INTERPROCESS_OFFSET_PTR_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <boost/type_traits/is_convertible.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/container/detail/type_traits.hpp> //alignment_of, aligned_storage
|
||||
#include <boost/assert.hpp>
|
||||
#include <iosfwd>
|
||||
|
||||
//!\file
|
||||
//!Describes a smart pointer that stores the offset between this pointer and
|
||||
//!target pointee, called offset_ptr.
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
//Predeclarations
|
||||
template <class T>
|
||||
struct has_trivial_destructor;
|
||||
|
||||
#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
namespace interprocess {
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
namespace ipcdetail {
|
||||
|
||||
template<class OffsetType, std::size_t OffsetAlignment>
|
||||
union offset_ptr_internal
|
||||
{
|
||||
BOOST_STATIC_ASSERT(sizeof(OffsetType) >= sizeof(uintptr_t));
|
||||
|
||||
explicit offset_ptr_internal(OffsetType off)
|
||||
: m_offset(off)
|
||||
{}
|
||||
|
||||
OffsetType m_offset; //Distance between this object and pointee address
|
||||
|
||||
typename ::boost::container::container_detail::aligned_storage
|
||||
< sizeof(OffsetType)//for offset_type_alignment m_offset will be enough
|
||||
, (OffsetAlignment == offset_type_alignment) ? 1u : OffsetAlignment
|
||||
>::type alignment_helper;
|
||||
};
|
||||
|
||||
//Note: using the address of a local variable to point to another address
|
||||
//is not standard conforming and this can be optimized-away by the compiler.
|
||||
//Non-inlining is a method to remain illegal but correct
|
||||
|
||||
//Undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_XXX if your compiler can inline
|
||||
//this code without breaking the library
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// offset_ptr_to_raw_pointer
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR
|
||||
BOOST_INTERPROCESS_FORCEINLINE void * offset_ptr_to_raw_pointer(const volatile void *this_ptr, uintptr_t offset)
|
||||
{
|
||||
typedef pointer_uintptr_caster<void*> caster_t;
|
||||
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR
|
||||
if(offset == 1){
|
||||
return 0;
|
||||
}
|
||||
else{
|
||||
return caster_t(caster_t(this_ptr).uintptr() + offset).pointer();
|
||||
}
|
||||
#else
|
||||
uintptr_t mask = offset == 1;
|
||||
--mask;
|
||||
uintptr_t target_offset = caster_t(this_ptr).uintptr() + offset;
|
||||
target_offset &= mask;
|
||||
return caster_t(target_offset).pointer();
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// offset_ptr_to_offset
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF
|
||||
BOOST_INTERPROCESS_FORCEINLINE uintptr_t offset_ptr_to_offset(const volatile void *ptr, const volatile void *this_ptr)
|
||||
{
|
||||
typedef pointer_uintptr_caster<void*> caster_t;
|
||||
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF
|
||||
//offset == 1 && ptr != 0 is not legal for this pointer
|
||||
if(!ptr){
|
||||
return 1;
|
||||
}
|
||||
else{
|
||||
uintptr_t offset = caster_t(ptr).uintptr() - caster_t(this_ptr).uintptr();
|
||||
BOOST_ASSERT(offset != 1);
|
||||
return offset;
|
||||
}
|
||||
#else
|
||||
//const uintptr_t other = -uintptr_t(ptr != 0);
|
||||
//const uintptr_t offset = (caster_t(ptr).uintptr() - caster_t(this_ptr).uintptr()) & other;
|
||||
//return offset + uintptr_t(!other);
|
||||
//
|
||||
uintptr_t offset = caster_t(ptr).uintptr() - caster_t(this_ptr).uintptr();
|
||||
--offset;
|
||||
uintptr_t mask = uintptr_t(ptr == 0);
|
||||
--mask;
|
||||
offset &= mask;
|
||||
return ++offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// offset_ptr_to_offset_from_other
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER
|
||||
BOOST_INTERPROCESS_FORCEINLINE uintptr_t offset_ptr_to_offset_from_other
|
||||
(const volatile void *this_ptr, const volatile void *other_ptr, uintptr_t other_offset)
|
||||
{
|
||||
typedef pointer_uintptr_caster<void*> caster_t;
|
||||
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER
|
||||
if(other_offset == 1){
|
||||
return 1;
|
||||
}
|
||||
else{
|
||||
uintptr_t offset = caster_t(other_ptr).uintptr() - caster_t(this_ptr).uintptr() + other_offset;
|
||||
BOOST_ASSERT(offset != 1);
|
||||
return offset;
|
||||
}
|
||||
#else
|
||||
uintptr_t mask = other_offset == 1;
|
||||
--mask;
|
||||
uintptr_t offset = caster_t(other_ptr).uintptr() - caster_t(this_ptr).uintptr();
|
||||
offset &= mask;
|
||||
return offset + other_offset;
|
||||
|
||||
//uintptr_t mask = -uintptr_t(other_offset != 1);
|
||||
//uintptr_t offset = caster_t(other_ptr).uintptr() - caster_t(this_ptr).uintptr();
|
||||
//offset &= mask;
|
||||
//return offset + other_offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Let's assume cast to void and cv cast don't change any target address
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
template<class From, class To>
|
||||
struct offset_ptr_maintains_address
|
||||
{
|
||||
static const bool value = ipcdetail::is_cv_same<From, To>::value
|
||||
|| ipcdetail::is_cv_same<void, To>::value
|
||||
|| ipcdetail::is_cv_same<char, To>::value
|
||||
;
|
||||
};
|
||||
|
||||
template<class From, class To, class Ret = void>
|
||||
struct enable_if_convertible_equal_address
|
||||
: enable_if_c< ::boost::is_convertible<From*, To*>::value
|
||||
&& offset_ptr_maintains_address<From, To>::value
|
||||
, Ret>
|
||||
{};
|
||||
|
||||
template<class From, class To, class Ret = void>
|
||||
struct enable_if_convertible_unequal_address
|
||||
: enable_if_c< ::boost::is_convertible<From*, To*>::value
|
||||
&& !offset_ptr_maintains_address<From, To>::value
|
||||
, Ret>
|
||||
{};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!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 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.
|
||||
//!
|
||||
//! \tparam PointedType The type of the pointee.
|
||||
//! \tparam DifferenceType A signed integer type that can represent the arithmetic operations on the pointer
|
||||
//! \tparam OffsetType An unsigned integer type that can represent the
|
||||
//! distance between two pointers reinterpret_cast-ed as unsigned integers. This type
|
||||
//! should be at least of the same size of std::uintptr_t. In some systems it's possible to communicate
|
||||
//! between 32 and 64 bit processes using 64 bit offsets.
|
||||
//! \tparam OffsetAlignment Alignment of the OffsetType stored inside. In some systems might be necessary
|
||||
//! to align it to 64 bits in order to communicate 32 and 64 bit processes using 64 bit offsets.
|
||||
//!
|
||||
//!<b>Note</b>: offset_ptr uses implementation defined properties, present in most platforms, for
|
||||
//!performance reasons:
|
||||
//! - Assumes that uintptr_t representation of nullptr is (uintptr_t)zero.
|
||||
//! - Assumes that incrementing a uintptr_t obtained from a pointer is equivalent
|
||||
//! to incrementing the pointer and then converting it back to uintptr_t.
|
||||
template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment>
|
||||
class offset_ptr
|
||||
{
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
typedef offset_ptr<PointedType, DifferenceType, OffsetType, OffsetAlignment> self_t;
|
||||
void unspecified_bool_type_func() const {}
|
||||
typedef void (self_t::*unspecified_bool_type)() const;
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
public:
|
||||
typedef PointedType element_type;
|
||||
typedef PointedType * pointer;
|
||||
typedef typename ipcdetail::
|
||||
add_reference<PointedType>::type reference;
|
||||
typedef typename ipcdetail::
|
||||
remove_volatile<typename ipcdetail::
|
||||
remove_const<PointedType>::type
|
||||
>::type value_type;
|
||||
typedef DifferenceType difference_type;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef OffsetType offset_type;
|
||||
|
||||
public: //Public Functions
|
||||
|
||||
//!Default constructor (null pointer).
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr() BOOST_NOEXCEPT
|
||||
: internal(1)
|
||||
{}
|
||||
|
||||
//!Constructor from raw pointer (allows "0" pointer conversion).
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(pointer ptr) BOOST_NOEXCEPT
|
||||
: internal(static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset(ptr, this)))
|
||||
{}
|
||||
|
||||
//!Constructor from other pointer.
|
||||
//!Never throws.
|
||||
template <class T>
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr( T *ptr
|
||||
, typename ipcdetail::enable_if< ::boost::is_convertible<T*, PointedType*> >::type * = 0) BOOST_NOEXCEPT
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset(static_cast<PointedType*>(ptr), this)))
|
||||
{}
|
||||
|
||||
//!Constructor from other offset_ptr
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr& ptr) BOOST_NOEXCEPT
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.internal.m_offset)))
|
||||
{}
|
||||
|
||||
//!Constructor from other offset_ptr. If pointers of pointee types are
|
||||
//!convertible, offset_ptrs will be convertibles. Never throws.
|
||||
template<class T2>
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr( const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
, typename ipcdetail::enable_if_convertible_equal_address<T2, PointedType>::type* = 0
|
||||
#endif
|
||||
) BOOST_NOEXCEPT
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.get_offset())))
|
||||
{}
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!Constructor from other offset_ptr. If pointers of pointee types are
|
||||
//!convertible, offset_ptrs will be convertibles. Never throws.
|
||||
template<class T2>
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr( const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
|
||||
, typename ipcdetail::enable_if_convertible_unequal_address<T2, PointedType>::type* = 0) BOOST_NOEXCEPT
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset(static_cast<PointedType*>(ptr.get()), this)))
|
||||
{}
|
||||
|
||||
#endif
|
||||
|
||||
//!Emulates static_cast operator.
|
||||
//!Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::static_cast_tag) BOOST_NOEXCEPT
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset(static_cast<PointedType*>(r.get()), this)))
|
||||
{}
|
||||
|
||||
//!Emulates const_cast operator.
|
||||
//!Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::const_cast_tag) BOOST_NOEXCEPT
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset(const_cast<PointedType*>(r.get()), this)))
|
||||
{}
|
||||
|
||||
//!Emulates dynamic_cast operator.
|
||||
//!Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::dynamic_cast_tag) BOOST_NOEXCEPT
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset(dynamic_cast<PointedType*>(r.get()), this)))
|
||||
{}
|
||||
|
||||
//!Emulates reinterpret_cast operator.
|
||||
//!Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::reinterpret_cast_tag) BOOST_NOEXCEPT
|
||||
: internal(static_cast<OffsetType>
|
||||
(ipcdetail::offset_ptr_to_offset(reinterpret_cast<PointedType*>(r.get()), this)))
|
||||
{}
|
||||
|
||||
//!Obtains raw pointer from offset.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE pointer get() const BOOST_NOEXCEPT
|
||||
{ return (pointer)ipcdetail::offset_ptr_to_raw_pointer(this, this->internal.m_offset); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_type get_offset() const BOOST_NOEXCEPT
|
||||
{ return this->internal.m_offset; }
|
||||
|
||||
//!Pointer-like -> operator. It can return 0 pointer.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE pointer operator->() const BOOST_NOEXCEPT
|
||||
{ return this->get(); }
|
||||
|
||||
//!Dereferencing operator, if it is a null offset_ptr behavior
|
||||
//! is undefined. Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE reference operator* () const BOOST_NOEXCEPT
|
||||
{
|
||||
pointer p = this->get();
|
||||
reference r = *p;
|
||||
return r;
|
||||
}
|
||||
|
||||
//!Indexing operator.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE reference operator[](difference_type idx) const BOOST_NOEXCEPT
|
||||
{ return this->get()[idx]; }
|
||||
|
||||
//!Assignment from pointer (saves extra conversion).
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (pointer from) BOOST_NOEXCEPT
|
||||
{
|
||||
this->internal.m_offset =
|
||||
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset(from, this));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Assignment from other offset_ptr.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (const offset_ptr & ptr) BOOST_NOEXCEPT
|
||||
{
|
||||
this->internal.m_offset =
|
||||
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.internal.m_offset));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Assignment from related offset_ptr. If pointers of pointee types
|
||||
//! are assignable, offset_ptrs will be assignable. Never throws.
|
||||
template<class T2> BOOST_INTERPROCESS_FORCEINLINE
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
typename ipcdetail::enable_if_c
|
||||
< ::boost::is_convertible<T2*, PointedType*>::value, offset_ptr&>::type
|
||||
#else
|
||||
offset_ptr&
|
||||
#endif
|
||||
operator= (const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr) BOOST_NOEXCEPT
|
||||
{
|
||||
this->assign(ptr, ipcdetail::bool_<ipcdetail::offset_ptr_maintains_address<T2, PointedType>::value>());
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
//!offset_ptr += difference_type.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr &operator+= (difference_type offset) BOOST_NOEXCEPT
|
||||
{ this->inc_offset(offset * sizeof (PointedType)); return *this; }
|
||||
|
||||
//!offset_ptr -= difference_type.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr &operator-= (difference_type offset) BOOST_NOEXCEPT
|
||||
{ this->dec_offset(offset * sizeof (PointedType)); return *this; }
|
||||
|
||||
//!++offset_ptr.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator++ (void) BOOST_NOEXCEPT
|
||||
{ this->inc_offset(sizeof (PointedType)); return *this; }
|
||||
|
||||
//!offset_ptr++.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr operator++ (int) BOOST_NOEXCEPT
|
||||
{
|
||||
offset_ptr tmp(*this);
|
||||
this->inc_offset(sizeof (PointedType));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//!--offset_ptr.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator-- (void) BOOST_NOEXCEPT
|
||||
{ this->dec_offset(sizeof (PointedType)); return *this; }
|
||||
|
||||
//!offset_ptr--.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr operator-- (int) BOOST_NOEXCEPT
|
||||
{
|
||||
offset_ptr tmp(*this);
|
||||
this->dec_offset(sizeof (PointedType));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//!safe bool conversion operator.
|
||||
//!Never throws.
|
||||
#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
|
||||
BOOST_INTERPROCESS_FORCEINLINE operator unspecified_bool_type() const BOOST_NOEXCEPT
|
||||
{ return this->internal.m_offset != 1? &self_t::unspecified_bool_type_func : 0; }
|
||||
#else
|
||||
explicit operator bool() const BOOST_NOEXCEPT
|
||||
{ return this->internal.m_offset != 1; }
|
||||
#endif
|
||||
|
||||
//!Not operator. Not needed in theory, but improves portability.
|
||||
//!Never throws
|
||||
BOOST_INTERPROCESS_FORCEINLINE bool operator! () const BOOST_NOEXCEPT
|
||||
{ return this->internal.m_offset == 1; }
|
||||
|
||||
//!Compatibility with pointer_traits
|
||||
//!
|
||||
template <class U>
|
||||
struct rebind
|
||||
{ typedef offset_ptr<U, DifferenceType, OffsetType, OffsetAlignment> other; };
|
||||
|
||||
//!Compatibility with pointer_traits
|
||||
//!
|
||||
BOOST_INTERPROCESS_FORCEINLINE static offset_ptr pointer_to(reference r) BOOST_NOEXCEPT
|
||||
{ return offset_ptr(&r); }
|
||||
|
||||
//!difference_type + offset_ptr
|
||||
//!operation
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator+(difference_type diff, offset_ptr right) BOOST_NOEXCEPT
|
||||
{ right += diff; return right; }
|
||||
|
||||
//!offset_ptr + difference_type
|
||||
//!operation
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator+(offset_ptr left, difference_type diff) BOOST_NOEXCEPT
|
||||
{ left += diff; return left; }
|
||||
|
||||
//!offset_ptr - diff
|
||||
//!operation
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator-(offset_ptr left, difference_type diff) BOOST_NOEXCEPT
|
||||
{ left -= diff; return left; }
|
||||
|
||||
//!offset_ptr - diff
|
||||
//!operation
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator-(difference_type diff, offset_ptr right) BOOST_NOEXCEPT
|
||||
{ right -= diff; return right; }
|
||||
|
||||
//!offset_ptr - offset_ptr
|
||||
//!operation
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend difference_type operator-(const offset_ptr &pt, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return difference_type(pt.get()- pt2.get()); }
|
||||
|
||||
//Comparison
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() == pt2.get(); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() != pt2.get(); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() < pt2.get(); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() <= pt2.get(); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() > pt2.get(); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() >= pt2.get(); }
|
||||
|
||||
//Comparison to raw ptr to support literal 0
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1 == pt2.get(); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1 != pt2.get(); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1 < pt2.get(); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1 <= pt2.get(); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1 > pt2.get(); }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
|
||||
{ return pt1 >= pt2.get(); }
|
||||
|
||||
//Comparison
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() == pt2; }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() != pt2; }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() < pt2; }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() <= pt2; }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() > pt2; }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
|
||||
{ return pt1.get() >= pt2; }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE friend void swap(offset_ptr &left, offset_ptr &right) BOOST_NOEXCEPT
|
||||
{
|
||||
pointer ptr = right.get();
|
||||
right = left;
|
||||
left = ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
template<class T2>
|
||||
BOOST_INTERPROCESS_FORCEINLINE void assign(const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr, ipcdetail::bool_<true>) BOOST_NOEXCEPT
|
||||
{ //no need to pointer adjustment
|
||||
this->internal.m_offset =
|
||||
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.get_offset()));
|
||||
}
|
||||
|
||||
template<class T2>
|
||||
BOOST_INTERPROCESS_FORCEINLINE void assign(const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr, ipcdetail::bool_<false>) BOOST_NOEXCEPT
|
||||
{ //we must convert to raw before calculating the offset
|
||||
this->internal.m_offset =
|
||||
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset(static_cast<PointedType*>(ptr.get()), this));
|
||||
}
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
BOOST_INTERPROCESS_FORCEINLINE void inc_offset(DifferenceType bytes) BOOST_NOEXCEPT
|
||||
{ internal.m_offset += bytes; }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE void dec_offset(DifferenceType bytes) BOOST_NOEXCEPT
|
||||
{ internal.m_offset -= bytes; }
|
||||
|
||||
ipcdetail::offset_ptr_internal<OffsetType, OffsetAlignment> internal;
|
||||
|
||||
public:
|
||||
BOOST_INTERPROCESS_FORCEINLINE const OffsetType &priv_offset() const BOOST_NOEXCEPT
|
||||
{ return internal.m_offset; }
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE OffsetType &priv_offset() BOOST_NOEXCEPT
|
||||
{ return internal.m_offset; }
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
};
|
||||
|
||||
//!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(); }
|
||||
|
||||
//!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>
|
||||
BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
static_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
|
||||
{
|
||||
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>
|
||||
BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
const_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
|
||||
{
|
||||
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>
|
||||
BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
dynamic_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
|
||||
{
|
||||
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>
|
||||
BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
reinterpret_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
|
||||
{
|
||||
return boost::interprocess::offset_ptr<T1, P1, O1, A1>
|
||||
(r, boost::interprocess::ipcdetail::reinterpret_cast_tag());
|
||||
}
|
||||
|
||||
} //namespace interprocess {
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
///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> >
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
namespace move_detail {
|
||||
|
||||
///has_trivial_destructor<> == true_type specialization for optimizations
|
||||
template <class T, class P, class O, std::size_t A>
|
||||
struct is_trivially_destructible< ::boost::interprocess::offset_ptr<T, P, O, A> >
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
} //namespace move_detail {
|
||||
|
||||
namespace interprocess {
|
||||
|
||||
//!to_raw_pointer() enables boost::mem_fn to recognize offset_ptr.
|
||||
//!Never throws.
|
||||
template <class T, class P, class O, std::size_t A>
|
||||
BOOST_INTERPROCESS_FORCEINLINE T * to_raw_pointer(boost::interprocess::offset_ptr<T, P, O, A> const & p) BOOST_NOEXCEPT
|
||||
{ return ipcdetail::to_raw_pointer(p); }
|
||||
|
||||
} //namespace interprocess
|
||||
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
} //namespace boost {
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
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 uintptr_t Mask = ((uintptr_t(1) << uintptr_t(NumBits)) - uintptr_t(1)) << uintptr_t(1);
|
||||
BOOST_STATIC_ASSERT(0 ==(Mask&1));
|
||||
|
||||
//We must ALWAYS take argument "n" by reference as a copy of a null pointer
|
||||
//with a bit (e.g. offset == 3) would be incorrectly copied and interpreted as non-null.
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE static pointer get_pointer(const pointer &n) BOOST_NOEXCEPT
|
||||
{
|
||||
pointer p;
|
||||
O const tmp_off = n.priv_offset() & O(~Mask);
|
||||
p.priv_offset() = boost::interprocess::ipcdetail::offset_ptr_to_offset_from_other(&p, &n, tmp_off);
|
||||
return p;
|
||||
}
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE static void set_pointer(pointer &n, const pointer &p) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(0 == (get_bits)(p));
|
||||
O const stored_bits = O(n.priv_offset() & Mask);
|
||||
n = p;
|
||||
n.priv_offset() |= stored_bits;
|
||||
}
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE static std::size_t get_bits(const pointer &n) BOOST_NOEXCEPT
|
||||
{
|
||||
return std::size_t((n.priv_offset() & Mask) >> 1u);
|
||||
}
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE static void set_bits(pointer &n, std::size_t const b) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(b < (std::size_t(1) << NumBits));
|
||||
O tmp = n.priv_offset();
|
||||
tmp &= O(~Mask);
|
||||
tmp |= O(b << 1u);
|
||||
n.priv_offset() = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace intrusive
|
||||
|
||||
//Predeclaration
|
||||
template<class T, class U>
|
||||
struct pointer_to_other;
|
||||
|
||||
//Backwards compatibility with pointer_to_other
|
||||
template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment, class U>
|
||||
struct pointer_to_other
|
||||
< ::boost::interprocess::offset_ptr<PointedType, DifferenceType, OffsetType, OffsetAlignment>, U >
|
||||
{
|
||||
typedef ::boost::interprocess::offset_ptr<U, DifferenceType, OffsetType, OffsetAlignment> type;
|
||||
};
|
||||
|
||||
} //namespace boost{
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_OFFSET_PTR_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2007-2012.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DELETER_HPP
|
||||
#define BOOST_INTERPROCESS_DELETER_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/interprocess_fwd.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include <boost/intrusive/pointer_traits.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::intrusive::
|
||||
pointer_traits<typename SegmentManager::void_pointer>::template
|
||||
rebind_pointer<T>::type pointer;
|
||||
|
||||
private:
|
||||
typedef typename boost::intrusive::
|
||||
pointer_traits<pointer>::template
|
||||
rebind_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::to_raw_pointer(p)); }
|
||||
};
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DELETER_HPP
|
||||
@@ -0,0 +1,181 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Parts of the pthread code come from Boost Threads code:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \
|
||||
(defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined (BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES))
|
||||
#include <boost/interprocess/sync/posix/recursive_mutex.hpp>
|
||||
#define BOOST_INTERPROCESS_USE_POSIX
|
||||
//Experimental...
|
||||
#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS)
|
||||
#include <boost/interprocess/sync/windows/recursive_mutex.hpp>
|
||||
#define BOOST_INTERPROCESS_USE_WINDOWS
|
||||
#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
#include <boost/interprocess/sync/spin/recursive_mutex.hpp>
|
||||
#define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
|
||||
#endif
|
||||
|
||||
#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail{
|
||||
namespace robust_emulation_helpers {
|
||||
|
||||
template<class T>
|
||||
class mutex_traits;
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
|
||||
//!\file
|
||||
//!Describes interprocess_recursive_mutex and shared_recursive_try_mutex classes
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
//!Wraps a interprocess_mutex that can be placed in shared memory and can be
|
||||
//!shared between processes. Allows several locking calls by the same
|
||||
//!process. Allows timed lock tries
|
||||
class interprocess_recursive_mutex
|
||||
{
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
//Non-copyable
|
||||
interprocess_recursive_mutex(const interprocess_recursive_mutex &);
|
||||
interprocess_recursive_mutex &operator=(const interprocess_recursive_mutex &);
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
public:
|
||||
//!Constructor.
|
||||
//!Throws interprocess_exception on error.
|
||||
interprocess_recursive_mutex();
|
||||
|
||||
//!Destructor. If any process uses the mutex after the destructor is called
|
||||
//!the result is undefined. Does not throw.
|
||||
~interprocess_recursive_mutex();
|
||||
|
||||
//!Effects: The calling thread tries to obtain ownership of the mutex, and
|
||||
//! if another thread has ownership of the mutex, it waits until it can
|
||||
//! obtain the ownership. If a thread takes ownership of the mutex the
|
||||
//! mutex must be unlocked by the same mutex. The mutex must be unlocked
|
||||
//! the same number of times it is locked.
|
||||
//!Throws: interprocess_exception on error.
|
||||
void lock();
|
||||
|
||||
//!Tries to lock the interprocess_mutex, returns false when interprocess_mutex
|
||||
//!is already locked, returns true when success. The mutex must be unlocked
|
||||
//!the same number of times it is locked.
|
||||
//!Throws: interprocess_exception if a severe error is found
|
||||
bool try_lock();
|
||||
|
||||
//!Tries to lock the interprocess_mutex, if interprocess_mutex can't be locked before
|
||||
//!abs_time time, returns false. The mutex must be unlocked
|
||||
//! the same number of times it is locked.
|
||||
//!Throws: interprocess_exception if a severe error is found
|
||||
bool timed_lock(const boost::posix_time::ptime &abs_time);
|
||||
|
||||
//!Effects: The calling thread releases the exclusive ownership of the mutex.
|
||||
//! If the mutex supports recursive locking, the mutex must be unlocked the
|
||||
//! same number of times it is locked.
|
||||
//!Throws: interprocess_exception on error.
|
||||
void unlock();
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
private:
|
||||
|
||||
#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
|
||||
#undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
|
||||
void take_ownership(){ mutex.take_ownership(); }
|
||||
friend class ipcdetail::robust_emulation_helpers::mutex_traits<interprocess_recursive_mutex>;
|
||||
ipcdetail::spin_recursive_mutex mutex;
|
||||
#elif defined(BOOST_INTERPROCESS_USE_POSIX)
|
||||
#undef BOOST_INTERPROCESS_USE_POSIX
|
||||
ipcdetail::posix_recursive_mutex mutex;
|
||||
#elif defined(BOOST_INTERPROCESS_USE_WINDOWS)
|
||||
#undef BOOST_INTERPROCESS_USE_WINDOWS
|
||||
ipcdetail::windows_recursive_mutex mutex;
|
||||
#else
|
||||
#error "Unknown platform for interprocess_mutex"
|
||||
#endif
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
};
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
|
||||
inline interprocess_recursive_mutex::interprocess_recursive_mutex(){}
|
||||
|
||||
inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){}
|
||||
|
||||
inline void interprocess_recursive_mutex::lock()
|
||||
{
|
||||
#ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING
|
||||
boost::posix_time::ptime wait_time
|
||||
= microsec_clock::universal_time()
|
||||
+ boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS);
|
||||
if (!mutex.timed_lock(wait_time)){
|
||||
throw interprocess_exception(timeout_when_locking_error, "Interprocess mutex timeout when locking. Possible deadlock: owner died without unlocking?");
|
||||
}
|
||||
#else
|
||||
mutex.lock();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool interprocess_recursive_mutex::try_lock()
|
||||
{ return mutex.try_lock(); }
|
||||
|
||||
inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
|
||||
{ return mutex.timed_lock(abs_time); }
|
||||
|
||||
inline void interprocess_recursive_mutex::unlock()
|
||||
{ mutex.unlock(); }
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP
|
||||
@@ -0,0 +1,60 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP
|
||||
#define BOOST_INTERPROCESS_MUTEX_FAMILY_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# 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/sync/null_mutex.hpp>
|
||||
|
||||
//!\file
|
||||
//!Describes a shared interprocess_mutex family fit algorithm used to allocate objects in shared memory.
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace interprocess {
|
||||
|
||||
//!Describes interprocess_mutex family to use with Interprocess framework
|
||||
//!based on boost::interprocess synchronization objects.
|
||||
struct mutex_family
|
||||
{
|
||||
typedef boost::interprocess::interprocess_mutex mutex_type;
|
||||
typedef boost::interprocess::interprocess_recursive_mutex recursive_mutex_type;
|
||||
};
|
||||
|
||||
//!Describes interprocess_mutex family to use with Interprocess frameworks
|
||||
//!based on null operation synchronization objects.
|
||||
struct null_mutex_family
|
||||
{
|
||||
typedef boost::interprocess::null_mutex mutex_type;
|
||||
typedef boost::interprocess::null_mutex recursive_mutex_type;
|
||||
};
|
||||
|
||||
} //namespace interprocess {
|
||||
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_NULL_MUTEX_HPP
|
||||
#define BOOST_INTERPROCESS_NULL_MUTEX_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
|
||||
//!\file
|
||||
//!Describes null_mutex classes
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
namespace posix_time
|
||||
{ class ptime; }
|
||||
|
||||
#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
namespace interprocess {
|
||||
|
||||
//!Implements a mutex that simulates a mutex without doing any operation and
|
||||
//!simulates a successful operation.
|
||||
class null_mutex
|
||||
{
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
null_mutex(const null_mutex&);
|
||||
null_mutex &operator= (const null_mutex&);
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
public:
|
||||
|
||||
//!Constructor.
|
||||
//!Empty.
|
||||
null_mutex(){}
|
||||
|
||||
//!Destructor.
|
||||
//!Empty.
|
||||
~null_mutex(){}
|
||||
|
||||
//!Simulates a mutex lock() operation. Empty function.
|
||||
void lock(){}
|
||||
|
||||
//!Simulates a mutex try_lock() operation.
|
||||
//!Equivalent to "return true;"
|
||||
bool try_lock()
|
||||
{ return true; }
|
||||
|
||||
//!Simulates a mutex timed_lock() operation.
|
||||
//!Equivalent to "return true;"
|
||||
bool timed_lock(const boost::posix_time::ptime &)
|
||||
{ return true; }
|
||||
|
||||
//!Simulates a mutex unlock() operation.
|
||||
//!Empty function.
|
||||
void unlock(){}
|
||||
|
||||
//!Simulates a mutex lock_sharable() operation.
|
||||
//!Empty function.
|
||||
void lock_sharable(){}
|
||||
|
||||
//!Simulates a mutex try_lock_sharable() operation.
|
||||
//!Equivalent to "return true;"
|
||||
bool try_lock_sharable()
|
||||
{ return true; }
|
||||
|
||||
//!Simulates a mutex timed_lock_sharable() operation.
|
||||
//!Equivalent to "return true;"
|
||||
bool timed_lock_sharable(const boost::posix_time::ptime &)
|
||||
{ return true; }
|
||||
|
||||
//!Simulates a mutex unlock_sharable() operation.
|
||||
//!Empty function.
|
||||
void unlock_sharable(){}
|
||||
|
||||
//!Simulates a mutex lock_upgradable() operation.
|
||||
//!Empty function.
|
||||
void lock_upgradable(){}
|
||||
|
||||
//!Simulates a mutex try_lock_upgradable() operation.
|
||||
//!Equivalent to "return true;"
|
||||
bool try_lock_upgradable()
|
||||
{ return true; }
|
||||
|
||||
//!Simulates a mutex timed_lock_upgradable() operation.
|
||||
//!Equivalent to "return true;"
|
||||
bool timed_lock_upgradable(const boost::posix_time::ptime &)
|
||||
{ return true; }
|
||||
|
||||
//!Simulates a mutex unlock_upgradable() operation.
|
||||
//!Empty function.
|
||||
void unlock_upgradable(){}
|
||||
|
||||
//!Simulates unlock_and_lock_upgradable().
|
||||
//!Empty function.
|
||||
void unlock_and_lock_upgradable(){}
|
||||
|
||||
//!Simulates unlock_and_lock_sharable().
|
||||
//!Empty function.
|
||||
void unlock_and_lock_sharable(){}
|
||||
|
||||
//!Simulates unlock_upgradable_and_lock_sharable().
|
||||
//!Empty function.
|
||||
void unlock_upgradable_and_lock_sharable(){}
|
||||
|
||||
//Promotions
|
||||
|
||||
//!Simulates unlock_upgradable_and_lock().
|
||||
//!Empty function.
|
||||
void unlock_upgradable_and_lock(){}
|
||||
|
||||
//!Simulates try_unlock_upgradable_and_lock().
|
||||
//!Equivalent to "return true;"
|
||||
bool try_unlock_upgradable_and_lock()
|
||||
{ return true; }
|
||||
|
||||
//!Simulates timed_unlock_upgradable_and_lock().
|
||||
//!Equivalent to "return true;"
|
||||
bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &)
|
||||
{ return true; }
|
||||
|
||||
//!Simulates try_unlock_sharable_and_lock().
|
||||
//!Equivalent to "return true;"
|
||||
bool try_unlock_sharable_and_lock()
|
||||
{ return true; }
|
||||
|
||||
//!Simulates try_unlock_sharable_and_lock_upgradable().
|
||||
//!Equivalent to "return true;"
|
||||
bool try_unlock_sharable_and_lock_upgradable()
|
||||
{ return true; }
|
||||
};
|
||||
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_NULL_MUTEX_HPP
|
||||
@@ -0,0 +1,137 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Parts of the pthread code come from Boost Threads code:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
|
||||
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
|
||||
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
|
||||
# include <boost/interprocess/detail/os_thread_functions.hpp>
|
||||
# include <boost/interprocess/sync/detail/common_algorithms.hpp>
|
||||
#endif
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
class posix_recursive_mutex
|
||||
{
|
||||
posix_recursive_mutex(const posix_recursive_mutex &);
|
||||
posix_recursive_mutex &operator=(const posix_recursive_mutex &);
|
||||
public:
|
||||
|
||||
posix_recursive_mutex();
|
||||
~posix_recursive_mutex();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
bool timed_lock(const boost::posix_time::ptime &abs_time);
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_mut;
|
||||
};
|
||||
|
||||
inline posix_recursive_mutex::posix_recursive_mutex()
|
||||
{
|
||||
mutexattr_wrapper mut_attr(true);
|
||||
mutex_initializer mut(m_mut, mut_attr);
|
||||
mut.release();
|
||||
}
|
||||
|
||||
inline posix_recursive_mutex::~posix_recursive_mutex()
|
||||
{
|
||||
int res = pthread_mutex_destroy(&m_mut);
|
||||
BOOST_ASSERT(res == 0);(void)res;
|
||||
}
|
||||
|
||||
inline void posix_recursive_mutex::lock()
|
||||
{
|
||||
if (pthread_mutex_lock(&m_mut) != 0)
|
||||
throw lock_exception();
|
||||
}
|
||||
|
||||
inline bool posix_recursive_mutex::try_lock()
|
||||
{
|
||||
int res = pthread_mutex_trylock(&m_mut);
|
||||
if (!(res == 0 || res == EBUSY))
|
||||
throw lock_exception();
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
inline bool posix_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
|
||||
{
|
||||
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
|
||||
//Posix does not support infinity absolute time so handle it here
|
||||
if(abs_time == boost::posix_time::pos_infin){
|
||||
this->lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
timespec ts = ptime_to_timespec(abs_time);
|
||||
int res = pthread_mutex_timedlock(&m_mut, &ts);
|
||||
if (res != 0 && res != ETIMEDOUT)
|
||||
throw lock_exception();
|
||||
return res == 0;
|
||||
|
||||
#else //BOOST_INTERPROCESS_POSIX_TIMEOUTS
|
||||
|
||||
return ipcdetail::try_based_timed_lock(*this, abs_time);
|
||||
|
||||
#endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS
|
||||
}
|
||||
|
||||
inline void posix_recursive_mutex::unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_unlock(&m_mut);
|
||||
BOOST_ASSERT(res == 0); (void)res;
|
||||
}
|
||||
|
||||
} //namespace ipcdetail {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP
|
||||
@@ -0,0 +1,176 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Parts of the pthread code come from Boost Threads code:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear
|
||||
// in supporting documentation. William E. Kempf makes no representations
|
||||
// about the suitability of this software for any purpose.
|
||||
// It is provided "as is" without express or implied warranty.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
|
||||
#include <boost/interprocess/detail/os_thread_functions.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/interprocess/detail/os_thread_functions.hpp>
|
||||
#include <boost/interprocess/sync/spin/mutex.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
class spin_recursive_mutex
|
||||
{
|
||||
spin_recursive_mutex(const spin_recursive_mutex &);
|
||||
spin_recursive_mutex &operator=(const spin_recursive_mutex &);
|
||||
public:
|
||||
|
||||
spin_recursive_mutex();
|
||||
~spin_recursive_mutex();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
bool timed_lock(const boost::posix_time::ptime &abs_time);
|
||||
void unlock();
|
||||
void take_ownership();
|
||||
private:
|
||||
spin_mutex m_mutex;
|
||||
unsigned int m_nLockCount;
|
||||
volatile ipcdetail::OS_systemwide_thread_id_t m_nOwner;
|
||||
volatile boost::uint32_t m_s;
|
||||
};
|
||||
|
||||
inline spin_recursive_mutex::spin_recursive_mutex()
|
||||
: m_nLockCount(0), m_nOwner(ipcdetail::get_invalid_systemwide_thread_id()){}
|
||||
|
||||
inline spin_recursive_mutex::~spin_recursive_mutex(){}
|
||||
|
||||
inline void spin_recursive_mutex::lock()
|
||||
{
|
||||
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
|
||||
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
|
||||
handle_t old_id;
|
||||
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
|
||||
if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)){
|
||||
if((unsigned int)(m_nLockCount+1) == 0){
|
||||
//Overflow, throw an exception
|
||||
throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow");
|
||||
}
|
||||
++m_nLockCount;
|
||||
}
|
||||
else{
|
||||
m_mutex.lock();
|
||||
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
|
||||
m_nLockCount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool spin_recursive_mutex::try_lock()
|
||||
{
|
||||
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
|
||||
handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
|
||||
handle_t old_id;
|
||||
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
|
||||
if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it
|
||||
if((unsigned int)(m_nLockCount+1) == 0){
|
||||
//Overflow, throw an exception
|
||||
throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow");
|
||||
}
|
||||
++m_nLockCount;
|
||||
return true;
|
||||
}
|
||||
if(m_mutex.try_lock()){
|
||||
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
|
||||
m_nLockCount = 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool spin_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
|
||||
{
|
||||
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
|
||||
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
|
||||
handle_t old_id;
|
||||
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
|
||||
if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it
|
||||
if((unsigned int)(m_nLockCount+1) == 0){
|
||||
//Overflow, throw an exception
|
||||
throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow");
|
||||
}
|
||||
++m_nLockCount;
|
||||
return true;
|
||||
}
|
||||
//m_mutex supports abs_time so no need to check it
|
||||
if(m_mutex.timed_lock(abs_time)){
|
||||
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
|
||||
m_nLockCount = 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void spin_recursive_mutex::unlock()
|
||||
{
|
||||
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
|
||||
handle_t old_id;
|
||||
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
|
||||
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
|
||||
(void)old_id;
|
||||
(void)thr_id;
|
||||
BOOST_ASSERT(ipcdetail::equal_systemwide_thread_id(thr_id, old_id));
|
||||
--m_nLockCount;
|
||||
if(!m_nLockCount){
|
||||
const handle_t new_id(ipcdetail::get_invalid_systemwide_thread_id());
|
||||
ipcdetail::systemwide_thread_id_copy(new_id, m_nOwner);
|
||||
m_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
inline void spin_recursive_mutex::take_ownership()
|
||||
{
|
||||
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
|
||||
this->m_nLockCount = 1;
|
||||
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
|
||||
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
|
||||
}
|
||||
|
||||
} //namespace ipcdetail {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP
|
||||
@@ -0,0 +1,47 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/interprocess for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
#
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
#include <boost/interprocess/sync/windows/mutex.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace interprocess {
|
||||
namespace ipcdetail {
|
||||
|
||||
//Windows mutex is already recursive
|
||||
class windows_recursive_mutex
|
||||
: public windows_mutex
|
||||
{
|
||||
windows_recursive_mutex(const windows_recursive_mutex &);
|
||||
windows_recursive_mutex &operator=(const windows_recursive_mutex &);
|
||||
public:
|
||||
windows_recursive_mutex() : windows_mutex() {}
|
||||
};
|
||||
|
||||
} //namespace ipcdetail {
|
||||
} //namespace interprocess {
|
||||
} //namespace boost {
|
||||
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP
|
||||
Reference in New Issue
Block a user