Fixes #10011 segment_manager::find( unique_instance_t* ) fails to compile

This commit is contained in:
Ion Gaztañaga
2014-06-02 14:40:19 +02:00
parent 81a5fcf56d
commit aa09229e8a
9 changed files with 692 additions and 101 deletions

View File

@@ -6751,6 +6751,7 @@ thank them:
* [@https://svn.boost.org/trac/boost/ticket/9835 Trac #9835 (['"Boost Interprocess fails to compile with Android NDK GCC 4.8, -Werror=unused-variable"])].
* [@https://svn.boost.org/trac/boost/ticket/9911 Trac #9911 (['"get_tmp_base_dir(...) failure"])].
* [@https://svn.boost.org/trac/boost/ticket/9946 Trac #9946 (['"ret_ptr uninitialized in init_atomic_func, fini_atomic_func"])].
* [@https://svn.boost.org/trac/boost/ticket/10011 Trac #10011 (['"segment_manager::find( unique_instance_t* ) fails to compile"])].
* [@https://svn.boost.org/trac/boost/ticket/10021 Trac #10021 (['"Interprocess and BOOST_USE_WINDOWS_H"])].
* [@https://github.com/boostorg/interprocess/pull/2 GitHub #2] (['"Provide support for the Cray C++ compiler. The Cray compiler defines __GNUC__"]]).
* [@https://github.com/boostorg/interprocess/pull/3 GitHub #3] (['"Fix/mingw interprocess_exception throw in file_wrapper::priv_open_or_create"]]).

View File

@@ -609,7 +609,7 @@ class basic_managed_memory_impl
{ mp_header->template destroy_ptr<T>(ptr); }
//!Returns the name of an object created with construct/find_or_construct
//!functions. Does not throw
//!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); }

View File

@@ -32,6 +32,7 @@
#include <string> //char_traits
#include <new> //std::nothrow
#include <utility> //std::pair
#include <iterator> //std::iterator_traits
#include <boost/assert.hpp> //BOOST_ASSERT
#include <functional> //unary_function
#ifndef BOOST_NO_EXCEPTIONS
@@ -323,6 +324,15 @@ class char_ptr_holder
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;
};
@@ -472,12 +482,12 @@ class segment_manager_iterator_value_adaptor<Iterator, false>
template<class Iterator, bool intrusive>
struct segment_manager_iterator_transform
: std::unary_function< typename Iterator::value_type
: std::unary_function< typename std::iterator_traits<Iterator>::value_type
, segment_manager_iterator_value_adaptor<Iterator, intrusive> >
{
typedef segment_manager_iterator_value_adaptor<Iterator, intrusive> result_type;
result_type operator()(const typename Iterator::value_type &arg) const
result_type operator()(const typename std::iterator_traits<Iterator>::value_type &arg) const
{ return result_type(arg); }
};

View File

@@ -61,9 +61,9 @@ template <class Iterator, class UnaryFunction>
class transform_iterator
: public UnaryFunction
, public std::iterator
< typename Iterator::iterator_category
< typename std::iterator_traits<Iterator>::iterator_category
, typename ipcdetail::remove_reference<typename UnaryFunction::result_type>::type
, typename Iterator::difference_type
, typename std::iterator_traits<Iterator>::difference_type
, operator_arrow_proxy<typename UnaryFunction::result_type>
, typename UnaryFunction::result_type>
{
@@ -115,33 +115,33 @@ class transform_iterator
friend bool operator>= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i < i2); }
friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2)
friend typename std::iterator_traits<Iterator>::difference_type operator- (const transform_iterator& i, const transform_iterator& i2)
{ return i2.distance_to(i); }
//Arithmetic
transform_iterator& operator+=(typename Iterator::difference_type off)
transform_iterator& operator+=(typename std::iterator_traits<Iterator>::difference_type off)
{ this->advance(off); return *this; }
transform_iterator operator+(typename Iterator::difference_type off) const
transform_iterator operator+(typename std::iterator_traits<Iterator>::difference_type off) const
{
transform_iterator other(*this);
other.advance(off);
return other;
}
friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right)
friend transform_iterator operator+(typename std::iterator_traits<Iterator>::difference_type off, const transform_iterator& right)
{ return right + off; }
transform_iterator& operator-=(typename Iterator::difference_type off)
transform_iterator& operator-=(typename std::iterator_traits<Iterator>::difference_type off)
{ this->advance(-off); return *this; }
transform_iterator operator-(typename Iterator::difference_type off) const
transform_iterator operator-(typename std::iterator_traits<Iterator>::difference_type off) const
{ return *this + (-off); }
typename UnaryFunction::result_type operator*() const
{ return dereference(); }
typename UnaryFunction::result_type operator[](typename Iterator::difference_type off) const
typename UnaryFunction::result_type operator[](typename std::iterator_traits<Iterator>::difference_type off) const
{ return UnaryFunction::operator()(m_it[off]); }
operator_arrow_proxy<typename UnaryFunction::result_type>
@@ -172,10 +172,10 @@ class transform_iterator
typename UnaryFunction::result_type dereference() const
{ return UnaryFunction::operator()(*m_it); }
void advance(typename Iterator::difference_type n)
void advance(typename std::iterator_traits<Iterator>::difference_type n)
{ std::advance(m_it, n); }
typename Iterator::difference_type distance_to(const transform_iterator &other)const
typename std::iterator_traits<Iterator>::difference_type distance_to(const transform_iterator &other)const
{ return std::distance(other.m_it, m_it); }
};

View File

@@ -34,8 +34,8 @@ class null_index
/// @endcond
public:
typedef void * iterator;
typedef const void * const_iterator;
typedef int * iterator;
typedef const int * const_iterator;
//!begin() is equal
//!to end()

View File

@@ -188,6 +188,8 @@ class segment_manager_base
return ret;
}
/// @cond
template<class T>
std::pair<T *, bool>
allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
@@ -215,6 +217,8 @@ class segment_manager_base
return ret;
}
/// @endcond
//!Deallocates the bytes allocated with allocate/allocate_many()
//!pointed by addr
void deallocate (void *addr)
@@ -343,19 +347,19 @@ class segment_manager
segment_manager();
segment_manager(const segment_manager &);
segment_manager &operator=(const segment_manager &);
typedef segment_manager_base<MemoryAlgorithm> Base;
typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_t;
/// @endcond
public:
typedef MemoryAlgorithm memory_algorithm;
typedef typename Base::void_pointer void_pointer;
typedef typename Base::size_type size_type;
typedef typename Base::difference_type difference_type;
typedef CharType char_type;
typedef MemoryAlgorithm memory_algorithm;
typedef typename segment_manager_base_t::void_pointer void_pointer;
typedef typename segment_manager_base_t::size_type size_type;
typedef typename segment_manager_base_t::difference_type difference_type;
typedef CharType char_type;
typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
static const size_type PayloadPerAllocation = Base::PayloadPerAllocation;
static const size_type PayloadPerAllocation = segment_manager_base_t::PayloadPerAllocation;
/// @cond
private:
@@ -379,7 +383,7 @@ class segment_manager
,is_intrusive_index<index_type>::value> unique_transform;
/// @endcond
typedef typename Base::mutex_family mutex_family;
typedef typename segment_manager_base_t::mutex_family mutex_family;
typedef transform_iterator
<typename named_index_t::const_iterator, named_transform> const_named_iterator;
@@ -409,39 +413,31 @@ class segment_manager
//!the segment manager is being constructed.
//!Can throw
explicit segment_manager(size_type segment_size)
: Base(segment_size, priv_get_reserved_bytes())
, m_header(static_cast<Base*>(get_this_pointer()))
: segment_manager_base_t(segment_size, priv_get_reserved_bytes())
, m_header(static_cast<segment_manager_base_t*>(get_this_pointer()))
{
(void) anonymous_instance; (void) unique_instance;
BOOST_ASSERT(static_cast<const void*>(this) == static_cast<const void*>(static_cast<Base*>(this)));
//Check EBO is applied, it's required
const void * const this_addr = this;
const void *const segm_addr = static_cast<segment_manager_base_t*>(this);
(void)this_addr; (void)segm_addr;
BOOST_ASSERT( this_addr == segm_addr);
}
//!Tries to find a previous named allocation. Returns the address
//!Tries to find a previous named/unique allocation. Returns the address
//!and the object count. On failure the first member of the
//!returned pair is 0.
template <class T>
std::pair<T*, size_type> find (const CharType* name)
std::pair<T*, size_type> find (char_ptr_holder_t name)
{ return this->priv_find_impl<T>(name, true); }
//!Tries to find a previous unique allocation. Returns the address
//!and the object count. On failure the first member of the
//!returned pair is 0.
template <class T>
std::pair<T*, size_type> find (const ipcdetail::unique_instance_t* name)
{ return this->priv_find_impl<T>(name, true); }
//!Tries to find a previous named allocation. Returns the address
//!Tries to find a previous named/unique allocation. Returns the address
//!and the object count. On failure the first member of the
//!returned pair is 0. This search is not mutex-protected!
//!Use it only inside atomic_func() calls, where the internal mutex
//!is guaranteed to be locked.
template <class T>
std::pair<T*, size_type> find_no_lock (const CharType* name)
{ return this->priv_find_impl<T>(name, false); }
//!Tries to find a previous unique allocation. Returns the address
//!and the object count. On failure the first member of the
//!returned pair is 0. This search is not mutex-protected!
template <class T>
std::pair<T*, size_type> find_no_lock (const ipcdetail::unique_instance_t* name)
std::pair<T*, size_type> find_no_lock (char_ptr_holder_t name)
{ return this->priv_find_impl<T>(name, false); }
//!Returns throwing "construct" proxy
@@ -500,7 +496,7 @@ class segment_manager
//!Calls object function blocking recursive interprocess_mutex and guarantees that
//!no new named_alloc or destroy will be executed by any process while
//!executing the object function call*/
//!executing the object function call
template <class Func>
void atomic_func(Func &f)
{ scoped_lock<rmutex> guard(m_header); f(); }
@@ -523,28 +519,26 @@ class segment_manager
}
}
//!Destroys a previously created unique instance.
//!Destroys a previously created named/unique instance.
//!Returns false if the object was not present.
template <class T>
bool destroy(const ipcdetail::unique_instance_t *)
bool destroy(char_ptr_holder_t name)
{
BOOST_ASSERT(!name.is_anonymous());
ipcdetail::placement_destroy<T> dtor;
return this->priv_generic_named_destroy<char>
(typeid(T).name(), m_header.m_unique_index, dtor, is_intrusive_t());
}
//!Destroys the named object with
//!the given name. Returns false if that object can't be found.
template <class T>
bool destroy(const CharType *name)
{
ipcdetail::placement_destroy<T> dtor;
return this->priv_generic_named_destroy<CharType>
(name, m_header.m_named_index, dtor, is_intrusive_t());
if(name.is_unique()){
return this->priv_generic_named_destroy<char>
( typeid(T).name(), m_header.m_unique_index , dtor, is_intrusive_t());
}
else{
return this->priv_generic_named_destroy<CharType>
( name.get(), m_header.m_named_index, dtor, is_intrusive_t());
}
}
//!Destroys an anonymous, unique or named object
//!using it's address
//!using its address
template <class T>
void destroy_ptr(const T *p)
{
@@ -628,7 +622,7 @@ class segment_manager
//!Obtains the minimum size needed by the
//!segment manager
static size_type get_min_size()
{ return Base::get_min_size(priv_get_reserved_bytes()); }
{ return segment_manager_base_t::get_min_size(priv_get_reserved_bytes()); }
//!Returns a constant iterator to the beginning of the information about
//!the named allocations performed in this segment manager
@@ -685,8 +679,8 @@ class segment_manager
typedef boost::interprocess::deleter<T, segment_manager> type;
};
//!Returns an instance of the default allocator for type T
//!initialized that allocates memory from this segment manager.
//!Returns an instance of the default deleter for type T
//!that will delete an object constructed in this segment manager.
template<class T>
typename deleter<T>::type
get_deleter()
@@ -742,11 +736,8 @@ class segment_manager
return std::pair<T*, size_type>(static_cast<T*>(ret), size);
}
void *priv_generic_construct(const CharType *name,
size_type num,
bool try2find,
bool dothrow,
ipcdetail::in_place_interface &table)
void *priv_generic_construct
(const CharType *name, size_type num, bool try2find, bool dothrow, ipcdetail::in_place_interface &table)
{
void *ret;
//Security overflow check
@@ -800,7 +791,7 @@ class segment_manager
static const CharType *priv_get_instance_name(block_header_t *ctrl_data)
{
boost::interprocess::allocation_type type = ctrl_data->alloc_type();
if(type != named_type){
if(type == anonymous_type){
BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) ||
(type == unique_type && ctrl_data->m_num_char != 0) );
return 0;
@@ -832,8 +823,8 @@ class segment_manager
static size_type priv_get_reserved_bytes()
{
//Get the number of bytes until the end of (*this)
//beginning in the end of the Base base.
return sizeof(segment_manager) - sizeof(Base);
//beginning in the end of the segment_manager_base_t base.
return sizeof(segment_manager) - sizeof(segment_manager_base_t);
}
template <class CharT>
@@ -841,9 +832,7 @@ class segment_manager
(const CharT* name,
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
ipcdetail::in_place_interface &table,
size_type &length,
ipcdetail::true_ is_intrusive,
bool use_lock)
size_type &length, ipcdetail::true_ is_intrusive, bool use_lock)
{
(void)is_intrusive;
typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
@@ -880,9 +869,7 @@ class segment_manager
(const CharT* name,
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
ipcdetail::in_place_interface &table,
size_type &length,
ipcdetail::false_ is_intrusive,
bool use_lock)
size_type &length, ipcdetail::false_ is_intrusive, bool use_lock)
{
(void)is_intrusive;
typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
@@ -918,8 +905,7 @@ class segment_manager
bool priv_generic_named_destroy
(block_header_t *block_header,
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
ipcdetail::in_place_interface &table,
ipcdetail::true_ is_node_index)
ipcdetail::in_place_interface &table, ipcdetail::true_ is_node_index)
{
(void)is_node_index;
typedef typename IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> >::iterator index_it;
@@ -943,8 +929,7 @@ class segment_manager
template <class CharT>
bool priv_generic_named_destroy(const CharT *name,
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
ipcdetail::in_place_interface &table,
ipcdetail::true_ is_intrusive_index)
ipcdetail::in_place_interface &table, ipcdetail::true_ is_intrusive_index)
{
(void)is_intrusive_index;
typedef IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > index_type;
@@ -1060,21 +1045,17 @@ class segment_manager
}
//Call destructors and free memory
std::size_t destroyed;
std::size_t destroyed;
table.destroy_n(values, num, destroyed);
this->deallocate(memory);
return true;
}
template<class CharT>
void * priv_generic_named_construct(unsigned char type,
const CharT *name,
size_type num,
bool try2find,
bool dothrow,
ipcdetail::in_place_interface &table,
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
ipcdetail::true_ is_intrusive)
void * priv_generic_named_construct
(unsigned char type, const CharT *name, size_type num, bool try2find,
bool dothrow, ipcdetail::in_place_interface &table,
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::true_ is_intrusive)
{
(void)is_intrusive;
std::size_t namelen = std::char_traits<CharT>::length(name);
@@ -1196,14 +1177,10 @@ class segment_manager
//!Generic named new function for
//!named functions
template<class CharT>
void * priv_generic_named_construct(unsigned char type,
const CharT *name,
size_type num,
bool try2find,
bool dothrow,
ipcdetail::in_place_interface &table,
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index,
ipcdetail::false_ is_intrusive)
void * priv_generic_named_construct
(unsigned char type, const CharT *name, size_type num, bool try2find, bool dothrow,
ipcdetail::in_place_interface &table,
IndexType<ipcdetail::index_config<CharT, MemoryAlgorithm> > &index, ipcdetail::false_ is_intrusive)
{
(void)is_intrusive;
std::size_t namelen = std::char_traits<CharT>::length(name);
@@ -1346,9 +1323,9 @@ class segment_manager
named_index_t m_named_index;
unique_index_t m_unique_index;
header_t(Base *restricted_segment_mngr)
: m_named_index (restricted_segment_mngr)
, m_unique_index(restricted_segment_mngr)
header_t(segment_manager_base_t *segment_mngr_base)
: m_named_index (segment_mngr_base)
, m_unique_index(segment_mngr_base)
{}
} m_header;

View File

@@ -483,6 +483,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boost_use_windows_h", "boos
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "segment_manager_test", "segment_manager_test.vcproj", "{56CE18C9-0000-0000-0000-000000000000}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
@@ -975,6 +979,10 @@ Global
{518CE8C3-6512-FA75-46EF-B917A3A116D1}.Debug.Build.0 = Debug|Win32
{518CE8C3-6512-FA75-46EF-B917A3A116D1}.Release.ActiveCfg = Release|Win32
{518CE8C3-6512-FA75-46EF-B917A3A116D1}.Release.Build.0 = Release|Win32
{56CE18C9-0000-0000-0000-000000000000}.Debug.ActiveCfg = Debug|Win32
{56CE18C9-0000-0000-0000-000000000000}.Debug.Build.0 = Debug|Win32
{56CE18C9-0000-0000-0000-000000000000}.Release.ActiveCfg = Release|Win32
{56CE18C9-0000-0000-0000-000000000000}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection

View File

@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="segment_manager_test"
ProjectGUID="{56CE18C9-0000-0000-0000-000000000000}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="../../Bin/Win32/Debug"
IntermediateDirectory="Debug/segment_manager_test"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../../.."
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="FALSE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib"
OutputFile="$(OutDir)/segment_manager_test_d.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../../stage/lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/segment_manager_test.pdb"
SubSystem="1"
TargetMachine="1"
FixedBaseAddress="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="../../Bin/Win32/Release"
IntermediateDirectory="Release/segment_manager_test"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../../../.."
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
RuntimeLibrary="2"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="FALSE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib"
OutputFile="$(OutDir)/segment_manager_test.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../../stage/lib"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{47FC4F21-A627-7641-06A6-A22AD322A75F}">
<File
RelativePath="..\..\test\segment_manager_test.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{33897750-B034-B78B-89BD-E25F1F9B2E6E}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,457 @@
#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/unordered_map_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>
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;
}
};
template <class SegmentManager>
bool test_segment_manager()
{
typedef typename SegmentManager::size_type size_type;
const unsigned int ShmSizeSize = 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( ShmSizeSize );
mapped_region mapping( sh_mem, read_write );
SegmentManager* seg_mgr = new( mapping.get_address() ) SegmentManager( ShmSizeSize );
std::size_t free_mem_before = seg_mgr->get_free_memory();
std::size_t size_before = seg_mgr->get_size();
if(size_before != ShmSizeSize)
return false;
if(!seg_mgr->all_memory_deallocated())
return false;
if(seg_mgr->get_min_size() >= ShmSizeSize)
return false;
{//test get_free_memory() / allocate()/deallocate()
const size_type Size = ShmSizeSize/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;
try{ seg_mgr->allocate(ShmSizeSize*2); }catch(interprocess_exception&){}
if(seg_mgr->get_free_memory() != free_mem_before)
return false;
if(seg_mgr->allocate(ShmSizeSize*2, std::nothrow))
return false;
if(seg_mgr->get_free_memory() != free_mem_before)
return false;
}
{//test allocate_aligned
const std::size_t Alignment = 128u;
void *mem = seg_mgr->allocate_aligned(ShmSizeSize/4, 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(ShmSizeSize/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;
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{ seg_mgr->allocate_aligned(ShmSizeSize*2, Alignment); }catch(interprocess_exception&){}
if(seg_mgr->get_free_memory() != free_mem_before)
return false;
if(seg_mgr->allocate_aligned(ShmSizeSize*2, Alignment, std::nothrow))
return false;
if(seg_mgr->get_free_memory() != free_mem_before)
return false;
}
{//test shrink_to_fit
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;
}
{//test zero_free_memory
const size_type Size(ShmSizeSize/2+1), Size2(ShmSizeSize/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);
static unsigned char zerobuf[Size];
//Deallocate and check still non-zero
seg_mgr->deallocate(mem);
seg_mgr->deallocate(mem2);
if(!std::memcmp(mem, zerobuf, Size))
return false;
if(!std::memcmp(mem2, zerobuf, 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;
}
{//test anonymous object
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);
try{ seg_mgr->template construct<int>(anonymous_instance)[ShmSizeSize](); }catch(interprocess_exception&){}
if(seg_mgr->template construct<int>(anonymous_instance, std::nothrow)[ShmSizeSize]())
try{ seg_mgr->template construct_it<int>(anonymous_instance)[ShmSizeSize](&int_array_values[0]); }catch(interprocess_exception&){}
if(seg_mgr->template construct_it<int>(anonymous_instance, std::nothrow)[ShmSizeSize](&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;
}
{//test named object
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 i = 0, imax = seg_mgr->get_num_named_objects(); i != imax; ++i){ ++nb; }
if(nb != ne)
return false;
seg_mgr->destroy_ptr(uint_object);
seg_mgr->template destroy<int>(object2_name);
}
try{ seg_mgr->template construct<unsigned int>(object1_name)[ShmSizeSize](); }catch(interprocess_exception&){}
if(seg_mgr->template construct<int>(object2_name, std::nothrow)[ShmSizeSize]())
try{ seg_mgr->template construct_it<unsigned int>(object1_name)[ShmSizeSize](&int_array_values[0]); }catch(interprocess_exception&){}
if(seg_mgr->template construct_it<int>(object2_name, std::nothrow)[ShmSizeSize](&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;
}
{//test unique object
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 i = 0, imax = seg_mgr->get_num_unique_objects(); i != imax; ++i){ ++nb; }
if(nb != ne)
return false;
seg_mgr->destroy_ptr(uint_object);
seg_mgr->template destroy<int>(unique_instance);
}
try{ seg_mgr->template construct<unsigned int>(unique_instance)[ShmSizeSize](); }catch(interprocess_exception&){}
if(seg_mgr->template construct<int>(unique_instance, std::nothrow)[ShmSizeSize]())
try{ seg_mgr->template construct_it<unsigned int>(unique_instance)[ShmSizeSize](&int_array_values[0]); }catch(interprocess_exception&){}
if(seg_mgr->template construct_it<int>(unique_instance, std::nothrow)[ShmSizeSize](&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;
}
{//test allocator/deleter
if(!seg_mgr->all_memory_deallocated())
return false;
typedef typename SegmentManager::template allocator<float>::type allocator_t;
typedef typename SegmentManager::template deleter<float>::type deleter_t;
allocator_t alloc(seg_mgr->template get_allocator<float>());
deleter_t delet(seg_mgr->template get_deleter<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;
}
{//test allocator/deleter
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 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, null_index > segment_manager_t;
if(!test_segment_manager<segment_manager_t>())
return false;
}*/
/*
{
typedef segment_manager< char, MemoryAlgorithm, unordered_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;
}