mirror of
https://github.com/boostorg/interprocess.git
synced 2026-01-19 04:12:13 +00:00
Implement new ABI for segment_manager that supports overaligned types.
This commit is contained in:
@@ -6774,6 +6774,9 @@ thank them:
|
||||
|
||||
* Some workarounds for Cygwin were added. Regression tests now work on Cygwin64.
|
||||
|
||||
* [*ABI breaking]: `segment_manager` nows uses a new implementation that supports overaligned types and fixes some existing bugs.
|
||||
You can obtain the pre-Boost 1.87 ABI #defining `BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI` to `1` before including Boost.Interprocess headers.
|
||||
|
||||
* Fixed bugs:
|
||||
* [@https://github.com/boostorg/interprocess/issues/210 GitHub #210 (['"Bug in boost::interprocess::ipcdetail::sync_handles::obtain_mutex"])].
|
||||
* [@https://github.com/boostorg/interprocess/issues/192 GitHub #192 (['"managed_windows_shared_memory crash on destruction"])].
|
||||
|
||||
@@ -71,6 +71,12 @@ class mem_algo_deallocator
|
||||
{ if(m_ptr) m_algo.deallocate(m_ptr); }
|
||||
};
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI)
|
||||
#define BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI 2
|
||||
#endif //#if !defined(BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI)
|
||||
|
||||
#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI == 1)
|
||||
|
||||
template<class size_type>
|
||||
struct block_header
|
||||
{
|
||||
@@ -91,6 +97,7 @@ struct block_header
|
||||
, m_alloc_type_sizeof_char( (unsigned char)((al_type << 5u) | ((unsigned char)szof_char & 0x1F)) )
|
||||
{};
|
||||
|
||||
template<std::size_t>
|
||||
size_type total_size() const
|
||||
{
|
||||
if(alloc_type() != anonymous_type){
|
||||
@@ -104,13 +111,13 @@ struct block_header
|
||||
size_type value_bytes() const
|
||||
{ return m_value_bytes; }
|
||||
|
||||
template<class Header>
|
||||
template<std::size_t , class Header>
|
||||
size_type total_size_with_header() const
|
||||
{
|
||||
return get_rounded_size
|
||||
( size_type(sizeof(Header))
|
||||
, size_type(::boost::container::dtl::alignment_of<block_header<size_type> >::value))
|
||||
+ total_size();
|
||||
+ this->template total_size<0>();
|
||||
}
|
||||
|
||||
unsigned char alloc_type() const
|
||||
@@ -176,6 +183,10 @@ struct block_header
|
||||
return hdr;
|
||||
}
|
||||
|
||||
template<std::size_t, class >
|
||||
static size_type front_space()
|
||||
{ return 0u; }
|
||||
|
||||
private:
|
||||
size_type value_offset() const
|
||||
{
|
||||
@@ -188,26 +199,200 @@ struct block_header
|
||||
}
|
||||
};
|
||||
|
||||
#elif (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI == 2)
|
||||
|
||||
template <class BlockHeader, class Header>
|
||||
struct header_to_block_header_offset
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR std::size_t value = sizeof(Header)
|
||||
+ ct_rounded_size< sizeof(BlockHeader)
|
||||
, boost::move_detail::alignment_of<Header>::value
|
||||
>::value
|
||||
- sizeof(BlockHeader);
|
||||
};
|
||||
|
||||
template <std::size_t MemAlignment, class BlockHeader, class Header>
|
||||
struct prefix_offsets
|
||||
{
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT(MemAlignment >= boost::move_detail::alignment_of<Header>::value);
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT(MemAlignment >= boost::move_detail::alignment_of<BlockHeader>::value);
|
||||
|
||||
BOOST_STATIC_CONSTEXPR std::size_t both_headers =
|
||||
header_to_block_header_offset<BlockHeader, Header>::value + sizeof(BlockHeader);
|
||||
|
||||
BOOST_STATIC_CONSTEXPR std::size_t total_prefix = ct_rounded_size<both_headers, MemAlignment>::value;
|
||||
|
||||
BOOST_STATIC_CONSTEXPR std::size_t block_header_prefix = total_prefix - sizeof(BlockHeader);
|
||||
|
||||
BOOST_STATIC_CONSTEXPR std::size_t front_space = total_prefix - both_headers;
|
||||
};
|
||||
|
||||
template <std::size_t MemAlignment, class BlockHeader>
|
||||
struct prefix_offsets<MemAlignment, BlockHeader, void>
|
||||
{
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT(MemAlignment >= boost::move_detail::alignment_of<BlockHeader>::value);
|
||||
|
||||
BOOST_STATIC_CONSTEXPR std::size_t total_prefix = ct_rounded_size<sizeof(BlockHeader), MemAlignment>::value;
|
||||
|
||||
BOOST_STATIC_CONSTEXPR std::size_t block_header_prefix = total_prefix - sizeof(BlockHeader);
|
||||
|
||||
BOOST_STATIC_CONSTEXPR std::size_t front_space = block_header_prefix;
|
||||
};
|
||||
|
||||
template<class size_type>
|
||||
struct block_header
|
||||
{
|
||||
const size_type m_value_bytes;
|
||||
const unsigned short m_num_char;
|
||||
const unsigned char m_alloc_type_sizeof_char;
|
||||
|
||||
block_header(size_type val_bytes
|
||||
,size_type
|
||||
,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_alloc_type_sizeof_char( (unsigned char)((al_type << 5u) | ((unsigned char)szof_char & 0x1F)) )
|
||||
{};
|
||||
|
||||
template<std::size_t MemAlignment>
|
||||
size_type total_size() const
|
||||
{
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t block_header_prefix =
|
||||
prefix_offsets<MemAlignment, block_header, void>::block_header_prefix;
|
||||
if(alloc_type() != anonymous_type){
|
||||
return block_header_prefix + name_offset() + (m_num_char+1u)*sizeof_char();
|
||||
}
|
||||
else{
|
||||
return block_header_prefix + this->value_offset() + m_value_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t MemAlignment, class Header>
|
||||
size_type total_size_with_header() const
|
||||
{
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t block_header_prefix =
|
||||
prefix_offsets<MemAlignment, block_header, Header>::block_header_prefix;
|
||||
return block_header_prefix + name_offset() + (m_num_char + 1u) * sizeof_char();
|
||||
}
|
||||
|
||||
size_type value_bytes() const
|
||||
{ return m_value_bytes; }
|
||||
|
||||
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*>(move_detail::force_ptr<const CharType*>
|
||||
(reinterpret_cast<const char*>(this) + name_offset()));
|
||||
}
|
||||
|
||||
unsigned short name_length() const
|
||||
{ return m_num_char; }
|
||||
|
||||
void *value() const
|
||||
{
|
||||
return const_cast<char*>((reinterpret_cast<const char*>(this) + this->value_offset()));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static block_header *block_header_from_value(T *value)
|
||||
{
|
||||
BOOST_ASSERT(is_ptr_aligned(value, ::boost::container::dtl::alignment_of<T>::value));
|
||||
block_header* hdr =
|
||||
const_cast<block_header*>
|
||||
(move_detail::force_ptr<const block_header*>
|
||||
(reinterpret_cast<const char*>(value) - value_offset()));
|
||||
|
||||
//Some sanity checks
|
||||
BOOST_ASSERT(hdr->m_value_bytes % sizeof(T) == 0);
|
||||
return hdr;
|
||||
}
|
||||
|
||||
template<class Header>
|
||||
static block_header *from_first_header(Header *header)
|
||||
{
|
||||
BOOST_ASSERT(is_ptr_aligned(header));
|
||||
block_header * const hdr = move_detail::force_ptr<block_header*>(
|
||||
reinterpret_cast<char*>(header) + header_to_block_header_offset<block_header, Header>::value
|
||||
);
|
||||
//Some sanity checks
|
||||
BOOST_ASSERT(is_ptr_aligned(hdr));
|
||||
return hdr;
|
||||
}
|
||||
|
||||
template<class Header>
|
||||
static const block_header *from_first_header(const Header *header)
|
||||
{ return from_first_header(const_cast<Header*>(header)); }
|
||||
|
||||
template<class Header>
|
||||
static Header *to_first_header(block_header *bheader)
|
||||
{
|
||||
BOOST_ASSERT(is_ptr_aligned(bheader));
|
||||
Header * hdr = move_detail::force_ptr<Header*>(
|
||||
reinterpret_cast<char*>(bheader) - header_to_block_header_offset<block_header, Header>::value
|
||||
);
|
||||
//Some sanity checks
|
||||
BOOST_ASSERT(is_ptr_aligned(hdr));
|
||||
return hdr;
|
||||
}
|
||||
|
||||
template<std::size_t MemAlignment, class Header>
|
||||
static size_type front_space()
|
||||
{
|
||||
return prefix_offsets<MemAlignment, block_header, Header>::front_space;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static size_type value_offset()
|
||||
{
|
||||
return size_type(sizeof(block_header));
|
||||
}
|
||||
|
||||
size_type name_offset() const
|
||||
{
|
||||
return this->value_offset() + get_rounded_size(size_type(m_value_bytes), size_type(sizeof_char()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#else //(BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI == )
|
||||
|
||||
#error "Incorrect BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI value!"
|
||||
|
||||
#endif
|
||||
|
||||
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)
|
||||
intrusive_compare_key(const CharT* str, std::size_t len)
|
||||
: mp_str(str), m_len(len)
|
||||
{}
|
||||
|
||||
const CharT *str() const
|
||||
{ return mp_str; }
|
||||
const CharT* str() const
|
||||
{
|
||||
return mp_str;
|
||||
}
|
||||
|
||||
std::size_t len() const
|
||||
{ return m_len; }
|
||||
{
|
||||
return m_len;
|
||||
}
|
||||
|
||||
const CharT * mp_str;
|
||||
const CharT* mp_str;
|
||||
std::size_t m_len;
|
||||
};
|
||||
|
||||
|
||||
//!This struct indicates an anonymous object creation
|
||||
//!allocation
|
||||
template<instance_type type>
|
||||
@@ -377,7 +562,13 @@ struct index_config
|
||||
|
||||
template<class HeaderBase>
|
||||
struct intrusive_value_type
|
||||
{ typedef intrusive_value_type_impl<HeaderBase, CharT, typename segment_manager_base::size_type> type; };
|
||||
{
|
||||
typedef intrusive_value_type_impl
|
||||
< HeaderBase
|
||||
, CharT
|
||||
, typename segment_manager_base::size_type
|
||||
> type;
|
||||
};
|
||||
|
||||
typedef intrusive_compare_key<CharT> compare_key_type;
|
||||
};
|
||||
|
||||
@@ -75,6 +75,7 @@ class segment_manager_base
|
||||
typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
|
||||
typedef typename MemoryAlgorithm::void_pointer void_pointer;
|
||||
typedef typename MemoryAlgorithm::mutex_family mutex_family;
|
||||
static const std::size_t MemAlignment = MemoryAlgorithm::Alignment;
|
||||
typedef MemoryAlgorithm memory_algorithm;
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
@@ -310,6 +311,7 @@ class segment_manager
|
||||
typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
|
||||
|
||||
static const size_type PayloadPerAllocation = segment_manager_base_t::PayloadPerAllocation;
|
||||
static const size_type MemAlignment = segment_manager_base_t::MemAlignment;
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
private:
|
||||
@@ -698,6 +700,7 @@ class segment_manager
|
||||
{
|
||||
typedef typename Proxy::object_type object_type;
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t t_alignment = boost::move_detail::alignment_of<object_type>::value;
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t alloc_alignment = t_alignment > MemAlignment ? t_alignment : MemAlignment;
|
||||
block_header_t block_info ( size_type(sizeof(object_type)*num)
|
||||
, size_type(t_alignment)
|
||||
, anonymous_type
|
||||
@@ -705,7 +708,12 @@ class segment_manager
|
||||
, 0);
|
||||
|
||||
//Check if there is enough memory
|
||||
void *ptr_struct = this->allocate(block_info.total_size(), nothrow<>::get());
|
||||
const std::size_t total_size = block_info.template total_size<alloc_alignment>();
|
||||
#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI < 2)
|
||||
void *ptr_struct = this->allocate(total_size, nothrow<>::get());
|
||||
#else
|
||||
void* ptr_struct = this->allocate_aligned(total_size, alloc_alignment, nothrow<>::get());
|
||||
#endif
|
||||
if(!ptr_struct){
|
||||
return ipcdetail::null_or_bad_alloc<object_type>(dothrow);
|
||||
}
|
||||
@@ -715,7 +723,10 @@ class segment_manager
|
||||
(ptr_struct, *static_cast<segment_manager_base_type*>(this));
|
||||
|
||||
//Now construct the header
|
||||
block_header_t * hdr = ::new(ptr_struct, boost_container_new_t()) block_header_t(block_info);
|
||||
const std::size_t front_space = block_header_t::template front_space< alloc_alignment, void>();
|
||||
|
||||
block_header_t * const hdr = ::new((char*)ptr_struct + front_space, boost_container_new_t()) block_header_t(block_info);
|
||||
BOOST_ASSERT(is_ptr_aligned(hdr));
|
||||
void *ptr = 0; //avoid gcc warning
|
||||
ptr = hdr->value();
|
||||
|
||||
@@ -724,14 +735,16 @@ class segment_manager
|
||||
|
||||
//All constructors successful, disable rollback
|
||||
mem.release();
|
||||
return static_cast<object_type*>(ptr);
|
||||
object_type* const pret = static_cast<object_type*>(ptr);
|
||||
BOOST_ASSERT(is_ptr_aligned(pret));
|
||||
return pret;
|
||||
}
|
||||
|
||||
//!Calls the destructor and makes an anonymous deallocate
|
||||
template <class T>
|
||||
void priv_anonymous_destroy(const T *object)
|
||||
{
|
||||
|
||||
BOOST_ASSERT(is_ptr_aligned(object));
|
||||
//Get control data from associated with this object
|
||||
block_header_t *ctrl_data = block_header_t::block_header_from_value(object);
|
||||
|
||||
@@ -745,12 +758,19 @@ class segment_manager
|
||||
//Call destructors and free memory
|
||||
//Build scoped ptr to avoid leaks with destructor exception
|
||||
priv_destroy_n(object, ctrl_data->m_value_bytes/sizeof(T));
|
||||
this->deallocate(ctrl_data);
|
||||
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t t_alignment =
|
||||
boost::move_detail::alignment_of<T>::value;
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t alloc_alignment =
|
||||
t_alignment > MemAlignment ? t_alignment : MemAlignment;
|
||||
const std::size_t front_space = block_header_t::template front_space<alloc_alignment, void>();
|
||||
this->deallocate((char*)ctrl_data-front_space);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void priv_destroy_ptr(const T *ptr)
|
||||
{
|
||||
BOOST_ASSERT(is_ptr_aligned(ptr));
|
||||
block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr);
|
||||
switch(ctrl_data->alloc_type()){
|
||||
case anonymous_type:
|
||||
@@ -909,7 +929,7 @@ class segment_manager
|
||||
|
||||
template <class T, class CharT>
|
||||
bool priv_generic_named_destroy_impl
|
||||
(const typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator &it,
|
||||
(typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator it,
|
||||
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index)
|
||||
{
|
||||
typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_t;
|
||||
@@ -926,13 +946,20 @@ class segment_manager
|
||||
index.erase(it);
|
||||
|
||||
void *memory;
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t t_alignment =
|
||||
boost::move_detail::alignment_of<T>::value;
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t alloc_alignment =
|
||||
t_alignment > MemAlignment ? t_alignment : MemAlignment;
|
||||
|
||||
BOOST_IF_CONSTEXPR(is_node_index_t::value || is_intrusive_t::value){
|
||||
index_data_t*ihdr = block_header_t::template to_first_header<index_data_t>(ctrl_data);
|
||||
const std::size_t front_space = block_header_t::template front_space<alloc_alignment, index_data_t>();
|
||||
memory = (char*)ihdr - front_space;
|
||||
ihdr->~index_data_t();
|
||||
memory = ihdr;
|
||||
}
|
||||
else{
|
||||
memory = ctrl_data;
|
||||
const std::size_t front_space = block_header_t::template front_space<alloc_alignment, void>();
|
||||
memory = (char*)ctrl_data - front_space;
|
||||
}
|
||||
|
||||
//Call destructors and free memory
|
||||
@@ -967,6 +994,7 @@ class segment_manager
|
||||
typedef typename Proxy::object_type object_type;
|
||||
std::size_t namelen = std::char_traits<CharT>::length(name);
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t t_alignment = boost::move_detail::alignment_of<object_type>::value;
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t alloc_alignment = t_alignment > MemAlignment ? t_alignment: MemAlignment ;
|
||||
|
||||
block_header_t block_info ( size_type(sizeof(object_type)*num)
|
||||
, size_type(t_alignment)
|
||||
@@ -1016,23 +1044,40 @@ class segment_manager
|
||||
//Allocates buffer for name + data, this can throw (it hurts)
|
||||
void *buffer_ptr;
|
||||
block_header_t * hdr;
|
||||
std::size_t front_space;
|
||||
|
||||
//Allocate and construct the headers
|
||||
BOOST_IF_CONSTEXPR(is_node_index_t::value || is_intrusive_t::value){
|
||||
size_type total_size = block_info.template total_size_with_header<index_data_t>();
|
||||
const size_type total_size = block_info.template total_size_with_header<alloc_alignment, index_data_t>();
|
||||
#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI < 2)
|
||||
buffer_ptr = this->allocate(total_size, nothrow<>::get());
|
||||
#else
|
||||
buffer_ptr = this->allocate_aligned(total_size, alloc_alignment, nothrow<>::get());
|
||||
#endif
|
||||
|
||||
if(!buffer_ptr)
|
||||
return ipcdetail::null_or_bad_alloc<object_type>(dothrow);
|
||||
hdr = block_header_t::template from_first_header<index_data_t>(static_cast<index_data_t*>(buffer_ptr));
|
||||
|
||||
front_space = block_header_t::template front_space<alloc_alignment, index_data_t>();
|
||||
hdr = block_header_t::template from_first_header(reinterpret_cast<index_data_t*>((void*)((char*)buffer_ptr+front_space)));
|
||||
}
|
||||
else{
|
||||
buffer_ptr = this->allocate(block_info.total_size(), nothrow<>::get());
|
||||
const size_type total_size = block_info.template total_size<alloc_alignment>();
|
||||
#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI < 2)
|
||||
buffer_ptr = this->allocate(total_size, nothrow<>::get());
|
||||
#else
|
||||
buffer_ptr = this->allocate_aligned(total_size, alloc_alignment, nothrow<>::get());
|
||||
#endif
|
||||
|
||||
front_space = block_header_t::template front_space<alloc_alignment, void>();
|
||||
|
||||
//Check if there is enough memory
|
||||
if (!buffer_ptr)
|
||||
return ipcdetail::null_or_bad_alloc<object_type>(dothrow);
|
||||
hdr = static_cast<block_header_t*>(buffer_ptr);
|
||||
hdr = reinterpret_cast<block_header_t*>((void*)((char*)buffer_ptr + front_space));
|
||||
}
|
||||
|
||||
BOOST_ASSERT(is_ptr_aligned(hdr));
|
||||
hdr = ::new(hdr, boost_container_new_t()) block_header_t(block_info);
|
||||
|
||||
//Build scoped ptr to avoid leaks with constructor exception
|
||||
@@ -1048,7 +1093,8 @@ class segment_manager
|
||||
index_it it;
|
||||
BOOST_INTERPROCESS_TRY{
|
||||
BOOST_IF_CONSTEXPR(is_node_index_t::value || is_intrusive_t::value) {
|
||||
index_data_t* index_data = ::new(buffer_ptr, boost_container_new_t()) index_data_t();
|
||||
index_data_t* index_data = ::new((char*)buffer_ptr + front_space, boost_container_new_t()) index_data_t();
|
||||
BOOST_ASSERT(is_ptr_aligned(index_data));
|
||||
it = index.insert_commit(compare_key_t(name_ptr, namelen), hdr, *index_data, commit_data);
|
||||
}
|
||||
else{
|
||||
@@ -1074,7 +1120,9 @@ class segment_manager
|
||||
//Release rollbacks since construction was successful
|
||||
v_eraser.release();
|
||||
mem.release();
|
||||
return static_cast<object_type*>(ptr);
|
||||
object_type* const pret = static_cast<object_type*>(ptr);
|
||||
BOOST_ASSERT(is_ptr_aligned(pret));
|
||||
return pret;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -8,609 +8,5 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/interprocess/indexes/flat_map_index.hpp>
|
||||
#include <boost/interprocess/indexes/map_index.hpp>
|
||||
#include <boost/interprocess/indexes/null_index.hpp>
|
||||
#include <boost/interprocess/indexes/iset_index.hpp>
|
||||
#include <boost/interprocess/indexes/iunordered_set_index.hpp>
|
||||
|
||||
#include <boost/interprocess/mem_algo/simple_seq_fit.hpp>
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/mapped_region.hpp>
|
||||
#include <boost/interprocess/segment_manager.hpp>
|
||||
#include <boost/interprocess/shared_memory_object.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include "get_process_id_name.hpp"
|
||||
#include <cstddef>
|
||||
#include <new>
|
||||
#include <cstring>
|
||||
#include <typeinfo>
|
||||
|
||||
using namespace boost::interprocess;
|
||||
|
||||
template <class SegmentManager>
|
||||
struct atomic_func_test
|
||||
{
|
||||
SegmentManager &rsm;
|
||||
int *object;
|
||||
|
||||
atomic_func_test(SegmentManager &sm)
|
||||
: rsm(sm), object()
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
object = rsm.template find<int>("atomic_func_find_object").first;
|
||||
}
|
||||
private:
|
||||
atomic_func_test operator=(const atomic_func_test&);
|
||||
atomic_func_test(const atomic_func_test&);
|
||||
};
|
||||
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_allocate_deallocate(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
typedef typename SegmentManager::size_type size_type;
|
||||
{//test get_free_memory() / allocate()/deallocate()
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const size_type Size = MappedRegionSize / 2;
|
||||
void* mem = seg_mgr->allocate(Size + 1);
|
||||
const size_type free_mem = seg_mgr->get_free_memory();
|
||||
if (free_mem >= Size)
|
||||
return false;
|
||||
if (seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
const size_type Size2 = free_mem / 2;
|
||||
void* mem2 = seg_mgr->allocate(size_type(Size2 + 1), std::nothrow);
|
||||
if (seg_mgr->get_free_memory() >= Size2)
|
||||
return false;
|
||||
if (seg_mgr->size(mem) < (Size + 1))
|
||||
return false;
|
||||
if (seg_mgr->size(mem2) < (Size2 + 1))
|
||||
return false;
|
||||
seg_mgr->deallocate(mem);
|
||||
seg_mgr->deallocate(mem2);
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->allocate(MappedRegionSize * 2); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) {}
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if (seg_mgr->allocate(MappedRegionSize * 2, std::nothrow))
|
||||
return false;
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_allocate_aligned(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
const std::size_t InitialAlignment = SegmentManager::memory_algorithm::Alignment;
|
||||
const std::size_t RegionAlignment = mapped_region::get_page_size();
|
||||
|
||||
for( std::size_t alignment = InitialAlignment
|
||||
; (alignment <= MappedRegionSize/8 && alignment <= RegionAlignment/4)
|
||||
; alignment <<= 1u) {
|
||||
|
||||
//Allocate two buffers and test the alignment inside the mapped region
|
||||
void *mem = seg_mgr->allocate_aligned(MappedRegionSize/8, alignment);
|
||||
if(seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
|
||||
std::size_t offset = static_cast<std::size_t>
|
||||
(static_cast<const char *>(mem) - static_cast<const char *>(mapping.get_address()));
|
||||
if(offset & (alignment -1))
|
||||
return false;
|
||||
void *mem2 = seg_mgr->allocate_aligned(MappedRegionSize/4, alignment, std::nothrow);
|
||||
std::size_t offset2 = static_cast<std::size_t>
|
||||
(static_cast<const char *>(mem2) - static_cast<const char *>(mapping.get_address()));
|
||||
if(offset2 & (alignment -1))
|
||||
return false;
|
||||
|
||||
//Deallocate them
|
||||
seg_mgr->deallocate(mem);
|
||||
seg_mgr->deallocate(mem2);
|
||||
if(!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
if(seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
|
||||
//Try an imposible size to test error is signalled
|
||||
bool allocate_aligned_throws = false;
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->allocate_aligned(MappedRegionSize*2, alignment); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&){ allocate_aligned_throws = true; }
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (!allocate_aligned_throws)
|
||||
return false;
|
||||
|
||||
if (seg_mgr->allocate_aligned(MappedRegionSize*2, alignment, std::nothrow))
|
||||
return false;
|
||||
|
||||
if(seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if(seg_mgr->allocate_aligned(MappedRegionSize*2, alignment, std::nothrow))
|
||||
return false;
|
||||
if(seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_shrink_to_fit(SegmentManager* seg_mgr, mapped_region &)
|
||||
{
|
||||
typedef typename SegmentManager::size_type size_type;
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
std::size_t size_before = seg_mgr->get_size();
|
||||
seg_mgr->shrink_to_fit();
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
std::size_t empty_shrunk_size = seg_mgr->get_size();
|
||||
std::size_t empty_shrunk_free_mem = seg_mgr->get_free_memory();
|
||||
if (empty_shrunk_size >= size_before)
|
||||
return false;
|
||||
if (empty_shrunk_free_mem >= size_before)
|
||||
return false;
|
||||
seg_mgr->grow(size_type(size_before - empty_shrunk_size));
|
||||
if (seg_mgr->get_size() != size_before)
|
||||
return false;
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_zero_free_memory(SegmentManager* seg_mgr, mapped_region &mapping)
|
||||
{
|
||||
typedef typename SegmentManager::size_type size_type;
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
const size_type Size(MappedRegionSize / 2 + 1), Size2(MappedRegionSize / 8);
|
||||
void* mem = seg_mgr->allocate(Size);
|
||||
void* mem2 = seg_mgr->allocate(Size2);
|
||||
//Mark memory to non-zero
|
||||
std::memset(mem, 0xFF, Size);
|
||||
std::memset(mem2, 0xFF, Size2);
|
||||
//Deallocate and check still non-zero
|
||||
seg_mgr->deallocate(mem);
|
||||
seg_mgr->deallocate(mem2);
|
||||
{ //Use byte per byte comparison as "static unsigned char zerobuf[Size]"
|
||||
//seems to be problematic in some compilers
|
||||
unsigned char* const mem_uch_ptr = static_cast<unsigned char*>(mem);
|
||||
unsigned char* const mem2_uch_ptr = static_cast<unsigned char*>(mem2);
|
||||
size_type zeroes = 0;
|
||||
for (size_type i = 0; i != Size; ++i) {
|
||||
if (!mem_uch_ptr[i])
|
||||
++zeroes;
|
||||
}
|
||||
if (zeroes == Size)
|
||||
return false;
|
||||
|
||||
zeroes = 0;
|
||||
for (size_type i = 0; i != Size2; ++i) {
|
||||
if (!mem2_uch_ptr[i])
|
||||
++zeroes;
|
||||
}
|
||||
if (zeroes == Size2)
|
||||
return false;
|
||||
}
|
||||
//zero_free_memory and check it's zeroed
|
||||
seg_mgr->zero_free_memory();
|
||||
//TODO: some parts are not zeroed because they are used
|
||||
//as internal metadata, find a way to test this
|
||||
//if(std::memcmp(mem, zerobuf, Size))
|
||||
//return false;
|
||||
//if(std::memcmp(mem2, zerobuf, Size2))
|
||||
//return false;
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_anoymous_object(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
|
||||
int* int_object = seg_mgr->template construct<int>(anonymous_instance)();
|
||||
if (1 != seg_mgr->get_instance_length(int_object))
|
||||
return false;
|
||||
if (anonymous_type != seg_mgr->get_instance_type(int_object))
|
||||
return false;
|
||||
if (seg_mgr->get_instance_name(int_object))
|
||||
return false;
|
||||
seg_mgr->destroy_ptr(int_object);
|
||||
int const int_array_values[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
int* int_array = seg_mgr->template construct_it<int>(anonymous_instance, std::nothrow)[10](&int_array_values[0]);
|
||||
if (10 != seg_mgr->get_instance_length(int_object))
|
||||
return false;
|
||||
if (anonymous_type != seg_mgr->get_instance_type(int_array))
|
||||
return false;
|
||||
if (seg_mgr->get_instance_name(int_array))
|
||||
return false;
|
||||
seg_mgr->destroy_ptr(int_array);
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct<int>(anonymous_instance)[MappedRegionSize](); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) {}
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (seg_mgr->template construct<int>(anonymous_instance, std::nothrow)[MappedRegionSize]())
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct_it<long int>(anonymous_instance)[MappedRegionSize](&int_array_values[0]); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) {}
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (seg_mgr->template construct_it<int>(anonymous_instance, std::nothrow)[MappedRegionSize](&int_array_values[0]))
|
||||
return false;
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_named_object(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
|
||||
const char* const object1_name = "object1";
|
||||
const char* const object2_name = "object2";
|
||||
int const int_array_values[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
for (std::size_t i = 0; i != 4; ++i) {
|
||||
if (seg_mgr->template find<unsigned int>(object1_name).first)
|
||||
return false;
|
||||
//Single element construction
|
||||
unsigned int* uint_object = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
uint_object = seg_mgr->template construct<unsigned int>(object1_name)();
|
||||
break;
|
||||
case 1:
|
||||
uint_object = seg_mgr->template construct<unsigned int>(object1_name, std::nothrow)();
|
||||
break;
|
||||
case 2:
|
||||
uint_object = seg_mgr->template find_or_construct<unsigned int>(object1_name)();
|
||||
break;
|
||||
case 3:
|
||||
uint_object = seg_mgr->template find_or_construct<unsigned int>(object1_name, std::nothrow)();
|
||||
break;
|
||||
}
|
||||
std::pair<unsigned int*, std::size_t> find_ret = seg_mgr->template find<unsigned int>(object1_name);
|
||||
if (uint_object != find_ret.first)
|
||||
return false;
|
||||
if (1 != find_ret.second)
|
||||
return false;
|
||||
if (1 != seg_mgr->get_instance_length(uint_object))
|
||||
return false;
|
||||
if (named_type != seg_mgr->get_instance_type(uint_object))
|
||||
return false;
|
||||
if (std::strcmp(object1_name, seg_mgr->get_instance_name(uint_object)))
|
||||
return false;
|
||||
//Array construction
|
||||
if (seg_mgr->template find<int>(object2_name).first)
|
||||
return false;
|
||||
int* int_array = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
int_array = seg_mgr->template construct_it<int>(object2_name)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 1:
|
||||
int_array = seg_mgr->template construct_it<int>(object2_name, std::nothrow)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 2:
|
||||
int_array = seg_mgr->template find_or_construct_it<int>(object2_name)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 3:
|
||||
int_array = seg_mgr->template find_or_construct_it<int>(object2_name, std::nothrow)[10](&int_array_values[0]);
|
||||
break;
|
||||
}
|
||||
std::pair<int*, std::size_t> find_ret2 = seg_mgr->template find<int>(object2_name);
|
||||
if (int_array != find_ret2.first)
|
||||
return false;
|
||||
if (10 != find_ret2.second)
|
||||
return false;
|
||||
if (10 != seg_mgr->get_instance_length(int_array))
|
||||
return false;
|
||||
if (named_type != seg_mgr->get_instance_type(int_array))
|
||||
return false;
|
||||
if (std::strcmp(object2_name, seg_mgr->get_instance_name(int_array)))
|
||||
return false;
|
||||
if (seg_mgr->get_num_named_objects() != 2)
|
||||
return false;
|
||||
typename SegmentManager::const_named_iterator nb(seg_mgr->named_begin());
|
||||
typename SegmentManager::const_named_iterator ne(seg_mgr->named_end());
|
||||
for (std::size_t j = 0, imax = seg_mgr->get_num_named_objects(); j != imax; ++j) { ++nb; }
|
||||
if (nb != ne)
|
||||
return false;
|
||||
seg_mgr->destroy_ptr(uint_object);
|
||||
seg_mgr->template destroy<int>(object2_name);
|
||||
}
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct<unsigned int>(object1_name)[MappedRegionSize](); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) {}
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (seg_mgr->template construct<int>(object2_name, std::nothrow)[MappedRegionSize]())
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct_it<int>(object1_name)[MappedRegionSize](&int_array_values[0]); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) {}
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (seg_mgr->template construct_it<int>(object2_name, std::nothrow)[MappedRegionSize](&int_array_values[0]))
|
||||
return false;
|
||||
seg_mgr->shrink_to_fit_indexes();
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
seg_mgr->reserve_named_objects(1);
|
||||
//In indexes with no capacity() memory won't be allocated so don't check anything was allocated.
|
||||
//if(seg_mgr->all_memory_deallocated()) return false;
|
||||
seg_mgr->shrink_to_fit_indexes();
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_unique_object(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
|
||||
int const int_array_values[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
for (std::size_t i = 0; i != 4; ++i) {
|
||||
if (seg_mgr->template find<unsigned int>(unique_instance).first)
|
||||
return false;
|
||||
//Single element construction
|
||||
unsigned int* uint_object = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
uint_object = seg_mgr->template construct<unsigned int>(unique_instance)();
|
||||
break;
|
||||
case 1:
|
||||
uint_object = seg_mgr->template construct<unsigned int>(unique_instance, std::nothrow)();
|
||||
break;
|
||||
case 2:
|
||||
uint_object = seg_mgr->template find_or_construct<unsigned int>(unique_instance)();
|
||||
break;
|
||||
case 3:
|
||||
uint_object = seg_mgr->template find_or_construct<unsigned int>(unique_instance, std::nothrow)();
|
||||
break;
|
||||
}
|
||||
std::pair<unsigned int*, std::size_t> find_ret = seg_mgr->template find<unsigned int>(unique_instance);
|
||||
if (uint_object != find_ret.first)
|
||||
return false;
|
||||
if (1 != find_ret.second)
|
||||
return false;
|
||||
if (1 != seg_mgr->get_instance_length(uint_object))
|
||||
return false;
|
||||
if (unique_type != seg_mgr->get_instance_type(uint_object))
|
||||
return false;
|
||||
if (std::strcmp(typeid(unsigned int).name(), seg_mgr->get_instance_name(uint_object)))
|
||||
return false;
|
||||
//Array construction
|
||||
if (seg_mgr->template find<int>(unique_instance).first)
|
||||
return false;
|
||||
int* int_array = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
int_array = seg_mgr->template construct_it<int>(unique_instance)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 1:
|
||||
int_array = seg_mgr->template construct_it<int>(unique_instance, std::nothrow)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 2:
|
||||
int_array = seg_mgr->template find_or_construct_it<int>(unique_instance)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 3:
|
||||
int_array = seg_mgr->template find_or_construct_it<int>(unique_instance, std::nothrow)[10](&int_array_values[0]);
|
||||
break;
|
||||
}
|
||||
std::pair<int*, std::size_t> find_ret2 = seg_mgr->template find<int>(unique_instance);
|
||||
if (int_array != find_ret2.first)
|
||||
return false;
|
||||
if (10 != find_ret2.second)
|
||||
return false;
|
||||
if (10 != seg_mgr->get_instance_length(int_array))
|
||||
return false;
|
||||
if (unique_type != seg_mgr->get_instance_type(int_array))
|
||||
return false;
|
||||
if (std::strcmp(typeid(int).name(), seg_mgr->get_instance_name(int_array)))
|
||||
return false;
|
||||
if (seg_mgr->get_num_unique_objects() != 2)
|
||||
return false;
|
||||
typename SegmentManager::const_unique_iterator nb(seg_mgr->unique_begin());
|
||||
typename SegmentManager::const_unique_iterator ne(seg_mgr->unique_end());
|
||||
for (std::size_t j = 0, imax = seg_mgr->get_num_unique_objects(); j != imax; ++j) { ++nb; }
|
||||
if (nb != ne)
|
||||
return false;
|
||||
seg_mgr->destroy_ptr(uint_object);
|
||||
seg_mgr->template destroy<int>(unique_instance);
|
||||
}
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct<unsigned int>(unique_instance)[MappedRegionSize](); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) {}
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (seg_mgr->template construct<int>(unique_instance, std::nothrow)[MappedRegionSize]())
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct_it<long int>(unique_instance)[MappedRegionSize](&int_array_values[0]); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) {}
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (seg_mgr->template construct_it<int>(unique_instance, std::nothrow)[MappedRegionSize](&int_array_values[0]))
|
||||
return false;
|
||||
seg_mgr->shrink_to_fit_indexes();
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
seg_mgr->reserve_unique_objects(1);
|
||||
//In indexes with no capacity() memory won't be allocated so don't check anything was allocated.
|
||||
//if(seg_mgr->all_memory_deallocated()) return false;
|
||||
seg_mgr->shrink_to_fit_indexes();
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
template <class SegmentManager>
|
||||
bool test_atomic_func(SegmentManager* seg_mgr, mapped_region& )
|
||||
{
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
int* int_object = seg_mgr->template construct<int>("atomic_func_find_object")();
|
||||
atomic_func_test<SegmentManager> func(*seg_mgr);
|
||||
seg_mgr->atomic_func(func);
|
||||
if (int_object != func.object)
|
||||
return 1;
|
||||
seg_mgr->destroy_ptr(int_object);
|
||||
seg_mgr->shrink_to_fit_indexes();
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_allocator_deleter(SegmentManager* seg_mgr, mapped_region&)
|
||||
{//test allocator/deleter
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
typedef typename SegmentManager::template allocator<float>::type allocator_t;
|
||||
|
||||
allocator_t alloc(seg_mgr->template get_allocator<float>());
|
||||
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
offset_ptr<float> f = alloc.allocate(50);
|
||||
if (seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
alloc.deallocate(f, 50);
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
typedef typename SegmentManager::template deleter<float>::type deleter_t;
|
||||
deleter_t delet(seg_mgr->template get_deleter<float>());
|
||||
delet(seg_mgr->template construct<float>(anonymous_instance)());
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_get_memory_algorithm(SegmentManager* seg_mgr, mapped_region&)
|
||||
{
|
||||
{
|
||||
typename SegmentManager::memory_algorithm& mem_algo =
|
||||
seg_mgr->get_memory_algorithm();
|
||||
const typename SegmentManager::memory_algorithm& const_mem_algo =
|
||||
const_cast<const SegmentManager*>(seg_mgr)->get_memory_algorithm();
|
||||
if (&mem_algo != &const_mem_algo)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_segment_manager()
|
||||
{
|
||||
const unsigned int MappedRegionSize = 1024*64u;
|
||||
std::string shmname(test::get_process_id_name());
|
||||
|
||||
shared_memory_object::remove(shmname.c_str());
|
||||
shared_memory_object sh_mem( create_only, shmname.c_str(), read_write );
|
||||
sh_mem.truncate( MappedRegionSize );
|
||||
mapped_region mapping( sh_mem, read_write );
|
||||
|
||||
//Remove shared memory to minimize risk of garbage on crash
|
||||
shared_memory_object::remove(shmname.c_str());
|
||||
|
||||
SegmentManager* seg_mgr = new( mapping.get_address() ) SegmentManager( MappedRegionSize );
|
||||
std::size_t size_before = seg_mgr->get_size();
|
||||
|
||||
if(size_before != MappedRegionSize)
|
||||
return false;
|
||||
if(!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
if(seg_mgr->get_min_size() >= MappedRegionSize)
|
||||
return false;
|
||||
|
||||
if (!test_allocate_deallocate(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_allocate_aligned(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_shrink_to_fit(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_zero_free_memory(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_anoymous_object(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_named_object(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_unique_object(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_allocator_deleter(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_atomic_func(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_allocator_deleter(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_get_memory_algorithm(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class MemoryAlgorithm>
|
||||
bool test_each_algo()
|
||||
{
|
||||
{
|
||||
typedef segment_manager< char, MemoryAlgorithm, flat_map_index > segment_manager_t;
|
||||
if(!test_segment_manager<segment_manager_t>())
|
||||
return false;
|
||||
}
|
||||
{
|
||||
typedef segment_manager< char, MemoryAlgorithm, map_index > segment_manager_t;
|
||||
if(!test_segment_manager<segment_manager_t>())
|
||||
return false;
|
||||
}
|
||||
{
|
||||
typedef segment_manager< char, MemoryAlgorithm, iset_index > segment_manager_t;
|
||||
if(!test_segment_manager<segment_manager_t>())
|
||||
return false;
|
||||
}
|
||||
{
|
||||
typedef segment_manager< char, MemoryAlgorithm, iunordered_set_index > segment_manager_t;
|
||||
if(!test_segment_manager<segment_manager_t>())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if(!test_each_algo< simple_seq_fit< null_mutex_family > >())
|
||||
return 1;
|
||||
if(!test_each_algo< rbtree_best_fit< null_mutex_family > >())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI 2
|
||||
#include "segment_manager_test.hpp"
|
||||
|
||||
860
test/segment_manager_test.hpp
Normal file
860
test/segment_manager_test.hpp
Normal file
@@ -0,0 +1,860 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2004-2019. Distributed under the 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.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/interprocess/indexes/flat_map_index.hpp>
|
||||
#include <boost/interprocess/indexes/map_index.hpp>
|
||||
#include <boost/interprocess/indexes/null_index.hpp>
|
||||
#include <boost/interprocess/indexes/iset_index.hpp>
|
||||
#include <boost/interprocess/indexes/iunordered_set_index.hpp>
|
||||
|
||||
#include <boost/interprocess/mem_algo/simple_seq_fit.hpp>
|
||||
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
|
||||
#include <boost/interprocess/mapped_region.hpp>
|
||||
#include <boost/interprocess/segment_manager.hpp>
|
||||
#include <boost/interprocess/shared_memory_object.hpp>
|
||||
#include <boost/interprocess/sync/mutex_family.hpp>
|
||||
#include <boost/interprocess/exceptions.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
#include "get_process_id_name.hpp"
|
||||
#include <cstddef>
|
||||
#include <new>
|
||||
#include <cstring>
|
||||
#include <typeinfo>
|
||||
#include <iostream>
|
||||
|
||||
using namespace boost::interprocess;
|
||||
|
||||
template<std::size_t Align>
|
||||
struct IntLike;
|
||||
|
||||
#define BOOST_INTERPROCESS_ALIGNED_INTLIKE(A)\
|
||||
template<>\
|
||||
struct IntLike<A>\
|
||||
{\
|
||||
IntLike(){}\
|
||||
\
|
||||
IntLike(int i) : data(i) {}\
|
||||
\
|
||||
BOOST_ALIGNMENT(A) int data;\
|
||||
\
|
||||
operator int() const { return data; }\
|
||||
};\
|
||||
//
|
||||
|
||||
//Up to 4K alignment (typical page size)
|
||||
BOOST_INTERPROCESS_ALIGNED_INTLIKE(16)
|
||||
BOOST_INTERPROCESS_ALIGNED_INTLIKE(32)
|
||||
BOOST_INTERPROCESS_ALIGNED_INTLIKE(64)
|
||||
BOOST_INTERPROCESS_ALIGNED_INTLIKE(128)
|
||||
BOOST_INTERPROCESS_ALIGNED_INTLIKE(256)
|
||||
|
||||
#undef BOOST_INTERPROCESS_ALIGNED_INTLIKE
|
||||
|
||||
template <class SegmentManager>
|
||||
struct atomic_func_test
|
||||
{
|
||||
SegmentManager &rsm;
|
||||
int *object;
|
||||
|
||||
atomic_func_test(SegmentManager &sm)
|
||||
: rsm(sm), object()
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
object = rsm.template find<int>("atomic_func_find_object").first;
|
||||
}
|
||||
private:
|
||||
atomic_func_test operator=(const atomic_func_test&);
|
||||
atomic_func_test(const atomic_func_test&);
|
||||
};
|
||||
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_allocate_deallocate(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
typedef typename SegmentManager::size_type size_type;
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
|
||||
for (std::size_t size = 1; size <= (MappedRegionSize / 2); size <<= 1 ) {
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
|
||||
//Allocate memory
|
||||
void* mem = seg_mgr->allocate(size + 1);
|
||||
const size_type free_mem = seg_mgr->get_free_memory();
|
||||
if (free_mem >= (free_mem_before-size))
|
||||
return false;
|
||||
if (seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
//Allocate half of the rest
|
||||
const size_type Size2 = free_mem / 2;
|
||||
void* mem2 = seg_mgr->allocate(size_type(Size2 + 1), std::nothrow);
|
||||
|
||||
//Sanity checks
|
||||
if (seg_mgr->get_free_memory() >= Size2)
|
||||
return false;
|
||||
if (seg_mgr->size(mem) < (size + 1))
|
||||
return false;
|
||||
if (seg_mgr->size(mem2) < (Size2 + 1))
|
||||
return false;
|
||||
|
||||
//Deallocate both
|
||||
seg_mgr->deallocate(mem);
|
||||
seg_mgr->deallocate(mem2);
|
||||
|
||||
//Sanity checks again
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
|
||||
//Try an imposible size to test error is signalled
|
||||
bool operation_throws = false;
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->allocate(MappedRegionSize * 2); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) { operation_throws = true; }
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (!operation_throws)
|
||||
return false;
|
||||
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
|
||||
if (seg_mgr->allocate(MappedRegionSize*2u, std::nothrow))
|
||||
return false;
|
||||
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_allocate_aligned(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
const std::size_t InitialAlignment = SegmentManager::memory_algorithm::Alignment;
|
||||
const std::size_t RegionAlignment = mapped_region::get_page_size();
|
||||
|
||||
for( std::size_t alignment = InitialAlignment
|
||||
; (alignment <= MappedRegionSize/8 && alignment <= RegionAlignment/4)
|
||||
; alignment <<= 1u) {
|
||||
|
||||
//Allocate two buffers and test the alignment inside the mapped region
|
||||
void *mem = seg_mgr->allocate_aligned(MappedRegionSize/8, alignment);
|
||||
if(seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
|
||||
std::size_t offset = static_cast<std::size_t>
|
||||
(static_cast<const char *>(mem) - static_cast<const char *>(mapping.get_address()));
|
||||
if(offset & (alignment -1))
|
||||
return false;
|
||||
void *mem2 = seg_mgr->allocate_aligned(MappedRegionSize/4, alignment, std::nothrow);
|
||||
std::size_t offset2 = static_cast<std::size_t>
|
||||
(static_cast<const char *>(mem2) - static_cast<const char *>(mapping.get_address()));
|
||||
if(offset2 & (alignment -1))
|
||||
return false;
|
||||
|
||||
//Deallocate them
|
||||
seg_mgr->deallocate(mem);
|
||||
seg_mgr->deallocate(mem2);
|
||||
if(!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
if(seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
|
||||
//Try an imposible size to test error is signalled
|
||||
bool operation_throws = false;
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->allocate_aligned(MappedRegionSize*2, alignment); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&){ operation_throws = true; }
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (!operation_throws)
|
||||
return false;
|
||||
|
||||
if (seg_mgr->allocate_aligned(MappedRegionSize*2, alignment, std::nothrow))
|
||||
return false;
|
||||
if(seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if(seg_mgr->allocate_aligned(MappedRegionSize*2, alignment, std::nothrow))
|
||||
return false;
|
||||
if(seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_shrink_to_fit(SegmentManager* seg_mgr, mapped_region &)
|
||||
{
|
||||
typedef typename SegmentManager::size_type size_type;
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
std::size_t size_before = seg_mgr->get_size();
|
||||
seg_mgr->shrink_to_fit();
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
std::size_t empty_shrunk_size = seg_mgr->get_size();
|
||||
std::size_t empty_shrunk_free_mem = seg_mgr->get_free_memory();
|
||||
if (empty_shrunk_size >= size_before)
|
||||
return false;
|
||||
if (empty_shrunk_free_mem >= size_before)
|
||||
return false;
|
||||
seg_mgr->grow(size_type(size_before - empty_shrunk_size));
|
||||
if (seg_mgr->get_size() != size_before)
|
||||
return false;
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_zero_free_memory(SegmentManager* seg_mgr, mapped_region &mapping)
|
||||
{
|
||||
typedef typename SegmentManager::size_type size_type;
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
const size_type Size(MappedRegionSize / 2 + 1), Size2(MappedRegionSize / 8);
|
||||
void* mem = seg_mgr->allocate(Size);
|
||||
void* mem2 = seg_mgr->allocate(Size2);
|
||||
//Mark memory to non-zero
|
||||
std::memset(mem, 0xFF, Size);
|
||||
std::memset(mem2, 0xFF, Size2);
|
||||
//Deallocate and check still non-zero
|
||||
seg_mgr->deallocate(mem);
|
||||
seg_mgr->deallocate(mem2);
|
||||
{ //Use byte per byte comparison as "static unsigned char zerobuf[Size]"
|
||||
//seems to be problematic in some compilers
|
||||
unsigned char* const mem_uch_ptr = static_cast<unsigned char*>(mem);
|
||||
unsigned char* const mem2_uch_ptr = static_cast<unsigned char*>(mem2);
|
||||
size_type zeroes = 0;
|
||||
for (size_type i = 0; i != Size; ++i) {
|
||||
if (!mem_uch_ptr[i])
|
||||
++zeroes;
|
||||
}
|
||||
if (zeroes == Size)
|
||||
return false;
|
||||
|
||||
zeroes = 0;
|
||||
for (size_type i = 0; i != Size2; ++i) {
|
||||
if (!mem2_uch_ptr[i])
|
||||
++zeroes;
|
||||
}
|
||||
if (zeroes == Size2)
|
||||
return false;
|
||||
}
|
||||
//zero_free_memory and check it's zeroed
|
||||
seg_mgr->zero_free_memory();
|
||||
//TODO: some parts are not zeroed because they are used
|
||||
//as internal metadata, find a way to test this
|
||||
//if(std::memcmp(mem, zerobuf, Size))
|
||||
//return false;
|
||||
//if(std::memcmp(mem2, zerobuf, Size2))
|
||||
//return false;
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class IntLike, class SegmentManager>
|
||||
bool test_anonymous_object_type(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
|
||||
//Construct single object
|
||||
{
|
||||
IntLike* int_object = seg_mgr->template construct<IntLike>(anonymous_instance)();
|
||||
BOOST_ASSERT(is_ptr_aligned(int_object, boost::move_detail::alignment_of<IntLike>::value));
|
||||
if (!is_ptr_aligned(int_object, boost::move_detail::alignment_of<IntLike>::value))
|
||||
return false;
|
||||
if (1 != seg_mgr->get_instance_length(int_object))
|
||||
return false;
|
||||
if (anonymous_type != seg_mgr->get_instance_type(int_object))
|
||||
return false;
|
||||
if (seg_mgr->get_instance_name(int_object))
|
||||
return false;
|
||||
seg_mgr->destroy_ptr(int_object);
|
||||
}
|
||||
{
|
||||
//Construct array object
|
||||
IntLike* int_array = seg_mgr->template construct_it<IntLike>(anonymous_instance, std::nothrow)[5]();
|
||||
BOOST_ASSERT(is_ptr_aligned(int_array, boost::move_detail::alignment_of<IntLike>::value));
|
||||
if (!is_ptr_aligned(int_array, boost::move_detail::alignment_of<IntLike>::value))
|
||||
return false;
|
||||
if (5 != seg_mgr->get_instance_length(int_array))
|
||||
return false;
|
||||
if (anonymous_type != seg_mgr->get_instance_type(int_array))
|
||||
return false;
|
||||
if (seg_mgr->get_instance_name(int_array))
|
||||
return false;
|
||||
seg_mgr->destroy_ptr(int_array);
|
||||
}
|
||||
{
|
||||
//Construct array object from it
|
||||
const signed char int_array_values[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
IntLike* int_array = seg_mgr->template construct_it<IntLike>(anonymous_instance, std::nothrow)[10](&int_array_values[0]);
|
||||
BOOST_ASSERT(is_ptr_aligned(int_array, boost::move_detail::alignment_of<IntLike>::value));
|
||||
if (!is_ptr_aligned(int_array, boost::move_detail::alignment_of<IntLike>::value))
|
||||
return false;
|
||||
if (10 != seg_mgr->get_instance_length(int_array))
|
||||
return false;
|
||||
if (anonymous_type != seg_mgr->get_instance_type(int_array))
|
||||
return false;
|
||||
if (seg_mgr->get_instance_name(int_array))
|
||||
return false;
|
||||
seg_mgr->destroy_ptr(int_array);
|
||||
}
|
||||
|
||||
//Try an imposible size to test error is signalled
|
||||
{
|
||||
bool operation_throws = false;
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct<IntLike>(anonymous_instance)[MappedRegionSize](); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) { operation_throws = true; }
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (!operation_throws)
|
||||
return false;
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
}
|
||||
{
|
||||
if (seg_mgr->template construct<IntLike>(anonymous_instance, std::nothrow)[MappedRegionSize]())
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
}
|
||||
{
|
||||
const signed char int_array_values[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
if (seg_mgr->template construct_it<IntLike>(anonymous_instance, std::nothrow)[MappedRegionSize](&int_array_values[0]))
|
||||
return false;
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_anonymous_object(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
if (!test_anonymous_object_type<signed char>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_anonymous_object_type<short int>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_anonymous_object_type<int>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_anonymous_object_type<long int>(seg_mgr, mapping))
|
||||
return false;
|
||||
#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI >= 2)
|
||||
if (!test_anonymous_object_type<long long int>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_anonymous_object_type<IntLike<16> >(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_anonymous_object_type<IntLike<32> >(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_anonymous_object_type<IntLike<64> >(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_anonymous_object_type<IntLike<128> >(seg_mgr, mapping))
|
||||
return false;
|
||||
#endif //#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI >= 2)
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class IntLike, class SegmentManager>
|
||||
bool test_named_object_type(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
|
||||
const char* const object1_name = "object1";
|
||||
const char* const object2_name = "object2";
|
||||
const signed char int_array_values[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
for (std::size_t i = 0; i != 4; ++i) {
|
||||
if (seg_mgr->template find<IntLike>(object1_name).first)
|
||||
return false;
|
||||
//Single element construction
|
||||
IntLike* int_object = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
int_object = seg_mgr->template construct<IntLike>(object1_name)();
|
||||
break;
|
||||
case 1:
|
||||
int_object = seg_mgr->template construct<IntLike>(object1_name, std::nothrow)();
|
||||
break;
|
||||
case 2:
|
||||
int_object = seg_mgr->template find_or_construct<IntLike>(object1_name)();
|
||||
break;
|
||||
case 3:
|
||||
int_object = seg_mgr->template find_or_construct<IntLike>(object1_name, std::nothrow)();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!is_ptr_aligned(int_object, boost::move_detail::alignment_of<IntLike>::value)){
|
||||
std::cout << "\ntype/alignment: " << typeid(IntLike).name() << "/" << boost::move_detail::alignment_of<IntLike>::value << "\n segment_manager: " << typeid(SegmentManager).name()
|
||||
<< "\nmem alignment: " << SegmentManager::memory_algorithm::Alignment <<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::pair<IntLike*, std::size_t> find_ret = seg_mgr->template find<IntLike>(object1_name);
|
||||
if (int_object != find_ret.first)
|
||||
return false;
|
||||
if (1 != find_ret.second)
|
||||
return false;
|
||||
if (1 != seg_mgr->get_instance_length(int_object))
|
||||
return false;
|
||||
if (named_type != seg_mgr->get_instance_type(int_object))
|
||||
return false;
|
||||
if (std::strcmp(object1_name, seg_mgr->get_instance_name(int_object)))
|
||||
return false;
|
||||
|
||||
//Array construction
|
||||
if (seg_mgr->template find<IntLike>(object2_name).first)
|
||||
return false;
|
||||
IntLike* int_array = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
int_array = seg_mgr->template construct_it<IntLike>(object2_name)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 1:
|
||||
int_array = seg_mgr->template construct_it<IntLike>(object2_name, std::nothrow)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 2:
|
||||
int_array = seg_mgr->template find_or_construct_it<IntLike>(object2_name)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 3:
|
||||
int_array = seg_mgr->template find_or_construct_it<IntLike>(object2_name, std::nothrow)[10](&int_array_values[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(is_ptr_aligned(int_array, boost::move_detail::alignment_of<IntLike>::value));
|
||||
if (!is_ptr_aligned(int_array, boost::move_detail::alignment_of<IntLike>::value))
|
||||
return false;
|
||||
|
||||
std::pair<IntLike*, std::size_t> find_ret2 = seg_mgr->template find<IntLike>(object2_name);
|
||||
if (int_array != find_ret2.first)
|
||||
return false;
|
||||
if (10 != find_ret2.second)
|
||||
return false;
|
||||
if (10 != seg_mgr->get_instance_length(int_array))
|
||||
return false;
|
||||
if (named_type != seg_mgr->get_instance_type(int_array))
|
||||
return false;
|
||||
if (std::strcmp(object2_name, seg_mgr->get_instance_name(int_array)))
|
||||
return false;
|
||||
if (seg_mgr->get_num_named_objects() != 2)
|
||||
return false;
|
||||
typename SegmentManager::const_named_iterator nb(seg_mgr->named_begin());
|
||||
typename SegmentManager::const_named_iterator ne(seg_mgr->named_end());
|
||||
for (std::size_t j = 0, imax = seg_mgr->get_num_named_objects(); j != imax; ++j) { ++nb; }
|
||||
if (nb != ne)
|
||||
return false;
|
||||
seg_mgr->destroy_ptr(int_object);
|
||||
seg_mgr->template destroy<IntLike>(object2_name);
|
||||
}
|
||||
|
||||
//Try an imposible size to test error is signalled
|
||||
{
|
||||
bool operation_throws = false;
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct<IntLike>(object1_name)[MappedRegionSize](); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) { operation_throws = true;}
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (!operation_throws)
|
||||
return false;
|
||||
|
||||
if (seg_mgr->template construct<IntLike>(object2_name, std::nothrow)[MappedRegionSize]())
|
||||
return false;
|
||||
}
|
||||
{
|
||||
bool operation_throws = false;
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct_it<IntLike>(object1_name)[MappedRegionSize](&int_array_values[0]); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) { operation_throws = true; }
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (!operation_throws)
|
||||
return false;
|
||||
|
||||
if (seg_mgr->template construct_it<IntLike>(object2_name, std::nothrow)[MappedRegionSize](&int_array_values[0]))
|
||||
return false;
|
||||
}
|
||||
|
||||
seg_mgr->shrink_to_fit_indexes();
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
seg_mgr->reserve_named_objects(1);
|
||||
|
||||
//In indexes with no capacity() memory won't be allocated so don't check anything was allocated.
|
||||
//if(seg_mgr->all_memory_deallocated()) return false;
|
||||
seg_mgr->shrink_to_fit_indexes();
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_named_object(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
if (!test_named_object_type<signed char>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_named_object_type<short int>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_named_object_type<int>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_named_object_type<long int>(seg_mgr, mapping))
|
||||
return false;
|
||||
#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI >= 2)
|
||||
if (!test_named_object_type<long long int>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_named_object_type<IntLike<16> >(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_named_object_type<IntLike<32> >(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_named_object_type<IntLike<64> >(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_named_object_type<IntLike<128> >(seg_mgr, mapping))
|
||||
return false;
|
||||
#endif //#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI >= 2)
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class IntLike, class SegmentManager>
|
||||
bool test_unique_object_type(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
const std::size_t MappedRegionSize = mapping.get_size();
|
||||
const std::size_t free_mem_before = seg_mgr->get_free_memory();
|
||||
|
||||
const signed char int_array_values[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
for (std::size_t i = 0; i != 4; ++i) {
|
||||
if (seg_mgr->template find<IntLike>(unique_instance).first)
|
||||
return false;
|
||||
//Single element construction
|
||||
IntLike* int_object = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
int_object = seg_mgr->template construct<IntLike>(unique_instance)();
|
||||
break;
|
||||
case 1:
|
||||
int_object = seg_mgr->template construct<IntLike>(unique_instance, std::nothrow)();
|
||||
break;
|
||||
case 2:
|
||||
int_object = seg_mgr->template find_or_construct<IntLike>(unique_instance)();
|
||||
break;
|
||||
case 3:
|
||||
int_object = seg_mgr->template find_or_construct<IntLike>(unique_instance, std::nothrow)();
|
||||
break;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(is_ptr_aligned(int_object, boost::move_detail::alignment_of<IntLike>::value));
|
||||
if (!is_ptr_aligned(int_object, boost::move_detail::alignment_of<IntLike>::value))
|
||||
return false;
|
||||
|
||||
std::pair<IntLike*, std::size_t> find_ret = seg_mgr->template find<IntLike>(unique_instance);
|
||||
if (int_object != find_ret.first)
|
||||
return false;
|
||||
if (1 != find_ret.second)
|
||||
return false;
|
||||
if (1 != seg_mgr->get_instance_length(int_object))
|
||||
return false;
|
||||
if (unique_type != seg_mgr->get_instance_type(int_object))
|
||||
return false;
|
||||
if (std::strcmp(typeid(IntLike).name(), seg_mgr->get_instance_name(int_object)))
|
||||
return false;
|
||||
//Array construction
|
||||
if (!seg_mgr->template find<IntLike>(unique_instance).first)
|
||||
return false;
|
||||
|
||||
seg_mgr->destroy_ptr(int_object);
|
||||
|
||||
IntLike* int_array = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
int_array = seg_mgr->template construct_it<IntLike>(unique_instance)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 1:
|
||||
int_array = seg_mgr->template construct_it<IntLike>(unique_instance, std::nothrow)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 2:
|
||||
int_array = seg_mgr->template find_or_construct_it<IntLike>(unique_instance)[10](&int_array_values[0]);
|
||||
break;
|
||||
case 3:
|
||||
int_array = seg_mgr->template find_or_construct_it<IntLike>(unique_instance, std::nothrow)[10](&int_array_values[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(is_ptr_aligned(int_array, boost::move_detail::alignment_of<IntLike>::value));
|
||||
if (!is_ptr_aligned(int_array, boost::move_detail::alignment_of<IntLike>::value))
|
||||
return false;
|
||||
|
||||
std::pair<IntLike*, std::size_t> find_ret2 = seg_mgr->template find<IntLike>(unique_instance);
|
||||
if (int_array != find_ret2.first)
|
||||
return false;
|
||||
if (10 != find_ret2.second)
|
||||
return false;
|
||||
if (10 != seg_mgr->get_instance_length(int_array))
|
||||
return false;
|
||||
if (unique_type != seg_mgr->get_instance_type(int_array))
|
||||
return false;
|
||||
if (std::strcmp(typeid(IntLike).name(), seg_mgr->get_instance_name(int_array)))
|
||||
return false;
|
||||
if (seg_mgr->get_num_unique_objects() != 1)
|
||||
return false;
|
||||
typename SegmentManager::const_unique_iterator nb(seg_mgr->unique_begin());
|
||||
typename SegmentManager::const_unique_iterator ne(seg_mgr->unique_end());
|
||||
for (std::size_t j = 0, imax = seg_mgr->get_num_unique_objects(); j != imax; ++j) { ++nb; }
|
||||
if (nb != ne)
|
||||
return false;
|
||||
seg_mgr->template destroy<IntLike>(unique_instance);
|
||||
}
|
||||
//Try an imposible size to test error is signalled
|
||||
{
|
||||
bool operation_throws = false;
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct<IntLike>(unique_instance)[MappedRegionSize](); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) { operation_throws = true; }
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (!operation_throws)
|
||||
return false;
|
||||
if (seg_mgr->template construct<IntLike>(unique_instance, std::nothrow)[MappedRegionSize]())
|
||||
return false;
|
||||
}
|
||||
{
|
||||
bool operation_throws = false;
|
||||
BOOST_INTERPROCESS_TRY{ seg_mgr->template construct_it<IntLike>(unique_instance)[MappedRegionSize](&int_array_values[0]); }
|
||||
BOOST_INTERPROCESS_CATCH(interprocess_exception&) { operation_throws = true; }
|
||||
BOOST_INTERPROCESS_CATCH_END
|
||||
if (!operation_throws)
|
||||
return false;
|
||||
if (seg_mgr->template construct_it<IntLike>(unique_instance, std::nothrow)[MappedRegionSize](&int_array_values[0]))
|
||||
return false;
|
||||
}
|
||||
|
||||
seg_mgr->shrink_to_fit_indexes();
|
||||
|
||||
if (seg_mgr->get_free_memory() != free_mem_before)
|
||||
return false;
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
|
||||
seg_mgr->reserve_unique_objects(1);
|
||||
|
||||
//In indexes with no capacity() memory won't be allocated so don't check anything was allocated.
|
||||
//if(seg_mgr->all_memory_deallocated()) return false;
|
||||
seg_mgr->shrink_to_fit_indexes();
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_unique_object(SegmentManager* seg_mgr, mapped_region& mapping)
|
||||
{
|
||||
if (!test_unique_object_type<signed char>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_unique_object_type<short int>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_unique_object_type<int>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_unique_object_type<long int>(seg_mgr, mapping))
|
||||
return false;
|
||||
#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI >= 2)
|
||||
if (!test_unique_object_type<long long int>(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_unique_object_type<IntLike<16> >(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_unique_object_type<IntLike<32> >(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_unique_object_type<IntLike<64> >(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_unique_object_type<IntLike<128> >(seg_mgr, mapping))
|
||||
return false;
|
||||
#endif //#if (BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI >= 2)
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_atomic_func(SegmentManager* seg_mgr, mapped_region& )
|
||||
{
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
int* int_object = seg_mgr->template construct<int>("atomic_func_find_object")();
|
||||
atomic_func_test<SegmentManager> func(*seg_mgr);
|
||||
seg_mgr->atomic_func(func);
|
||||
if (int_object != func.object)
|
||||
return 1;
|
||||
seg_mgr->destroy_ptr(int_object);
|
||||
seg_mgr->shrink_to_fit_indexes();
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_allocator_deleter(SegmentManager* seg_mgr, mapped_region&)
|
||||
{//test allocator/deleter
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
typedef typename SegmentManager::template allocator<float>::type allocator_t;
|
||||
|
||||
allocator_t alloc(seg_mgr->template get_allocator<float>());
|
||||
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
offset_ptr<float> f = alloc.allocate(50);
|
||||
if (seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
alloc.deallocate(f, 50);
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
typedef typename SegmentManager::template deleter<float>::type deleter_t;
|
||||
deleter_t delet(seg_mgr->template get_deleter<float>());
|
||||
delet(seg_mgr->template construct<float>(anonymous_instance)());
|
||||
if (!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_get_memory_algorithm(SegmentManager* seg_mgr, mapped_region&)
|
||||
{
|
||||
{
|
||||
typename SegmentManager::memory_algorithm& mem_algo =
|
||||
seg_mgr->get_memory_algorithm();
|
||||
const typename SegmentManager::memory_algorithm& const_mem_algo =
|
||||
const_cast<const SegmentManager*>(seg_mgr)->get_memory_algorithm();
|
||||
if (&mem_algo != &const_mem_algo)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class SegmentManager>
|
||||
bool test_segment_manager()
|
||||
{
|
||||
const unsigned int MappedRegionSize = 1024*64u;
|
||||
std::string shmname(test::get_process_id_name());
|
||||
|
||||
shared_memory_object::remove(shmname.c_str());
|
||||
shared_memory_object sh_mem( create_only, shmname.c_str(), read_write );
|
||||
sh_mem.truncate( MappedRegionSize );
|
||||
mapped_region mapping( sh_mem, read_write );
|
||||
|
||||
//Remove shared memory to minimize risk of garbage on crash
|
||||
shared_memory_object::remove(shmname.c_str());
|
||||
|
||||
SegmentManager* seg_mgr = new( mapping.get_address() ) SegmentManager( MappedRegionSize );
|
||||
std::size_t size_before = seg_mgr->get_size();
|
||||
|
||||
if(size_before != MappedRegionSize)
|
||||
return false;
|
||||
if(!seg_mgr->all_memory_deallocated())
|
||||
return false;
|
||||
if(seg_mgr->get_min_size() >= MappedRegionSize)
|
||||
return false;
|
||||
|
||||
if (!test_allocate_deallocate(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_allocate_aligned(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_shrink_to_fit(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_zero_free_memory(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_anonymous_object(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_named_object(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_unique_object(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_allocator_deleter(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_atomic_func(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_allocator_deleter(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
if (!test_get_memory_algorithm(seg_mgr, mapping))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class MemoryAlgorithm>
|
||||
bool test_each_algo()
|
||||
{
|
||||
{
|
||||
typedef segment_manager< char, MemoryAlgorithm, flat_map_index > segment_manager_t;
|
||||
if(!test_segment_manager<segment_manager_t>())
|
||||
return false;
|
||||
}
|
||||
{
|
||||
typedef segment_manager< char, MemoryAlgorithm, map_index > segment_manager_t;
|
||||
if(!test_segment_manager<segment_manager_t>())
|
||||
return false;
|
||||
}
|
||||
{
|
||||
typedef segment_manager< char, MemoryAlgorithm, iset_index > segment_manager_t;
|
||||
if(!test_segment_manager<segment_manager_t>())
|
||||
return false;
|
||||
}
|
||||
{
|
||||
typedef segment_manager< char, MemoryAlgorithm, iunordered_set_index > segment_manager_t;
|
||||
if(!test_segment_manager<segment_manager_t>())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if(!test_each_algo< simple_seq_fit< null_mutex_family > >())
|
||||
return 1;
|
||||
if(!test_each_algo< rbtree_best_fit< null_mutex_family > >())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
12
test/segment_manager_v1_test.cpp
Normal file
12
test/segment_manager_v1_test.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2004-2019. Distributed under the 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.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI 1
|
||||
#include "segment_manager_test.hpp"
|
||||
Reference in New Issue
Block a user