diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/interprocess/test | |
parent | Initial commit. (diff) | |
download | ceph-upstream.tar.xz ceph-upstream.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/interprocess/test')
94 files changed, 16383 insertions, 0 deletions
diff --git a/src/boost/libs/interprocess/test/Jamfile.v2 b/src/boost/libs/interprocess/test/Jamfile.v2 new file mode 100644 index 00000000..a09bf8f2 --- /dev/null +++ b/src/boost/libs/interprocess/test/Jamfile.v2 @@ -0,0 +1,40 @@ +# Boost Interprocess Library Test Jamfile + +# (C) Copyright Ion Gaztanaga 2006. +# Use, modification and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# Adapted from John Maddock's TR1 Jamfile.v2 +# Copyright John Maddock 2005. +# Use, modification and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# this rule enumerates through all the sources and invokes +# the run rule for each source, the result is a list of all +# the run rules, which we can pass on to the test_suite rule: + +rule test_all +{ + local all_rules = ; + + for local fileb in [ glob *.cpp ] + { + all_rules += [ run $(fileb) + : # additional args + : # test-files + : # requirements + <toolset>acc:<linkflags>-lrt + <toolset>acc-pa_risc:<linkflags>-lrt + <toolset>gcc,<target-os>windows:<linkflags>"-lole32 -loleaut32 -lpsapi -ladvapi32" + <target-os>hpux,<toolset>gcc:<linkflags>"-Wl,+as,mpas" + <target-os>windows,<toolset>clang:<linkflags>"-lole32 -loleaut32 -lpsapi -ladvapi32" + <target-os>linux:<linkflags>"-lrt" + ] ; + } + + return $(all_rules) ; +} + +test-suite interprocess_test : [ test_all r ] : <threading>multi ; diff --git a/src/boost/libs/interprocess/test/adaptive_node_pool_test.cpp b/src/boost/libs/interprocess/test/adaptive_node_pool_test.cpp new file mode 100644 index 00000000..3caae188 --- /dev/null +++ b/src/boost/libs/interprocess/test/adaptive_node_pool_test.cpp @@ -0,0 +1,30 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS +#include <boost/interprocess/detail/config_begin.hpp> +#include "node_pool_test.hpp" +#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp> +#include <vector> + +using namespace boost::interprocess; +typedef managed_shared_memory::segment_manager segment_manager_t; + +int main () +{ + typedef ipcdetail::private_adaptive_node_pool + <segment_manager_t, 4, 64, 64, 5> node_pool_t; + + if(!test::test_all_node_pool<node_pool_t>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/adaptive_pool_test.cpp b/src/boost/libs/interprocess/test/adaptive_pool_test.cpp new file mode 100644 index 00000000..59c7f979 --- /dev/null +++ b/src/boost/libs/interprocess/test/adaptive_pool_test.cpp @@ -0,0 +1,71 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/allocators/adaptive_pool.hpp> +#include "print_container.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include "list_test.hpp" +#include "vector_test.hpp" + +using namespace boost::interprocess; + +//We will work with wide characters for shared memory objects +//Alias an adaptive pool that allocates ints +typedef adaptive_pool + <int, managed_shared_memory::segment_manager> shmem_node_allocator_t; + +typedef ipcdetail::adaptive_pool_v1 + <int, managed_shared_memory::segment_manager> shmem_node_allocator_v1_t; + +namespace boost { +namespace interprocess { + +//Explicit instantiations to catch compilation errors +template class adaptive_pool<int, managed_shared_memory::segment_manager>; +template class adaptive_pool<void, managed_shared_memory::segment_manager>; + +namespace ipcdetail { + +template class ipcdetail::adaptive_pool_v1<int, managed_shared_memory::segment_manager>; +template class ipcdetail::adaptive_pool_v1<void, managed_shared_memory::segment_manager>; + +}}} + +//Alias list types +typedef list<int, shmem_node_allocator_t> MyShmList; +typedef list<int, shmem_node_allocator_v1_t> MyShmListV1; + +//Alias vector types +typedef vector<int, shmem_node_allocator_t> MyShmVector; +typedef vector<int, shmem_node_allocator_v1_t> MyShmVectorV1; + +int main () +{ + if(test::list_test<managed_shared_memory, MyShmList, true>()) + return 1; + + if(test::list_test<managed_shared_memory, MyShmListV1, true>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyShmVector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyShmVectorV1>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/allocator_v1.hpp b/src/boost/libs/interprocess/test/allocator_v1.hpp new file mode 100644 index 00000000..d68ef9f4 --- /dev/null +++ b/src/boost/libs/interprocess/test/allocator_v1.hpp @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_ALLOCATOR_V1_HPP +#define BOOST_INTERPROCESS_ALLOCATOR_V1_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#include <boost/intrusive/pointer_traits.hpp> + +#include <boost/interprocess/interprocess_fwd.hpp> +#include <boost/interprocess/containers/allocation_type.hpp> +#include <boost/interprocess/detail/utilities.hpp> +#include <boost/interprocess/exceptions.hpp> +#include <boost/move/adl_move_swap.hpp> +#include <boost/static_assert.hpp> + +//!\file +//!Describes an allocator_v1 that allocates portions of fixed size +//!memory buffer (shared memory, mapped file...) + +namespace boost { +namespace interprocess { +namespace test { + +//!An STL compatible allocator_v1 that uses a segment manager as +//!memory source. The internal pointer type will of the same type (raw, smart) as +//!"typename SegmentManager::void_pointer" type. This allows +//!placing the allocator_v1 in shared memory, memory mapped-files, etc...*/ +template<class T, class SegmentManager> +class allocator_v1 +{ + private: + typedef allocator_v1<T, SegmentManager> self_t; + typedef SegmentManager segment_manager; + typedef typename segment_manager::void_pointer aux_pointer_t; + + typedef typename boost::intrusive:: + pointer_traits<aux_pointer_t>::template + rebind_pointer<const void>::type cvoid_ptr; + + typedef typename boost::intrusive:: + pointer_traits<cvoid_ptr>::template + rebind_pointer<segment_manager>::type alloc_ptr_t; + + template<class T2, class SegmentManager2> + allocator_v1& operator=(const allocator_v1<T2, SegmentManager2>&); + + allocator_v1& operator=(const allocator_v1&); + + alloc_ptr_t mp_mngr; + + public: + typedef T value_type; + + typedef typename boost::intrusive:: + pointer_traits<cvoid_ptr>::template + rebind_pointer<T>::type pointer; + + typedef typename boost::intrusive:: + pointer_traits<cvoid_ptr>::template + rebind_pointer<const T>::type const_pointer; + + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + //!Obtains an allocator_v1 of other type + template<class T2> + struct rebind + { + typedef allocator_v1<T2, SegmentManager> other; + }; + + //!Returns the segment manager. Never throws + segment_manager* get_segment_manager()const + { return ipcdetail::to_raw_pointer(mp_mngr); } +/* + //!Returns address of mutable object. Never throws + pointer address(reference value) const + { return pointer(addressof(value)); } + + //!Returns address of non mutable object. Never throws + const_pointer address(const_reference value) const + { return const_pointer(addressof(value)); } +*/ + //!Constructor from the segment manager. Never throws + allocator_v1(segment_manager *segment_mngr) + : mp_mngr(segment_mngr) { } + + //!Constructor from other allocator_v1. Never throws + allocator_v1(const allocator_v1 &other) + : mp_mngr(other.get_segment_manager()){ } + + //!Constructor from related allocator_v1. Never throws + template<class T2> + allocator_v1(const allocator_v1<T2, SegmentManager> &other) + : mp_mngr(other.get_segment_manager()){} + + //!Allocates memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_ptr hint = 0) + { + if(size_overflows<sizeof(T)>(count)){ + throw bad_alloc(); + } + (void)hint; return pointer(static_cast<T*>(mp_mngr->allocate(count*sizeof(T)))); + } + + //!Deallocates memory previously allocated. Never throws + void deallocate(const pointer &ptr, size_type) + { mp_mngr->deallocate((void*)ipcdetail::to_raw_pointer(ptr)); } + + //!Construct object, calling constructor. + //!Throws if T(const T&) throws + void construct(const pointer &ptr, const_reference value) + { new((void*)ipcdetail::to_raw_pointer(ptr)) value_type(value); } + + //!Destroys object. Throws if object's destructor throws + void destroy(const pointer &ptr) + { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } + + //!Returns the number of elements that could be allocated. Never throws + size_type max_size() const + { return mp_mngr->get_size(); } + + //!Swap segment manager. Does not throw. If each allocator_v1 is placed in + //!different memory segments, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2) + { ::boost::adl_move_swap(alloc1.mp_mngr, alloc2.mp_mngr); } +}; + +//!Equality test for same type of allocator_v1 +template<class T, class SegmentManager> inline +bool operator==(const allocator_v1<T , SegmentManager> &alloc1, + const allocator_v1<T, SegmentManager> &alloc2) + { return alloc1.get_segment_manager() == alloc2.get_segment_manager(); } + +//!Inequality test for same type of allocator_v1 +template<class T, class SegmentManager> inline +bool operator!=(const allocator_v1<T, SegmentManager> &alloc1, + const allocator_v1<T, SegmentManager> &alloc2) + { return alloc1.get_segment_manager() != alloc2.get_segment_manager(); } + +} //namespace test { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_ALLOCATOR_V1_HPP + diff --git a/src/boost/libs/interprocess/test/allocexcept_test.cpp b/src/boost/libs/interprocess/test/allocexcept_test.cpp new file mode 100644 index 00000000..696b2797 --- /dev/null +++ b/src/boost/libs/interprocess/test/allocexcept_test.cpp @@ -0,0 +1,95 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <iostream> +#include <functional> +#include "print_container.hpp" +#include <string> +#include "get_process_id_name.hpp" + +struct InstanceCounter +{ + InstanceCounter(){++counter;} + InstanceCounter(const InstanceCounter&){++counter;} + ~InstanceCounter(){--counter;} + static std::size_t counter; +}; + +std::size_t InstanceCounter::counter = 0; + +using namespace boost::interprocess; + + +int main () +{ + const int memsize = 16384; + const char *const shMemName = test::get_process_id_name(); + + try{ + shared_memory_object::remove(shMemName); + + //Named allocate capable shared mem allocator + managed_shared_memory segment(create_only, shMemName, memsize); + + //STL compatible allocator object, uses allocate(), deallocate() functions + typedef allocator<InstanceCounter, + managed_shared_memory::segment_manager> + inst_allocator_t; + const inst_allocator_t myallocator (segment.get_segment_manager()); + + typedef vector<InstanceCounter, inst_allocator_t> MyVect; + + //We'll provoke an exception, let's see if exception handling works + try{ + //Fill vector until there is no more memory + MyVect myvec(myallocator); + int i; + for(i = 0; true; ++i){ + myvec.push_back(InstanceCounter()); + } + } + catch(boost::interprocess::bad_alloc &){ + if(InstanceCounter::counter != 0) + return 1; + } + + //We'll provoke an exception, let's see if exception handling works + try{ + //Fill vector at the beginning until there is no more memory + MyVect myvec(myallocator); + int i; + InstanceCounter ic; + for(i = 0; true; ++i){ + myvec.insert(myvec.begin(), i, ic); + } + } + catch(boost::interprocess::bad_alloc &){ + if(InstanceCounter::counter != 0) + return 1; + } + catch(std::length_error &){ + if(InstanceCounter::counter != 0) + return 1; + } + } + catch(...){ + shared_memory_object::remove(shMemName); + throw; + } + shared_memory_object::remove(shMemName); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/anonymous_shared_memory_test.cpp b/src/boost/libs/interprocess/test/anonymous_shared_memory_test.cpp new file mode 100644 index 00000000..cdff6e66 --- /dev/null +++ b/src/boost/libs/interprocess/test/anonymous_shared_memory_test.cpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <iostream> +#include <boost/interprocess/mapped_region.hpp> +#include <boost/interprocess/anonymous_shared_memory.hpp> +#include <cstddef> +#include <exception> + +using namespace boost::interprocess; + +int main () +{ + try{ + const std::size_t MemSize = 99999*2; + { + //Now check anonymous mapping + mapped_region region(anonymous_shared_memory(MemSize)); + + //Write pattern + unsigned char *pattern = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0 + ;i < MemSize + ;++i, ++pattern){ + *pattern = static_cast<unsigned char>(i); + } + + //Check pattern + pattern = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0 + ;i < MemSize + ;++i, ++pattern){ + if(*pattern != static_cast<unsigned char>(i)){ + return 1; + } + } + } + } + catch(std::exception &exc){ + std::cout << "Unhandled exception: " << exc.what() << std::endl; + return 1; + } + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/boost_interprocess_check.hpp b/src/boost/libs/interprocess/test/boost_interprocess_check.hpp new file mode 100644 index 00000000..675613c9 --- /dev/null +++ b/src/boost/libs/interprocess/test/boost_interprocess_check.hpp @@ -0,0 +1,27 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_CHECK_HEADER +#define BOOST_INTERPROCESS_TEST_CHECK_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/exceptions.hpp> +#include <iostream> + +namespace boost { namespace interprocess { namespace test { + +#define BOOST_INTERPROCESS_CHECK( P ) \ + if(!(P)) do{ assert(P); std::cout << "Failed: " << #P << " file: " << __FILE__ << " line : " << __LINE__ << std::endl; throw boost::interprocess::interprocess_exception(#P);}while(0) + +}}} //namespace boost { namespace interprocess { namespace test { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_TEST_CHECK_HEADER diff --git a/src/boost/libs/interprocess/test/boost_use_windows_h.cpp b/src/boost/libs/interprocess/test/boost_use_windows_h.cpp new file mode 100644 index 00000000..2fb1a612 --- /dev/null +++ b/src/boost/libs/interprocess/test/boost_use_windows_h.cpp @@ -0,0 +1,38 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2014. 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 _WIN32_WINNT 0x0501 +#define BOOST_USE_WINDOWS_H + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#ifdef BOOST_INTERPROCESS_WINDOWS + +#include <boost/interprocess/windows_shared_memory.hpp> + +using namespace boost::interprocess; + +int main () +{ + windows_shared_memory dummy; + static_cast<void>(dummy); + return 0; +} + +#else + +int main() +{ + return 0; +} + +#endif + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/bufferstream_test.cpp b/src/boost/libs/interprocess/test/bufferstream_test.cpp new file mode 100644 index 00000000..6b6cb24c --- /dev/null +++ b/src/boost/libs/interprocess/test/bufferstream_test.cpp @@ -0,0 +1,144 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/streams/bufferstream.hpp> +#include <sstream> +#include <cstring> + +namespace boost{ +namespace interprocess{ + +//Force instantiations to catch compile-time errors +template class basic_bufferbuf<char>; +template class basic_bufferstream<char>; +template class basic_ibufferstream<char>; +template class basic_obufferstream<char>; + +}} + +using namespace boost::interprocess; + +static int bufferstream_test() +{ + //Static big enough buffer + { + const int BufSize = 10001; + //This will be zero-initialized + static char buffer [BufSize]; + bufferstream bufstream; + if(bufstream.tellg() != std::streampos(0)){ + return 1; + } + if(bufstream.tellp() != std::streampos(0)){ + return 1; + } + std::stringstream std_stringstream; + std::string str1, str2, str3("testline:"); + int number1, number2; + + //Make sure we have null in the last byte + bufstream.buffer(buffer, BufSize-1); + for(int i = 0; i < 100; ++i){ + bufstream << "testline: " << i << std::endl; + std_stringstream << "testline: " << i << std::endl; + } + + if(std::strcmp(buffer, std_stringstream.str().c_str()) != 0){ + return 1; + } + + //We shouldn't have reached the end of the buffer writing + if(bufstream.bad()){ + assert(0); + return 1; + } + + bufstream.buffer(buffer, BufSize-1); + for(int i = 0; i < 100; ++i){ + bufstream >> str1 >> number1; + std_stringstream >> str2 >> number2; + if((str1 != str2) || (str1 != str3)){ + assert(0); return 1; + } + if((number1 != number2) || (number1 != i)){ + assert(0); return 1; + } + } + //We shouldn't have reached the end of the buffer reading + if(bufstream.eof()){ + assert(0); + return 1; + } + } + + //Static small buffer. Check if buffer + //overflow protection works. + { + const int BufSize = 101; + //This will be zero-initialized + static char buffer [BufSize]; + bufferstream bufstream; + std::stringstream std_stringstream; + std::string str1; + int number1; + + //Make sure we have null in the last byte + bufstream.buffer(buffer, BufSize-1); + for(int i = 0; i < 100; ++i){ + bufstream << "testline: " << i << std::endl; + std_stringstream << "testline: " << i << std::endl; + } + + //Contents should be different + if(std::strcmp(buffer, std_stringstream.str().c_str()) == 0){ + return 1; + } + //The stream shouldn't be in good health + if(bufstream.good()){ + assert(0); + return 1; + } + //The bad flag should be active. This indicates overflow attempt + if(!bufstream.bad()){ + assert(0); + return 1; + } + + //Now let's test read overflow + bufstream.clear(); + bufstream.buffer(buffer, BufSize-1); + for(int i = 0; i < 100; ++i){ + bufstream >> str1 >> number1; + } + //The stream shouldn't be in good health + if(bufstream.good()){ + assert(0); + return 1; + } + //The eof flag indicates we have reached the end of the + //buffer while reading + if(!bufstream.eof()){ + assert(0); + return 1; + } + } + return 0; +} + +int main () +{ + if(bufferstream_test()){ + return 1; + } + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/cached_adaptive_pool_test.cpp b/src/boost/libs/interprocess/test/cached_adaptive_pool_test.cpp new file mode 100644 index 00000000..ee5b86c2 --- /dev/null +++ b/src/boost/libs/interprocess/test/cached_adaptive_pool_test.cpp @@ -0,0 +1,73 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/allocators/cached_adaptive_pool.hpp> +#include "print_container.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include "list_test.hpp" +#include "vector_test.hpp" + +using namespace boost::interprocess; + +//We will work with wide characters for shared memory objects +//Alias an cached adaptive pool that allocates ints +typedef cached_adaptive_pool + <int, managed_shared_memory::segment_manager> + cached_node_allocator_t; + +typedef ipcdetail::cached_adaptive_pool_v1 + <int, managed_shared_memory::segment_manager> + cached_node_allocator_v1_t; + +namespace boost { +namespace interprocess { + +//Explicit instantiations to catch compilation errors +template class cached_adaptive_pool<int, managed_shared_memory::segment_manager>; +template class cached_adaptive_pool<void, managed_shared_memory::segment_manager>; + +namespace ipcdetail { + +template class ipcdetail::cached_adaptive_pool_v1<int, managed_shared_memory::segment_manager>; +template class ipcdetail::cached_adaptive_pool_v1<void, managed_shared_memory::segment_manager>; + +}}} + +//Alias list types +typedef list<int, cached_node_allocator_t> MyShmList; +typedef list<int, cached_node_allocator_v1_t> MyShmListV1; + +//Alias vector types +typedef vector<int, cached_node_allocator_t> MyShmVector; +typedef vector<int, cached_node_allocator_v1_t> MyShmVectorV1; + +int main () +{ + if(test::list_test<managed_shared_memory, MyShmList, true>()) + return 1; + + if(test::list_test<managed_shared_memory, MyShmListV1, true>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyShmVector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyShmVectorV1>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/cached_node_allocator_test.cpp b/src/boost/libs/interprocess/test/cached_node_allocator_test.cpp new file mode 100644 index 00000000..8ffa0f0b --- /dev/null +++ b/src/boost/libs/interprocess/test/cached_node_allocator_test.cpp @@ -0,0 +1,67 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/allocators/cached_node_allocator.hpp> +#include "print_container.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include "list_test.hpp" +#include "vector_test.hpp" + +using namespace boost::interprocess; + +//Alias an integer node allocator type +typedef cached_node_allocator + <int, managed_shared_memory::segment_manager> + cached_node_allocator_t; +typedef ipcdetail::cached_node_allocator_v1 + <int, managed_shared_memory::segment_manager> + cached_node_allocator_v1_t; + +namespace boost { +namespace interprocess { + +//Explicit instantiations to catch compilation errors +template class cached_node_allocator<int, managed_shared_memory::segment_manager>; +template class cached_node_allocator<void, managed_shared_memory::segment_manager>; + +namespace ipcdetail { + +template class ipcdetail::cached_node_allocator_v1<int, managed_shared_memory::segment_manager>; +template class ipcdetail::cached_node_allocator_v1<void, managed_shared_memory::segment_manager>; + +}}} + +//Alias list types +typedef list<int, cached_node_allocator_t> MyShmList; +typedef list<int, cached_node_allocator_v1_t> MyShmListV1; + +//Alias vector types +typedef vector<int, cached_node_allocator_t> MyShmVector; +typedef vector<int, cached_node_allocator_v1_t> MyShmVectorV1; + +int main () +{ + if(test::list_test<managed_shared_memory, MyShmList, true>()) + return 1; + if(test::list_test<managed_shared_memory, MyShmListV1, true>()) + return 1; + if(test::vector_test<managed_shared_memory, MyShmVector>()) + return 1; + if(test::vector_test<managed_shared_memory, MyShmVectorV1>()) + return 1; + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/check_equal_containers.hpp b/src/boost/libs/interprocess/test/check_equal_containers.hpp new file mode 100644 index 00000000..423a84cd --- /dev/null +++ b/src/boost/libs/interprocess/test/check_equal_containers.hpp @@ -0,0 +1,92 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_CHECK_EQUAL_CONTAINERS_HPP +#define BOOST_INTERPROCESS_TEST_CHECK_EQUAL_CONTAINERS_HPP + +#include <boost/interprocess/detail/config_begin.hpp> +// container/detail +#include <boost/container/detail/iterator.hpp> +#include <boost/container/detail/pair.hpp> + +namespace boost{ +namespace interprocess{ +namespace test{ + +template< class T1, class T2> +bool CheckEqual( const T1 &t1, const T2 &t2 + , typename boost::container::dtl::enable_if_c + <!boost::container::dtl::is_pair<T1>::value && + !boost::container::dtl::is_pair<T2>::value + >::type* = 0) +{ return t1 == t2; } + +template< class Pair1, class Pair2> +bool CheckEqual( const Pair1 &pair1, const Pair2 &pair2 + , typename boost::container::dtl::enable_if_c + <boost::container::dtl::is_pair<Pair1>::value && + boost::container::dtl::is_pair<Pair2>::value + >::type* = 0) +{ + return CheckEqual(pair1.first, pair2.first) && CheckEqual(pair1.second, pair2.second); +} + + +//Function to check if both containers are equal +template<class MyShmCont + ,class MyStdCont> +bool CheckEqualContainers(MyShmCont *shmcont, MyStdCont *stdcont) +{ + if(shmcont->size() != stdcont->size()) + return false; + + typename MyShmCont::iterator itshm(shmcont->begin()), itshmend(shmcont->end()); + typename MyStdCont::iterator itstd(stdcont->begin()); + typename MyStdCont::size_type dist = + typename MyStdCont::size_type(boost::container::iterator_distance(itshm, itshmend)); + if(dist != shmcont->size()){ + return false; + } + std::size_t i = 0; + for(; itshm != itshmend; ++itshm, ++itstd, ++i){ + if(!CheckEqual(*itstd, *itshm)) + return false; + } + return true; +} + +template<class MyShmCont + ,class MyStdCont> +bool CheckEqualPairContainers(MyShmCont *shmcont, MyStdCont *stdcont) +{ + if(shmcont->size() != stdcont->size()) + return false; + + typedef typename MyShmCont::key_type key_type; + typedef typename MyShmCont::mapped_type mapped_type; + + typename MyShmCont::iterator itshm(shmcont->begin()), itshmend(shmcont->end()); + typename MyStdCont::iterator itstd(stdcont->begin()); + for(; itshm != itshmend; ++itshm, ++itstd){ + if(itshm->first != key_type(itstd->first)) + return false; + + if(itshm->second != mapped_type(itstd->second)) + return false; + } + return true; +} +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_TEST_CHECK_EQUAL_CONTAINERS_HPP diff --git a/src/boost/libs/interprocess/test/condition_any_test.cpp b/src/boost/libs/interprocess/test/condition_any_test.cpp new file mode 100644 index 00000000..8349fed3 --- /dev/null +++ b/src/boost/libs/interprocess/test/condition_any_test.cpp @@ -0,0 +1,34 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/sync/interprocess_condition_any.hpp> +#include <boost/interprocess/sync/interprocess_mutex.hpp> +#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp> +#include <boost/interprocess/sync/spin/mutex.hpp> + +#include "condition_test_template.hpp" + +using namespace boost::interprocess; + +int main () +{ + if(!test::do_test_condition<interprocess_condition_any, interprocess_mutex>()) + return 1; + if(!test::do_test_condition<interprocess_condition_any, ipcdetail::spin_mutex>()) + return 1; + if(!test::do_test_condition<interprocess_condition_any, interprocess_recursive_mutex>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/condition_test.cpp b/src/boost/libs/interprocess/test/condition_test.cpp new file mode 100644 index 00000000..089c0a6f --- /dev/null +++ b/src/boost/libs/interprocess/test/condition_test.cpp @@ -0,0 +1,40 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/sync/interprocess_condition.hpp> +#include <boost/interprocess/sync/interprocess_mutex.hpp> +#include "condition_test_template.hpp" + +#if defined(BOOST_INTERPROCESS_WINDOWS) +#include <boost/interprocess/sync/windows/condition.hpp> +#include <boost/interprocess/sync/windows/mutex.hpp> +#include <boost/interprocess/sync/spin/condition.hpp> +#include <boost/interprocess/sync/spin/mutex.hpp> +#endif + +using namespace boost::interprocess; + +int main () +{ + #if defined(BOOST_INTERPROCESS_WINDOWS) + if(!test::do_test_condition<ipcdetail::windows_condition, ipcdetail::windows_mutex>()) + return 1; + if(!test::do_test_condition<ipcdetail::spin_condition, ipcdetail::spin_mutex>()) + return 1; + #endif + if(!test::do_test_condition<interprocess_condition, interprocess_mutex>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/condition_test_template.hpp b/src/boost/libs/interprocess/test/condition_test_template.hpp new file mode 100644 index 00000000..03e80ba4 --- /dev/null +++ b/src/boost/libs/interprocess/test/condition_test_template.hpp @@ -0,0 +1,401 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP +#define BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/detail/os_thread_functions.hpp> +#include "boost_interprocess_check.hpp" +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <iostream> + +namespace boost{ +namespace interprocess{ +namespace test { + +boost::posix_time::ptime ptime_delay(int secs) +{ + return microsec_clock::universal_time() + + boost::posix_time::time_duration(0, 0, secs); +} + +template <typename F, typename T> +class binder +{ +public: + binder(const F& f, const T& p) + : func(f), param(p) { } + void operator()() const { func(param); } + +private: + F func; + T param; +}; + +template <typename F, typename T> +binder<F, T> bind_function(F func, T param) +{ + return binder<F, T>(func, param); +} + +template <class Condition, class Mutex> +struct condition_test_data +{ + condition_test_data() : notified(0), awoken(0) { } + + ~condition_test_data() + {} + + Mutex mutex; + Condition condition; + int notified; + int awoken; +}; + +template <class Condition, class Mutex> +void condition_test_thread(condition_test_data<Condition, Mutex>* data) +{ + boost::interprocess::scoped_lock<Mutex> + lock(data->mutex); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + while (!(data->notified > 0)) + data->condition.wait(lock); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + data->awoken++; +} + +struct cond_predicate +{ + cond_predicate(int& var, int val) : _var(var), _val(val) { } + + bool operator()() { return _var == _val; } + + int& _var; + int _val; +}; + +template <class Condition, class Mutex> +void condition_test_waits(condition_test_data<Condition, Mutex>* data) +{ + boost::interprocess::scoped_lock<Mutex> + lock(data->mutex); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + + // Test wait. + while (data->notified != 1) + data->condition.wait(lock); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 1); + data->awoken++; + data->condition.notify_one(); + + // Test predicate wait. + data->condition.wait(lock, cond_predicate(data->notified, 2)); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 2); + data->awoken++; + data->condition.notify_one(); + + // Test timed_wait. + while (data->notified != 3) + data->condition.timed_wait(lock, ptime_delay(5)); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 3); + data->awoken++; + data->condition.notify_one(); + + // Test predicate timed_wait. + cond_predicate pred(data->notified, 4); + bool ret = data->condition.timed_wait(lock, ptime_delay(5), pred); + BOOST_INTERPROCESS_CHECK(ret);(void)ret; + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(pred()); + BOOST_INTERPROCESS_CHECK(data->notified == 4); + data->awoken++; + data->condition.notify_one(); +} + +template <class Condition, class Mutex> +void do_test_condition_notify_one() +{ + condition_test_data<Condition, Mutex> data; + + boost::interprocess::ipcdetail::OS_thread_t thread; + boost::interprocess::ipcdetail::thread_launch(thread, bind_function(&condition_test_thread<Condition, Mutex>, &data)); + //Make sure thread is blocked + boost::interprocess::ipcdetail::thread_sleep(1000); + { + boost::interprocess::scoped_lock<Mutex> + lock(data.mutex); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + data.notified++; + data.condition.notify_one(); + } + + boost::interprocess::ipcdetail::thread_join(thread); + BOOST_INTERPROCESS_CHECK(data.awoken == 1); +} + +template <class Condition, class Mutex> +void do_test_condition_notify_all() +{ + const int NUMTHREADS = 3; + + boost::interprocess::ipcdetail::OS_thread_t thgroup[NUMTHREADS]; + condition_test_data<Condition, Mutex> data; + + for(int i = 0; i< NUMTHREADS; ++i){ + boost::interprocess::ipcdetail::thread_launch(thgroup[i], bind_function(&condition_test_thread<Condition, Mutex>, &data)); + } + + //Make sure all threads are blocked + boost::interprocess::ipcdetail::thread_sleep(1000); + { + boost::interprocess::scoped_lock<Mutex> + lock(data.mutex); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + data.notified++; + } + data.condition.notify_all(); + + for(int i = 0; i< NUMTHREADS; ++i){ + boost::interprocess::ipcdetail::thread_join(thgroup[i]); + } + BOOST_INTERPROCESS_CHECK(data.awoken == NUMTHREADS); +} + +template <class Condition, class Mutex> +void do_test_condition_waits() +{ + condition_test_data<Condition, Mutex> data; + boost::interprocess::ipcdetail::OS_thread_t thread; + boost::interprocess::ipcdetail::thread_launch(thread, bind_function(&condition_test_waits<Condition, Mutex>, &data)); + + { + boost::interprocess::scoped_lock<Mutex> + lock(data.mutex); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + + boost::interprocess::ipcdetail::thread_sleep(1000); + data.notified++; + data.condition.notify_one(); + while (data.awoken != 1) + data.condition.wait(lock); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data.awoken == 1); + + boost::interprocess::ipcdetail::thread_sleep(1000); + data.notified++; + data.condition.notify_one(); + while (data.awoken != 2) + data.condition.wait(lock); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data.awoken == 2); + + boost::interprocess::ipcdetail::thread_sleep(1000); + data.notified++; + data.condition.notify_one(); + while (data.awoken != 3) + data.condition.wait(lock); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data.awoken == 3); + + boost::interprocess::ipcdetail::thread_sleep(1000); + data.notified++; + data.condition.notify_one(); + while (data.awoken != 4) + data.condition.wait(lock); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data.awoken == 4); + } + + boost::interprocess::ipcdetail::thread_join(thread); + BOOST_INTERPROCESS_CHECK(data.awoken == 4); +} +/* +//Message queue simulation test +template <class Condition> +inline Condition &cond_empty() +{ + static Condition cond_empty; + return cond_empty; +} + +template <class Condition> +inline Condition &cond_full() +{ + static Condition cond_full; + return cond_full; +} + + +template <class Mutex> +inline Mutex &mutex() +{ + static Mutex mut; + return mut; +} +*/ +static volatile int count = 0; +static volatile int waiting_readers = 0; +static volatile int waiting_writer = 0; +const int queue_size = 3; +const int thread_factor = 10; +const int NumThreads = thread_factor*queue_size; + +//Function that removes items from queue +template <class Condition, class Mutex> +struct condition_func +{ + condition_func(Condition &cond_full, Condition &cond_empty, Mutex &mutex) + : cond_full_(cond_full), cond_empty_(cond_empty), mutex_(mutex) + {} + + void operator()() + { + boost::interprocess::scoped_lock<Mutex>lock(mutex_); + while(count == 0){ + ++waiting_readers; + cond_empty_.wait(lock); + --waiting_readers; + } + --count; + if(waiting_writer) + cond_full_.notify_one(); + } + Condition &cond_full_; + Condition &cond_empty_; + Mutex &mutex_; +}; + +//Queue functions +template <class Condition, class Mutex> +void do_test_condition_queue_notify_one(void) +{ + //Force mutex and condition creation + Condition cond_empty; + Condition cond_full; + Mutex mutex; + + //Create threads that will decrease count + { + //Initialize counters + count = 0; + waiting_readers = 0; + waiting_writer = 0; + + boost::interprocess::ipcdetail::OS_thread_t thgroup[NumThreads]; + for(int i = 0; i< NumThreads; ++i){ + condition_func<Condition, Mutex> func(cond_full, cond_empty, mutex); + boost::interprocess::ipcdetail::thread_launch(thgroup[i], func); + } + + //Add 20 elements one by one in the queue simulation + //The sender will block if it fills the queue + for(int i = 0; i < NumThreads; ++i){ + boost::interprocess::scoped_lock<Mutex> lock(mutex); + while(count == queue_size){ + ++waiting_writer; + cond_full.wait(lock); + --waiting_writer; + } + count++; + + if(waiting_readers) + cond_empty.notify_one(); + } + for(int i = 0; i< NumThreads; ++i){ + boost::interprocess::ipcdetail::thread_join(thgroup[i]); + } + BOOST_INTERPROCESS_CHECK(count == 0); + BOOST_INTERPROCESS_CHECK(waiting_readers == 0); + BOOST_INTERPROCESS_CHECK(waiting_writer == 0); + } +} + +//Queue functions +template <class Condition, class Mutex> +void do_test_condition_queue_notify_all(void) +{ + //Force mutex and condition creation + Condition cond_empty; + Condition cond_full; + Mutex mutex; + + //Create threads that will decrease count + { + //Initialize counters + count = 0; + waiting_readers = 0; + waiting_writer = 0; + + boost::interprocess::ipcdetail::OS_thread_t thgroup[NumThreads]; + for(int i = 0; i< NumThreads; ++i){ + condition_func<Condition, Mutex> func(cond_full, cond_empty, mutex); + boost::interprocess::ipcdetail::thread_launch(thgroup[i], func); + } + + //Fill queue to the max size and notify all several times + for(int i = 0; i < NumThreads; ++i){ + boost::interprocess::scoped_lock<Mutex>lock(mutex); + while(count == queue_size){ + ++waiting_writer; + cond_full.wait(lock); + --waiting_writer; + } + count++; + + if(waiting_readers) + cond_empty.notify_all(); + } + for(int i = 0; i< NumThreads; ++i){ + boost::interprocess::ipcdetail::thread_join(thgroup[i]); + } + BOOST_INTERPROCESS_CHECK(count == 0); + BOOST_INTERPROCESS_CHECK(waiting_readers == 0); + BOOST_INTERPROCESS_CHECK(waiting_writer == 0); + } +} + +template <class Condition, class Mutex> +bool do_test_condition() +{ + std::cout << "do_test_condition_notify_one<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl; + do_test_condition_notify_one<Condition, Mutex>(); + std::cout << "do_test_condition_notify_all<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl; + do_test_condition_notify_all<Condition, Mutex>(); + std::cout << "do_test_condition_waits<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl; + do_test_condition_waits<Condition, Mutex>(); + std::cout << "do_test_condition_queue_notify_one<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl; + do_test_condition_queue_notify_one<Condition, Mutex>(); + std::cout << "do_test_condition_queue_notify_all<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl; + do_test_condition_queue_notify_all<Condition, Mutex>(); + return true; +} + +} //namespace test +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP diff --git a/src/boost/libs/interprocess/test/data_test.cpp b/src/boost/libs/interprocess/test/data_test.cpp new file mode 100644 index 00000000..450031b2 --- /dev/null +++ b/src/boost/libs/interprocess/test/data_test.cpp @@ -0,0 +1,97 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <functional> +#include <string> +#include "print_container.hpp" +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +int main () +{ + const int memsize = 65536; + std::string process_name; + test::get_process_id_name(process_name); + const char *const shMemName = process_name.c_str(); + + try{ + shared_memory_object::remove(shMemName); + + //Create shared memory + managed_shared_memory segment(create_only, shMemName, memsize); + + //STL compatible allocator object, uses allocate(), deallocate() functions + typedef allocator<int, managed_shared_memory::segment_manager> + shmem_allocator_int_t; + + const shmem_allocator_int_t myallocator (segment.get_segment_manager()); + + const int max = 100; + void *array[max]; + + const char *allocName = "testAllocation"; + + typedef boost::interprocess::vector<int, shmem_allocator_int_t > MyVect; + + //---- ALLOC, NAMED_ALLOC, NAMED_NEW TEST ----// + { + int i; + //Let's allocate some memory + for(i = 0; i < max; ++i){ + array[i] = segment.allocate(i+1); + } + + //Deallocate allocated memory + for(i = 0; i < max; ++i){ + segment.deallocate(array[i]); + } + + bool res; + + MyVect *shmem_vect; + + //Construct and find + shmem_vect = segment.construct<MyVect> (allocName) (myallocator); + res = (shmem_vect == segment.find<MyVect>(allocName).first); + if(!res) + return 1; + //Destroy and check it is not present + segment.destroy<MyVect> (allocName); + res = (0 == segment.find<MyVect>(allocName).first); + if(!res) + return 1; + + //Construct, dump to a file + shmem_vect = segment.construct<MyVect> (allocName) (myallocator); + + if(shmem_vect != segment.find<MyVect>(allocName).first) + return 1; + //Destroy and check it is not present + segment.destroy<MyVect> (allocName); + res = (0 == segment.find<MyVect>(allocName).first); + if(!res) + return 1; + } + } + catch(...){ + shared_memory_object::remove(shMemName); + throw; + } + shared_memory_object::remove(shMemName); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/deque_test.cpp b/src/boost/libs/interprocess/test/deque_test.cpp new file mode 100644 index 00000000..4b3ee3cd --- /dev/null +++ b/src/boost/libs/interprocess/test/deque_test.cpp @@ -0,0 +1,312 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <memory> +#include <deque> +#include <iostream> +#include <list> + +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/deque.hpp> +#include <boost/interprocess/indexes/flat_map_index.hpp> +#include "print_container.hpp" +#include "check_equal_containers.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include <boost/interprocess/allocators/allocator.hpp> +#include "allocator_v1.hpp" +#include <boost/interprocess/exceptions.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/interprocess/detail/mpl.hpp> +#include <boost/interprocess/detail/type_traits.hpp> +#include <string> +#include "get_process_id_name.hpp" +#include "emplace_test.hpp" + +/////////////////////////////////////////////////////////////////// +// // +// This example repeats the same operations with std::deque and // +// shmem_deque using the node allocator // +// and compares the values of both containers // +// // +/////////////////////////////////////////////////////////////////// + +using namespace boost::interprocess; + +//Function to check if both sets are equal +template<class V1, class V2> +bool copyable_only(V1 *, V2 *, ipcdetail::false_type) +{ + return true; +} + +//Function to check if both sets are equal +template<class V1, class V2> +bool copyable_only(V1 *shmdeque, V2 *stddeque, ipcdetail::true_type) +{ + typedef typename V1::value_type IntType; + std::size_t size = shmdeque->size(); + stddeque->insert(stddeque->end(), 50, 1); + shmdeque->insert(shmdeque->end(), 50, IntType(1)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + { + IntType move_me(1); + stddeque->insert(stddeque->begin()+size/2, 50, 1); + shmdeque->insert(shmdeque->begin()+size/2, 50, boost::move(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + } + { + IntType move_me(2); + shmdeque->assign(shmdeque->size()/2, boost::move(move_me)); + stddeque->assign(stddeque->size()/2, 2); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + } + { + IntType move_me(1); + stddeque->clear(); + shmdeque->clear(); + stddeque->insert(stddeque->begin(), 50, 1); + shmdeque->insert(shmdeque->begin(), 50, boost::move(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + stddeque->insert(stddeque->begin()+20, 50, 1); + shmdeque->insert(shmdeque->begin()+20, 50, boost::move(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + stddeque->insert(stddeque->begin()+20, 20, 1); + shmdeque->insert(shmdeque->begin()+20, 20, boost::move(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + } + { + IntType move_me(1); + stddeque->clear(); + shmdeque->clear(); + stddeque->insert(stddeque->end(), 50, 1); + shmdeque->insert(shmdeque->end(), 50, boost::move(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + stddeque->insert(stddeque->end()-20, 50, 1); + shmdeque->insert(shmdeque->end()-20, 50, boost::move(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + stddeque->insert(stddeque->end()-20, 20, 1); + shmdeque->insert(shmdeque->end()-20, 20, boost::move(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + } + + return true; +} + + +template<class IntType, template<class T, class SegmentManager> class AllocatorType > +bool do_test() +{ + //Customize managed_shared_memory class + typedef basic_managed_shared_memory + <char, + //simple_seq_fit<mutex_family>, + rbtree_best_fit<mutex_family>, + //flat_map_index + iset_index + > my_managed_shared_memory; + + //Alias AllocatorType type + typedef AllocatorType<IntType, my_managed_shared_memory::segment_manager> + shmem_allocator_t; + + //Alias deque types + typedef deque<IntType, shmem_allocator_t> MyShmDeque; + typedef std::deque<int> MyStdDeque; + const int Memsize = 65536; + const char *const shMemName = test::get_process_id_name(); + const int max = 100; + + /*try*/{ + shared_memory_object::remove(shMemName); + + //Create shared memory + my_managed_shared_memory segment(create_only, shMemName, Memsize); + + segment.reserve_named_objects(100); + + //Shared memory allocator must be always be initialized + //since it has no default constructor + MyShmDeque *shmdeque = segment.template construct<MyShmDeque>("MyShmDeque") + (segment.get_segment_manager()); + + MyStdDeque *stddeque = new MyStdDeque; + + /*try*/{ + //Compare several shared memory deque operations with std::deque + for(int i = 0; i < max*50; ++i){ + IntType move_me(i); + shmdeque->insert(shmdeque->end(), boost::move(move_me)); + stddeque->insert(stddeque->end(), i); + shmdeque->insert(shmdeque->end(), IntType(i)); + stddeque->insert(stddeque->end(), int(i)); + } + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + shmdeque->clear(); + stddeque->clear(); + + for(int i = 0; i < max*50; ++i){ + IntType move_me(i); + shmdeque->push_back(boost::move(move_me)); + stddeque->push_back(i); + shmdeque->push_back(IntType(i)); + stddeque->push_back(i); + } + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + shmdeque->clear(); + stddeque->clear(); + + for(int i = 0; i < max*50; ++i){ + IntType move_me(i); + shmdeque->push_front(boost::move(move_me)); + stddeque->push_front(i); + shmdeque->push_front(IntType(i)); + stddeque->push_front(int(i)); + } + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + typename MyShmDeque::iterator it; + typename MyShmDeque::const_iterator cit = it; + (void)cit; + + shmdeque->erase(shmdeque->begin()++); + stddeque->erase(stddeque->begin()++); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + shmdeque->erase(shmdeque->begin()); + stddeque->erase(stddeque->begin()); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + { + //Initialize values + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me (-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + + shmdeque->insert(shmdeque->end() + ,::boost::make_move_iterator(&aux_vect[0]) + ,::boost::make_move_iterator(aux_vect + 50)); + stddeque->insert(stddeque->end(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + for(int i = 0, j = static_cast<int>(shmdeque->size()); i < j; ++i){ + shmdeque->erase(shmdeque->begin()); + stddeque->erase(stddeque->begin()); + } + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + } + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + shmdeque->insert(shmdeque->begin() + ,::boost::make_move_iterator(&aux_vect[0]) + ,::boost::make_move_iterator(aux_vect + 50)); + stddeque->insert(stddeque->begin(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + } + + if(!copyable_only(shmdeque, stddeque + ,ipcdetail::bool_<!ipcdetail::is_same<IntType, test::movable_int>::value>())){ + return false; + } + + shmdeque->erase(shmdeque->begin()); + stddeque->erase(stddeque->begin()); + + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + for(int i = 0; i < max; ++i){ + IntType move_me(i); + shmdeque->insert(shmdeque->begin(), boost::move(move_me)); + stddeque->insert(stddeque->begin(), i); + } + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + //Test insertion from list + { + std::list<int> l(50, int(1)); + shmdeque->insert(shmdeque->begin(), l.begin(), l.end()); + stddeque->insert(stddeque->begin(), l.begin(), l.end()); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + shmdeque->assign(l.begin(), l.end()); + stddeque->assign(l.begin(), l.end()); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + } + + shmdeque->resize(100); + stddeque->resize(100); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + + shmdeque->resize(200); + stddeque->resize(200); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + + segment.template destroy<MyShmDeque>("MyShmDeque"); + delete stddeque; + segment.shrink_to_fit_indexes(); + + if(!segment.all_memory_deallocated()) + return false; + }/* + catch(std::exception &ex){ + std::cout << ex.what() << std::endl; + return false; + }*/ + + std::cout << std::endl << "Test OK!" << std::endl; + }/* + catch(...){ + shared_memory_object::remove(shMemName); + throw; + }*/ + shared_memory_object::remove(shMemName); + return true; +} + +int main () +{ + if(!do_test<int, allocator>()) + return 1; + + if(!do_test<test::movable_int, allocator>()) + return 1; + + if(!do_test<test::copyable_int, allocator>()) + return 1; + + if(!do_test<int, test::allocator_v1>()) + return 1; + + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_FRONT | test::EMPLACE_BEFORE); + + if(!boost::interprocess::test::test_emplace + < deque<test::EmplaceInt>, Options>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/dummy_test_allocator.hpp b/src/boost/libs/interprocess/test/dummy_test_allocator.hpp new file mode 100644 index 00000000..42e5403e --- /dev/null +++ b/src/boost/libs/interprocess/test/dummy_test_allocator.hpp @@ -0,0 +1,149 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DUMMY_TEST_ALLOCATOR_HPP +#define BOOST_INTERPROCESS_DUMMY_TEST_ALLOCATOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#include <boost/interprocess/interprocess_fwd.hpp> +#include <boost/interprocess/containers/allocation_type.hpp> +#include <boost/interprocess/detail/utilities.hpp> +#include <boost/interprocess/containers/version_type.hpp> +#include <boost/interprocess/exceptions.hpp> +#include <cstddef> + +//!\file +//!Describes an allocator to test expand capabilities + +namespace boost { +namespace interprocess { +namespace test { + +//This allocator just allows two allocations. The first one will return +//mp_buffer + m_offset configured in the constructor. The second one +//will return mp_buffer. +template<class T> +class dummy_test_allocator +{ + private: + typedef dummy_test_allocator<T> self_t; + typedef void * aux_pointer_t; + typedef const void * cvoid_ptr; + + template<class T2> + dummy_test_allocator& operator=(const dummy_test_allocator<T2>&); + + dummy_test_allocator& operator=(const dummy_test_allocator&); + + public: + typedef T value_type; + typedef T * pointer; + typedef const T * const_pointer; + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + +// typedef boost::interprocess::version_type<dummy_test_allocator, 2> version; + + template<class T2> + struct rebind + { typedef dummy_test_allocator<T2> other; }; + + //!Default constructor. Never throws + dummy_test_allocator() + {} + + //!Constructor from other dummy_test_allocator. Never throws + dummy_test_allocator(const dummy_test_allocator &) + {} + + //!Constructor from related dummy_test_allocator. Never throws + template<class T2> + dummy_test_allocator(const dummy_test_allocator<T2> &) + {} + + pointer address(reference value) + { return pointer(addressof(value)); } + + const_pointer address(const_reference value) const + { return const_pointer(addressof(value)); } + + pointer allocate(size_type, cvoid_ptr = 0) + { return 0; } + + void deallocate(const pointer &, size_type) + { } + + template<class Convertible> + void construct(pointer, const Convertible &) + {} + + void destroy(pointer) + {} + + size_type max_size() const + { return 0; } + + friend void swap(self_t &, self_t &) + {} + + //Experimental version 2 dummy_test_allocator functions + + pointer allocation_command(boost::interprocess::allocation_type, + size_type, size_type &, pointer &) + { return pointer(); } + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. + size_type size(const pointer &) const + { return 0; } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one() + { return pointer(); } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &) + {} +}; + +//!Equality test for same type of dummy_test_allocator +template<class T> inline +bool operator==(const dummy_test_allocator<T> &, + const dummy_test_allocator<T> &) +{ return false; } + +//!Inequality test for same type of dummy_test_allocator +template<class T> inline +bool operator!=(const dummy_test_allocator<T> &, + const dummy_test_allocator<T> &) +{ return true; } + +} //namespace test { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_DUMMY_TEST_ALLOCATOR_HPP + diff --git a/src/boost/libs/interprocess/test/emplace_test.hpp b/src/boost/libs/interprocess/test/emplace_test.hpp new file mode 100644 index 00000000..71cb2882 --- /dev/null +++ b/src/boost/libs/interprocess/test/emplace_test.hpp @@ -0,0 +1,627 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTERPROCESS_TEST_EMPLACE_TEST_HPP +#define BOOST_INTERPROCESS_TEST_EMPLACE_TEST_HPP + +#include <iostream> +#include <typeinfo> +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/detail/mpl.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/interprocess/detail/utilities.hpp> +#include <boost/move/detail/type_traits.hpp> //make_unsigned, alignment_of + +namespace boost{ +namespace interprocess{ +namespace test{ + +class EmplaceInt +{ + private: + BOOST_MOVABLE_BUT_NOT_COPYABLE(EmplaceInt) + + public: + EmplaceInt() + : a_(0), b_(0), c_(0), d_(0), e_(0) + {} + EmplaceInt(int a, int b = 0, int c = 0, int d = 0, int e = 0) + : a_(a), b_(b), c_(c), d_(d), e_(e) + {} + + EmplaceInt(BOOST_RV_REF(EmplaceInt) o) + : a_(o.a_), b_(o.b_), c_(o.c_), d_(o.d_), e_(o.e_) + {} + + EmplaceInt& operator=(BOOST_RV_REF(EmplaceInt) o) + { + this->a_ = o.a_; + this->b_ = o.b_; + this->c_ = o.c_; + this->d_ = o.d_; + this->e_ = o.e_; + return *this; + } + + friend bool operator==(const EmplaceInt &l, const EmplaceInt &r) + { + return l.a_ == r.a_ && + l.b_ == r.b_ && + l.c_ == r.c_ && + l.d_ == r.d_ && + l.e_ == r.e_; + } + + friend bool operator<(const EmplaceInt &l, const EmplaceInt &r) + { return l.sum() < r.sum(); } + + friend bool operator>(const EmplaceInt &l, const EmplaceInt &r) + { return l.sum() > r.sum(); } + + friend bool operator!=(const EmplaceInt &l, const EmplaceInt &r) + { return !(l == r); } + + friend std::ostream &operator <<(std::ostream &os, const EmplaceInt &v) + { + os << "EmplaceInt: " << v.a_ << ' ' << v.b_ << ' ' << v.c_ << ' ' << v.d_ << ' ' << v.e_; + return os; + } + + //private: + int sum() const + { return this->a_ + this->b_ + this->c_ + this->d_ + this->e_; } + + int a_, b_, c_, d_, e_; + int padding[6]; +}; + + +} //namespace test { + +namespace test { + +enum EmplaceOptions{ + EMPLACE_BACK = 1 << 0, + EMPLACE_FRONT = 1 << 1, + EMPLACE_BEFORE = 1 << 2, + EMPLACE_AFTER = 1 << 3, + EMPLACE_ASSOC = 1 << 4, + EMPLACE_HINT = 1 << 5, + EMPLACE_ASSOC_PAIR = 1 << 6, + EMPLACE_HINT_PAIR = 1 << 7 +}; + +template<class Container> +bool test_expected_container(const Container &ec, const EmplaceInt *Expected, unsigned int only_first_n) +{ + typedef typename Container::const_iterator const_iterator; + const_iterator itb(ec.begin()), ite(ec.end()); + unsigned int cur = 0; + if(only_first_n > ec.size()){ + return false; + } + for(; itb != ite && only_first_n--; ++itb, ++cur){ + const EmplaceInt & cr = *itb; + if(cr != Expected[cur]){ + return false; + } + } + return true; +} + +template<class Container> +bool test_expected_container(const Container &ec, const std::pair<EmplaceInt, EmplaceInt> *Expected, unsigned int only_first_n) +{ + typedef typename Container::const_iterator const_iterator; + const_iterator itb(ec.begin()), ite(ec.end()); + unsigned int cur = 0; + if(only_first_n > ec.size()){ + return false; + } + for(; itb != ite && only_first_n--; ++itb, ++cur){ + if(itb->first != Expected[cur].first){ + std::cout << "Error in first: " << itb->first << ' ' << Expected[cur].first << std::endl; + return false; + + } + else if(itb->second != Expected[cur].second){ + std::cout << "Error in second: " << itb->second << ' ' << Expected[cur].second << std::endl; + return false; + } + } + return true; +} + +static EmplaceInt expected [10]; + +typedef std::pair<EmplaceInt, EmplaceInt> EmplaceIntPair; +static boost::container::dtl::aligned_storage<sizeof(EmplaceIntPair)*10>::type pair_storage; + +static EmplaceIntPair* initialize_emplace_int_pair() +{ + EmplaceIntPair* ret = reinterpret_cast<EmplaceIntPair*>(&pair_storage); + for(unsigned int i = 0; i != 10; ++i){ + new(&ret->first)EmplaceInt(); + new(&ret->second)EmplaceInt(); + } + return ret; +} + +static EmplaceIntPair * expected_pair = initialize_emplace_int_pair(); + + +template<class Container> +bool test_emplace_back(ipcdetail::true_) +{ + std::cout << "Starting test_emplace_back." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + Container c; + c.emplace_back(); + if(!test_expected_container(c, &expected[0], 1)) + return false; + c.emplace_back(1); + if(!test_expected_container(c, &expected[0], 2)) + return false; + c.emplace_back(1, 2); + if(!test_expected_container(c, &expected[0], 3)) + return false; + c.emplace_back(1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)) + return false; + c.emplace_back(1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)) + return false; + c.emplace_back(1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)) + return false; + } + + return true; +} + +template<class Container> +bool test_emplace_back(ipcdetail::false_) +{ return true; } + +template<class Container> +bool test_emplace_front(ipcdetail::true_) +{ + std::cout << "Starting test_emplace_front." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + { + new(&expected [0]) EmplaceInt(1, 2, 3, 4, 5); + new(&expected [1]) EmplaceInt(1, 2, 3, 4); + new(&expected [2]) EmplaceInt(1, 2, 3); + new(&expected [3]) EmplaceInt(1, 2); + new(&expected [4]) EmplaceInt(1); + new(&expected [5]) EmplaceInt(); + Container c; + c.emplace_front(); + if(!test_expected_container(c, &expected[0] + 5, 1)) + return false; + c.emplace_front(1); + if(!test_expected_container(c, &expected[0] + 4, 2)) + return false; + c.emplace_front(1, 2); + if(!test_expected_container(c, &expected[0] + 3, 3)) + return false; + c.emplace_front(1, 2, 3); + if(!test_expected_container(c, &expected[0] + 2, 4)) + return false; + c.emplace_front(1, 2, 3, 4); + if(!test_expected_container(c, &expected[0] + 1, 5)) + return false; + c.emplace_front(1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0] + 0, 6)) + return false; + } + return true; +} + +template<class Container> +bool test_emplace_front(ipcdetail::false_) +{ return true; } + +template<class Container> +bool test_emplace_before(ipcdetail::true_) +{ + std::cout << "Starting test_emplace_before." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(); + Container c; + c.emplace(c.cend(), 1); + c.emplace(c.cbegin()); + if(!test_expected_container(c, &expected[0], 2)) + return false; + c.emplace(c.cend()); + if(!test_expected_container(c, &expected[0], 3)) + return false; + } + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + //emplace_front-like + Container c; + c.emplace(c.cbegin(), 1, 2, 3, 4, 5); + c.emplace(c.cbegin(), 1, 2, 3, 4); + c.emplace(c.cbegin(), 1, 2, 3); + c.emplace(c.cbegin(), 1, 2); + c.emplace(c.cbegin(), 1); + c.emplace(c.cbegin()); + if(!test_expected_container(c, &expected[0], 6)) + return false; + c.clear(); + //emplace_back-like + typename Container::const_iterator i = c.emplace(c.cend()); + if(!test_expected_container(c, &expected[0], 1)) + return false; + i = c.emplace(++i, 1); + if(!test_expected_container(c, &expected[0], 2)) + return false; + i = c.emplace(++i, 1, 2); + if(!test_expected_container(c, &expected[0], 3)) + return false; + i = c.emplace(++i, 1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)) + return false; + i = c.emplace(++i, 1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)) + return false; + i = c.emplace(++i, 1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)) + return false; + c.clear(); + //emplace in the middle + c.emplace(c.cbegin()); + i = c.emplace(c.cend(), 1, 2, 3, 4, 5); + i = c.emplace(i, 1, 2, 3, 4); + i = c.emplace(i, 1, 2, 3); + i = c.emplace(i, 1, 2); + i = c.emplace(i, 1); + + if(!test_expected_container(c, &expected[0], 6)) + return false; + } + return true; +} + +template<class Container> +bool test_emplace_before(ipcdetail::false_) +{ return true; } + +template<class Container> +bool test_emplace_after(ipcdetail::true_) +{ + std::cout << "Starting test_emplace_after." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(); + Container c; + typename Container::const_iterator i = c.emplace_after(c.cbefore_begin(), 1); + c.emplace_after(c.cbefore_begin()); + if(!test_expected_container(c, &expected[0], 2)) + return false; + c.emplace_after(i); + if(!test_expected_container(c, &expected[0], 3)) + return false; + } + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + //emplace_front-like + Container c; + c.emplace_after(c.cbefore_begin(), 1, 2, 3, 4, 5); + c.emplace_after(c.cbefore_begin(), 1, 2, 3, 4); + c.emplace_after(c.cbefore_begin(), 1, 2, 3); + c.emplace_after(c.cbefore_begin(), 1, 2); + c.emplace_after(c.cbefore_begin(), 1); + c.emplace_after(c.cbefore_begin()); + if(!test_expected_container(c, &expected[0], 6)) + return false; + c.clear(); + //emplace_back-like + typename Container::const_iterator i = c.emplace_after(c.cbefore_begin()); + if(!test_expected_container(c, &expected[0], 1)) + return false; + i = c.emplace_after(i, 1); + if(!test_expected_container(c, &expected[0], 2)) + return false; + i = c.emplace_after(i, 1, 2); + if(!test_expected_container(c, &expected[0], 3)) + return false; + i = c.emplace_after(i, 1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)) + return false; + i = c.emplace_after(i, 1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)) + return false; + i = c.emplace_after(i, 1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)) + return false; + c.clear(); + //emplace_after in the middle + i = c.emplace_after(c.cbefore_begin()); + c.emplace_after(i, 1, 2, 3, 4, 5); + c.emplace_after(i, 1, 2, 3, 4); + c.emplace_after(i, 1, 2, 3); + c.emplace_after(i, 1, 2); + c.emplace_after(i, 1); + + if(!test_expected_container(c, &expected[0], 6)) + return false; + } + return true; +} + +template<class Container> +bool test_emplace_after(ipcdetail::false_) +{ return true; } + +template<class Container> +bool test_emplace_assoc(ipcdetail::true_) +{ + std::cout << "Starting test_emplace_assoc." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + { + Container c; + c.emplace(); + if(!test_expected_container(c, &expected[0], 1)) + return false; + c.emplace(1); + if(!test_expected_container(c, &expected[0], 2)) + return false; + c.emplace(1, 2); + if(!test_expected_container(c, &expected[0], 3)) + return false; + c.emplace(1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)) + return false; + c.emplace(1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)) + return false; + c.emplace(1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)) + return false; + } + return true; +} + +template<class Container> +bool test_emplace_assoc(ipcdetail::false_) +{ return true; } + +template<class Container> +bool test_emplace_hint(ipcdetail::true_) +{ + std::cout << "Starting test_emplace_hint." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + + { + Container c; + typename Container::const_iterator it; + it = c.emplace_hint(c.begin()); + if(!test_expected_container(c, &expected[0], 1)) + return false; + it = c.emplace_hint(it, 1); + if(!test_expected_container(c, &expected[0], 2)) + return false; + it = c.emplace_hint(it, 1, 2); + if(!test_expected_container(c, &expected[0], 3)) + return false; + it = c.emplace_hint(it, 1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)) + return false; + it = c.emplace_hint(it, 1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)) + return false; + it = c.emplace_hint(it, 1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)) + return false; + } + + return true; +} + +template<class Container> +bool test_emplace_hint(ipcdetail::false_) +{ return true; } + +template<class Container> +bool test_emplace_assoc_pair(ipcdetail::true_) +{ + std::cout << "Starting test_emplace_assoc_pair." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + new(&expected_pair[0].first) EmplaceInt(); + new(&expected_pair[0].second) EmplaceInt(); + new(&expected_pair[1].first) EmplaceInt(1); + new(&expected_pair[1].second) EmplaceInt(); + new(&expected_pair[2].first) EmplaceInt(2); + new(&expected_pair[2].second) EmplaceInt(2); +// new(&expected_pair[3].first) EmplaceInt(3); +// new(&expected_pair[3].second) EmplaceInt(2, 3); +// new(&expected_pair[4].first) EmplaceInt(4); +// new(&expected_pair[4].second) EmplaceInt(2, 3, 4); +// new(&expected_pair[5].first) EmplaceInt(5); +// new(&expected_pair[5].second) EmplaceInt(2, 3, 4, 5); + { //piecewise construct missing + /* + Container c; + c.emplace(); + if(!test_expected_container(c, &expected_pair[0], 1)){ + std::cout << "Error after c.emplace();\n"; + return false; + } + c.emplace(1); + if(!test_expected_container(c, &expected_pair[0], 2)){ + std::cout << "Error after c.emplace(1);\n"; + return false; + } + c.emplace(2, 2); + if(!test_expected_container(c, &expected_pair[0], 3)){ + std::cout << "Error after c.emplace(2, 2);\n"; + return false; + } + c.emplace(3, 2, 3); + if(!test_expected_container(c, &expected_pair[0], 4)){ + std::cout << "Error after c.emplace(3, 2, 3);\n"; + return false; + } + c.emplace(4, 2, 3, 4); + if(!test_expected_container(c, &expected_pair[0], 5)){ + std::cout << "Error after c.emplace(4, 2, 3, 4);\n"; + return false; + } + c.emplace(5, 2, 3, 4, 5); + if(!test_expected_container(c, &expected_pair[0], 6)){ + std::cout << "Error after c.emplace(5, 2, 3, 4, 5);\n"; + return false; + }*/ + } + return true; +} + +template<class Container> +bool test_emplace_assoc_pair(ipcdetail::false_) +{ return true; } + +template<class Container> +bool test_emplace_hint_pair(ipcdetail::true_) +{ + std::cout << "Starting test_emplace_hint_pair." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + new(&expected_pair[0].first) EmplaceInt(); + new(&expected_pair[0].second) EmplaceInt(); + new(&expected_pair[1].first) EmplaceInt(1); + new(&expected_pair[1].second) EmplaceInt(); + new(&expected_pair[2].first) EmplaceInt(2); + new(&expected_pair[2].second) EmplaceInt(2);/* + new(&expected_pair[3].first) EmplaceInt(3); + new(&expected_pair[3].second) EmplaceInt(2, 3); + new(&expected_pair[4].first) EmplaceInt(4); + new(&expected_pair[4].second) EmplaceInt(2, 3, 4); + new(&expected_pair[5].first) EmplaceInt(5); + new(&expected_pair[5].second) EmplaceInt(2, 3, 4, 5);*/ + {/* + Container c; + typename Container::const_iterator it; + it = c.emplace_hint(c.begin()); + if(!test_expected_container(c, &expected_pair[0], 1)){ + std::cout << "Error after c.emplace(1);\n"; + return false; + } + it = c.emplace_hint(it, 1); + if(!test_expected_container(c, &expected_pair[0], 2)){ + std::cout << "Error after c.emplace(it, 1);\n"; + return false; + } + it = c.emplace_hint(it, 2, 2); + if(!test_expected_container(c, &expected_pair[0], 3)){ + std::cout << "Error after c.emplace(it, 2, 2);\n"; + return false; + } + it = c.emplace_hint(it, 3, 2, 3); + if(!test_expected_container(c, &expected_pair[0], 4)){ + std::cout << "Error after c.emplace(it, 3, 2, 3);\n"; + return false; + } + it = c.emplace_hint(it, 4, 2, 3, 4); + if(!test_expected_container(c, &expected_pair[0], 5)){ + std::cout << "Error after c.emplace(it, 4, 2, 3, 4);\n"; + return false; + } + it = c.emplace_hint(it, 5, 2, 3, 4, 5); + if(!test_expected_container(c, &expected_pair[0], 6)){ + std::cout << "Error after c.emplace(it, 5, 2, 3, 4, 5);\n"; + return false; + }*/ + } + return true; +} + +template<class Container> +bool test_emplace_hint_pair(ipcdetail::false_) +{ return true; } + +template <EmplaceOptions O, EmplaceOptions Mask> +struct emplace_active +{ + static const bool value = (0 != (O & Mask)); + typedef ipcdetail::bool_<value> type; + operator type() const{ return type(); } +}; + +template<class Container, EmplaceOptions O> +bool test_emplace() +{ + if(!test_emplace_back<Container>(emplace_active<O, EMPLACE_BACK>())) + return false; + if(!test_emplace_front<Container>(emplace_active<O, EMPLACE_FRONT>())) + return false; + if(!test_emplace_before<Container>(emplace_active<O, EMPLACE_BEFORE>())) + return false; + if(!test_emplace_after<Container>(emplace_active<O, EMPLACE_AFTER>())) + return false; + if(!test_emplace_assoc<Container>(emplace_active<O, EMPLACE_ASSOC>())) + return false; + if(!test_emplace_hint<Container>(emplace_active<O, EMPLACE_HINT>())) + return false; + if(!test_emplace_assoc_pair<Container>(emplace_active<O, EMPLACE_ASSOC_PAIR>())) + return false; + if(!test_emplace_hint_pair<Container>(emplace_active<O, EMPLACE_HINT_PAIR>())) + return false; + return true; +} + +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_TEST_EMPLACE_TEST_HPP diff --git a/src/boost/libs/interprocess/test/enable_shared_from_this_test.cpp b/src/boost/libs/interprocess/test/enable_shared_from_this_test.cpp new file mode 100644 index 00000000..342e0a7e --- /dev/null +++ b/src/boost/libs/interprocess/test/enable_shared_from_this_test.cpp @@ -0,0 +1,97 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, 2003 Peter Dimov +// +// This file is the adaptation of shared_from_this_test.cpp from smart_ptr library +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/smart_ptr/enable_shared_from_this.hpp> +#include <boost/interprocess/smart_ptr/shared_ptr.hpp> + +#include <boost/core/lightweight_test.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include "get_process_id_name.hpp" + +// + +using namespace boost::interprocess; + +typedef allocator<void, managed_shared_memory::segment_manager> + v_allocator_t; + +struct X; + +typedef deleter<X, managed_shared_memory::segment_manager> x_deleter_t; + +struct X : + public enable_shared_from_this<X, v_allocator_t, x_deleter_t> +{ +}; + +typedef shared_ptr<X, v_allocator_t, x_deleter_t> v_shared_ptr; + + +template<class ManagedMemory> +void test_enable_shared_this(ManagedMemory &managed_mem) +{ + v_shared_ptr p(make_managed_shared_ptr + (managed_mem.template construct<X>(anonymous_instance)(), managed_mem)); + + v_shared_ptr q = p->shared_from_this(); + BOOST_TEST(p == q); + BOOST_TEST(!(p < q) && !(q < p)); + + X v2(*p); + + try + { + //This should throw bad_weak_ptr + v_shared_ptr r = v2.shared_from_this(); + BOOST_ERROR("v2.shared_from_this() failed to throw"); + } + catch(boost::interprocess::bad_weak_ptr const &) + { + //This is the expected path + } + catch(...){ + BOOST_ERROR("v2.shared_from_this() threw an unexpected exception"); + } + + try + { + //This should not throw bad_weak_ptr + *p = X(); + v_shared_ptr r = p->shared_from_this(); + BOOST_TEST(p == r); + BOOST_TEST(!(p < r) && !(r < p)); + } + catch(boost::interprocess::bad_weak_ptr const &) + { + BOOST_ERROR("p->shared_from_this() threw bad_weak_ptr after *p = X()"); + } + catch(...) + { + BOOST_ERROR("p->shared_from_this() threw an unexpected exception after *p = X()"); + } +} + + +int main() +{ + std::string process_name; + test::get_process_id_name(process_name); + shared_memory_object::remove(process_name.c_str()); + managed_shared_memory shmem(create_only, process_name.c_str(), 65536); + test_enable_shared_this(shmem); + shared_memory_object::remove(process_name.c_str()); + return boost::report_errors(); +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/expand_bwd_test_allocator.hpp b/src/boost/libs/interprocess/test/expand_bwd_test_allocator.hpp new file mode 100644 index 00000000..7124c574 --- /dev/null +++ b/src/boost/libs/interprocess/test/expand_bwd_test_allocator.hpp @@ -0,0 +1,193 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_EXPAND_BWD_TEST_ALLOCATOR_HPP +#define BOOST_INTERPROCESS_EXPAND_BWD_TEST_ALLOCATOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#include <boost/interprocess/interprocess_fwd.hpp> +#include <boost/interprocess/containers/allocation_type.hpp> +#include <boost/assert.hpp> +#include <boost/interprocess/detail/utilities.hpp> +#include <boost/interprocess/containers/version_type.hpp> +#include <boost/interprocess/exceptions.hpp> +#include <boost/move/adl_move_swap.hpp> +#include <memory> +#include <cstddef> +#include <cassert> +#include <new> + +//!\file +//!Describes an allocator to test expand capabilities + +namespace boost { +namespace interprocess { +namespace test { + +//This allocator just allows two allocations. The first one will return +//mp_buffer + m_offset configured in the constructor. The second one +//will return mp_buffer. +template<class T> +class expand_bwd_test_allocator +{ + private: + typedef expand_bwd_test_allocator<T> self_t; + typedef void * aux_pointer_t; + typedef const void * cvoid_ptr; + + template<class T2> + expand_bwd_test_allocator& operator=(const expand_bwd_test_allocator<T2>&); + + expand_bwd_test_allocator& operator=(const expand_bwd_test_allocator&); + + public: + typedef T value_type; + typedef T * pointer; + typedef const T * const_pointer; + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef boost::interprocess::version_type<expand_bwd_test_allocator, 2> version; + + //Dummy multiallocation chain + struct multiallocation_chain{}; + + template<class T2> + struct rebind + { typedef expand_bwd_test_allocator<T2> other; }; + + //!Constructor from the segment manager. Never throws + expand_bwd_test_allocator(T *buf, size_type sz, difference_type offset) + : mp_buffer(buf), m_size(sz) + , m_offset(offset), m_allocations(0){ } + + //!Constructor from other expand_bwd_test_allocator. Never throws + expand_bwd_test_allocator(const expand_bwd_test_allocator &other) + : mp_buffer(other.mp_buffer), m_size(other.m_size) + , m_offset(other.m_offset), m_allocations(0){ } + + //!Constructor from related expand_bwd_test_allocator. Never throws + template<class T2> + expand_bwd_test_allocator(const expand_bwd_test_allocator<T2> &other) + : mp_buffer(other.mp_buffer), m_size(other.m_size) + , m_offset(other.m_offset), m_allocations(0){ } + + pointer address(reference value) + { return pointer(addressof(value)); } + + const_pointer address(const_reference value) const + { return const_pointer(addressof(value)); } + + pointer allocate(size_type , cvoid_ptr hint = 0) + { (void)hint; return 0; } + + void deallocate(const pointer &, size_type) + {} + + template<class Convertible> + void construct(pointer ptr, const Convertible &value) + { new((void*)ptr) value_type(value); } + + void destroy(pointer ptr) + { (*ptr).~value_type(); } + + size_type max_size() const + { return m_size; } + + friend void swap(self_t &alloc1, self_t &alloc2) + { + ::boost::adl_move_swap(alloc1.mp_buffer, alloc2.mp_buffer); + ::boost::adl_move_swap(alloc1.m_size, alloc2.m_size); + ::boost::adl_move_swap(alloc1.m_offset, alloc2.m_offset); + } + + //Experimental version 2 expand_bwd_test_allocator functions + + pointer allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse) + { + (void)reuse; (void)command; + //This allocator only expands backwards! + assert(m_allocations == 0 || (command & boost::interprocess::expand_bwd)); + prefer_in_recvd_out_size = limit_size; + + if(m_allocations == 0){ + if((m_offset + limit_size) > m_size){ + assert(0); + } + ++m_allocations; + return mp_buffer + m_offset; + } + else if(m_allocations == 1){ + if(limit_size > m_size){ + assert(0); + } + ++m_allocations; + return mp_buffer; + } + else{ + assert(0); + throw std::bad_alloc(); + } + } + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. + size_type size(const pointer &p) const + { (void)p; return m_size; } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one() + { return this->allocate(1); } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p) + { return this->deallocate(p, 1); } + + pointer mp_buffer; + size_type m_size; + difference_type m_offset; + char m_allocations; +}; + +//!Equality test for same type of expand_bwd_test_allocator +template<class T> inline +bool operator==(const expand_bwd_test_allocator<T> &, + const expand_bwd_test_allocator<T> &) +{ return false; } + +//!Inequality test for same type of expand_bwd_test_allocator +template<class T> inline +bool operator!=(const expand_bwd_test_allocator<T> &, + const expand_bwd_test_allocator<T> &) +{ return true; } + +} //namespace test { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_EXPAND_BWD_TEST_ALLOCATOR_HPP + diff --git a/src/boost/libs/interprocess/test/expand_bwd_test_template.hpp b/src/boost/libs/interprocess/test/expand_bwd_test_template.hpp new file mode 100644 index 00000000..91d1146b --- /dev/null +++ b/src/boost/libs/interprocess/test/expand_bwd_test_template.hpp @@ -0,0 +1,269 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_ALLOCATION_TEST_TEMPLATE_HEADER +#define BOOST_INTERPROCESS_TEST_ALLOCATION_TEST_TEMPLATE_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include "expand_bwd_test_allocator.hpp" +#include <boost/interprocess/detail/type_traits.hpp> +#include <algorithm> //std::equal +#include <vector> +#include <iostream> + +namespace boost { namespace interprocess { namespace test { + +template<class T> +struct value_holder +{ + value_holder(T val) : m_value(val){} + value_holder(): m_value(0){} + ~value_holder(){ m_value = 0; } + bool operator == (const value_holder &other) const + { return m_value == other.m_value; } + bool operator != (const value_holder &other) const + { return m_value != other.m_value; } + + T m_value; +}; + +template<class T> +struct triple_value_holder +{ + triple_value_holder(T val) + : m_value1(val) + , m_value2(val) + , m_value3(val) + {} + + triple_value_holder() + : m_value1(0) + , m_value2(0) + , m_value3(0) + {} + + ~triple_value_holder() + { m_value1 = m_value2 = m_value3 = 0; } + + bool operator == (const triple_value_holder &other) const + { + return m_value1 == other.m_value1 + && m_value2 == other.m_value2 + && m_value3 == other.m_value3; + } + + bool operator != (const triple_value_holder &other) const + { + return m_value1 != other.m_value1 + || m_value2 != other.m_value2 + || m_value3 != other.m_value3; + } + + T m_value1; + T m_value2; + T m_value3; +}; + +typedef value_holder<int> int_holder; +typedef triple_value_holder<int> triple_int_holder; + + + +//Function to check if both sets are equal +template <class Vector1, class Vector2> +bool CheckEqualVector(const Vector1 &vector1, const Vector2 &vector2) +{ + if(vector1.size() != vector2.size()) + return false; + return std::equal(vector1.begin(), vector1.end(), vector2.begin()); +} + +template<class Vector> +bool CheckUninitializedIsZero(const Vector & v) +{ + typedef typename Vector::value_type value_type; + typename Vector::size_type sz = v.size(); + typename Vector::size_type extra = v.capacity() - v.size(); + value_type comp(0); + + const value_type *holder = &v[0] + sz; + + while(extra--){ + if(*holder++ != comp) + return false; + } + return true; +} + + +//This function tests all the possible combinations when +//inserting data in a vector and expanding backwards +template<class VectorWithExpandBwdAllocator> +bool test_insert_with_expand_bwd() +{ + typedef typename VectorWithExpandBwdAllocator::value_type value_type; + typedef typename boost::interprocess::ipcdetail::remove_volatile<value_type>::type non_volatile_value_type; + typedef std::vector<non_volatile_value_type> Vect; + const int MemorySize = 1000; + + //Distance old and new buffer + const int Offset[] = + { 350, 250, 150, 150, + 150, 50, 50, 50 }; + //Insert position + const int Position[] = + { 100, 100, 100, 100, + 100, 100, 100, 100 }; + //Initial vector size + const int InitialSize[] = + { 200, 200, 200, 200, + 200, 200, 200, 200 }; + //Size of the data to insert + const int InsertSize[] = + { 100, 100, 100, 200, + 300, 25, 100, 200 }; + //Number of tests + const int Iterations = sizeof(InsertSize)/sizeof(int); + + for(int iteration = 0; iteration < Iterations; ++iteration) + { + value_type *memory = new value_type[MemorySize]; + try { + std::vector<non_volatile_value_type> initial_data; + initial_data.resize(InitialSize[iteration]); + for(int i = 0; i < InitialSize[iteration]; ++i){ + initial_data[i] = i; + } + + Vect data_to_insert; + data_to_insert.resize(InsertSize[iteration]); + for(int i = 0; i < InsertSize[iteration]; ++i){ + data_to_insert[i] = -i; + } + + expand_bwd_test_allocator<value_type> alloc + (&memory[0], MemorySize, Offset[iteration]); + VectorWithExpandBwdAllocator vector(alloc); + vector.insert( vector.begin() + , initial_data.begin(), initial_data.end()); + vector.insert( vector.begin() + Position[iteration] + , data_to_insert.begin(), data_to_insert.end()); + initial_data.insert(initial_data.begin() + Position[iteration] + , data_to_insert.begin(), data_to_insert.end()); + //Now check that values are equal + if(!CheckEqualVector(vector, initial_data)){ + std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl + << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl + << " Iteration: " << iteration << std::endl; + return false; + } + } + catch(...){ + delete [](const_cast<non_volatile_value_type*>(memory)); + throw; + } + delete [](const_cast<non_volatile_value_type*>(memory)); + } + + return true; +} + +//This function tests all the possible combinations when +//inserting data in a vector and expanding backwards +template<class VectorWithExpandBwdAllocator> +bool test_assign_with_expand_bwd() +{ + typedef typename VectorWithExpandBwdAllocator::value_type value_type; + typedef typename boost::interprocess::ipcdetail::remove_volatile<value_type>::type non_volatile_value_type; + const int MemorySize = 200; + + const int Offset[] = { 50, 50, 50}; + const int InitialSize[] = { 25, 25, 25}; + const int InsertSize[] = { 15, 35, 55}; + const int Iterations = sizeof(InsertSize)/sizeof(int); + + for(int iteration = 0; iteration <Iterations; ++iteration) + { + value_type *memory = new value_type[MemorySize]; + try { + //Create initial data + std::vector<non_volatile_value_type> initial_data; + initial_data.resize(InitialSize[iteration]); + for(int i = 0; i < InitialSize[iteration]; ++i){ + initial_data[i] = i; + } + + //Create data to insert + std::vector<non_volatile_value_type> data_to_insert; + data_to_insert.resize(InsertSize[iteration]); + for(int i = 0; i < InsertSize[iteration]; ++i){ + data_to_insert[i] = -i; + } + + //Insert initial data to the vector to test + expand_bwd_test_allocator<value_type> alloc + (&memory[0], MemorySize, Offset[iteration]); + VectorWithExpandBwdAllocator vector(alloc); + vector.insert( vector.begin() + , initial_data.begin(), initial_data.end()); + + //Insert data + vector.insert(vector.cbegin(), data_to_insert.begin(), data_to_insert.end()); + initial_data.insert(initial_data.begin(), data_to_insert.begin(), data_to_insert.end()); + + //Now check that values are equal + if(!CheckEqualVector(vector, initial_data)){ + std::cout << "test_insert_with_expand_bwd::CheckEqualVector failed." << std::endl + << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl + << " Iteration: " << iteration << std::endl; + return false; + } + } + catch(...){ + delete [](const_cast<typename boost::interprocess::ipcdetail::remove_volatile<value_type>::type*>(memory)); + throw; + } + delete [](const_cast<typename boost::interprocess::ipcdetail::remove_volatile<value_type>::type*>(memory)); + } + + return true; +} + +//This function calls all tests +template<class VectorWithExpandBwdAllocator> +bool test_all_expand_bwd() +{ + std::cout << "Starting test_insert_with_expand_bwd." << std::endl << " Class: " + << typeid(VectorWithExpandBwdAllocator).name() << std::endl; + + if(!test_insert_with_expand_bwd<VectorWithExpandBwdAllocator>()){ + std::cout << "test_allocation_direct_deallocation failed. Class: " + << typeid(VectorWithExpandBwdAllocator).name() << std::endl; + return false; + } + + std::cout << "Starting test_assign_with_expand_bwd." << std::endl << " Class: " + << typeid(VectorWithExpandBwdAllocator).name() << std::endl; + + if(!test_assign_with_expand_bwd<VectorWithExpandBwdAllocator>()){ + std::cout << "test_allocation_direct_deallocation failed. Class: " + << typeid(VectorWithExpandBwdAllocator).name() << std::endl; + return false; + } + + return true; +} + +}}} //namespace boost { namespace interprocess { namespace test { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_TEST_ALLOCATION_TEST_TEMPLATE_HEADER + diff --git a/src/boost/libs/interprocess/test/file_lock_test.cpp b/src/boost/libs/interprocess/test/file_lock_test.cpp new file mode 100644 index 00000000..6dcfd926 --- /dev/null +++ b/src/boost/libs/interprocess/test/file_lock_test.cpp @@ -0,0 +1,80 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/sync/file_lock.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/interprocess/file_mapping.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include "mutex_test_template.hpp" +#include "sharable_mutex_test_template.hpp" +#include "get_process_id_name.hpp" +#include <fstream> +#include <cstdio> //std::remove + +using namespace boost::interprocess; + +inline std::string get_filename() +{ + std::string ret (ipcdetail::get_temporary_path()); + ret += "/"; + ret += test::get_process_id_name(); + return ret; +} + +//This wrapper is necessary to have a default constructor +//in generic mutex_test_template functions +class file_lock_lock_test_wrapper + : public boost::interprocess::file_lock +{ + public: + file_lock_lock_test_wrapper() + : boost::interprocess::file_lock(get_filename().c_str()) + {} +}; + +int main () +{ + //Destroy and create file + { + std::remove(get_filename().c_str()); + std::ofstream file(get_filename().c_str()); + if(!file){ + return 1; + } + file_lock flock(get_filename().c_str()); + { + scoped_lock<file_lock> sl(flock); + } + { + scoped_lock<file_lock> sl(flock, try_to_lock); + } + { + scoped_lock<file_lock> sl(flock, test::delay(1)); + } + } + { + //Now test move semantics + file_lock mapping(get_filename().c_str()); + file_lock move_ctor(boost::move(mapping)); + file_lock move_assign; + move_assign = boost::move(move_ctor); + mapping.swap(move_assign); + } + + //test::test_all_lock<file_lock_lock_test_wrapper>(); + //test::test_all_mutex<file_lock_lock_test_wrapper>(); + //test::test_all_sharable_mutex<file_lock_lock_test_wrapper>(); + std::remove(get_filename().c_str()); + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/file_mapping_test.cpp b/src/boost/libs/interprocess/test/file_mapping_test.cpp new file mode 100644 index 00000000..c3ce1614 --- /dev/null +++ b/src/boost/libs/interprocess/test/file_mapping_test.cpp @@ -0,0 +1,164 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <ios> //std::streamoff +#include <fstream> //std::ofstream, std::ifstream +#include <iostream> +#include <boost/interprocess/file_mapping.hpp> +#include <boost/interprocess/mapped_region.hpp> +#include <boost/container/vector.hpp> +#include <stdexcept> //std::exception +#include <cstddef> //std::size_t +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +inline std::string get_filename() +{ + std::string ret (ipcdetail::get_temporary_path()); + ret += "/"; + ret += test::get_process_id_name(); + return ret; +} + +file_mapping get_file_mapping() +{ + file_mapping f; + return file_mapping(boost::move(f)); +} + +int main () +{ + try{ + const std::size_t FileSize = 99999*2; + { + //Create file with given size + std::ofstream file(get_filename().c_str(), std::ios::binary | std::ios::trunc); + file.seekp(static_cast<std::streamoff>(FileSize-1)); + file.write("", 1); + } + + { + //Create a file mapping + file_mapping mapping(get_filename().c_str(), read_write); + //Create two mapped regions, one half of the file each + mapped_region region (mapping + ,read_write + ,0 + ,FileSize/2 + ); + + mapped_region region2(mapping + ,read_write + ,FileSize/2 + ,FileSize - FileSize/2 + ); + + //Fill two regions with a pattern + unsigned char *filler = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + *filler++ = static_cast<unsigned char>(i); + } + + filler = static_cast<unsigned char*>(region2.get_address()); + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + *filler++ = static_cast<unsigned char>(i); + } + if(!region.flush(0, 0, false)){ + return 1; + } + + if(!region2.flush(0, 0, true)){ + return 1; + } + } + + //See if the pattern is correct in the file + { + //Open the file + std::ifstream file(get_filename().c_str(), std::ios::binary); + + //Create a memory buffer + boost::container::vector<unsigned char> memory(FileSize/2 +1); + + //Fill buffer + file.read(static_cast<char*>(static_cast<void*>(memory.data())) + , FileSize/2); + + unsigned char *checker = memory.data(); + //Check pattern + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + if(*checker++ != static_cast<unsigned char>(i)){ + return 1; + } + } + + //Fill buffer + file.read(static_cast<char*>(static_cast<void*>(memory.data())) + , FileSize - FileSize/2); + + checker = memory.data(); + //Check pattern + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + if(*checker++ != static_cast<unsigned char>(i)){ + return 1; + } + } + } + + //Now check the pattern mapping a single read only mapped_region + { + //Create a file mapping + file_mapping mapping(get_filename().c_str(), read_only); + + //Create a single regions, mapping all the file + mapped_region region (mapping + ,read_only + ); + + //Check pattern + unsigned char *pattern = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + if(*pattern != static_cast<unsigned char>(i)){ + return 1; + } + } + } + { + //Now test move semantics + file_mapping mapping(get_filename().c_str(), read_only); + file_mapping move_ctor(boost::move(mapping)); + file_mapping move_assign; + move_assign = boost::move(move_ctor); + mapping.swap(move_assign); + file_mapping ret(get_file_mapping()); + } + } + catch(std::exception &exc){ + file_mapping::remove(get_filename().c_str()); + std::cout << "Unhandled exception: " << exc.what() << std::endl; + throw; + } + file_mapping::remove(get_filename().c_str()); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/flat_map_index_allocation_test.cpp b/src/boost/libs/interprocess/test/flat_map_index_allocation_test.cpp new file mode 100644 index 00000000..41476ab3 --- /dev/null +++ b/src/boost/libs/interprocess/test/flat_map_index_allocation_test.cpp @@ -0,0 +1,25 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/indexes/flat_map_index.hpp> +#include "named_allocation_test_template.hpp" + +int main () +{ + using namespace boost::interprocess; + if(!test::test_named_allocation<flat_map_index>()){ + return 1; + } + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/flat_tree_test.cpp b/src/boost/libs/interprocess/test/flat_tree_test.cpp new file mode 100644 index 00000000..bd4af0f7 --- /dev/null +++ b/src/boost/libs/interprocess/test/flat_tree_test.cpp @@ -0,0 +1,202 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <set> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/flat_set.hpp> +#include <boost/interprocess/containers/flat_map.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/indexes/flat_map_index.hpp> +#include "print_container.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include "set_test.hpp" +#include "map_test.hpp" +#include "emplace_test.hpp" + +///////////////////////////////////////////////////////////////// +// +// This example repeats the same operations with std::set and +// shmem_set using the node allocator +// and compares the values of both containers +// +///////////////////////////////////////////////////////////////// + +using namespace boost::interprocess; + +//Customize managed_shared_memory class +typedef basic_managed_shared_memory + <char, + //simple_seq_fit<mutex_family>, + rbtree_best_fit<mutex_family>, + iset_index + > my_managed_shared_memory; + +//Alias allocator type +typedef allocator<int, my_managed_shared_memory::segment_manager> + shmem_allocator_t; +typedef allocator<test::movable_int, my_managed_shared_memory::segment_manager> + shmem_movable_allocator_t; +typedef allocator<std::pair<int, int>, my_managed_shared_memory::segment_manager> + shmem_pair_allocator_t; +typedef allocator<std::pair<test::movable_int, test::movable_int>, my_managed_shared_memory::segment_manager> + shmem_movable_pair_allocator_t; + +typedef allocator<test::movable_and_copyable_int, my_managed_shared_memory::segment_manager> + shmem_move_copy_allocator_t; + +typedef allocator<test::copyable_int, my_managed_shared_memory::segment_manager> + shmem_copy_allocator_t; + +typedef allocator<std::pair<test::movable_and_copyable_int, test::movable_and_copyable_int>, my_managed_shared_memory::segment_manager> + shmem_move_copy_pair_allocator_t; + +//Alias set types +typedef std::set<int> MyStdSet; +typedef std::multiset<int> MyStdMultiSet; +typedef std::map<int, int> MyStdMap; +typedef std::multimap<int, int> MyStdMultiMap; + +typedef flat_set<int, std::less<int>, shmem_allocator_t> MyShmSet; +typedef flat_multiset<int, std::less<int>, shmem_allocator_t> MyShmMultiSet; +typedef flat_map<int, int, std::less<int>, shmem_pair_allocator_t> MyShmMap; +typedef flat_multimap<int, int, std::less<int>, shmem_pair_allocator_t> MyShmMultiMap; + +typedef flat_set<test::movable_int, std::less<test::movable_int> + ,shmem_movable_allocator_t> MyMovableShmSet; +typedef flat_multiset<test::movable_int,std::less<test::movable_int> + ,shmem_movable_allocator_t> MyMovableShmMultiSet; +typedef flat_map<test::movable_int, test::movable_int + ,std::less<test::movable_int> + ,shmem_movable_pair_allocator_t> MyMovableShmMap; +typedef flat_multimap<test::movable_int, test::movable_int + ,std::less<test::movable_int> + ,shmem_movable_pair_allocator_t> MyMovableShmMultiMap; + +typedef flat_set<test::movable_and_copyable_int, std::less<test::movable_and_copyable_int> + ,shmem_move_copy_allocator_t> MyMoveCopyShmSet; +typedef flat_multiset<test::movable_and_copyable_int,std::less<test::movable_and_copyable_int> + ,shmem_move_copy_allocator_t> MyMoveCopyShmMultiSet; + +typedef flat_set<test::copyable_int, std::less<test::copyable_int> + ,shmem_copy_allocator_t> MyCopyShmSet; +typedef flat_multiset<test::copyable_int,std::less<test::copyable_int> + ,shmem_copy_allocator_t> MyCopyShmMultiSet; + +typedef flat_map<test::movable_and_copyable_int, test::movable_and_copyable_int + ,std::less<test::movable_and_copyable_int> + ,shmem_move_copy_pair_allocator_t> MyMoveCopyShmMap; +typedef flat_multimap<test::movable_and_copyable_int, test::movable_and_copyable_int + ,std::less<test::movable_and_copyable_int> + ,shmem_move_copy_pair_allocator_t> MyMoveCopyShmMultiMap; + +int main() +{ + using namespace boost::interprocess::test; + + if (0 != set_test<my_managed_shared_memory + ,MyShmSet + ,MyStdSet + ,MyShmMultiSet + ,MyStdMultiSet>()){ + std::cout << "Error in set_test<MyShmSet>" << std::endl; + return 1; + } + + if (0 != set_test_copyable<my_managed_shared_memory + ,MyShmSet + ,MyStdSet + ,MyShmMultiSet + ,MyStdMultiSet>()){ + std::cout << "Error in set_test<MyShmSet>" << std::endl; + return 1; + } + + if (0 != set_test<my_managed_shared_memory + ,MyMovableShmSet + ,MyStdSet + ,MyMovableShmMultiSet + ,MyStdMultiSet>()){ + std::cout << "Error in set_test<MyMovableShmSet>" << std::endl; + return 1; + } + + if (0 != set_test<my_managed_shared_memory + ,MyMoveCopyShmSet + ,MyStdSet + ,MyMoveCopyShmMultiSet + ,MyStdMultiSet>()){ + std::cout << "Error in set_test<MyMoveCopyShmSet>" << std::endl; + return 1; + } + + if (0 != set_test<my_managed_shared_memory + ,MyCopyShmSet + ,MyStdSet + ,MyCopyShmMultiSet + ,MyStdMultiSet>()){ + std::cout << "Error in set_test<MyCopyShmSet>" << std::endl; + return 1; + } + + if (0 != map_test<my_managed_shared_memory + ,MyShmMap + ,MyStdMap + ,MyShmMultiMap + ,MyStdMultiMap>()){ + std::cout << "Error in map_test<MyShmMap>" << std::endl; + return 1; + } + + if (0 != map_test_copyable<my_managed_shared_memory + ,MyShmMap + ,MyStdMap + ,MyShmMultiMap + ,MyStdMultiMap>()){ + std::cout << "Error in map_test<MyShmMap>" << std::endl; + return 1; + } + +// if (0 != map_test<my_managed_shared_memory +// ,MyMovableShmMap +// ,MyStdMap +// ,MyMovableShmMultiMap +// ,MyStdMultiMap>()){ +// return 1; +// } + + if (0 != map_test<my_managed_shared_memory + ,MyMoveCopyShmMap + ,MyStdMap + ,MyMoveCopyShmMultiMap + ,MyStdMultiMap>()){ + std::cout << "Error in map_test<MyMoveCopyShmMap>" << std::endl; + return 1; + } + + //#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC_MINOR__ < 3) + const test::EmplaceOptions SetOptions = (test::EmplaceOptions)(test::EMPLACE_HINT | test::EMPLACE_ASSOC); + const test::EmplaceOptions MapOptions = (test::EmplaceOptions)(test::EMPLACE_HINT_PAIR | test::EMPLACE_ASSOC_PAIR); + + if(!boost::interprocess::test::test_emplace<flat_map<test::EmplaceInt, test::EmplaceInt>, MapOptions>()) + return 1; + if(!boost::interprocess::test::test_emplace<flat_multimap<test::EmplaceInt, test::EmplaceInt>, MapOptions>()) + return 1; + if(!boost::interprocess::test::test_emplace<flat_set<test::EmplaceInt>, SetOptions>()) + return 1; + if(!boost::interprocess::test::test_emplace<flat_multiset<test::EmplaceInt>, SetOptions>()) + return 1; + //#endif //!defined(__GNUC__) + return 0; + +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/get_process_id_name.hpp b/src/boost/libs/interprocess/test/get_process_id_name.hpp new file mode 100644 index 00000000..f79384ab --- /dev/null +++ b/src/boost/libs/interprocess/test/get_process_id_name.hpp @@ -0,0 +1,71 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_GET_PROCESS_ID_NAME_HPP +#define BOOST_INTERPROCESS_GET_PROCESS_ID_NAME_HPP + +#include <boost/config.hpp> +#include <string> //std::string +#include <sstream> //std::stringstream +#include <boost/interprocess/detail/os_thread_functions.hpp> + +namespace boost{ +namespace interprocess{ +namespace test{ + +inline void get_process_id_name(std::string &str) +{ + std::stringstream sstr; + sstr << "process_" << boost::interprocess::ipcdetail::get_current_process_id() << std::ends; + str = sstr.str().c_str(); +} + +inline void get_process_id_ptr_name(std::string &str, const void *ptr) +{ + std::stringstream sstr; + sstr << "process_" << boost::interprocess::ipcdetail::get_current_process_id() << "_" << ptr << std::ends; + str = sstr.str().c_str(); +} + +inline const char *get_process_id_name() +{ + static std::string str; + get_process_id_name(str); + return str.c_str(); +} + +inline const char *get_process_id_ptr_name(void *ptr) +{ + static std::string str; + get_process_id_ptr_name(str, ptr); + return str.c_str(); +} + +inline const char *add_to_process_id_name(const char *name) +{ + static std::string str; + get_process_id_name(str); + str += name; + return str.c_str(); +} + +inline const char *add_to_process_id_ptr_name(const char *name, void *ptr) +{ + static std::string str; + get_process_id_ptr_name(str, ptr); + str += name; + return str.c_str(); +} + +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#endif //#ifndef BOOST_INTERPROCESS_GET_PROCESS_ID_NAME_HPP diff --git a/src/boost/libs/interprocess/test/heap_allocator_v1.hpp b/src/boost/libs/interprocess/test/heap_allocator_v1.hpp new file mode 100644 index 00000000..278d52e0 --- /dev/null +++ b/src/boost/libs/interprocess/test/heap_allocator_v1.hpp @@ -0,0 +1,166 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_HEAP_ALLOCATOR_V1_HPP +#define BOOST_INTERPROCESS_HEAP_ALLOCATOR_V1_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#include <boost/intrusive/pointer_traits.hpp> + +#include <boost/interprocess/interprocess_fwd.hpp> +#include <boost/interprocess/containers/allocation_type.hpp> +#include <boost/interprocess/detail/utilities.hpp> +#include <boost/interprocess/containers/version_type.hpp> +#include <boost/interprocess/exceptions.hpp> +#include <boost/move/adl_move_swap.hpp> + +//!\file +//!Describes an heap_allocator_v1 that allocates portions of fixed size +//!memory buffer (shared memory, mapped file...) + +namespace boost { +namespace interprocess { +namespace test { + +//!An STL compatible heap_allocator_v1 that uses a segment manager as +//!memory source. The internal pointer type will of the same type (raw, smart) as +//!"typename SegmentManager::void_pointer" type. This allows +//!placing the heap_allocator_v1 in shared memory, memory mapped-files, etc...*/ +template<class T, class SegmentManager> +class heap_allocator_v1 +{ + private: + typedef heap_allocator_v1<T, SegmentManager> self_t; + typedef SegmentManager segment_manager; + typedef typename segment_manager::void_pointer aux_pointer_t; + + typedef typename boost::intrusive:: + pointer_traits<aux_pointer_t>::template + rebind_pointer<const void>::type cvoid_ptr; + + typedef typename boost::intrusive:: + pointer_traits<cvoid_ptr>::template + rebind_pointer<segment_manager>::type alloc_ptr_t; + + template<class T2, class SegmentManager2> + heap_allocator_v1& operator=(const heap_allocator_v1<T2, SegmentManager2>&); + + heap_allocator_v1& operator=(const heap_allocator_v1&); + + alloc_ptr_t mp_mngr; + + public: + typedef T value_type; + typedef typename boost::intrusive:: + pointer_traits<cvoid_ptr>::template + rebind_pointer<T>::type pointer; + typedef typename boost::intrusive:: + pointer_traits<cvoid_ptr>::template + rebind_pointer<const T>::type const_pointer; + typedef typename ipcdetail::add_reference + <value_type>::type reference; + typedef typename ipcdetail::add_reference + <const value_type>::type const_reference; + typedef typename SegmentManager::size_type size_type; + typedef typename SegmentManager::difference_type difference_type; + + //!Obtains an heap_allocator_v1 of other type + template<class T2> + struct rebind + { + typedef heap_allocator_v1<T2, SegmentManager> other; + }; + + //!Returns the segment manager. Never throws + segment_manager* get_segment_manager()const + { return ipcdetail::to_raw_pointer(mp_mngr); } + + //!Returns address of mutable object. Never throws + pointer address(reference value) const + { return pointer(addressof(value)); } + + //!Returns address of non mutable object. Never throws + const_pointer address(const_reference value) const + { return const_pointer(addressof(value)); } + + //!Constructor from the segment manager. Never throws + heap_allocator_v1(segment_manager *segment_mngr) + : mp_mngr(segment_mngr) { } + + //!Constructor from other heap_allocator_v1. Never throws + heap_allocator_v1(const heap_allocator_v1 &other) + : mp_mngr(other.get_segment_manager()){ } + + //!Constructor from related heap_allocator_v1. Never throws + template<class T2> + heap_allocator_v1(const heap_allocator_v1<T2, SegmentManager> &other) + : mp_mngr(other.get_segment_manager()){} + + //!Allocates memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_ptr hint = 0) + { + (void)hint; + char *raw_mem = ::new char[sizeof(value_type)*count]; + return boost::intrusive::pointer_traits<pointer>::pointer_to(reinterpret_cast<value_type &>(*raw_mem)); + } + + //!Deallocates memory previously allocated. Never throws + void deallocate(const pointer &ptr, size_type) + { + char *ptr_raw = (char*)ipcdetail::to_raw_pointer(ptr); + ::delete[] ptr_raw; + } + + //!Construct object, calling constructor. + //!Throws if T(const T&) throws + void construct(const pointer &ptr, const_reference value) + { new((void*)ipcdetail::to_raw_pointer(ptr)) value_type(value); } + + //!Destroys object. Throws if object's destructor throws + void destroy(const pointer &ptr) + { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } + + //!Returns the number of elements that could be allocated. Never throws + size_type max_size() const + { return mp_mngr->get_size(); } + + //!Swap segment manager. Does not throw. If each heap_allocator_v1 is placed in + //!different memory segments, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2) + { ::boost::adl_move_swap(alloc1.mp_mngr, alloc2.mp_mngr); } +}; + +//!Equality test for same type of heap_allocator_v1 +template<class T, class SegmentManager> inline +bool operator==(const heap_allocator_v1<T , SegmentManager> &alloc1, + const heap_allocator_v1<T, SegmentManager> &alloc2) + { return alloc1.get_segment_manager() == alloc2.get_segment_manager(); } + +//!Inequality test for same type of heap_allocator_v1 +template<class T, class SegmentManager> inline +bool operator!=(const heap_allocator_v1<T, SegmentManager> &alloc1, + const heap_allocator_v1<T, SegmentManager> &alloc2) + { return alloc1.get_segment_manager() != alloc2.get_segment_manager(); } + +} //namespace test { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_HEAP_ALLOCATOR_V1_HPP + diff --git a/src/boost/libs/interprocess/test/intermodule_singleton_test.cpp b/src/boost/libs/interprocess/test/intermodule_singleton_test.cpp new file mode 100644 index 00000000..915a9fe8 --- /dev/null +++ b/src/boost/libs/interprocess/test/intermodule_singleton_test.cpp @@ -0,0 +1,330 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/intermodule_singleton.hpp> +#include <boost/interprocess/detail/portable_intermodule_singleton.hpp> +#include <iostream> +#include <cstdlib> //for std::abort + +using namespace boost::interprocess; + +class MyClass +{ + public: + MyClass() + { + std::cout << "MyClass()\n" << std::endl; + } + + void shout() const + { + std::cout << "Shout\n" << std::endl; + } + + ~MyClass() + { + std::cout << "~MyClass()\n" << std::endl; + } +}; + +class MyDerivedClass + : public MyClass +{}; + +class MyThrowingClass +{ + public: + MyThrowingClass() + { + throw int(0); + } +}; + + +template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType > +int intermodule_singleton_test() +{ + bool exception_thrown = false; + bool exception_2_thrown = false; + + try{ + IntermoduleType<MyThrowingClass, true, false>::get(); + } + catch(int &){ + exception_thrown = true; + //Second try + try{ + IntermoduleType<MyThrowingClass, true, false>::get(); + } + catch(interprocess_exception &){ + exception_2_thrown = true; + } + } + + if(!exception_thrown || !exception_2_thrown){ + return 1; + } + + MyClass & mc = IntermoduleType<MyClass, true, false>::get(); + mc.shout(); + IntermoduleType<MyClass, true, false>::get().shout(); + IntermoduleType<MyDerivedClass, true, false>::get().shout(); + + //Second try + exception_2_thrown = false; + try{ + IntermoduleType<MyThrowingClass, true, false>::get(); + } + catch(interprocess_exception &){ + exception_2_thrown = true; + } + if(!exception_2_thrown){ + return 1; + } + + return 0; +} + +//A class simulating a logger +//We'll register constructor/destructor counts +//to test the singleton was correctly resurrected +//by LogUser singleton. +template<class Tag> +class Logger +{ + public: + Logger() + { + ++constructed_times; + std::cout << "Logger(),tag:" << typeid(Tag).name() << "(construct #" << constructed_times << ")\n" << std::endl; + } + + void log_it() + {} + + ~Logger() + { + ++destroyed_times; + std::cout << "~Logger(),tag:" << typeid(Tag).name() << "(destroy #" << destroyed_times << ")\n" << std::endl; + } + + static unsigned int constructed_times; + static unsigned int destroyed_times; +}; + +template<class Tag> +unsigned int Logger<Tag>::constructed_times; + +template<class Tag> +unsigned int Logger<Tag>::destroyed_times; + +//A class simulating a logger user. +//The destructor uses the logger so that +//the logger is resurrected if it was +//already destroyed +template<class LogSingleton> +class LogUser +{ + public: + LogUser() + { + std::cout << "LogUser(),tag:" << typeid(LogSingleton).name() << "\n" << std::endl; + } + + void function_using_log() + { LogSingleton::get().log_it(); } + + ~LogUser() + { + std::cout << "~LogUser(),tag:" << typeid(LogSingleton).name() << "\n" << std::endl; + LogSingleton::get().log_it(); + } +}; + +//A class that tests the correct +//phoenix singleton behaviour. +//Logger should be resurrected by LogUser +template<class Tag> +class LogPhoenixTester +{ + public: + LogPhoenixTester() + { + std::cout << "LogPhoenixTester(), tag: " << typeid(Tag).name() << "\n" << std::endl; + } + + void dummy() + {} + + ~LogPhoenixTester() + { + //Test Phoenix singleton was correctly executed: + //created and destroyed two times + //This test will be executed after main ends + std::cout << "~LogPhoenixTester(), tag: " << typeid(Tag).name() << "\n" << std::endl; + if(Logger<Tag>::constructed_times != Logger<Tag>::destroyed_times || + Logger<Tag>::constructed_times != 2) + { + std::stringstream sstr; + sstr << "LogPhoenixTester failed for tag "; + sstr << typeid(Tag).name(); + sstr << "\n"; + if(Logger<Tag>::constructed_times != 2){ + sstr << "Logger<Tag>::constructed_times != 2\n"; + sstr << "("; + sstr << Logger<Tag>::constructed_times << ")\n"; + } + else{ + sstr << "Logger<Tag>::constructed_times != Logger<Tag>::destroyed_times\n"; + sstr << "(" << Logger<Tag>::constructed_times << " vs. " << Logger<Tag>::destroyed_times << ")\n"; + } + std::cout << "~LogPhoenixTester(), error: " << sstr.str() << std::endl; + std::abort(); + } + } +}; + +//A class simulating a logger user. +//The destructor uses the logger so that +//the logger is resurrected if it was +//already destroyed +template<class LogSingleton> +class LogDeadReferenceUser +{ + public: + LogDeadReferenceUser() + { + std::cout << "LogDeadReferenceUser(), LogSingleton: " << typeid(LogSingleton).name() << "\n" << std::endl; + } + + void function_using_log() + { LogSingleton::get().log_it(); } + + ~LogDeadReferenceUser() + { + std::cout << "~LogDeadReferenceUser(), LogSingleton: " << typeid(LogSingleton).name() << "\n" << std::endl; + //Make sure the exception is thrown as we are + //trying to use a dead non-phoenix singleton + try{ + LogSingleton::get().log_it(); + std::string s("LogDeadReferenceUser failed for LogSingleton "); + s += typeid(LogSingleton).name(); + std::cout << "~LogDeadReferenceUser(), error: " << s << std::endl; + std::abort(); + } + catch(interprocess_exception &){ + //Correct behaviour + } + } +}; + +template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType > +int phoenix_singleton_test() +{ + typedef int DummyType; + typedef IntermoduleType<DummyType, true, true> Tag; + typedef Logger<Tag> LoggerType; + typedef IntermoduleType<LoggerType, true, true> LoggerSingleton; + typedef LogUser<LoggerSingleton> LogUserType; + typedef IntermoduleType<LogUserType, true, true> LogUserSingleton; + typedef IntermoduleType<LogPhoenixTester<Tag>, true, true> LogPhoenixTesterSingleton; + + //Instantiate Phoenix tester singleton so that it will be destroyed the last + LogPhoenixTesterSingleton::get().dummy(); + + //Now instantitate a log user singleton + LogUserType &log_user = LogUserSingleton::get(); + + //Then force LoggerSingleton instantiation + //calling a function that will use it. + //After main ends, LoggerSingleton will be destroyed + //before LogUserSingleton due to LIFO + //singleton semantics + log_user.function_using_log(); + + //Next, LogUserSingleton destructor will resurrect + //LoggerSingleton. + //After that LoggerSingleton will be destroyed and + //lastly LogPhoenixTester will be destroyed checking + //LoggerSingleton was correctly destroyed. + return 0; +} + +template < template<class T, bool LazyInit, bool Phoenix> class IntermoduleType > +int dead_reference_singleton_test() +{ + typedef int DummyType; + typedef IntermoduleType<DummyType, true, false> Tag; + typedef Logger<Tag> LoggerType; + typedef IntermoduleType<LoggerType, true, false> LoggerSingleton; + typedef LogDeadReferenceUser<LoggerSingleton> LogDeadReferenceUserType; + typedef IntermoduleType<LogDeadReferenceUserType, true, false> LogDeadReferenceUserSingleton; + + //Now instantitate a log user singleton + LogDeadReferenceUserType &log_user = LogDeadReferenceUserSingleton::get(); + + //Then force LoggerSingleton instantiation + //calling a function that will use it. + //After main ends, LoggerSingleton will be destroyed + //before LogDeadReferenceUserType due to LIFO + //singleton semantics + log_user.function_using_log(); + + //Next, LogDeadReferenceUserType destructor will try to use + //LoggerSingleton and an exception will be raised an catched. + return 0; +} + +//reduce name length +template<typename C, bool LazyInit, bool Phoenix> +class port_singleton + : public ipcdetail::portable_intermodule_singleton<C, LazyInit, Phoenix> +{}; + +#ifdef BOOST_INTERPROCESS_WINDOWS +template<typename C, bool LazyInit, bool Phoenix> +class win_singleton + : public ipcdetail::windows_intermodule_singleton< C, LazyInit, Phoenix> +{}; +#endif + +int main () +{ + if(0 != intermodule_singleton_test<port_singleton>()){ + return 1; + } + + #ifdef BOOST_INTERPROCESS_WINDOWS + if(0 != intermodule_singleton_test<win_singleton>()){ + return 1; + } + #endif + + //Only few platforms support this + #ifdef BOOST_INTERPROCESS_ATEXIT_CALLABLE_FROM_ATEXIT + //Phoenix singletons are tested after main ends, + //LogPhoenixTester does the work + phoenix_singleton_test<port_singleton>(); + #ifdef BOOST_INTERPROCESS_WINDOWS + phoenix_singleton_test<win_singleton>(); + #endif + #endif + + //Dead reference singletons are tested after main ends, + //LogDeadReferenceUser does the work + dead_reference_singleton_test<port_singleton>(); + #ifdef BOOST_INTERPROCESS_WINDOWS + dead_reference_singleton_test<win_singleton>(); + #endif + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/intrusive_ptr_test.cpp b/src/boost/libs/interprocess/test/intrusive_ptr_test.cpp new file mode 100644 index 00000000..f3e48125 --- /dev/null +++ b/src/boost/libs/interprocess/test/intrusive_ptr_test.cpp @@ -0,0 +1,546 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Peter Dimov 2002-2005. +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/offset_ptr.hpp> +#include <boost/interprocess/smart_ptr/intrusive_ptr.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> + +#include <boost/core/lightweight_test.hpp> +#include <boost/config.hpp> +#include <boost/move/adl_move_swap.hpp> +#include <boost/move/core.hpp> +#include <functional> + +typedef boost::interprocess::offset_ptr<void> VP; + +namespace { + int addref_release_calls = 0; +} + +namespace N +{ + +class base +{ + private: + + int use_count_; + + base(base const &); + base & operator=(base const &); + + protected: + + base(): use_count_(0) + { + } + + virtual ~base() + { + } + + public: + + long use_count() const + { + return use_count_; + } + + void add_ref() + { + ++addref_release_calls; + ++use_count_; + } + + void release() + { + ++addref_release_calls; + if(--use_count_ == 0) delete this; + } +}; + +inline void intrusive_ptr_add_ref(N::base *p) +{ p->add_ref(); } + +inline void intrusive_ptr_release(N::base *p) +{ p->release(); } + +} // namespace N + +struct X: public virtual N::base +{ +}; + +struct Y: public X +{ +}; + +// + +namespace n_element_type +{ + +void f(X &) +{ +} + +void test() +{ + typedef boost::interprocess::intrusive_ptr<X, VP>::element_type T; + T t; + f(t); +} + +} // namespace n_element_type + +namespace n_constructors +{ + +void default_constructor() +{ + boost::interprocess::intrusive_ptr<X, VP> px; + BOOST_TEST(px.get() == 0); +} + +void pointer_constructor() +{ + { + boost::interprocess::intrusive_ptr<X, VP> px(0); + BOOST_TEST(px.get() == 0); + } + + { + boost::interprocess::intrusive_ptr<X, VP> px(0, false); + BOOST_TEST(px.get() == 0); + } + + { + boost::interprocess::offset_ptr<X> p = new X; + BOOST_TEST(p->use_count() == 0); + + boost::interprocess::intrusive_ptr<X, VP> px(p); + BOOST_TEST(px.get() == p); + BOOST_TEST(px->use_count() == 1); + } + + { + boost::interprocess::offset_ptr<X> p = new X; + BOOST_TEST(p->use_count() == 0); + + intrusive_ptr_add_ref(p.get()); + BOOST_TEST(p->use_count() == 1); + + boost::interprocess::intrusive_ptr<X, VP> px(p, false); + BOOST_TEST(px.get() == p); + BOOST_TEST(px->use_count() == 1); + } +} + +void copy_constructor() +{ + { + boost::interprocess::intrusive_ptr<X, VP> px; + boost::interprocess::intrusive_ptr<X, VP> px2(px); + BOOST_TEST(px2.get() == px.get()); + } + + { + boost::interprocess::intrusive_ptr<Y, VP> py; + boost::interprocess::intrusive_ptr<X, VP> px(py); + BOOST_TEST(px.get() == py.get()); + } + + { + boost::interprocess::intrusive_ptr<X, VP> px(0); + boost::interprocess::intrusive_ptr<X, VP> px2(px); + BOOST_TEST(px2.get() == px.get()); + } + + { + boost::interprocess::intrusive_ptr<Y, VP> py(0); + boost::interprocess::intrusive_ptr<X, VP> px(py); + BOOST_TEST(px.get() == py.get()); + } + + { + boost::interprocess::intrusive_ptr<X, VP> px(0, false); + boost::interprocess::intrusive_ptr<X, VP> px2(px); + BOOST_TEST(px2.get() == px.get()); + } + + { + boost::interprocess::intrusive_ptr<Y, VP> py(0, false); + boost::interprocess::intrusive_ptr<X, VP> px(py); + BOOST_TEST(px.get() == py.get()); + } + + { + boost::interprocess::intrusive_ptr<X, VP> px(new X); + boost::interprocess::intrusive_ptr<X, VP> px2(px); + BOOST_TEST(px2.get() == px.get()); + } + + { + boost::interprocess::intrusive_ptr<Y, VP> py(new Y); + boost::interprocess::intrusive_ptr<X, VP> px(py); + BOOST_TEST(px.get() == py.get()); + } +} + +void move_constructor() +{ + { + int prev_addref_release_calls = addref_release_calls; + X* x = new X(); + boost::interprocess::intrusive_ptr<X, VP> px(x); + BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); + + //static_assert(std::is_nothrow_move_constructible< boost::interprocess::intrusive_ptr<X, VP> >::value, "test instrusive_ptr is nothrow move constructible"); + + boost::interprocess::intrusive_ptr<X, VP> px2(boost::move(px)); + BOOST_TEST(px2.get() == x); + BOOST_TEST(!px.get()); + BOOST_TEST(px2->use_count() == 1); + BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); + } +} + +void test() +{ + default_constructor(); + pointer_constructor(); + copy_constructor(); + move_constructor(); +} + +} // namespace n_constructors + +namespace n_destructor +{ + +void test() +{ + boost::interprocess::intrusive_ptr<X, VP> px(new X); + BOOST_TEST(px->use_count() == 1); + + { + boost::interprocess::intrusive_ptr<X, VP> px2(px); + BOOST_TEST(px->use_count() == 2); + } + + BOOST_TEST(px->use_count() == 1); +} + +} // namespace n_destructor + +namespace n_assignment +{ + +void copy_assignment() +{ +} + +void move_assignment() +{ + { + int prev_addref_release_calls = addref_release_calls; + X* x = new X(); + boost::interprocess::intrusive_ptr<X, VP> px(x); + BOOST_TEST(px->use_count() == 1); + BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); + + //static_assert(std::is_nothrow_move_assignable< boost::interprocess::intrusive_ptr<X, VP> >::value, "test if nothrow move assignable "); + + boost::interprocess::intrusive_ptr<X, VP> px2; + px2 = boost::move(px); + BOOST_TEST(px2.get() == x); + BOOST_TEST(!px.get()); + BOOST_TEST(px2->use_count() == 1); + BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); + } +} + +void conversion_assignment() +{ +} + +void pointer_assignment() +{ +} + +void test() +{ + copy_assignment(); + conversion_assignment(); + pointer_assignment(); + move_assignment(); +} + +} // namespace n_assignment + +namespace n_access +{ + +void test() +{ + { + boost::interprocess::intrusive_ptr<X, VP> px; + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + } + + { + boost::interprocess::intrusive_ptr<X, VP> px(0); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + } + + { + boost::interprocess::intrusive_ptr<X, VP> px + (boost::interprocess::offset_ptr<X>(new X)); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(&*px == boost::interprocess::ipcdetail::to_raw_pointer(px.get())); + BOOST_TEST(px.operator ->() == px.get()); + } +} + +} // namespace n_access + +namespace n_swap +{ + +void test() +{ + { + boost::interprocess::intrusive_ptr<X, VP> px; + boost::interprocess::intrusive_ptr<X, VP> px2; + + px.swap(px2); + + BOOST_TEST(px.get() == 0); + BOOST_TEST(px2.get() == 0); + + ::boost::adl_move_swap(px, px2); + + BOOST_TEST(px.get() == 0); + BOOST_TEST(px2.get() == 0); + } + + { + boost::interprocess::offset_ptr<X> p = new X; + boost::interprocess::intrusive_ptr<X, VP> px; + boost::interprocess::intrusive_ptr<X, VP> px2(p); + boost::interprocess::intrusive_ptr<X, VP> px3(px2); + + px.swap(px2); + + BOOST_TEST(px.get() == p); + BOOST_TEST(px->use_count() == 2); + BOOST_TEST(px2.get() == 0); + BOOST_TEST(px3.get() == p); + BOOST_TEST(px3->use_count() == 2); + + ::boost::adl_move_swap(px, px2); + + BOOST_TEST(px.get() == 0); + BOOST_TEST(px2.get() == p); + BOOST_TEST(px2->use_count() == 2); + BOOST_TEST(px3.get() == p); + BOOST_TEST(px3->use_count() == 2); + } + + { + boost::interprocess::offset_ptr<X> p1 = new X; + boost::interprocess::offset_ptr<X> p2 = new X; + boost::interprocess::intrusive_ptr<X, VP> px(p1); + boost::interprocess::intrusive_ptr<X, VP> px2(p2); + boost::interprocess::intrusive_ptr<X, VP> px3(px2); + + px.swap(px2); + + BOOST_TEST(px.get() == p2); + BOOST_TEST(px->use_count() == 2); + BOOST_TEST(px2.get() == p1); + BOOST_TEST(px2->use_count() == 1); + BOOST_TEST(px3.get() == p2); + BOOST_TEST(px3->use_count() == 2); + + ::boost::adl_move_swap(px, px2); + + BOOST_TEST(px.get() == p1); + BOOST_TEST(px->use_count() == 1); + BOOST_TEST(px2.get() == p2); + BOOST_TEST(px2->use_count() == 2); + BOOST_TEST(px3.get() == p2); + BOOST_TEST(px3->use_count() == 2); + } +} + +} // namespace n_swap + +namespace n_comparison +{ + +template<class T, class U, class VP> +void test2(boost::interprocess::intrusive_ptr<T, VP> const & p, + boost::interprocess::intrusive_ptr<U, VP> const & q) +{ + BOOST_TEST((p == q) == (p.get() == q.get())); + BOOST_TEST((p != q) == (p.get() != q.get())); +} + +template<class T, class VP> +void test3(boost::interprocess::intrusive_ptr<T, VP> const & p, + boost::interprocess::intrusive_ptr<T, VP> const & q) +{ + BOOST_TEST((p == q) == (p.get() == q.get())); + BOOST_TEST((p.get() == q) == (p.get() == q.get())); + BOOST_TEST((p == q.get()) == (p.get() == q.get())); + BOOST_TEST((p != q) == (p.get() != q.get())); + BOOST_TEST((p.get() != q) == (p.get() != q.get())); + BOOST_TEST((p != q.get()) == (p.get() != q.get())); + + // 'less' moved here as a g++ 2.9x parse error workaround + std::less<boost::interprocess::offset_ptr<T> > less; + BOOST_TEST((p < q) == less(p.get(), q.get())); +} + +void test() +{ + { + boost::interprocess::intrusive_ptr<X, VP> px; + test3(px, px); + + boost::interprocess::intrusive_ptr<X, VP> px2; + test3(px, px2); + + boost::interprocess::intrusive_ptr<X, VP> px3(px); + test3(px3, px3); + test3(px, px3); + } + + { + boost::interprocess::intrusive_ptr<X, VP> px; + + boost::interprocess::intrusive_ptr<X, VP> px2(new X); + test3(px, px2); + test3(px2, px2); + + boost::interprocess::intrusive_ptr<X, VP> px3(new X); + test3(px2, px3); + + boost::interprocess::intrusive_ptr<X, VP> px4(px2); + test3(px2, px4); + test3(px4, px4); + } + + { + boost::interprocess::intrusive_ptr<X, VP> px(new X); + + boost::interprocess::intrusive_ptr<Y, VP> py(new Y); + test2(px, py); + + boost::interprocess::intrusive_ptr<X, VP> px2(py); + test2(px2, py); + test3(px, px2); + test3(px2, px2); + } +} + +} // namespace n_comparison + +namespace n_static_cast +{ + +void test() +{ +} + +} // namespace n_static_cast + +namespace n_dynamic_cast +{ + +void test() +{ +} + +} // namespace n_dynamic_cast + +namespace n_transitive +{ + +struct X: public N::base +{ + boost::interprocess::intrusive_ptr<X, VP> next; +}; + +void test() +{ + boost::interprocess::intrusive_ptr<X, VP> p(new X); + p->next = boost::interprocess::intrusive_ptr<X, VP>(new X); + BOOST_TEST(!p->next->next); + p = p->next; + BOOST_TEST(!p->next); +} + +} // namespace n_transitive + +namespace n_report_1 +{ + +class foo: public N::base +{ + public: + + foo(): m_self(this) + { + } + + void suicide() + { + m_self = 0; + } + + private: + + boost::interprocess::intrusive_ptr<foo, VP> m_self; +}; + +void test() +{ + boost::interprocess::offset_ptr<foo> foo_ptr = new foo; + foo_ptr->suicide(); +} + +} // namespace n_report_1 + +int main() +{ + n_element_type::test(); + n_constructors::test(); + n_destructor::test(); + n_assignment::test(); + n_access::test(); + n_swap::test(); + n_comparison::test(); + n_static_cast::test(); + n_dynamic_cast::test(); + + n_transitive::test(); + n_report_1::test(); + + return boost::report_errors(); +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/iset_index_allocation_test.cpp b/src/boost/libs/interprocess/test/iset_index_allocation_test.cpp new file mode 100644 index 00000000..42d03ff8 --- /dev/null +++ b/src/boost/libs/interprocess/test/iset_index_allocation_test.cpp @@ -0,0 +1,24 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/indexes/iset_index.hpp> +#include "named_allocation_test_template.hpp" + +int main () +{ + using namespace boost::interprocess; + if(!test::test_named_allocation<iset_index>()){ + return 1; + } + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/iunordered_set_index_allocation_test.cpp b/src/boost/libs/interprocess/test/iunordered_set_index_allocation_test.cpp new file mode 100644 index 00000000..5e8e966d --- /dev/null +++ b/src/boost/libs/interprocess/test/iunordered_set_index_allocation_test.cpp @@ -0,0 +1,25 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/indexes/iunordered_set_index.hpp> +#include "named_allocation_test_template.hpp" + +int main () +{ + using namespace boost::interprocess; + if(!test::test_named_allocation<iunordered_set_index>()){ + return 1; + } + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/list_test.cpp b/src/boost/libs/interprocess/test/list_test.cpp new file mode 100644 index 00000000..4ecf55a4 --- /dev/null +++ b/src/boost/libs/interprocess/test/list_test.cpp @@ -0,0 +1,63 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/offset_ptr.hpp> +#include "dummy_test_allocator.hpp" +#include "list_test.hpp" +#include "movable_int.hpp" +#include "emplace_test.hpp" + +using namespace boost::interprocess; + +typedef allocator<int, managed_shared_memory::segment_manager> ShmemAllocator; +typedef list<int, ShmemAllocator> MyList; + +//typedef allocator<volatile int, managed_shared_memory::segment_manager> ShmemVolatileAllocator; +//typedef list<volatile int, ShmemVolatileAllocator> MyVolatileList; + +typedef allocator<test::movable_int, managed_shared_memory::segment_manager> ShmemMoveAllocator; +typedef list<test::movable_int, ShmemMoveAllocator> MyMoveList; + +typedef allocator<test::movable_and_copyable_int, managed_shared_memory::segment_manager> ShmemCopyMoveAllocator; +typedef list<test::movable_and_copyable_int, ShmemCopyMoveAllocator> MyCopyMoveList; + +typedef allocator<test::copyable_int, managed_shared_memory::segment_manager> ShmemCopyAllocator; +typedef list<test::copyable_int, ShmemCopyAllocator> MyCopyList; + +int main () +{ + if(test::list_test<managed_shared_memory, MyList, true>()) + return 1; + +// if(test::list_test<managed_shared_memory, MyVolatileList, true>()) +// return 1; + + if(test::list_test<managed_shared_memory, MyMoveList, true>()) + return 1; + + if(test::list_test<managed_shared_memory, MyCopyMoveList, true>()) + return 1; + + if(test::list_test<managed_shared_memory, MyCopyList, true>()) + return 1; + + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_FRONT | test::EMPLACE_BEFORE); + + if(!boost::interprocess::test::test_emplace<list<test::EmplaceInt>, Options>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/list_test.hpp b/src/boost/libs/interprocess/test/list_test.hpp new file mode 100644 index 00000000..a7c40633 --- /dev/null +++ b/src/boost/libs/interprocess/test/list_test.hpp @@ -0,0 +1,281 @@ +//////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +//////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_LIST_TEST_HEADER +#define BOOST_INTERPROCESS_TEST_LIST_TEST_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include "check_equal_containers.hpp" +#include <memory> +#include <list> +#include <vector> +#include <functional> +#include "print_container.hpp" +#include <boost/move/utility_core.hpp> +#include <string> +#include "get_process_id_name.hpp" + +namespace boost{ +namespace interprocess{ +namespace test{ + +template<bool DoublyLinked> +struct push_data_function +{ + template<class MyShmList, class MyStdList> + static int execute(int max, MyShmList *shmlist, MyStdList *stdlist) + { + typedef typename MyShmList::value_type IntType; + for(int i = 0; i < max; ++i){ + IntType move_me(i); + shmlist->push_back(boost::move(move_me)); + stdlist->push_back(i); + shmlist->push_back(IntType(i)); + stdlist->push_back(int(i)); + } + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; + return 0; + } +}; + +template<> +struct push_data_function<false> +{ + template<class MyShmList, class MyStdList> + static int execute(int max, MyShmList *shmlist, MyStdList *stdlist) + { + typedef typename MyShmList::value_type IntType; + for(int i = 0; i < max; ++i){ + IntType move_me(i); + shmlist->push_front(boost::move(move_me)); + stdlist->push_front(i); + shmlist->push_front(IntType(i)); + stdlist->push_front(int(i)); + } + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; + return 0; + } +}; + +template<bool DoublyLinked> +struct pop_back_function +{ + template<class MyStdList, class MyShmList> + static int execute(MyShmList *shmlist, MyStdList *stdlist) + { + shmlist->pop_back(); + stdlist->pop_back(); + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; + return 0; + } +}; + +template<> +struct pop_back_function<false> +{ + template<class MyStdList, class MyShmList> + static int execute(MyShmList *shmlist, MyStdList *stdlist) + { + (void)shmlist; (void)stdlist; + return 0; + } +}; + +template<class ManagedSharedMemory + ,class MyShmList + ,bool DoublyLinked> +int list_test (bool copied_allocators_equal = true) +{ + typedef std::list<int> MyStdList; + typedef typename MyShmList::value_type IntType; + const int memsize = 65536; + const char *const shMemName = test::get_process_id_name(); + const int max = 100; + typedef push_data_function<DoublyLinked> push_data_t; + + try{ + //Named new capable shared mem allocator + //Create shared memory + shared_memory_object::remove(shMemName); + ManagedSharedMemory segment(create_only, shMemName, memsize); + + segment.reserve_named_objects(100); + + //Shared memory allocator must be always be initialized + //since it has no default constructor + MyShmList *shmlist = segment.template construct<MyShmList>("MyList") + (segment.get_segment_manager()); + + + MyStdList *stdlist = new MyStdList; + + if(push_data_t::execute(max/2, shmlist, stdlist)){ + return 1; + } + + shmlist->erase(shmlist->begin()++); + stdlist->erase(stdlist->begin()++); + if(!CheckEqualContainers(shmlist, stdlist)) return 1; + + if(pop_back_function<DoublyLinked>::execute(shmlist, stdlist)){ + return 1; + } + + shmlist->pop_front(); + stdlist->pop_front(); + if(!CheckEqualContainers(shmlist, stdlist)) return 1; + + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + shmlist->assign(::boost::make_move_iterator(&aux_vect[0]) + ,::boost::make_move_iterator(&aux_vect[50])); + stdlist->assign(&aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(shmlist, stdlist)) return 1; + } + + if(copied_allocators_equal){ + shmlist->sort(); + stdlist->sort(); + if(!CheckEqualContainers(shmlist, stdlist)) return 1; + } + + shmlist->reverse(); + stdlist->reverse(); + if(!CheckEqualContainers(shmlist, stdlist)) return 1; + + shmlist->reverse(); + stdlist->reverse(); + if(!CheckEqualContainers(shmlist, stdlist)) return 1; + + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + shmlist->insert(shmlist->begin() + ,::boost::make_move_iterator(&aux_vect[0]) + ,::boost::make_move_iterator(&aux_vect[50])); + stdlist->insert(stdlist->begin(), &aux_vect2[0], &aux_vect2[50]); + } + + shmlist->unique(); + stdlist->unique(); + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; + + if(copied_allocators_equal){ + shmlist->sort(std::greater<IntType>()); + stdlist->sort(std::greater<int>()); + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; + } + + shmlist->resize(25); + stdlist->resize(25); + shmlist->resize(50); + stdlist->resize(50); + shmlist->resize(0); + stdlist->resize(0); + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; + + if(push_data_t::execute(max/2, shmlist, stdlist)){ + return 1; + } + { + MyShmList othershmlist(shmlist->get_allocator()); + MyStdList otherstdlist; + + int listsize = (int)shmlist->size(); + + if(push_data_t::execute(listsize/2, shmlist, stdlist)){ + return 1; + } + + if(copied_allocators_equal){ + shmlist->splice(shmlist->begin(), othershmlist); + stdlist->splice(stdlist->begin(), otherstdlist); + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; + } + + listsize = (int)shmlist->size(); + + if(push_data_t::execute(listsize/2, shmlist, stdlist)){ + return 1; + } + + if(push_data_t::execute(listsize/2, &othershmlist, &otherstdlist)){ + return 1; + } + + if(copied_allocators_equal){ + shmlist->sort(std::greater<IntType>()); + stdlist->sort(std::greater<int>()); + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; + + othershmlist.sort(std::greater<IntType>()); + otherstdlist.sort(std::greater<int>()); + if(!CheckEqualContainers(&othershmlist, &otherstdlist)) + return 1; + + shmlist->merge(othershmlist, std::greater<IntType>()); + stdlist->merge(otherstdlist, std::greater<int>()); + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; + } + + for(int i = 0; i < max; ++i){ + shmlist->insert(shmlist->begin(), IntType(i)); + stdlist->insert(stdlist->begin(), int(i)); + } + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; + } + + segment.template destroy<MyShmList>("MyList"); + delete stdlist; + segment.shrink_to_fit_indexes(); + + if(!segment.all_memory_deallocated()) + return 1; + } + catch(...){ + shared_memory_object::remove(shMemName); + throw; + } + shared_memory_object::remove(shMemName); + return 0; +} + +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif diff --git a/src/boost/libs/interprocess/test/managed_mapped_file_test.cpp b/src/boost/libs/interprocess/test/managed_mapped_file_test.cpp new file mode 100644 index 00000000..8185e56c --- /dev/null +++ b/src/boost/libs/interprocess/test/managed_mapped_file_test.cpp @@ -0,0 +1,239 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#if defined(BOOST_INTERPROCESS_MAPPED_FILES) + +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/managed_mapped_file.hpp> +#include <cstdio> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +inline std::string get_filename() +{ + std::string ret (ipcdetail::get_temporary_path()); + ret += "/"; + ret += test::get_process_id_name(); + return ret; +} + +int main () +{ + const int FileSize = 65536*10; + std::string filename(get_filename()); + const char *FileName = filename.c_str(); + + //STL compatible allocator object for memory-mapped file + typedef allocator<int, managed_mapped_file::segment_manager> + allocator_int_t; + //A vector that uses that allocator + typedef boost::interprocess::vector<int, allocator_int_t> MyVect; + + { + //Remove the file it is already created + file_mapping::remove(FileName); + + const int max = 100; + void *array[max]; + //Named allocate capable shared memory allocator + managed_mapped_file mfile(create_only, FileName, FileSize); + + int i; + //Let's allocate some memory + for(i = 0; i < max; ++i){ + array[i] = mfile.allocate(i+1); + } + + //Deallocate allocated memory + for(i = 0; i < max; ++i){ + mfile.deallocate(array[i]); + } + } + + { + //Remove the file it is already created + file_mapping::remove(FileName); + + //Named allocate capable memory mapped file managed memory class + managed_mapped_file mfile(create_only, FileName, FileSize); + + //Construct the STL-like allocator with the segment manager + const allocator_int_t myallocator (mfile.get_segment_manager()); + + //Construct vector + MyVect *mfile_vect = mfile.construct<MyVect> ("MyVector") (myallocator); + + //Test that vector can be found via name + if(mfile_vect != mfile.find<MyVect>("MyVector").first) + return -1; + + //Destroy and check it is not present + mfile.destroy<MyVect> ("MyVector"); + if(0 != mfile.find<MyVect>("MyVector").first) + return -1; + + //Construct a vector in the memory-mapped file + mfile_vect = mfile.construct<MyVect> ("MyVector") (myallocator); + + //Flush cached data from memory-mapped file to disk + mfile.flush(); + } + { + //Map preexisting file again in memory + managed_mapped_file mfile(open_only, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first; + if(!mfile_vect) + return -1; + } + + { + { + //Map preexisting file again in copy-on-write + managed_mapped_file mfile(open_copy_on_write, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first; + if(!mfile_vect) + return -1; + + //Erase vector + mfile.destroy_ptr(mfile_vect); + + //Make sure vector is erased + mfile_vect = mfile.find<MyVect>("MyVector").first; + if(mfile_vect) + return -1; + } + //Now check vector is still in the file + { + //Map preexisting file again in copy-on-write + managed_mapped_file mfile(open_copy_on_write, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first; + if(!mfile_vect) + return -1; + } + } + { + //Map preexisting file again in copy-on-write + managed_mapped_file mfile(open_read_only, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first; + if(!mfile_vect) + return -1; + } + { + managed_mapped_file::size_type old_free_memory; + { + //Map preexisting file again in memory + managed_mapped_file mfile(open_only, FileName); + old_free_memory = mfile.get_free_memory(); + } + + //Now grow the file + managed_mapped_file::grow(FileName, FileSize); + + //Map preexisting file again in memory + managed_mapped_file mfile(open_only, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first; + if(!mfile_vect) + return -1; + + if(mfile.get_size() != (FileSize*2)) + return -1; + if(mfile.get_free_memory() <= old_free_memory) + return -1; + } + { + managed_mapped_file::size_type old_free_memory, next_free_memory, + old_file_size, next_file_size, final_file_size; + { + //Map preexisting file again in memory + managed_mapped_file mfile(open_only, FileName); + old_free_memory = mfile.get_free_memory(); + old_file_size = mfile.get_size(); + } + + //Now shrink the file + managed_mapped_file::shrink_to_fit(FileName); + + { + //Map preexisting file again in memory + managed_mapped_file mfile(open_only, FileName); + next_file_size = mfile.get_size(); + + //Check vector is still there + MyVect *mfile_vect = mfile.find<MyVect>("MyVector").first; + if(!mfile_vect) + return -1; + + next_free_memory = mfile.get_free_memory(); + if(next_free_memory >= old_free_memory) + return -1; + if(old_file_size <= next_file_size) + return -1; + } + + //Now destroy the vector + { + //Map preexisting file again in memory + managed_mapped_file mfile(open_only, FileName); + + //Destroy and check it is not present + mfile.destroy<MyVect>("MyVector"); + if(0 != mfile.find<MyVect>("MyVector").first) + return -1; + } + + //Now shrink the file + managed_mapped_file::shrink_to_fit(FileName); + { + //Map preexisting file again in memory + managed_mapped_file mfile(open_only, FileName); + final_file_size = mfile.get_size(); + if(next_file_size <= final_file_size) + return -1; + } + { + //Now test move semantics + managed_mapped_file original(open_only, FileName); + managed_mapped_file move_ctor(boost::move(original)); + managed_mapped_file move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); + } + } + + file_mapping::remove(FileName); + return 0; +} + +#else //#if defined(BOOST_INTERPROCESS_MAPPED_FILES) + +int main() +{ + return 0; +} + +#endif//#if defined(BOOST_INTERPROCESS_MAPPED_FILES) + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/managed_shared_memory_test.cpp b/src/boost/libs/interprocess/test/managed_shared_memory_test.cpp new file mode 100644 index 00000000..df850822 --- /dev/null +++ b/src/boost/libs/interprocess/test/managed_shared_memory_test.cpp @@ -0,0 +1,216 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <cstdio> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +int main () +{ + const int ShmemSize = 65536; + const char *const ShmemName = test::get_process_id_name(); + + //STL compatible allocator object for memory-mapped shmem + typedef allocator<int, managed_shared_memory::segment_manager> + allocator_int_t; + //A vector that uses that allocator + typedef boost::interprocess::vector<int, allocator_int_t> MyVect; + + { + //Remove the shmem it is already created + shared_memory_object::remove(ShmemName); + + const int max = 100; + void *array[max]; + //Named allocate capable shared memory allocator + managed_shared_memory shmem(create_only, ShmemName, ShmemSize); + + int i; + //Let's allocate some memory + for(i = 0; i < max; ++i){ + array[i] = shmem.allocate(i+1); + } + + //Deallocate allocated memory + for(i = 0; i < max; ++i){ + shmem.deallocate(array[i]); + } + } + + { + //Remove the shmem it is already created + shared_memory_object::remove(ShmemName); + + //Named allocate capable memory mapped shmem managed memory class + managed_shared_memory shmem(create_only, ShmemName, ShmemSize); + + //Construct the STL-like allocator with the segment manager + const allocator_int_t myallocator (shmem.get_segment_manager()); + + //Construct vector + MyVect *shmem_vect = shmem.construct<MyVect> ("MyVector") (myallocator); + + //Test that vector can be found via name + if(shmem_vect != shmem.find<MyVect>("MyVector").first) + return -1; + + //Destroy and check it is not present + shmem.destroy<MyVect> ("MyVector"); + if(0 != shmem.find<MyVect>("MyVector").first) + return -1; + + //Construct a vector in the memory-mapped shmem + shmem_vect = shmem.construct<MyVect> ("MyVector") (myallocator); + } + { + //Map preexisting shmem again in memory + managed_shared_memory shmem(open_only, ShmemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find<MyVect>("MyVector").first; + if(!shmem_vect) + return -1; + } + { + { + //Map preexisting shmem again in copy-on-write + managed_shared_memory shmem(open_copy_on_write, ShmemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find<MyVect>("MyVector").first; + if(!shmem_vect) + return -1; + + //Erase vector + shmem.destroy_ptr(shmem_vect); + + //Make sure vector is erased + shmem_vect = shmem.find<MyVect>("MyVector").first; + if(shmem_vect) + return -1; + } + //Now check vector is still in the shmem + { + //Map preexisting shmem again in copy-on-write + managed_shared_memory shmem(open_copy_on_write, ShmemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find<MyVect>("MyVector").first; + if(!shmem_vect) + return -1; + } + } + { + //Map preexisting shmem again in copy-on-write + managed_shared_memory shmem(open_read_only, ShmemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find<MyVect>("MyVector").first; + if(!shmem_vect) + return -1; + } + #ifndef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS_NO_GROW + { + managed_shared_memory::size_type old_free_memory; + { + //Map preexisting shmem again in memory + managed_shared_memory shmem(open_only, ShmemName); + old_free_memory = shmem.get_free_memory(); + } + + //Now grow the shmem + managed_shared_memory::grow(ShmemName, ShmemSize); + + //Map preexisting shmem again in memory + managed_shared_memory shmem(open_only, ShmemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find<MyVect>("MyVector").first; + if(!shmem_vect) + return -1; + + if(shmem.get_size() != (ShmemSize*2)) + return -1; + if(shmem.get_free_memory() <= old_free_memory) + return -1; + } + { + managed_shared_memory::size_type old_free_memory, next_free_memory, + old_shmem_size, next_shmem_size, final_shmem_size; + { + //Map preexisting shmem again in memory + managed_shared_memory shmem(open_only, ShmemName); + old_free_memory = shmem.get_free_memory(); + old_shmem_size = shmem.get_size(); + } + + //Now shrink the shmem + managed_shared_memory::shrink_to_fit(ShmemName); + + { + //Map preexisting shmem again in memory + managed_shared_memory shmem(open_only, ShmemName); + next_shmem_size = shmem.get_size(); + + //Check vector is still there + MyVect *shmem_vect = shmem.find<MyVect>("MyVector").first; + if(!shmem_vect) + return -1; + + next_free_memory = shmem.get_free_memory(); + if(next_free_memory >= old_free_memory) + return -1; + if(old_shmem_size <= next_shmem_size) + return -1; + } + + //Now destroy the vector + { + //Map preexisting shmem again in memory + managed_shared_memory shmem(open_only, ShmemName); + + //Destroy and check it is not present + shmem.destroy<MyVect>("MyVector"); + if(0 != shmem.find<MyVect>("MyVector").first) + return -1; + } + + //Now shrink the shmem + managed_shared_memory::shrink_to_fit(ShmemName); + { + //Map preexisting shmem again in memory + managed_shared_memory shmem(open_only, ShmemName); + final_shmem_size = shmem.get_size(); + if(next_shmem_size <= final_shmem_size) + return -1; + } + } + #endif //ifndef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS_NO_GROW + + { + //Now test move semantics + managed_shared_memory original(open_only, ShmemName); + managed_shared_memory move_ctor(boost::move(original)); + managed_shared_memory move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); + } + + shared_memory_object::remove(ShmemName); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/managed_windows_shared_memory_test.cpp b/src/boost/libs/interprocess/test/managed_windows_shared_memory_test.cpp new file mode 100644 index 00000000..aa01119e --- /dev/null +++ b/src/boost/libs/interprocess/test/managed_windows_shared_memory_test.cpp @@ -0,0 +1,152 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#ifdef BOOST_INTERPROCESS_WINDOWS + +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/managed_windows_shared_memory.hpp> +#include <cstdio> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +int main () +{ + const int MemSize = 65536; + const char *const MemName = test::get_process_id_name(); + + //STL compatible allocator object for shared memory + typedef allocator<int, managed_windows_shared_memory::segment_manager> + allocator_int_t; + //A vector that uses that allocator + typedef boost::interprocess::vector<int, allocator_int_t> MyVect; + + { + const int max = 100; + void *array[max]; + //Named allocate capable shared memory allocator + managed_windows_shared_memory w_shm(create_only, MemName, MemSize); + + int i; + //Let's allocate some memory + for(i = 0; i < max; ++i){ + array[i] = w_shm.allocate(i+1); + } + + //Deallocate allocated memory + for(i = 0; i < max; ++i){ + w_shm.deallocate(array[i]); + } + } + + { + //Named allocate capable shared memory managed memory class + managed_windows_shared_memory w_shm(create_only, MemName, MemSize); + + //Construct the STL-like allocator with the segment manager + const allocator_int_t myallocator (w_shm.get_segment_manager()); + + //Construct vector + MyVect *w_shm_vect = w_shm.construct<MyVect> ("MyVector") (myallocator); + + //Test that vector can be found via name + if(w_shm_vect != w_shm.find<MyVect>("MyVector").first) + return -1; + + //Destroy and check it is not present + w_shm.destroy<MyVect> ("MyVector"); + if(0 != w_shm.find<MyVect>("MyVector").first) + return -1; + + //Construct a vector in the shared memory + w_shm_vect = w_shm.construct<MyVect> ("MyVector") (myallocator); + + { + //Map preexisting segment again in memory + managed_windows_shared_memory w_shm_new(open_only, MemName); + + //Check vector is still there + w_shm_vect = w_shm_new.find<MyVect>("MyVector").first; + if(!w_shm_vect) + return -1; + + if(w_shm_new.get_size() != w_shm.get_size()) + return 1; + + { + { + //Map preexisting shmem again in copy-on-write + managed_windows_shared_memory shmem(open_copy_on_write, MemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find<MyVect>("MyVector").first; + if(!shmem_vect) + return -1; + + //Erase vector + shmem.destroy_ptr(shmem_vect); + + //Make sure vector is erased + shmem_vect = shmem.find<MyVect>("MyVector").first; + if(shmem_vect) + return -1; + } + //Now check vector is still in the s + { + //Map preexisting shmem again in copy-on-write + managed_windows_shared_memory shmem(open_copy_on_write, MemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find<MyVect>("MyVector").first; + if(!shmem_vect) + return -1; + } + } + { + //Map preexisting shmem again in copy-on-write + managed_windows_shared_memory shmem(open_read_only, MemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find<MyVect>("MyVector").first; + if(!shmem_vect) + return -1; + } + + //Destroy and check it is not present + w_shm_new.destroy_ptr(w_shm_vect); + if(0 != w_shm_new.find<MyVect>("MyVector").first) + return 1; + + //Now test move semantics + managed_windows_shared_memory original(open_only, MemName); + managed_windows_shared_memory move_ctor(boost::move(original)); + managed_windows_shared_memory move_assign; + move_assign = boost::move(move_ctor); + } + } + + return 0; +} + +#else + +int main() +{ + return 0; +} + +#endif + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/managed_xsi_shared_memory_test.cpp b/src/boost/libs/interprocess/test/managed_xsi_shared_memory_test.cpp new file mode 100644 index 00000000..14925964 --- /dev/null +++ b/src/boost/libs/interprocess/test/managed_xsi_shared_memory_test.cpp @@ -0,0 +1,174 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/managed_xsi_shared_memory.hpp> +#include <boost/interprocess/detail/file_wrapper.hpp> +#include <boost/interprocess/file_mapping.hpp> +#include <cstdio> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +void remove_shared_memory(const xsi_key &key) +{ + try{ + xsi_shared_memory xsi(open_only, key); + xsi_shared_memory::remove(xsi.get_shmid()); + } + catch(interprocess_exception &e){ + if(e.get_error_code() != not_found_error) + throw; + } +} + +class xsi_shared_memory_remover +{ + public: + xsi_shared_memory_remover(xsi_shared_memory &xsi_shm) + : xsi_shm_(xsi_shm) + {} + + ~xsi_shared_memory_remover() + { xsi_shared_memory::remove(xsi_shm_.get_shmid()); } + private: + xsi_shared_memory & xsi_shm_; +}; + +inline std::string get_filename() +{ + std::string ret (ipcdetail::get_temporary_path()); + ret += "/"; + ret += test::get_process_id_name(); + return ret; +} + +int main () +{ + const int ShmemSize = 65536; + std::string filename = get_filename(); + const char *const ShmemName = filename.c_str(); + + file_mapping::remove(ShmemName); + { ipcdetail::file_wrapper(create_only, ShmemName, read_write); } + xsi_key key(ShmemName, 1); + file_mapping::remove(ShmemName); + int shmid; + + //STL compatible allocator object for memory-mapped shmem + typedef allocator<int, managed_xsi_shared_memory::segment_manager> + allocator_int_t; + //A vector that uses that allocator + typedef boost::interprocess::vector<int, allocator_int_t> MyVect; + + { + //Remove the shmem it is already created + remove_shared_memory(key); + + const int max = 100; + void *array[max]; + //Named allocate capable shared memory allocator + managed_xsi_shared_memory shmem(create_only, key, ShmemSize); + shmid = shmem.get_shmid(); + int i; + //Let's allocate some memory + for(i = 0; i < max; ++i){ + array[i] = shmem.allocate(i+1); + } + + //Deallocate allocated memory + for(i = 0; i < max; ++i){ + shmem.deallocate(array[i]); + } + } + + { + //Remove the shmem it is already created + xsi_shared_memory::remove(shmid); + + //Named allocate capable memory mapped shmem managed memory class + managed_xsi_shared_memory shmem(create_only, key, ShmemSize); + shmid = shmem.get_shmid(); + + //Construct the STL-like allocator with the segment manager + const allocator_int_t myallocator (shmem.get_segment_manager()); + + //Construct vector + MyVect *shmem_vect = shmem.construct<MyVect> ("MyVector") (myallocator); + + //Test that vector can be found via name + if(shmem_vect != shmem.find<MyVect>("MyVector").first) + return -1; + + //Destroy and check it is not present + shmem.destroy<MyVect> ("MyVector"); + if(0 != shmem.find<MyVect>("MyVector").first) + return -1; + + //Construct a vector in the memory-mapped shmem + shmem_vect = shmem.construct<MyVect> ("MyVector") (myallocator); + } + { + //Map preexisting shmem again in memory + managed_xsi_shared_memory shmem(open_only, key); + shmid = shmem.get_shmid(); + + //Check vector is still there + MyVect *shmem_vect = shmem.find<MyVect>("MyVector").first; + if(!shmem_vect) + return -1; + } + + + { + //Now destroy the vector + { + //Map preexisting shmem again in memory + managed_xsi_shared_memory shmem(open_only, key); + shmid = shmem.get_shmid(); + + //Destroy and check it is not present + shmem.destroy<MyVect>("MyVector"); + if(0 != shmem.find<MyVect>("MyVector").first) + return -1; + } + + { + //Now test move semantics + managed_xsi_shared_memory original(open_only, key); + managed_xsi_shared_memory move_ctor(boost::move(original)); + managed_xsi_shared_memory move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); + } + } + + xsi_shared_memory::remove(shmid); + return 0; +} + +#else + +int main() +{ + return 0; +} + +#endif //#ifndef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/map_index_allocation_test.cpp b/src/boost/libs/interprocess/test/map_index_allocation_test.cpp new file mode 100644 index 00000000..27078f45 --- /dev/null +++ b/src/boost/libs/interprocess/test/map_index_allocation_test.cpp @@ -0,0 +1,25 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/indexes/map_index.hpp> +#include "named_allocation_test_template.hpp" + +int main () +{ + using namespace boost::interprocess; + if(!test::test_named_allocation<map_index>()){ + return 1; + } + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/map_test.hpp b/src/boost/libs/interprocess/test/map_test.hpp new file mode 100644 index 00000000..0a20a787 --- /dev/null +++ b/src/boost/libs/interprocess/test/map_test.hpp @@ -0,0 +1,593 @@ +//////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +//////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_MAP_TEST_HEADER +#define BOOST_INTERPROCESS_TEST_MAP_TEST_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include "check_equal_containers.hpp" +#include <map> + +// interprocess +#include <boost/interprocess/containers/pair.hpp> +// interprocess/detail +#include <boost/interprocess/detail/utilities.hpp> +// intrusive/detail +#include <boost/intrusive/detail/minimal_pair_header.hpp> +#include <boost/intrusive/detail/minimal_less_equal_header.hpp> +// std +#include <string> + +#include "print_container.hpp" +#include "get_process_id_name.hpp" + +template<class T1, class T2, class T3, class T4> +bool operator ==(std::pair<T1, T2> &p1, std::pair<T1, T2> &p2) +{ + return p1.first == p2.first && p1.second == p2.second; +} + +namespace boost{ +namespace interprocess{ +namespace test{ + +template<class ManagedSharedMemory + ,class MyShmMap + ,class MyStdMap + ,class MyShmMultiMap + ,class MyStdMultiMap> +int map_test () +{ + typedef typename MyShmMap::key_type IntType; + typedef boost::interprocess::pair<IntType, IntType> IntPairType; + typedef typename MyStdMap::value_type StdPairType; + const int memsize = 65536; + const char *const shMemName = test::get_process_id_name(); + const int max = 100; + + try{ + //Create shared memory + shared_memory_object::remove(shMemName); + ManagedSharedMemory segment(create_only, shMemName, memsize); + + segment.reserve_named_objects(100); + + //Shared memory allocator must be always be initialized + //since it has no default constructor + MyShmMap *shmmap = + segment.template construct<MyShmMap>("MyShmMap") + (std::less<IntType>(), segment.get_segment_manager()); + + MyStdMap *stdmap = new MyStdMap; + + MyShmMultiMap *shmmultimap = + segment.template construct<MyShmMultiMap>("MyShmMultiMap") + (std::less<IntType>(), segment.get_segment_manager()); + + MyStdMultiMap *stdmultimap = new MyStdMultiMap; + + //Test construction from a range + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + typedef typename MyStdMap::value_type StdValueType; + typedef typename MyStdMap::key_type StdKeyType; + typedef typename MyStdMap::mapped_type StdMappedType; + StdValueType aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + new(&aux_vect2[i])StdValueType(StdKeyType(i/2), StdMappedType(i/2)); + } + + IntPairType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + MyShmMap *shmmap2 = + segment.template construct<MyShmMap>("MyShmMap2") + ( ::boost::make_move_iterator(&aux_vect[0]) + , ::boost::make_move_iterator(aux_vect + 50) + , std::less<IntType>(), segment.get_segment_manager()); + + MyStdMap *stdmap2 = new MyStdMap(aux_vect2, aux_vect2 + 50); + + MyShmMultiMap *shmmultimap2 = + segment.template construct<MyShmMultiMap>("MyShmMultiMap2") + ( ::boost::make_move_iterator(&aux_vect3[0]) + , ::boost::make_move_iterator(aux_vect3 + 50) + , std::less<IntType>(), segment.get_segment_manager()); + + MyStdMultiMap *stdmultimap2 = new MyStdMultiMap(aux_vect2, aux_vect2 + 50); + if(!CheckEqualContainers(shmmap2, stdmap2)) return 1; + if(!CheckEqualContainers(shmmultimap2, stdmultimap2)) return 1; + + //ordered range insertion + //This is really nasty, but we have no other simple choice + for(int i = 0; i < 50; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + for(int i = 0; i < 50; ++i){ + new(&aux_vect2[i])StdValueType(StdKeyType(i), StdMappedType(i)); + } + + for(int i = 0; i < 50; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + MyShmMap *shmmap3 = + segment.template construct<MyShmMap>("MyShmMap3") + ( ordered_unique_range + , ::boost::make_move_iterator(&aux_vect[0]) + , ::boost::make_move_iterator(aux_vect + 50) + , std::less<IntType>(), segment.get_segment_manager()); + + MyStdMap *stdmap3 = new MyStdMap(aux_vect2, aux_vect2 + 50); + + MyShmMultiMap *shmmultimap3 = + segment.template construct<MyShmMultiMap>("MyShmMultiMap3") + ( ordered_range + , ::boost::make_move_iterator(&aux_vect3[0]) + , ::boost::make_move_iterator(aux_vect3 + 50) + , std::less<IntType>(), segment.get_segment_manager()); + + MyStdMultiMap *stdmultimap3 = new MyStdMultiMap(aux_vect2, aux_vect2 + 50); + + if(!CheckEqualContainers(shmmap3, stdmap3)){ + std::cout << "Error in construct<MyShmMap>(MyShmMap3)" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultimap3, stdmultimap3)){ + std::cout << "Error in construct<MyShmMultiMap>(MyShmMultiMap3)" << std::endl; + return 1; + } + + segment.destroy_ptr(shmmap2); + segment.destroy_ptr(shmmultimap2); + delete stdmap2; + delete stdmultimap2; + segment.destroy_ptr(shmmap3); + segment.destroy_ptr(shmmultimap3); + delete stdmap3; + delete stdmultimap3; + } + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + IntPairType aux_vect3[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + for(int i = 0; i < max; ++i){ + shmmap->insert(boost::move(aux_vect[i])); + stdmap->insert(StdPairType(i, i)); + shmmultimap->insert(boost::move(aux_vect3[i])); + stdmultimap->insert(StdPairType(i, i)); + } + + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + typename MyShmMap::iterator it; + typename MyShmMap::const_iterator cit = it; + (void)cit; + + shmmap->erase(shmmap->begin()++); + stdmap->erase(stdmap->begin()++); + shmmultimap->erase(shmmultimap->begin()++); + stdmultimap->erase(stdmultimap->begin()++); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + shmmap->erase(shmmap->begin()); + stdmap->erase(stdmap->begin()); + shmmultimap->erase(shmmultimap->begin()); + stdmultimap->erase(stdmultimap->begin()); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + //Swapping test + std::less<IntType> lessfunc; + MyShmMap tmpshmemap2 (lessfunc, segment.get_segment_manager()); + MyStdMap tmpstdmap2; + MyShmMultiMap tmpshmemultimap2(lessfunc, segment.get_segment_manager()); + MyStdMultiMap tmpstdmultimap2; + shmmap->swap(tmpshmemap2); + stdmap->swap(tmpstdmap2); + shmmultimap->swap(tmpshmemultimap2); + stdmultimap->swap(tmpstdmultimap2); + shmmap->swap(tmpshmemap2); + stdmap->swap(tmpstdmap2); + shmmultimap->swap(tmpshmemultimap2); + stdmultimap->swap(tmpstdmultimap2); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + } + //Insertion from other container + //Initialize values + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + IntPairType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + shmmap->insert(::boost::make_move_iterator(&aux_vect[0]), ::boost::make_move_iterator(aux_vect + 50)); + shmmultimap->insert(::boost::make_move_iterator(&aux_vect3[0]), ::boost::make_move_iterator(aux_vect3 + 50)); + for(std::size_t i = 0; i != 50; ++i){ + StdPairType stdpairtype(-1, -1); + stdmap->insert(stdpairtype); + stdmultimap->insert(stdpairtype); + } + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + for(int i = 0, j = static_cast<int>(shmmap->size()); i < j; ++i){ + shmmap->erase(IntType(i)); + stdmap->erase(i); + shmmultimap->erase(IntType(i)); + stdmultimap->erase(i); + } + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + } + { + IntPairType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect4[50]; + for(int i = 0; i < 50; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect4[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect5[50]; + for(int i = 0; i < 50; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect5[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + shmmap->insert(::boost::make_move_iterator(&aux_vect[0]), ::boost::make_move_iterator(aux_vect + 50)); + shmmap->insert(::boost::make_move_iterator(&aux_vect3[0]), ::boost::make_move_iterator(aux_vect3 + 50)); + shmmultimap->insert(::boost::make_move_iterator(&aux_vect4[0]), ::boost::make_move_iterator(aux_vect4 + 50)); + shmmultimap->insert(::boost::make_move_iterator(&aux_vect5[0]), ::boost::make_move_iterator(aux_vect5 + 50)); + + for(std::size_t i = 0; i != 50; ++i){ + StdPairType stdpairtype(-1, -1); + stdmap->insert(stdpairtype); + stdmultimap->insert(stdpairtype); + stdmap->insert(stdpairtype); + stdmultimap->insert(stdpairtype); + } + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + shmmap->erase(shmmap->begin()->first); + stdmap->erase(stdmap->begin()->first); + shmmultimap->erase(shmmultimap->begin()->first); + stdmultimap->erase(stdmultimap->begin()->first); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + } + + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + IntPairType aux_vect3[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + for(int i = 0; i < max; ++i){ + shmmap->insert(boost::move(aux_vect[i])); + stdmap->insert(StdPairType(i, i)); + shmmultimap->insert(boost::move(aux_vect3[i])); + stdmultimap->insert(StdPairType(i, i)); + } + + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + for(int i = 0; i < max; ++i){ + IntPairType intpair; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + shmmap->insert(shmmap->begin(), boost::move(intpair)); + stdmap->insert(stdmap->begin(), StdPairType(i, i)); + //PrintContainers(shmmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + shmmultimap->insert(shmmultimap->begin(), boost::move(intpair)); + stdmultimap->insert(stdmultimap->begin(), StdPairType(i, i)); + //PrintContainers(shmmultimap, stdmultimap); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + shmmap->insert(shmmap->end(), boost::move(intpair)); + stdmap->insert(stdmap->end(), StdPairType(i, i)); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + shmmultimap->insert(shmmultimap->end(), boost::move(intpair)); + stdmultimap->insert(stdmultimap->end(), StdPairType(i, i)); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + shmmap->insert(shmmap->lower_bound(IntType(i)), boost::move(intpair)); + stdmap->insert(stdmap->lower_bound(i), StdPairType(i, i)); + //PrintContainers(shmmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + { + IntType i1(i); + shmmultimap->insert(shmmultimap->lower_bound(boost::move(i1)), boost::move(intpair)); + stdmultimap->insert(stdmultimap->lower_bound(i), StdPairType(i, i)); + } + + //PrintContainers(shmmultimap, stdmultimap); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + { + IntType i1(i); + shmmap->insert(shmmap->upper_bound(boost::move(i1)), boost::move(intpair)); + stdmap->insert(stdmap->upper_bound(i), StdPairType(i, i)); + } + //PrintContainers(shmmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + { + IntType i1(i); + shmmultimap->insert(shmmultimap->upper_bound(boost::move(i1)), boost::move(intpair)); + stdmultimap->insert(stdmultimap->upper_bound(i), StdPairType(i, i)); + } + //PrintContainers(shmmultimap, stdmultimap); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + } + + //Compare count with std containers + for(int i = 0; i < max; ++i){ + if(shmmap->count(IntType(i)) != stdmap->count(i)){ + return -1; + } + + if(shmmultimap->count(IntType(i)) != stdmultimap->count(i)){ + return -1; + } + } + + //Now do count exercise + shmmap->erase(shmmap->begin(), shmmap->end()); + shmmultimap->erase(shmmultimap->begin(), shmmultimap->end()); + shmmap->clear(); + shmmultimap->clear(); + + for(int j = 0; j < 3; ++j) + for(int i = 0; i < 100; ++i){ + IntPairType intpair; + { + IntType i1(i), i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + shmmap->insert(boost::move(intpair)); + { + IntType i1(i), i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + shmmultimap->insert(boost::move(intpair)); + if(shmmap->count(IntType(i)) != typename MyShmMultiMap::size_type(1)) + return 1; + if(shmmultimap->count(IntType(i)) != typename MyShmMultiMap::size_type(j+1)) + return 1; + } + } + + segment.template destroy<MyShmMap>("MyShmMap"); + delete stdmap; + segment.destroy_ptr(shmmultimap); + delete stdmultimap; + + segment.shrink_to_fit_indexes(); + + if(!segment.all_memory_deallocated()) + return 1; + } + catch(...){ + shared_memory_object::remove(shMemName); + throw; + } + shared_memory_object::remove(shMemName); + return 0; +} + +template<class ManagedSharedMemory + ,class MyShmMap + ,class MyStdMap + ,class MyShmMultiMap + ,class MyStdMultiMap> +int map_test_copyable () +{ + typedef typename MyShmMap::key_type IntType; + typedef boost::interprocess::pair<IntType, IntType> IntPairType; + typedef typename MyStdMap::value_type StdPairType; + + const int memsize = 65536; + const char *const shMemName = test::get_process_id_name(); + const int max = 100; + + try{ + //Create shared memory + shared_memory_object::remove(shMemName); + ManagedSharedMemory segment(create_only, shMemName, memsize); + + segment.reserve_named_objects(100); + + //Shared memory allocator must be always be initialized + //since it has no default constructor + MyShmMap *shmmap = + segment.template construct<MyShmMap>("MyShmMap") + (std::less<IntType>(), segment.get_segment_manager()); + + MyStdMap *stdmap = new MyStdMap; + + MyShmMultiMap *shmmultimap = + segment.template construct<MyShmMultiMap>("MyShmMultiMap") + (std::less<IntType>(), segment.get_segment_manager()); + + MyStdMultiMap *stdmultimap = new MyStdMultiMap; + + int i; + for(i = 0; i < max; ++i){ + { + IntType i1(i), i2(i); + IntPairType intpair1(boost::move(i1), boost::move(i2)); + shmmap->insert(boost::move(intpair1)); + stdmap->insert(StdPairType(i, i)); + } + { + IntType i1(i), i2(i); + IntPairType intpair2(boost::move(i1), boost::move(i2)); + shmmultimap->insert(boost::move(intpair2)); + stdmultimap->insert(StdPairType(i, i)); + } + } + if(!CheckEqualContainers(shmmap, stdmap)) return 1; + if(!CheckEqualContainers(shmmultimap, stdmultimap)) return 1; + + { + //Now, test copy constructor + MyShmMap shmmapcopy(*shmmap); + MyStdMap stdmapcopy(*stdmap); + MyShmMultiMap shmmmapcopy(*shmmultimap); + MyStdMultiMap stdmmapcopy(*stdmultimap); + + if(!CheckEqualContainers(&shmmapcopy, &stdmapcopy)) + return 1; + if(!CheckEqualContainers(&shmmmapcopy, &stdmmapcopy)) + return 1; + + //And now assignment + shmmapcopy = *shmmap; + stdmapcopy = *stdmap; + shmmmapcopy = *shmmultimap; + stdmmapcopy = *stdmultimap; + + if(!CheckEqualContainers(&shmmapcopy, &stdmapcopy)) + return 1; + if(!CheckEqualContainers(&shmmmapcopy, &stdmmapcopy)) + return 1; + delete stdmap; + delete stdmultimap; + segment.destroy_ptr(shmmap); + segment.destroy_ptr(shmmultimap); + } + segment.shrink_to_fit_indexes(); + + if(!segment.all_memory_deallocated()) + return 1; + } + catch(...){ + shared_memory_object::remove(shMemName); + throw; + } + shared_memory_object::remove(shMemName); + return 0; +} + +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_TEST_MAP_TEST_HEADER diff --git a/src/boost/libs/interprocess/test/mapped_file_test.cpp b/src/boost/libs/interprocess/test/mapped_file_test.cpp new file mode 100644 index 00000000..9d19977a --- /dev/null +++ b/src/boost/libs/interprocess/test/mapped_file_test.cpp @@ -0,0 +1,100 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#if defined(BOOST_INTERPROCESS_MAPPED_FILES) + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/detail/file_wrapper.hpp> +#include <boost/interprocess/file_mapping.hpp> +#include <boost/interprocess/detail/managed_open_or_create_impl.hpp> +#include "named_creation_template.hpp" +#include <cstdio> +#include <cstring> +#include <string> +#include <boost/interprocess/detail/os_file_functions.hpp> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +static const std::size_t FileSize = 1000; +inline std::string get_filename() +{ + std::string ret (ipcdetail::get_temporary_path()); + ret += "/"; + ret += test::get_process_id_name(); + return ret; +} + +struct file_destroyer +{ + ~file_destroyer() + { + //The last destructor will destroy the file + file_mapping::remove(get_filename().c_str()); + } +}; + +//This wrapper is necessary to have a common constructor +//in generic named_creation_template functions +class mapped_file_creation_test_wrapper + : public file_destroyer + , public boost::interprocess::ipcdetail::managed_open_or_create_impl + <boost::interprocess::ipcdetail::file_wrapper, 0, true, false> +{ + typedef boost::interprocess::ipcdetail::managed_open_or_create_impl + <boost::interprocess::ipcdetail::file_wrapper, 0, true, false> mapped_file; + public: + mapped_file_creation_test_wrapper(boost::interprocess::create_only_t) + : mapped_file(boost::interprocess::create_only, get_filename().c_str(), FileSize, read_write, 0, permissions()) + {} + + mapped_file_creation_test_wrapper(boost::interprocess::open_only_t) + : mapped_file(boost::interprocess::open_only, get_filename().c_str(), read_write, 0) + {} + + mapped_file_creation_test_wrapper(boost::interprocess::open_or_create_t) + : mapped_file(boost::interprocess::open_or_create, get_filename().c_str(), FileSize, read_write, 0, permissions()) + {} +}; + +int main () +{ + typedef boost::interprocess::ipcdetail::managed_open_or_create_impl + <boost::interprocess::ipcdetail::file_wrapper, 0, true, false> mapped_file; + file_mapping::remove(get_filename().c_str()); + test::test_named_creation<mapped_file_creation_test_wrapper>(); + + //Create and get name, size and address + { + mapped_file file1(create_only, get_filename().c_str(), FileSize, read_write, 0, permissions()); + + //Overwrite all memory + std::memset(file1.get_user_address(), 0, file1.get_user_size()); + + //Now test move semantics + mapped_file move_ctor(boost::move(file1)); + mapped_file move_assign; + move_assign = boost::move(move_ctor); + } +// file_mapping::remove(get_filename().c_str()); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> + +#else //#if !defined(BOOST_INTERPROCESS_MAPPED_FILES) + +int main() +{ + return 0; +} + +#endif//#if !defined(BOOST_INTERPROCESS_MAPPED_FILES) diff --git a/src/boost/libs/interprocess/test/memory_algorithm_test.cpp b/src/boost/libs/interprocess/test/memory_algorithm_test.cpp new file mode 100644 index 00000000..9210640a --- /dev/null +++ b/src/boost/libs/interprocess/test/memory_algorithm_test.cpp @@ -0,0 +1,91 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/mem_algo/simple_seq_fit.hpp> +#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp> +#include <boost/interprocess/indexes/null_index.hpp> +#include <boost/interprocess/sync/mutex_family.hpp> +#include <boost/interprocess/detail/type_traits.hpp> +#include <boost/move/detail/type_traits.hpp> //make_unsigned, alignment_of +#include "memory_algorithm_test_template.hpp" +#include <iostream> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +const int Memsize = 16384; +const char *const shMemName = test::get_process_id_name(); + +int test_simple_seq_fit() +{ + //A shared memory with simple sequential fit algorithm + typedef basic_managed_shared_memory + <char + ,simple_seq_fit<mutex_family> + ,null_index + > my_managed_shared_memory; + + //Create shared memory + shared_memory_object::remove(shMemName); + my_managed_shared_memory segment(create_only, shMemName, Memsize); + + //Now take the segment manager and launch memory test + if(!test::test_all_allocation(*segment.get_segment_manager())){ + return 1; + } + return 0; +} + +template<std::size_t Alignment> +int test_rbtree_best_fit() +{ + //A shared memory with red-black tree best fit algorithm + typedef basic_managed_shared_memory + <char + ,rbtree_best_fit<mutex_family, offset_ptr<void>, Alignment> + ,null_index + > my_managed_shared_memory; + + //Create shared memory + shared_memory_object::remove(shMemName); + my_managed_shared_memory segment(create_only, shMemName, Memsize); + + //Now take the segment manager and launch memory test + if(!test::test_all_allocation(*segment.get_segment_manager())){ + return 1; + } + return 0; +} + +int main () +{ + const std::size_t void_ptr_align = ::boost::container::dtl::alignment_of<offset_ptr<void> >::value; + + if(test_simple_seq_fit()){ + return 1; + } + if(test_rbtree_best_fit<void_ptr_align>()){ + return 1; + } + if(test_rbtree_best_fit<2*void_ptr_align>()){ + return 1; + } + if(test_rbtree_best_fit<4*void_ptr_align>()){ + return 1; + } + + shared_memory_object::remove(shMemName); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/memory_algorithm_test_template.hpp b/src/boost/libs/interprocess/test/memory_algorithm_test_template.hpp new file mode 100644 index 00000000..10e880e7 --- /dev/null +++ b/src/boost/libs/interprocess/test/memory_algorithm_test_template.hpp @@ -0,0 +1,1036 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER +#define BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> + +#include <boost/interprocess/containers/vector.hpp> + +#include <vector> +#include <iostream> +#include <new> //std::nothrow +#include <cstring> //std::memset + +namespace boost { namespace interprocess { namespace test { + +enum deallocation_type { DirectDeallocation, InverseDeallocation, MixedDeallocation, EndDeallocationType }; + +//This test allocates until there is no more memory +//and after that deallocates all in the inverse order +template<class Allocator> +bool test_allocation(Allocator &a) +{ + for( deallocation_type t = DirectDeallocation + ; t != EndDeallocationType + ; t = (deallocation_type)((int)t + 1)){ + std::vector<void*> buffers; + typename Allocator::size_type free_memory = a.get_free_memory(); + + for(int i = 0; true; ++i){ + void *ptr = a.allocate(i, std::nothrow); + if(!ptr) + break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); + buffers.push_back(ptr); + } + + switch(t){ + case DirectDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + a.deallocate(buffers[j]); + } + } + break; + case InverseDeallocation: + { + for(int j = (int)buffers.size() + ;j-- + ;){ + a.deallocate(buffers[j]); + } + } + break; + case MixedDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + a.deallocate(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + } + break; + default: + break; + } + bool ok = free_memory == a.get_free_memory() && + a.all_memory_deallocated() && a.check_sanity(); + if(!ok) return ok; + } + return true; +} + +//This test allocates until there is no more memory +//and after that tries to shrink all the buffers to the +//half of the original size +template<class Allocator> +bool test_allocation_shrink(Allocator &a) +{ + std::vector<void*> buffers; + + //Allocate buffers with extra memory + for(int i = 0; true; ++i){ + void *ptr = a.allocate(i*2, std::nothrow); + if(!ptr) + break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); + buffers.push_back(ptr); + } + + //Now shrink to half + for(int i = 0, max = (int)buffers.size() + ;i < max + ; ++i){ + typename Allocator::size_type received_size; + char *reuse = static_cast<char*>(buffers[i]); + if(a.template allocation_command<char> + ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, i*2 + , received_size = i, reuse)){ + if(received_size > std::size_t(i*2)){ + return false; + } + if(received_size < std::size_t(i)){ + return false; + } + std::memset(buffers[i], 0, a.size(buffers[i])); + } + } + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + a.deallocate(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + + return a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates until there is no more memory +//and after that tries to expand all the buffers to +//avoid the wasted internal fragmentation +template<class Allocator> +bool test_allocation_expand(Allocator &a) +{ + std::vector<void*> buffers; + + //Allocate buffers with extra memory + for(int i = 0; true; ++i){ + void *ptr = a.allocate(i, std::nothrow); + if(!ptr) + break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); + buffers.push_back(ptr); + } + + //Now try to expand to the double of the size + for(int i = 0, max = (int)buffers.size() + ;i < max + ;++i){ + typename Allocator::size_type received_size; + std::size_t min_size = i+1; + std::size_t preferred_size = i*2; + preferred_size = min_size > preferred_size ? min_size : preferred_size; + + char *reuse = static_cast<char*>(buffers[i]); + while(a.template allocation_command<char> + ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size + , received_size = preferred_size, reuse)){ + //Check received size is bigger than minimum + if(received_size < min_size){ + return false; + } + //Now, try to expand further + min_size = received_size+1; + preferred_size = min_size*2; + } + } + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + a.deallocate(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + + return a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates until there is no more memory +//and after that tries to expand all the buffers to +//avoid the wasted internal fragmentation +template<class Allocator> +bool test_allocation_shrink_and_expand(Allocator &a) +{ + std::vector<void*> buffers; + std::vector<typename Allocator::size_type> received_sizes; + std::vector<bool> size_reduced; + + //Allocate buffers wand store received sizes + for(int i = 0; true; ++i){ + typename Allocator::size_type received_size; + char *reuse = 0; + void *ptr = a.template allocation_command<char> + ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, i, received_size = i*2, reuse); + if(!ptr){ + ptr = a.template allocation_command<char> + ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, 1, received_size = i*2, reuse); + if(!ptr) + break; + } + buffers.push_back(ptr); + received_sizes.push_back(received_size); + } + + //Now shrink to half + for(int i = 0, max = (int)buffers.size() + ; i < max + ; ++i){ + typename Allocator::size_type received_size; + char *reuse = static_cast<char*>(buffers[i]); + if(a.template allocation_command<char> + ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_sizes[i] + , received_size = i, reuse)){ + if(received_size > std::size_t(received_sizes[i])){ + return false; + } + if(received_size < std::size_t(i)){ + return false; + } + size_reduced.push_back(received_size != received_sizes[i]); + } + } + + //Now try to expand to the original size + for(int i = 0, max = (int)buffers.size() + ;i < max + ;++i){ + typename Allocator::size_type received_size; + std::size_t request_size = received_sizes[i]; + char *reuse = static_cast<char*>(buffers[i]); + if(a.template allocation_command<char> + ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, request_size + , received_size = request_size, reuse)){ + if(received_size != received_sizes[i]){ + return false; + } + } + else{ + return false; + } + } + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + a.deallocate(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + + return a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates until there is no more memory +//and after that deallocates the odd buffers to +//make room for expansions. The expansion will probably +//success since the deallocation left room for that. +template<class Allocator> +bool test_allocation_deallocation_expand(Allocator &a) +{ + std::vector<void*> buffers; + + //Allocate buffers with extra memory + for(int i = 0; true; ++i){ + void *ptr = a.allocate(i, std::nothrow); + if(!ptr) + break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); + buffers.push_back(ptr); + } + + //Now deallocate the half of the blocks + //so expand maybe can merge new free blocks + for(int i = 0, max = (int)buffers.size() + ;i < max + ;++i){ + if(i%2){ + a.deallocate(buffers[i]); + buffers[i] = 0; + } + } + + //Now try to expand to the double of the size + for(int i = 0, max = (int)buffers.size() + ;i < max + ;++i){ + // + if(buffers[i]){ + typename Allocator::size_type received_size; + std::size_t min_size = i+1; + std::size_t preferred_size = i*2; + preferred_size = min_size > preferred_size ? min_size : preferred_size; + + char *reuse = static_cast<char*>(buffers[i]); + while(a.template allocation_command<char> + ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size + , received_size = preferred_size, reuse)){ + //Check received size is bigger than minimum + if(received_size < min_size){ + return false; + } + //Now, try to expand further + min_size = received_size+1; + preferred_size = min_size*2; + } + } + } + + //Now erase null values from the vector + buffers.erase( std::remove(buffers.begin(), buffers.end(), static_cast<void*>(0)) + , buffers.end()); + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + a.deallocate(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + + return a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates until there is no more memory +//and after that deallocates all except the last. +//If the allocation algorithm is a bottom-up algorithm +//the last buffer will be in the end of the segment. +//Then the test will start expanding backwards, until +//the buffer fills all the memory +template<class Allocator> +bool test_allocation_with_reuse(Allocator &a) +{ + //We will repeat this test for different sized elements + for(int sizeof_object = 1; sizeof_object < 20; ++sizeof_object){ + std::vector<void*> buffers; + + //Allocate buffers with extra memory + for(int i = 0; true; ++i){ + void *ptr = a.allocate(i*sizeof_object, std::nothrow); + if(!ptr) + break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); + buffers.push_back(ptr); + } + + //Now deallocate all except the latest + //Now try to expand to the double of the sizeof_object + for(int i = 0, max = (int)buffers.size() - 1 + ;i < max + ;++i){ + a.deallocate(buffers[i]); + } + + //Save the unique buffer and clear vector + void *ptr = buffers.back(); + buffers.clear(); + + //Now allocate with reuse + typename Allocator::size_type received_size = 0; + for(int i = 0; true; ++i){ + std::size_t min_size = (received_size + 1); + std::size_t prf_size = (received_size + (i+1)*2); + void *reuse = ptr; + void *ret = a.raw_allocation_command + ( boost::interprocess::expand_bwd | boost::interprocess::nothrow_allocation, min_size + , received_size = prf_size, reuse, sizeof_object); + if(!ret) + break; + //If we have memory, this must be a buffer reuse + if(!reuse) + return 1; + if(received_size < min_size) + return 1; + ptr = ret; + } + //There is only a single block so deallocate it + a.deallocate(ptr); + + if(!a.all_memory_deallocated() || !a.check_sanity()) + return false; + } + return true; +} + + +//This test allocates memory with different alignments +//and checks returned memory is aligned. +template<class Allocator> +bool test_aligned_allocation(Allocator &a) +{ + //Allocate aligned buffers in a loop + //and then deallocate it + bool continue_loop = true; + for(unsigned int i = 1; continue_loop; i <<= 1){ + for(unsigned int j = 1; true; j <<= 1){ + void *ptr = a.allocate_aligned(i-1, j, std::nothrow); + if(!ptr){ + if(j == 1) + continue_loop = false; + break; + } + + if(((std::size_t)ptr & (j - 1)) != 0) + return false; + a.deallocate(ptr); + if(!a.all_memory_deallocated() || !a.check_sanity()){ + return false; + } + } + } + + return a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates memory with different alignments +//and checks returned memory is aligned. +template<class Allocator> +bool test_continuous_aligned_allocation(Allocator &a) +{ + std::vector<void*> buffers; + //Allocate aligned buffers in a loop + //and then deallocate it + bool continue_loop = true; + for(unsigned i = 1; continue_loop && i; i <<= 1){ + for(unsigned int j = 1; j; j <<= 1){ + for(bool any_allocated = false; 1;){ + void *ptr = a.allocate_aligned(i-1, j, std::nothrow); + buffers.push_back(ptr); + if(!ptr){ + if(j == 1 && !any_allocated){ + continue_loop = false; + } + break; + } + else{ + any_allocated = true; + } + + if(((std::size_t)ptr & (j - 1)) != 0) + return false; + } + //Deallocate all + for(unsigned int k = (int)buffers.size(); k--;){ + a.deallocate(buffers[k]); + } + buffers.clear(); + if(!a.all_memory_deallocated() && a.check_sanity()) + return false; + if(!continue_loop) + break; + } + } + + return a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates memory, writes it with a non-zero value and +//tests zero_free_memory initializes to zero for the next allocation +template<class Allocator> +bool test_clear_free_memory(Allocator &a) +{ + std::vector<void*> buffers; + + //Allocate memory + for(int i = 0; true; ++i){ + void *ptr = a.allocate(i, std::nothrow); + if(!ptr) + break; + std::size_t size = a.size(ptr); + std::memset(ptr, 1, size); + buffers.push_back(ptr); + } + + //Mark it + for(int i = 0, max = buffers.size(); i < max; ++i){ + std::memset(buffers[i], 1, i); + } + + //Deallocate all + for(int j = (int)buffers.size() + ;j-- + ;){ + a.deallocate(buffers[j]); + } + buffers.clear(); + + if(!a.all_memory_deallocated() && a.check_sanity()) + return false; + + //Now clear all free memory + a.zero_free_memory(); + + if(!a.all_memory_deallocated() && a.check_sanity()) + return false; + + //Now test all allocated memory is zero + //Allocate memory + const char *first_addr = 0; + for(int i = 0; true; ++i){ + void *ptr = a.allocate(i, std::nothrow); + if(!ptr) + break; + if(i == 0){ + first_addr = (char*)ptr; + } + std::size_t memsize = a.size(ptr); + buffers.push_back(ptr); + + for(int j = 0; j < (int)memsize; ++j){ + if(static_cast<char*>((char*)ptr)[j]){ + std::cout << "Zero memory test failed. in buffer " << i + << " byte " << j << " first address " << (void*) first_addr << " offset " << ((char*)ptr+j) - (char*)first_addr << " memsize: " << memsize << std::endl; + return false; + } + } + } + + //Deallocate all + for(int j = (int)buffers.size() + ;j-- + ;){ + a.deallocate(buffers[j]); + } + if(!a.all_memory_deallocated() && a.check_sanity()) + return false; + + return true; +} + + +//This test uses tests grow and shrink_to_fit functions +template<class Allocator> +bool test_grow_shrink_to_fit(Allocator &a) +{ + std::vector<void*> buffers; + + typename Allocator::size_type original_size = a.get_size(); + typename Allocator::size_type original_free = a.get_free_memory(); + + a.shrink_to_fit(); + + if(!a.all_memory_deallocated() && a.check_sanity()) + return false; + + typename Allocator::size_type shrunk_size = a.get_size(); + typename Allocator::size_type shrunk_free_memory = a.get_free_memory(); + if(shrunk_size != a.get_min_size()) + return 1; + + a.grow(original_size - shrunk_size); + + if(!a.all_memory_deallocated() && a.check_sanity()) + return false; + + if(original_size != a.get_size()) + return false; + if(original_free != a.get_free_memory()) + return false; + + //Allocate memory + for(int i = 0; true; ++i){ + void *ptr = a.allocate(i, std::nothrow); + if(!ptr) + break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); + buffers.push_back(ptr); + } + + //Now deallocate the half of the blocks + //so expand maybe can merge new free blocks + for(int i = 0, max = (int)buffers.size() + ;i < max + ;++i){ + if(i%2){ + a.deallocate(buffers[i]); + buffers[i] = 0; + } + } + + //Deallocate the rest of the blocks + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%5)*((int)buffers.size())/4; + if(pos == int(buffers.size())) + --pos; + a.deallocate(buffers[pos]); + buffers.erase(buffers.begin()+pos); + typename Allocator::size_type old_free = a.get_free_memory(); + a.shrink_to_fit(); + if(!a.check_sanity()) return false; + if(original_size < a.get_size()) return false; + if(old_free < a.get_free_memory()) return false; + + a.grow(original_size - a.get_size()); + + if(!a.check_sanity()) return false; + if(original_size != a.get_size()) return false; + if(old_free != a.get_free_memory()) return false; + } + + //Now shrink it to the maximum + a.shrink_to_fit(); + + if(a.get_size() != a.get_min_size()) + return 1; + + if(shrunk_free_memory != a.get_free_memory()) + return 1; + + if(!a.all_memory_deallocated() && a.check_sanity()) + return false; + + a.grow(original_size - shrunk_size); + + if(original_size != a.get_size()) + return false; + if(original_free != a.get_free_memory()) + return false; + + if(!a.all_memory_deallocated() && a.check_sanity()) + return false; + return true; +} + +//This test allocates multiple values until there is no more memory +//and after that deallocates all in the inverse order +template<class Allocator> +bool test_many_equal_allocation(Allocator &a) +{ + for( deallocation_type t = DirectDeallocation + ; t != EndDeallocationType + ; t = (deallocation_type)((int)t + 1)){ + typename Allocator::size_type free_memory = a.get_free_memory(); + + std::vector<void*> buffers2; + + //Allocate buffers with extra memory + for(int i = 0; true; ++i){ + void *ptr = a.allocate(i, std::nothrow); + if(!ptr) + break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); + if(!a.check_sanity()) + return false; + buffers2.push_back(ptr); + } + + //Now deallocate the half of the blocks + //so expand maybe can merge new free blocks + for(int i = 0, max = (int)buffers2.size() + ;i < max + ;++i){ + if(i%2){ + a.deallocate(buffers2[i]); + buffers2[i] = 0; + } + } + + if(!a.check_sanity()) + return false; + + typedef typename Allocator::multiallocation_chain multiallocation_chain; + std::vector<void*> buffers; + for(int i = 0; true; ++i){ + multiallocation_chain chain; + a.allocate_many(std::nothrow, i+1, (i+1)*2, chain); + if(chain.empty()) + break; + + typename multiallocation_chain::size_type n = chain.size(); + while(!chain.empty()){ + buffers.push_back(ipcdetail::to_raw_pointer(chain.pop_front())); + } + if(n != std::size_t((i+1)*2)) + return false; + } + + if(!a.check_sanity()) + return false; + + switch(t){ + case DirectDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + a.deallocate(buffers[j]); + } + } + break; + case InverseDeallocation: + { + for(int j = (int)buffers.size() + ;j-- + ;){ + a.deallocate(buffers[j]); + } + } + break; + case MixedDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + a.deallocate(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + } + break; + default: + break; + } + + //Deallocate the rest of the blocks + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers2.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers2.size())/4; + a.deallocate(buffers2[pos]); + buffers2.erase(buffers2.begin()+pos); + } + + bool ok = free_memory == a.get_free_memory() && + a.all_memory_deallocated() && a.check_sanity(); + if(!ok) return ok; + } + return true; +} + +//This test allocates multiple values until there is no more memory +//and after that deallocates all in the inverse order +template<class Allocator> +bool test_many_different_allocation(Allocator &a) +{ + typedef typename Allocator::multiallocation_chain multiallocation_chain; + const std::size_t ArraySize = 11; + typename Allocator::size_type requested_sizes[ArraySize]; + for(std::size_t i = 0; i < ArraySize; ++i){ + requested_sizes[i] = 4*i; + } + + for( deallocation_type t = DirectDeallocation + ; t != EndDeallocationType + ; t = (deallocation_type)((int)t + 1)){ + typename Allocator::size_type free_memory = a.get_free_memory(); + + std::vector<void*> buffers2; + + //Allocate buffers with extra memory + for(int i = 0; true; ++i){ + void *ptr = a.allocate(i, std::nothrow); + if(!ptr) + break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); + buffers2.push_back(ptr); + } + + //Now deallocate the half of the blocks + //so expand maybe can merge new free blocks + for(int i = 0, max = (int)buffers2.size() + ;i < max + ;++i){ + if(i%2){ + a.deallocate(buffers2[i]); + buffers2[i] = 0; + } + } + + std::vector<void*> buffers; + for(int i = 0; true; ++i){ + multiallocation_chain chain; + a.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain); + if(chain.empty()) + break; + typename multiallocation_chain::size_type n = chain.size(); + while(!chain.empty()){ + buffers.push_back(ipcdetail::to_raw_pointer(chain.pop_front())); + } + if(n != ArraySize) + return false; + } + + switch(t){ + case DirectDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + a.deallocate(buffers[j]); + } + } + break; + case InverseDeallocation: + { + for(int j = (int)buffers.size() + ;j-- + ;){ + a.deallocate(buffers[j]); + } + } + break; + case MixedDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + a.deallocate(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + } + break; + default: + break; + } + + //Deallocate the rest of the blocks + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers2.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers2.size())/4; + a.deallocate(buffers2[pos]); + buffers2.erase(buffers2.begin()+pos); + } + + bool ok = free_memory == a.get_free_memory() && + a.all_memory_deallocated() && a.check_sanity(); + if(!ok) return ok; + } + return true; +} + +//This test allocates multiple values until there is no more memory +//and after that deallocates all in the inverse order +template<class Allocator> +bool test_many_deallocation(Allocator &a) +{ + typedef typename Allocator::multiallocation_chain multiallocation_chain; + + typedef typename Allocator::multiallocation_chain multiallocation_chain; + const std::size_t ArraySize = 11; + vector<multiallocation_chain> buffers; + typename Allocator::size_type requested_sizes[ArraySize]; + for(std::size_t i = 0; i < ArraySize; ++i){ + requested_sizes[i] = 4*i; + } + typename Allocator::size_type free_memory = a.get_free_memory(); + + { + for(int i = 0; true; ++i){ + multiallocation_chain chain; + a.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain); + if(chain.empty()) + break; + buffers.push_back(boost::move(chain)); + } + for(int i = 0, max = (int)buffers.size(); i != max; ++i){ + a.deallocate_many(buffers[i]); + } + buffers.clear(); + bool ok = free_memory == a.get_free_memory() && + a.all_memory_deallocated() && a.check_sanity(); + if(!ok) return ok; + } + + { + for(int i = 0; true; ++i){ + multiallocation_chain chain; + a.allocate_many(std::nothrow, i*4, ArraySize, chain); + if(chain.empty()) + break; + buffers.push_back(boost::move(chain)); + } + for(int i = 0, max = (int)buffers.size(); i != max; ++i){ + a.deallocate_many(buffers[i]); + } + buffers.clear(); + + bool ok = free_memory == a.get_free_memory() && + a.all_memory_deallocated() && a.check_sanity(); + if(!ok) return ok; + } + + return true; +} + + +//This function calls all tests +template<class Allocator> +bool test_all_allocation(Allocator &a) +{ + std::cout << "Starting test_allocation. Class: " + << typeid(a).name() << std::endl; + + if(!test_allocation(a)){ + std::cout << "test_allocation_direct_deallocation failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + std::cout << "Starting test_many_equal_allocation. Class: " + << typeid(a).name() << std::endl; + + if(!test_many_equal_allocation(a)){ + std::cout << "test_many_equal_allocation failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + std::cout << "Starting test_many_different_allocation. Class: " + << typeid(a).name() << std::endl; + + if(!test_many_different_allocation(a)){ + std::cout << "test_many_different_allocation failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + if(!test_many_deallocation(a)){ + std::cout << "test_many_deallocation failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + std::cout << "Starting test_allocation_shrink. Class: " + << typeid(a).name() << std::endl; + + if(!test_allocation_shrink(a)){ + std::cout << "test_allocation_shrink failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + if(!test_allocation_shrink_and_expand(a)){ + std::cout << "test_allocation_shrink_and_expand failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + std::cout << "Starting test_allocation_expand. Class: " + << typeid(a).name() << std::endl; + + if(!test_allocation_expand(a)){ + std::cout << "test_allocation_expand failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + std::cout << "Starting test_allocation_deallocation_expand. Class: " + << typeid(a).name() << std::endl; + + if(!test_allocation_deallocation_expand(a)){ + std::cout << "test_allocation_deallocation_expand failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + std::cout << "Starting test_allocation_with_reuse. Class: " + << typeid(a).name() << std::endl; + + if(!test_allocation_with_reuse(a)){ + std::cout << "test_allocation_with_reuse failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + std::cout << "Starting test_aligned_allocation. Class: " + << typeid(a).name() << std::endl; + + if(!test_aligned_allocation(a)){ + std::cout << "test_aligned_allocation failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + std::cout << "Starting test_continuous_aligned_allocation. Class: " + << typeid(a).name() << std::endl; + + if(!test_continuous_aligned_allocation(a)){ + std::cout << "test_continuous_aligned_allocation failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + std::cout << "Starting test_clear_free_memory. Class: " + << typeid(a).name() << std::endl; + + if(!test_clear_free_memory(a)){ + std::cout << "test_clear_free_memory failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + std::cout << "Starting test_grow_shrink_to_fit. Class: " + << typeid(a).name() << std::endl; + + if(!test_grow_shrink_to_fit(a)){ + std::cout << "test_grow_shrink_to_fit failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + + return true; +} + +}}} //namespace boost { namespace interprocess { namespace test { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER + diff --git a/src/boost/libs/interprocess/test/message_queue_test.cpp b/src/boost/libs/interprocess/test/message_queue_test.cpp new file mode 100644 index 00000000..fe76cad5 --- /dev/null +++ b/src/boost/libs/interprocess/test/message_queue_test.cpp @@ -0,0 +1,376 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/ipc/message_queue.hpp> +#include <boost/interprocess/managed_external_buffer.hpp> +#include <boost/interprocess/managed_heap_memory.hpp> +#include <boost/interprocess/containers/map.hpp> +#include <boost/interprocess/containers/set.hpp> +#include <boost/interprocess/allocators/node_allocator.hpp> +#include <boost/interprocess/detail/os_thread_functions.hpp> +// intrusive/detail +#include <boost/intrusive/detail/minimal_pair_header.hpp> +#include <boost/intrusive/detail/minimal_less_equal_header.hpp> + +#include <boost/move/unique_ptr.hpp> + +#include <cstddef> +#include <memory> +#include <iostream> +#include <vector> +#include <stdexcept> +#include <limits> + +#include "get_process_id_name.hpp" + +//////////////////////////////////////////////////////////////////////////////// +// // +// This example tests the process shared message queue. // +// // +//////////////////////////////////////////////////////////////////////////////// + +using namespace boost::interprocess; + +//This test inserts messages with different priority and marks them with a +//time-stamp to check if receiver obtains highest priority messages first and +//messages with same priority are received in fifo order +bool test_priority_order() +{ + message_queue::remove(test::get_process_id_name()); + { + message_queue mq1 + (open_or_create, test::get_process_id_name(), 100, sizeof(std::size_t)), + mq2 + (open_or_create, test::get_process_id_name(), 100, sizeof(std::size_t)); + + //We test that the queue is ordered by priority and in the + //same priority, is a FIFO + message_queue::size_type recvd = 0; + unsigned int priority = 0; + std::size_t tstamp; + unsigned int priority_prev; + std::size_t tstamp_prev; + + //We will send 100 message with priority 0-9 + //The message will contain the timestamp of the message + for(std::size_t i = 0; i < 100; ++i){ + tstamp = i; + mq1.send(&tstamp, sizeof(tstamp), (unsigned int)(i%10)); + } + + priority_prev = (std::numeric_limits<unsigned int>::max)(); + tstamp_prev = 0; + + //Receive all messages and test those are ordered + //by priority and by FIFO in the same priority + for(std::size_t i = 0; i < 100; ++i){ + mq1.receive(&tstamp, sizeof(tstamp), recvd, priority); + if(priority > priority_prev) + return false; + if(priority == priority_prev && + tstamp <= tstamp_prev){ + return false; + } + priority_prev = priority; + tstamp_prev = tstamp; + } + + //Now retry it with different priority order + for(std::size_t i = 0; i < 100; ++i){ + tstamp = i; + mq1.send(&tstamp, sizeof(tstamp), (unsigned int)(9 - i%10)); + } + + priority_prev = (std::numeric_limits<unsigned int>::max)(); + tstamp_prev = 0; + + //Receive all messages and test those are ordered + //by priority and by FIFO in the same priority + for(std::size_t i = 0; i < 100; ++i){ + mq1.receive(&tstamp, sizeof(tstamp), recvd, priority); + if(priority > priority_prev) + return false; + if(priority == priority_prev && + tstamp <= tstamp_prev){ + return false; + } + priority_prev = priority; + tstamp_prev = tstamp; + } + } + message_queue::remove(test::get_process_id_name()); + return true; +} + +//[message_queue_test_test_serialize_db +//This test creates a in memory data-base using Interprocess machinery and +//serializes it through a message queue. Then rebuilds the data-base in +//another buffer and checks it against the original data-base +bool test_serialize_db() +{ + //Typedef data to create a Interprocess map + typedef std::pair<const std::size_t, std::size_t> MyPair; + typedef std::less<std::size_t> MyLess; + typedef node_allocator<MyPair, managed_external_buffer::segment_manager> + node_allocator_t; + typedef map<std::size_t, + std::size_t, + std::less<std::size_t>, + node_allocator_t> + MyMap; + + //Some constants + const std::size_t BufferSize = 65536; + const std::size_t MaxMsgSize = 100; + + //Allocate a memory buffer to hold the destiny database using vector<char> + std::vector<char> buffer_destiny(BufferSize, 0); + + message_queue::remove(test::get_process_id_name()); + { + //Create the message-queues + message_queue mq1(create_only, test::get_process_id_name(), 1, MaxMsgSize); + + //Open previously created message-queue simulating other process + message_queue mq2(open_only, test::get_process_id_name()); + + //A managed heap memory to create the origin database + managed_heap_memory db_origin(buffer_destiny.size()); + + //Construct the map in the first buffer + MyMap *map1 = db_origin.construct<MyMap>("MyMap") + (MyLess(), + db_origin.get_segment_manager()); + if(!map1) + return false; + + //Fill map1 until is full + try{ + std::size_t i = 0; + while(1){ + (*map1)[i] = i; + ++i; + } + } + catch(boost::interprocess::bad_alloc &){} + + //Data control data sending through the message queue + std::size_t sent = 0; + message_queue::size_type recvd = 0; + message_queue::size_type total_recvd = 0; + unsigned int priority; + + //Send whole first buffer through the mq1, read it + //through mq2 to the second buffer + while(1){ + //Send a fragment of buffer1 through mq1 + std::size_t bytes_to_send = MaxMsgSize < (db_origin.get_size() - sent) ? + MaxMsgSize : (db_origin.get_size() - sent); + mq1.send( &static_cast<char*>(db_origin.get_address())[sent] + , bytes_to_send + , 0); + sent += bytes_to_send; + //Receive the fragment through mq2 to buffer_destiny + mq2.receive( &buffer_destiny[total_recvd] + , BufferSize - recvd + , recvd + , priority); + total_recvd += recvd; + + //Check if we have received all the buffer + if(total_recvd == BufferSize){ + break; + } + } + + //The buffer will contain a copy of the original database + //so let's interpret the buffer with managed_external_buffer + managed_external_buffer db_destiny(open_only, &buffer_destiny[0], BufferSize); + + //Let's find the map + std::pair<MyMap *, managed_external_buffer::size_type> ret = db_destiny.find<MyMap>("MyMap"); + MyMap *map2 = ret.first; + + //Check if we have found it + if(!map2){ + return false; + } + + //Check if it is a single variable (not an array) + if(ret.second != 1){ + return false; + } + + //Now let's compare size + if(map1->size() != map2->size()){ + return false; + } + + //Now let's compare all db values + MyMap::size_type num_elements = map1->size(); + for(std::size_t i = 0; i < num_elements; ++i){ + if((*map1)[i] != (*map2)[i]){ + return false; + } + } + + //Destroy maps from db-s + db_origin.destroy_ptr(map1); + db_destiny.destroy_ptr(map2); + } + message_queue::remove(test::get_process_id_name()); + return true; +} +//] + +static const int MsgSize = 10; +static const int NumMsg = 1000; +static char msgsend [10]; +static char msgrecv [10]; + +static boost::interprocess::message_queue *pmessage_queue; + +void receiver() +{ + boost::interprocess::message_queue::size_type recvd_size; + unsigned int priority; + int nummsg = NumMsg; + + while(nummsg--){ + pmessage_queue->receive(msgrecv, MsgSize, recvd_size, priority); + } +} + +bool test_buffer_overflow() +{ + boost::interprocess::message_queue::remove(test::get_process_id_name()); + { + boost::movelib::unique_ptr<boost::interprocess::message_queue> + ptr(new boost::interprocess::message_queue + (create_only, test::get_process_id_name(), 10, 10)); + pmessage_queue = ptr.get(); + + //Launch the receiver thread + boost::interprocess::ipcdetail::OS_thread_t thread; + boost::interprocess::ipcdetail::thread_launch(thread, &receiver); + boost::interprocess::ipcdetail::thread_yield(); + + int nummsg = NumMsg; + + while(nummsg--){ + pmessage_queue->send(msgsend, MsgSize, 0); + } + + boost::interprocess::ipcdetail::thread_join(thread); + } + boost::interprocess::message_queue::remove(test::get_process_id_name()); + return true; +} + + +////////////////////////////////////////////////////////////////////////////// +// +// test_multi_sender_receiver is based on Alexander (aalutov's) +// testcase for ticket #9221. Many thanks. +// +////////////////////////////////////////////////////////////////////////////// + +static boost::interprocess::message_queue *global_queue = 0; +//We'll send MULTI_NUM_MSG_PER_SENDER messages per sender +static const int MULTI_NUM_MSG_PER_SENDER = 10000; +//Message queue message capacity +static const int MULTI_QUEUE_SIZE = (MULTI_NUM_MSG_PER_SENDER - 1)/MULTI_NUM_MSG_PER_SENDER + 1; +//We'll launch MULTI_THREAD_COUNT senders and MULTI_THREAD_COUNT receivers +static const int MULTI_THREAD_COUNT = 10; + +static void multisend() +{ + char buff; + for (int i = 0; i < MULTI_NUM_MSG_PER_SENDER; i++) { + global_queue->send(&buff, 1, 0); + } + global_queue->send(&buff, 0, 0); + //std::cout<<"writer thread complete"<<std::endl; +} + +static void multireceive() +{ + char buff; + size_t size; + int received_msgs = 0; + unsigned int priority; + do { + global_queue->receive(&buff, 1, size, priority); + ++received_msgs; + } while (size > 0); + --received_msgs; + //std::cout << "reader thread complete, read msgs: " << received_msgs << std::endl; +} + + +bool test_multi_sender_receiver() +{ + bool ret = true; + //std::cout << "Testing multi-sender / multi-receiver " << std::endl; + try { + boost::interprocess::message_queue::remove(test::get_process_id_name()); + boost::interprocess::message_queue mq + (boost::interprocess::open_or_create, test::get_process_id_name(), MULTI_QUEUE_SIZE, 1); + global_queue = &mq; + std::vector<boost::interprocess::ipcdetail::OS_thread_t> threads(MULTI_THREAD_COUNT*2); + + //Launch senders receiver thread + for (int i = 0; i < MULTI_THREAD_COUNT; i++) { + boost::interprocess::ipcdetail::thread_launch + (threads[i], &multisend); + } + + for (int i = 0; i < MULTI_THREAD_COUNT; i++) { + boost::interprocess::ipcdetail::thread_launch + (threads[MULTI_THREAD_COUNT+i], &multireceive); + } + + for (int i = 0; i < MULTI_THREAD_COUNT*2; i++) { + boost::interprocess::ipcdetail::thread_join(threads[i]); + //std::cout << "Joined thread " << i << std::endl; + } + } + catch (std::exception &e) { + std::cout << "error " << e.what() << std::endl; + ret = false; + } + boost::interprocess::message_queue::remove(test::get_process_id_name()); + return ret; +} + + +int main () +{ + if(!test_priority_order()){ + return 1; + } + + if(!test_serialize_db()){ + return 1; + } + + if(!test_buffer_overflow()){ + return 1; + } + + if(!test_multi_sender_receiver()){ + return 1; + } + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/movable_int.hpp b/src/boost/libs/interprocess/test/movable_int.hpp new file mode 100644 index 00000000..3890a468 --- /dev/null +++ b/src/boost/libs/interprocess/test/movable_int.hpp @@ -0,0 +1,293 @@ +/////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +/////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_MOVABLE_INT_HEADER +#define BOOST_INTERPROCESS_TEST_MOVABLE_INT_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/move/utility_core.hpp> + +namespace boost { +namespace interprocess { +namespace test { + +template<class T> +struct is_copyable; + +template<> +struct is_copyable<int> +{ + static const bool value = true; +}; + + +class movable_int +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(movable_int) + + public: + movable_int() + : m_int(0) + {} + + explicit movable_int(int a) + : m_int(a) + {} + + movable_int(BOOST_RV_REF(movable_int) mmi) + : m_int(mmi.m_int) + { mmi.m_int = 0; } + + movable_int & operator= (BOOST_RV_REF(movable_int) mmi) + { this->m_int = mmi.m_int; mmi.m_int = 0; return *this; } + + movable_int & operator= (int i) + { this->m_int = i; return *this; } + + bool operator ==(const movable_int &mi) const + { return this->m_int == mi.m_int; } + + bool operator !=(const movable_int &mi) const + { return this->m_int != mi.m_int; } + + bool operator <(const movable_int &mi) const + { return this->m_int < mi.m_int; } + + bool operator <=(const movable_int &mi) const + { return this->m_int <= mi.m_int; } + + bool operator >=(const movable_int &mi) const + { return this->m_int >= mi.m_int; } + + bool operator >(const movable_int &mi) const + { return this->m_int > mi.m_int; } + + int get_int() const + { return m_int; } + + friend bool operator==(const movable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const movable_int &r) + { return l == r.get_int(); } + + private: + int m_int; +}; + +template<class E, class T> +std::basic_ostream<E, T> & operator<< + (std::basic_ostream<E, T> & os, movable_int const & p) + +{ + os << p.get_int(); + return os; +} + + +template<> +struct is_copyable<movable_int> +{ + static const bool value = false; +}; + +class movable_and_copyable_int +{ + BOOST_COPYABLE_AND_MOVABLE(movable_and_copyable_int) + + public: + movable_and_copyable_int() + : m_int(0) + {} + + explicit movable_and_copyable_int(int a) + : m_int(a) + {} + + movable_and_copyable_int(const movable_and_copyable_int& mmi) + : m_int(mmi.m_int) + {} + + movable_and_copyable_int(BOOST_RV_REF(movable_and_copyable_int) mmi) + : m_int(mmi.m_int) + { mmi.m_int = 0; } + + movable_and_copyable_int &operator= (BOOST_COPY_ASSIGN_REF(movable_and_copyable_int) mi) + { this->m_int = mi.m_int; return *this; } + + movable_and_copyable_int & operator= (BOOST_RV_REF(movable_and_copyable_int) mmi) + { this->m_int = mmi.m_int; mmi.m_int = 0; return *this; } + + movable_and_copyable_int & operator= (int i) + { this->m_int = i; return *this; } + + bool operator ==(const movable_and_copyable_int &mi) const + { return this->m_int == mi.m_int; } + + bool operator !=(const movable_and_copyable_int &mi) const + { return this->m_int != mi.m_int; } + + bool operator <(const movable_and_copyable_int &mi) const + { return this->m_int < mi.m_int; } + + bool operator <=(const movable_and_copyable_int &mi) const + { return this->m_int <= mi.m_int; } + + bool operator >=(const movable_and_copyable_int &mi) const + { return this->m_int >= mi.m_int; } + + bool operator >(const movable_and_copyable_int &mi) const + { return this->m_int > mi.m_int; } + + int get_int() const + { return m_int; } + + friend bool operator==(const movable_and_copyable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const movable_and_copyable_int &r) + { return l == r.get_int(); } + + private: + int m_int; +}; + +template<class E, class T> +std::basic_ostream<E, T> & operator<< + (std::basic_ostream<E, T> & os, movable_and_copyable_int const & p) + +{ + os << p.get_int(); + return os; +} + +template<> +struct is_copyable<movable_and_copyable_int> +{ + static const bool value = true; +}; + +class copyable_int +{ + public: + copyable_int() + : m_int(0) + {} + + explicit copyable_int(int a) + : m_int(a) + {} + + copyable_int(const copyable_int& mmi) + : m_int(mmi.m_int) + {} + + copyable_int & operator= (int i) + { this->m_int = i; return *this; } + + bool operator ==(const copyable_int &mi) const + { return this->m_int == mi.m_int; } + + bool operator !=(const copyable_int &mi) const + { return this->m_int != mi.m_int; } + + bool operator <(const copyable_int &mi) const + { return this->m_int < mi.m_int; } + + bool operator <=(const copyable_int &mi) const + { return this->m_int <= mi.m_int; } + + bool operator >=(const copyable_int &mi) const + { return this->m_int >= mi.m_int; } + + bool operator >(const copyable_int &mi) const + { return this->m_int > mi.m_int; } + + int get_int() const + { return m_int; } + + friend bool operator==(const copyable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const copyable_int &r) + { return l == r.get_int(); } + + private: + int m_int; +}; + +template<class E, class T> +std::basic_ostream<E, T> & operator<< + (std::basic_ostream<E, T> & os, copyable_int const & p) + +{ + os << p.get_int(); + return os; +} + +template<> +struct is_copyable<copyable_int> +{ + static const bool value = true; +}; + +class non_copymovable_int +{ + non_copymovable_int(const non_copymovable_int& mmi); + non_copymovable_int & operator= (const non_copymovable_int &mi); + + public: + non_copymovable_int() + : m_int(0) + {} + + explicit non_copymovable_int(int a) + : m_int(a) + {} + + bool operator ==(const non_copymovable_int &mi) const + { return this->m_int == mi.m_int; } + + bool operator !=(const non_copymovable_int &mi) const + { return this->m_int != mi.m_int; } + + bool operator <(const non_copymovable_int &mi) const + { return this->m_int < mi.m_int; } + + bool operator <=(const non_copymovable_int &mi) const + { return this->m_int <= mi.m_int; } + + bool operator >=(const non_copymovable_int &mi) const + { return this->m_int >= mi.m_int; } + + bool operator >(const non_copymovable_int &mi) const + { return this->m_int > mi.m_int; } + + int get_int() const + { return m_int; } + + friend bool operator==(const non_copymovable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const non_copymovable_int &r) + { return l == r.get_int(); } + + private: + int m_int; +}; + +} //namespace test { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_TEST_MOVABLE_INT_HEADER diff --git a/src/boost/libs/interprocess/test/mutex_test.cpp b/src/boost/libs/interprocess/test/mutex_test.cpp new file mode 100644 index 00000000..e3bd4820 --- /dev/null +++ b/src/boost/libs/interprocess/test/mutex_test.cpp @@ -0,0 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/sync/interprocess_mutex.hpp> +#include "mutex_test_template.hpp" + +#if defined(BOOST_INTERPROCESS_WINDOWS) +#include <boost/interprocess/sync/windows/mutex.hpp> +#include <boost/interprocess/sync/spin/mutex.hpp> +#endif + +int main () +{ + using namespace boost::interprocess; + + #if defined(BOOST_INTERPROCESS_WINDOWS) + test::test_all_lock<ipcdetail::windows_mutex>(); + test::test_all_mutex<ipcdetail::windows_mutex>(); + test::test_all_lock<ipcdetail::spin_mutex>(); + test::test_all_mutex<ipcdetail::spin_mutex>(); + #endif + + test::test_all_lock<interprocess_mutex>(); + test::test_all_mutex<interprocess_mutex>(); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/mutex_test_template.hpp b/src/boost/libs/interprocess/test/mutex_test_template.hpp new file mode 100644 index 00000000..f298fb8b --- /dev/null +++ b/src/boost/libs/interprocess/test/mutex_test_template.hpp @@ -0,0 +1,394 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. + +#ifndef BOOST_INTERPROCESS_TEST_MUTEX_TEST_TEMPLATE_HEADER +#define BOOST_INTERPROCESS_TEST_MUTEX_TEST_TEMPLATE_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/exceptions.hpp> +#include "boost_interprocess_check.hpp" +#include "util.hpp" +#include <boost/interprocess/detail/os_thread_functions.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <iostream> + +namespace boost { namespace interprocess { namespace test { + +template <typename M> +struct test_lock +{ + typedef M mutex_type; + typedef boost::interprocess::scoped_lock<mutex_type> lock_type; + + + void operator()() + { + mutex_type interprocess_mutex; + + // Test the lock's constructors. + { + lock_type lock(interprocess_mutex, boost::interprocess::defer_lock); + BOOST_INTERPROCESS_CHECK(!lock); + } + lock_type lock(interprocess_mutex); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + + // Test the lock and unlock methods. + lock.unlock(); + BOOST_INTERPROCESS_CHECK(!lock); + lock.lock(); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + } +}; + +template <typename M> +struct test_trylock +{ + typedef M mutex_type; + typedef boost::interprocess::scoped_lock<mutex_type> try_to_lock_type; + + void operator()() + { + mutex_type interprocess_mutex; + + // Test the lock's constructors. + { + try_to_lock_type lock(interprocess_mutex, boost::interprocess::try_to_lock); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + } + { + try_to_lock_type lock(interprocess_mutex, boost::interprocess::defer_lock); + BOOST_INTERPROCESS_CHECK(!lock); + } + try_to_lock_type lock(interprocess_mutex); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + + // Test the lock, unlock and trylock methods. + lock.unlock(); + BOOST_INTERPROCESS_CHECK(!lock); + lock.lock(); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + lock.unlock(); + BOOST_INTERPROCESS_CHECK(!lock); + BOOST_INTERPROCESS_CHECK(lock.try_lock()); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + } +}; + +template <typename M> +struct test_timedlock +{ + typedef M mutex_type; + typedef boost::interprocess::scoped_lock<mutex_type> timed_lock_type; + + void operator()() + { + mutex_type interprocess_mutex; + + // Test the lock's constructors. + { + // Construct and initialize an ptime for a fast time out. + boost::posix_time::ptime pt = delay(1*BaseSeconds, 0); + + timed_lock_type lock(interprocess_mutex, pt); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + } + { + timed_lock_type lock(interprocess_mutex, boost::interprocess::defer_lock); + BOOST_INTERPROCESS_CHECK(!lock); + } + timed_lock_type lock(interprocess_mutex); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + + // Test the lock, unlock and timedlock methods. + lock.unlock(); + BOOST_INTERPROCESS_CHECK(!lock); + lock.lock(); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + lock.unlock(); + BOOST_INTERPROCESS_CHECK(!lock); + boost::posix_time::ptime pt = delay(3*BaseSeconds, 0); + BOOST_INTERPROCESS_CHECK(lock.timed_lock(pt)); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + } +}; + +template <typename M> +struct test_recursive_lock +{ + typedef M mutex_type; + typedef boost::interprocess::scoped_lock<mutex_type> lock_type; + + void operator()() + { + mutex_type mx; + { + lock_type lock1(mx); + lock_type lock2(mx); + } + { + lock_type lock1(mx, defer_lock); + lock_type lock2(mx, defer_lock); + } + { + lock_type lock1(mx, try_to_lock); + lock_type lock2(mx, try_to_lock); + } + { + //This should always lock + boost::posix_time::ptime pt = delay(2*BaseSeconds); + lock_type lock1(mx, pt); + lock_type lock2(mx, pt); + } + } +}; + +// plain_exclusive exercises the "infinite" lock for each +// read_write_mutex type. + +template<typename M> +void lock_and_sleep(void *arg, M &sm) +{ + data<M> *pdata = static_cast<data<M>*>(arg); + boost::interprocess::scoped_lock<M> l(sm); + if(pdata->m_secs){ + boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs)); + } + else{ + boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds)); + } + + ++shared_val; + pdata->m_value = shared_val; +} + +template<typename M> +void lock_and_catch_errors(void *arg, M &sm) +{ + data<M> *pdata = static_cast<data<M>*>(arg); + try + { + boost::interprocess::scoped_lock<M> l(sm); + if(pdata->m_secs){ + boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs)); + } + else{ + boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds)); + } + ++shared_val; + pdata->m_value = shared_val; + } + catch(interprocess_exception const & e) + { + pdata->m_error = e.get_error_code(); + } +} + +template<typename M> +void try_lock_and_sleep(void *arg, M &sm) +{ + data<M> *pdata = static_cast<data<M>*>(arg); + boost::interprocess::scoped_lock<M> l(sm, boost::interprocess::defer_lock); + if (l.try_lock()){ + boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds)); + ++shared_val; + pdata->m_value = shared_val; + } +} + +template<typename M> +void timed_lock_and_sleep(void *arg, M &sm) +{ + data<M> *pdata = static_cast<data<M>*>(arg); + boost::posix_time::ptime pt(delay(pdata->m_secs)); + boost::interprocess::scoped_lock<M> + l (sm, boost::interprocess::defer_lock); + if (l.timed_lock(pt)){ + boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds)); + ++shared_val; + pdata->m_value = shared_val; + } +} + +template<typename M> +void test_mutex_lock() +{ + shared_val = 0; + + M mtx; + + data<M> d1(1); + data<M> d2(2); + + // Locker one launches, holds the lock for 2*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tm1; + boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&lock_and_sleep, &d1, mtx)); + + //Wait 1*BaseSeconds + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + + // Locker two launches, but it won't hold the lock for 2*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tm2; + boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&lock_and_sleep, &d2, mtx)); + + //Wait completion + + boost::interprocess::ipcdetail::thread_join(tm1); + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + boost::interprocess::ipcdetail::thread_join(tm2); + + BOOST_INTERPROCESS_CHECK(d1.m_value == 1); + BOOST_INTERPROCESS_CHECK(d2.m_value == 2); +} + +template<typename M> +void test_mutex_lock_timeout() +{ + shared_val = 0; + + M mtx; + + int wait_time_s = BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS / 1000; + if (wait_time_s == 0 ) + wait_time_s = 1; + + data<M> d1(1, wait_time_s * 3); + data<M> d2(2, wait_time_s * 2); + + // Locker one launches, and holds the lock for wait_time_s * 2 seconds. + boost::interprocess::ipcdetail::OS_thread_t tm1; + boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&lock_and_sleep, &d1, mtx)); + + //Wait 1*BaseSeconds + boost::interprocess::ipcdetail::thread_sleep((1000*wait_time_s)); + + // Locker two launches, and attempts to hold the lock for wait_time_s * 2 seconds. + boost::interprocess::ipcdetail::OS_thread_t tm2; + boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&lock_and_catch_errors, &d2, mtx)); + + //Wait completion + boost::interprocess::ipcdetail::thread_join(tm1); + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + boost::interprocess::ipcdetail::thread_join(tm2); + + BOOST_INTERPROCESS_CHECK(d1.m_value == 1); + BOOST_INTERPROCESS_CHECK(d2.m_value == -1); + BOOST_INTERPROCESS_CHECK(d1.m_error == no_error); + BOOST_INTERPROCESS_CHECK(d2.m_error == boost::interprocess::timeout_when_locking_error); +} + +template<typename M> +void test_mutex_try_lock() +{ + shared_val = 0; + + M mtx; + + data<M> d1(1); + data<M> d2(2); + + // Locker one launches, holds the lock for 2*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tm1; + boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&try_lock_and_sleep, &d1, mtx)); + + //Wait 1*BaseSeconds + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + + // Locker two launches, but it should fail acquiring the lock + boost::interprocess::ipcdetail::OS_thread_t tm2; + boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&try_lock_and_sleep, &d2, mtx)); + + //Wait completion + boost::interprocess::ipcdetail::thread_join(tm1); + boost::interprocess::ipcdetail::thread_join(tm2); + + //Only the first should succeed locking + BOOST_INTERPROCESS_CHECK(d1.m_value == 1); + BOOST_INTERPROCESS_CHECK(d2.m_value == -1); +} + +template<typename M> +void test_mutex_timed_lock() + +{ + shared_val = 0; + + M mtx, m2; + + data<M> d1(1, 2*BaseSeconds); + data<M> d2(2, 2*BaseSeconds); + + // Locker one launches, holds the lock for 2*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tm1; + boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&timed_lock_and_sleep, &d1, mtx)); + + //Wait 1*BaseSeconds + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + + // Locker two launches, holds the lock for 2*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tm2; + boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&timed_lock_and_sleep, &d2, mtx)); + + //Wait completion + boost::interprocess::ipcdetail::thread_join(tm1); + boost::interprocess::ipcdetail::thread_join(tm2); + + //Both should succeed locking + BOOST_INTERPROCESS_CHECK(d1.m_value == 1); + BOOST_INTERPROCESS_CHECK(d2.m_value == 2); +} + +template <typename M> +inline void test_all_lock() +{ + //Now generic interprocess_mutex tests + std::cout << "test_lock<" << typeid(M).name() << ">" << std::endl; + test_lock<M>()(); + std::cout << "test_trylock<" << typeid(M).name() << ">" << std::endl; + test_trylock<M>()(); + std::cout << "test_timedlock<" << typeid(M).name() << ">" << std::endl; + test_timedlock<M>()(); +} + +template <typename M> +inline void test_all_recursive_lock() +{ + //Now generic interprocess_mutex tests + std::cout << "test_recursive_lock<" << typeid(M).name() << ">" << std::endl; + test_recursive_lock<M>()(); +} + +template<typename M> +void test_all_mutex() +{ + std::cout << "test_mutex_lock<" << typeid(M).name() << ">" << std::endl; + test_mutex_lock<M>(); + std::cout << "test_mutex_try_lock<" << typeid(M).name() << ">" << std::endl; + test_mutex_try_lock<M>(); + std::cout << "test_mutex_timed_lock<" << typeid(M).name() << ">" << std::endl; + test_mutex_timed_lock<M>(); +} + +}}} //namespace boost { namespace interprocess { namespace test { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_TEST_MUTEX_TEST_TEMPLATE_HEADER diff --git a/src/boost/libs/interprocess/test/mutex_timeout_test.cpp b/src/boost/libs/interprocess/test/mutex_timeout_test.cpp new file mode 100644 index 00000000..7dc4df52 --- /dev/null +++ b/src/boost/libs/interprocess/test/mutex_timeout_test.cpp @@ -0,0 +1,30 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +// enable timeout feature +#define BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING +#define BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS 1000 + +#include <boost/assert.hpp> +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/sync/interprocess_mutex.hpp> +#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp> +#include "mutex_test_template.hpp" + +int main () +{ + using namespace boost::interprocess; + test::test_mutex_lock_timeout<interprocess_mutex>(); + test::test_mutex_lock_timeout<interprocess_recursive_mutex>(); + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/named_allocation_test_template.hpp b/src/boost/libs/interprocess/test/named_allocation_test_template.hpp new file mode 100644 index 00000000..ca796349 --- /dev/null +++ b/src/boost/libs/interprocess/test/named_allocation_test_template.hpp @@ -0,0 +1,495 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_NAMED_ALLOCATION_TEST_TEMPLATE_HEADER +#define BOOST_INTERPROCESS_NAMED_ALLOCATION_TEST_TEMPLATE_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> + +// interprocess +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp> +#include <boost/interprocess/streams/bufferstream.hpp> +#include <boost/interprocess/sync/mutex_family.hpp> +// container +#include <boost/container/detail/iterator.hpp> +#include <boost/container/detail/minimal_char_traits_header.hpp> //char_traits +// std +#include <cstdio> +#include <iostream> +#include <new> +#include <set> +#include <vector> + +// local +#include "get_process_id_name.hpp" + +namespace boost { namespace interprocess { namespace test { + +namespace { + const wchar_t *get_prefix(wchar_t) + { return L"prefix_name_"; } + + const char *get_prefix(char) + { return "prefix_name_"; } +} + +//This test allocates until there is no more memory +//and after that deallocates all in the same order +template<class ManagedMemory> +bool test_names_and_types(ManagedMemory &m) +{ + typedef typename ManagedMemory::char_type char_type; + typedef std::char_traits<char_type> char_traits_type; + std::vector<char*> buffers; + const int BufferLen = 100; + char_type name[BufferLen]; + + basic_bufferstream<char_type> formatter(name, BufferLen); + + for(int i = 0; true; ++i){ + formatter.seekp(0); + formatter << get_prefix(char_type()) << i << std::ends; + + char *ptr = m.template construct<char>(name, std::nothrow)(i); + + if(!ptr) + break; + + std::size_t namelen = char_traits_type::length(m.get_instance_name(ptr)); + if(namelen != char_traits_type::length(name)){ + return 1; + } + + if(char_traits_type::compare(m.get_instance_name(ptr), name, namelen) != 0){ + return 1; + } + + if(m.template find<char>(name).first == 0) + return false; + + if(m.get_instance_type(ptr) != named_type) + return false; + + buffers.push_back(ptr); + } + + if(m.get_num_named_objects() != buffers.size() || !m.check_sanity()) + return false; + + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + m.destroy_ptr(buffers[j]); + } + + if(m.get_num_named_objects() != 0 || !m.check_sanity()) + return false; + m.shrink_to_fit_indexes(); + if(!m.all_memory_deallocated()) + return false; + return true; +} + + +//This test allocates until there is no more memory +//and after that deallocates all in the same order +template<class ManagedMemory> +bool test_named_iterators(ManagedMemory &m) +{ + typedef typename ManagedMemory::char_type char_type; + std::vector<char*> buffers; + const int BufferLen = 100; + char_type name[BufferLen]; + typedef std::basic_string<char_type> string_type; + std::set<string_type> names; + + basic_bufferstream<char_type> formatter(name, BufferLen); + + string_type aux_str; + + for(int i = 0; true; ++i){ + formatter.seekp(0); + formatter << get_prefix(char_type()) << i << std::ends; + char *ptr = m.template construct<char>(name, std::nothrow)(i); + if(!ptr) + break; + aux_str = name; + names.insert(aux_str); + buffers.push_back(ptr); + } + + if(m.get_num_named_objects() != buffers.size() || !m.check_sanity()) + return false; + + typedef typename ManagedMemory::const_named_iterator const_named_iterator; + const_named_iterator named_beg = m.named_begin(); + const_named_iterator named_end = m.named_end(); + + if((std::size_t)boost::container::iterator_distance(named_beg, named_end) != (std::size_t)buffers.size()){ + return 1; + } + + for(; named_beg != named_end; ++named_beg){ + const char_type *name_str = named_beg->name(); + aux_str = name_str; + if(names.find(aux_str) == names.end()){ + return 1; + } + + if(aux_str.size() != named_beg->name_length()){ + return 1; + } + + const void *found_value = m.template find<char>(name_str).first; + + if(found_value == 0) + return false; + if(found_value != named_beg->value()) + return false; + } + + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + m.destroy_ptr(buffers[j]); + } + + if(m.get_num_named_objects() != 0 || !m.check_sanity()) + return false; + m.shrink_to_fit_indexes(); + if(!m.all_memory_deallocated()) + return false; + return true; +} + +//This test allocates until there is no more memory +//and after that deallocates all in the same order +template<class ManagedMemory> +bool test_shrink_to_fit(ManagedMemory &m) +{ + typedef typename ManagedMemory::char_type char_type; + std::vector<char*> buffers; + const int BufferLen = 100; + char_type name[BufferLen]; + + basic_bufferstream<char_type> formatter(name, BufferLen); + + std::size_t free_memory_before = m.get_free_memory(); + + for(int i = 0; true; ++i){ + formatter.seekp(0); + formatter << get_prefix(char_type()) << i << std::ends; + + char *ptr = m.template construct<char>(name, std::nothrow)(i); + + if(!ptr) + break; + buffers.push_back(ptr); + } + + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + m.destroy_ptr(buffers[j]); + } + + std::size_t free_memory_after = m.get_free_memory(); + + if(free_memory_before != free_memory_after){ + m.shrink_to_fit_indexes(); + if(free_memory_before != free_memory_after) + return false; + } + return true; +} + +//This test allocates until there is no more memory +//and after that deallocates all in the same order +template<class ManagedMemory> +bool test_direct_named_allocation_destruction(ManagedMemory &m) +{ + typedef typename ManagedMemory::char_type char_type; + std::vector<char*> buffers; + const int BufferLen = 100; + char_type name[BufferLen]; + + basic_bufferstream<char_type> formatter(name, BufferLen); + + for(int i = 0; true; ++i){ + formatter.seekp(0); + formatter << get_prefix(char_type()) << i << std::ends; + char *ptr = m.template construct<char>(name, std::nothrow)(i); + if(!ptr) + break; + if(m.template find<char>(name).first == 0) + return false; + buffers.push_back(ptr); + } + + if(m.get_num_named_objects() != buffers.size() || !m.check_sanity()) + return false; + + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + m.destroy_ptr(buffers[j]); + } + + if(m.get_num_named_objects() != 0 || !m.check_sanity()) + return false; + m.shrink_to_fit_indexes(); + if(!m.all_memory_deallocated()) + return false; + return true; +} + +//This test allocates until there is no more memory +//and after that deallocates all in the inverse order +template<class ManagedMemory> +bool test_named_allocation_inverse_destruction(ManagedMemory &m) +{ + typedef typename ManagedMemory::char_type char_type; + + std::vector<char*> buffers; + const int BufferLen = 100; + char_type name[BufferLen]; + + basic_bufferstream<char_type> formatter(name, BufferLen); + + for(int i = 0; true; ++i){ + formatter.seekp(0); + formatter << get_prefix(char_type()) << i << std::ends; + char *ptr = m.template construct<char>(name, std::nothrow)(i); + if(!ptr) + break; + buffers.push_back(ptr); + } + + if(m.get_num_named_objects() != buffers.size() || !m.check_sanity()) + return false; + + for(int j = (int)buffers.size() + ;j-- + ;){ + m.destroy_ptr(buffers[j]); + } + + if(m.get_num_named_objects() != 0 || !m.check_sanity()) + return false; + m.shrink_to_fit_indexes(); + if(!m.all_memory_deallocated()) + return false; + return true; +} + +//This test allocates until there is no more memory +//and after that deallocates all following a pattern +template<class ManagedMemory> +bool test_named_allocation_mixed_destruction(ManagedMemory &m) +{ + typedef typename ManagedMemory::char_type char_type; + + std::vector<char*> buffers; + const int BufferLen = 100; + char_type name[BufferLen]; + + basic_bufferstream<char_type> formatter(name, BufferLen); + + for(int i = 0; true; ++i){ + formatter.seekp(0); + formatter << get_prefix(char_type()) << i << std::ends; + char *ptr = m.template construct<char>(name, std::nothrow)(i); + if(!ptr) + break; + buffers.push_back(ptr); + } + + if(m.get_num_named_objects() != buffers.size() || !m.check_sanity()) + return false; + + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + m.destroy_ptr(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + + if(m.get_num_named_objects() != 0 || !m.check_sanity()) + return false; + m.shrink_to_fit_indexes(); + if(!m.all_memory_deallocated()) + return false; + return true; +} + +//This test allocates until there is no more memory +//and after that deallocates all in the same order +template<class ManagedMemory> +bool test_inverse_named_allocation_destruction(ManagedMemory &m) +{ + typedef typename ManagedMemory::char_type char_type; + + std::vector<char*> buffers; + const int BufferLen = 100; + char_type name[BufferLen]; + + basic_bufferstream<char_type> formatter(name, BufferLen); + + for(unsigned int i = 0; true; ++i){ + formatter.seekp(0); + formatter << get_prefix(char_type()) << i << std::ends; + char *ptr = m.template construct<char>(name, std::nothrow)(i); + if(!ptr) + break; + buffers.push_back(ptr); + } + + if(m.get_num_named_objects() != buffers.size() || !m.check_sanity()) + return false; + + for(unsigned int j = 0, max = (unsigned int)buffers.size() + ;j < max + ;++j){ + m.destroy_ptr(buffers[j]); + } + + if(m.get_num_named_objects() != 0 || !m.check_sanity()) + return false; + m.shrink_to_fit_indexes(); + if(!m.all_memory_deallocated()) + return false; + return true; +} + +///This function calls all tests +template<class ManagedMemory> +bool test_all_named_allocation(ManagedMemory &m) +{ + std::cout << "Starting test_names_and_types. Class: " + << typeid(m).name() << std::endl; + + if(!test_names_and_types(m)){ + std::cout << "test_names_and_types failed. Class: " + << typeid(m).name() << std::endl; + return false; + } + + std::cout << "Starting test_direct_named_allocation_destruction. Class: " + << typeid(m).name() << std::endl; + + if(!test_direct_named_allocation_destruction(m)){ + std::cout << "test_direct_named_allocation_destruction failed. Class: " + << typeid(m).name() << std::endl; + return false; + } + + std::cout << "Starting test_named_allocation_inverse_destruction. Class: " + << typeid(m).name() << std::endl; + + if(!test_named_allocation_inverse_destruction(m)){ + std::cout << "test_named_allocation_inverse_destruction failed. Class: " + << typeid(m).name() << std::endl; + return false; + } + + std::cout << "Starting test_named_allocation_mixed_destruction. Class: " + << typeid(m).name() << std::endl; + + if(!test_named_allocation_mixed_destruction(m)){ + std::cout << "test_named_allocation_mixed_destruction failed. Class: " + << typeid(m).name() << std::endl; + return false; + } + + std::cout << "Starting test_inverse_named_allocation_destruction. Class: " + << typeid(m).name() << std::endl; + + if(!test_inverse_named_allocation_destruction(m)){ + std::cout << "test_inverse_named_allocation_destruction failed. Class: " + << typeid(m).name() << std::endl; + return false; + } + + if(!test_named_iterators(m)){ + std::cout << "test_named_iterators failed. Class: " + << typeid(m).name() << std::endl; + return false; + } + + return true; +} + +//This function calls all tests +template<template <class IndexConfig> class Index> +bool test_named_allocation() +{ + using namespace boost::interprocess; + + const int memsize = 163840; + const char *const shMemName = test::get_process_id_name(); + try + { + //A shared memory with rbtree best fit algorithm + typedef basic_managed_shared_memory + <char + ,rbtree_best_fit<mutex_family> + ,Index + > my_managed_shared_memory; + + //Create shared memory + shared_memory_object::remove(shMemName); + my_managed_shared_memory segment(create_only, shMemName, memsize); + + //Now take the segment manager and launch memory test + if(!test::test_all_named_allocation(*segment.get_segment_manager())){ + return false; + } + } + catch(...){ + shared_memory_object::remove(shMemName); + throw; + } + shared_memory_object::remove(shMemName); + + //Now test it with wchar_t + try + { + //A shared memory with simple sequential fit algorithm + typedef basic_managed_shared_memory + <wchar_t + ,rbtree_best_fit<mutex_family> + ,Index + > my_managed_shared_memory; + + //Create shared memory + shared_memory_object::remove(shMemName); + my_managed_shared_memory segment(create_only, shMemName, memsize); + + //Now take the segment manager and launch memory test + if(!test::test_all_named_allocation(*segment.get_segment_manager())){ + return false; + } + } + catch(...){ + shared_memory_object::remove(shMemName); + throw; + } + shared_memory_object::remove(shMemName); + + return true; +} + +}}} //namespace boost { namespace interprocess { namespace test { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_NAMED_ALLOCATION_TEST_TEMPLATE_HEADER diff --git a/src/boost/libs/interprocess/test/named_condition_any_test.cpp b/src/boost/libs/interprocess/test/named_condition_any_test.cpp new file mode 100644 index 00000000..500cb185 --- /dev/null +++ b/src/boost/libs/interprocess/test/named_condition_any_test.cpp @@ -0,0 +1,189 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/sync/named_mutex.hpp> +#include <boost/interprocess/sync/named_condition_any.hpp> +#include <boost/interprocess/sync/detail/locks.hpp> +#include "condition_test_template.hpp" +#include "named_creation_template.hpp" +#include <string> +#include <sstream> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +struct condition_deleter +{ + std::string name; + + ~condition_deleter() + { + if(name.empty()) + named_condition_any::remove(test::add_to_process_id_name("named_condition_any")); + else + named_condition_any::remove(name.c_str()); + } +}; + +inline std::string num_to_string(int n) +{ std::stringstream s; s << n; return s.str(); } + +//This wrapper is necessary to have a default constructor +//in generic mutex_test_template functions +class named_condition_any_test_wrapper + : public condition_deleter, public named_condition_any +{ + public: + + named_condition_any_test_wrapper() + : named_condition_any(open_or_create, + (test::add_to_process_id_name("test_cond") + num_to_string(count)).c_str()) + { + condition_deleter::name += test::add_to_process_id_name("test_cond"); + condition_deleter::name += num_to_string(count); + ++count; + } + + ~named_condition_any_test_wrapper() + { --count; } + + + template <typename L> + void wait(L& lock) + { + ipcdetail::internal_mutex_lock<L> internal_lock(lock); + named_condition_any::wait(internal_lock); + } + + template <typename L, typename Pr> + void wait(L& lock, Pr pred) + { + ipcdetail::internal_mutex_lock<L> internal_lock(lock); + named_condition_any::wait(internal_lock, pred); + } + + template <typename L> + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { + ipcdetail::internal_mutex_lock<L> internal_lock(lock); + return named_condition_any::timed_wait(internal_lock, abs_time); + } + + template <typename L, typename Pr> + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { + ipcdetail::internal_mutex_lock<L> internal_lock(lock); + return named_condition_any::timed_wait(internal_lock, abs_time, pred); + } + + static int count; +}; + +int named_condition_any_test_wrapper::count = 0; + +//This wrapper is necessary to have a common constructor +//in generic named_creation_template functions +class named_condition_any_creation_test_wrapper + : public condition_deleter, public named_condition_any +{ + public: + named_condition_any_creation_test_wrapper(create_only_t) + : named_condition_any(create_only, test::add_to_process_id_name("named_condition_any")) + { ++count_; } + + named_condition_any_creation_test_wrapper(open_only_t) + : named_condition_any(open_only, test::add_to_process_id_name("named_condition_any")) + { ++count_; } + + named_condition_any_creation_test_wrapper(open_or_create_t) + : named_condition_any(open_or_create, test::add_to_process_id_name("named_condition_any")) + { ++count_; } + + ~named_condition_any_creation_test_wrapper() { + if(--count_){ + ipcdetail::interprocess_tester:: + dont_close_on_destruction(static_cast<named_condition_any&>(*this)); + } + } + static int count_; +}; + +int named_condition_any_creation_test_wrapper::count_ = 0; + +struct mutex_deleter +{ + std::string name; + + ~mutex_deleter() + { + if(name.empty()) + named_mutex::remove(test::add_to_process_id_name("named_mutex")); + else + named_mutex::remove(name.c_str()); + } +}; + +//This wrapper is necessary to have a default constructor +//in generic mutex_test_template functions +class named_mutex_test_wrapper + : public mutex_deleter, public named_mutex +{ + public: + named_mutex_test_wrapper() + : named_mutex(open_or_create, + (test::add_to_process_id_name("test_mutex") + num_to_string(count)).c_str()) + { + mutex_deleter::name += test::add_to_process_id_name("test_mutex"); + mutex_deleter::name += num_to_string(count); + ++count; + } + + typedef named_mutex internal_mutex_type; + + internal_mutex_type &internal_mutex() + { return *this; } + + ~named_mutex_test_wrapper() + { --count; } + + static int count; +}; + +int named_mutex_test_wrapper::count = 0; + +int main () +{ + try{ + //Remove previous mutexes and conditions + named_mutex::remove(test::add_to_process_id_name("test_mutex0")); + named_condition_any::remove(test::add_to_process_id_name("test_cond0")); + named_condition_any::remove(test::add_to_process_id_name("test_cond1")); + named_condition_any::remove(test::add_to_process_id_name("named_condition_any")); + named_mutex::remove(test::add_to_process_id_name("named_mutex")); + + test::test_named_creation<named_condition_any_creation_test_wrapper>(); + test::do_test_condition<named_condition_any_test_wrapper + ,named_mutex_test_wrapper>(); + } + catch(std::exception &ex){ + std::cout << ex.what() << std::endl; + return 1; + } + named_mutex::remove(test::add_to_process_id_name("test_mutex0")); + named_condition_any::remove(test::add_to_process_id_name("test_cond0")); + named_condition_any::remove(test::add_to_process_id_name("test_cond1")); + named_condition_any::remove(test::add_to_process_id_name("named_condition_any")); + named_mutex::remove(test::add_to_process_id_name("named_mutex")); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/named_condition_test.cpp b/src/boost/libs/interprocess/test/named_condition_test.cpp new file mode 100644 index 00000000..6aa9c781 --- /dev/null +++ b/src/boost/libs/interprocess/test/named_condition_test.cpp @@ -0,0 +1,189 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/sync/named_mutex.hpp> +#include <boost/interprocess/sync/named_condition.hpp> +#include <boost/interprocess/sync/detail/locks.hpp> +#include "condition_test_template.hpp" +#include "named_creation_template.hpp" +#include <string> +#include <sstream> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +struct condition_deleter +{ + std::string name; + + ~condition_deleter() + { + if(name.empty()) + named_condition::remove(test::add_to_process_id_name("named_condition")); + else + named_condition::remove(name.c_str()); + } +}; + +inline std::string num_to_string(int n) +{ std::stringstream s; s << n; return s.str(); } + +//This wrapper is necessary to have a default constructor +//in generic mutex_test_template functions +class named_condition_test_wrapper + : public condition_deleter, public named_condition +{ + public: + + named_condition_test_wrapper() + : named_condition(open_or_create, + (test::add_to_process_id_name("test_cond") + num_to_string(count)).c_str()) + { + condition_deleter::name += test::add_to_process_id_name("test_cond"); + condition_deleter::name += num_to_string(count); + ++count; + } + + ~named_condition_test_wrapper() + { --count; } + + + template <typename L> + void wait(L& lock) + { + ipcdetail::internal_mutex_lock<L> internal_lock(lock); + named_condition::wait(internal_lock); + } + + template <typename L, typename Pr> + void wait(L& lock, Pr pred) + { + ipcdetail::internal_mutex_lock<L> internal_lock(lock); + named_condition::wait(internal_lock, pred); + } + + template <typename L> + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + { + ipcdetail::internal_mutex_lock<L> internal_lock(lock); + return named_condition::timed_wait(internal_lock, abs_time); + } + + template <typename L, typename Pr> + bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + { + ipcdetail::internal_mutex_lock<L> internal_lock(lock); + return named_condition::timed_wait(internal_lock, abs_time, pred); + } + + static int count; +}; + +int named_condition_test_wrapper::count = 0; + +//This wrapper is necessary to have a common constructor +//in generic named_creation_template functions +class named_condition_creation_test_wrapper + : public condition_deleter, public named_condition +{ + public: + named_condition_creation_test_wrapper(create_only_t) + : named_condition(create_only, test::add_to_process_id_name("named_condition")) + { ++count_; } + + named_condition_creation_test_wrapper(open_only_t) + : named_condition(open_only, test::add_to_process_id_name("named_condition")) + { ++count_; } + + named_condition_creation_test_wrapper(open_or_create_t) + : named_condition(open_or_create, test::add_to_process_id_name("named_condition")) + { ++count_; } + + ~named_condition_creation_test_wrapper() { + if(--count_){ + ipcdetail::interprocess_tester:: + dont_close_on_destruction(static_cast<named_condition&>(*this)); + } + } + static int count_; +}; + +int named_condition_creation_test_wrapper::count_ = 0; + +struct mutex_deleter +{ + std::string name; + + ~mutex_deleter() + { + if(name.empty()) + named_mutex::remove(test::add_to_process_id_name("named_mutex")); + else + named_mutex::remove(name.c_str()); + } +}; + +//This wrapper is necessary to have a default constructor +//in generic mutex_test_template functions +class named_mutex_test_wrapper + : public mutex_deleter, public named_mutex +{ + public: + named_mutex_test_wrapper() + : named_mutex(open_or_create, + (test::add_to_process_id_name("test_mutex") + num_to_string(count)).c_str()) + { + mutex_deleter::name += test::add_to_process_id_name("test_mutex"); + mutex_deleter::name += num_to_string(count); + ++count; + } + + typedef named_mutex internal_mutex_type; + + internal_mutex_type &internal_mutex() + { return *this; } + + ~named_mutex_test_wrapper() + { --count; } + + static int count; +}; + +int named_mutex_test_wrapper::count = 0; + +int main () +{ + try{ + //Remove previous mutexes and conditions + named_mutex::remove(test::add_to_process_id_name("test_mutex0")); + named_condition::remove(test::add_to_process_id_name("test_cond0")); + named_condition::remove(test::add_to_process_id_name("test_cond1")); + named_condition::remove(test::add_to_process_id_name("named_condition")); + named_mutex::remove(test::add_to_process_id_name("named_mutex")); + + test::test_named_creation<named_condition_creation_test_wrapper>(); + test::do_test_condition<named_condition_test_wrapper + ,named_mutex_test_wrapper>(); + } + catch(std::exception &ex){ + std::cout << ex.what() << std::endl; + return 1; + } + named_mutex::remove(test::add_to_process_id_name("test_mutex0")); + named_condition::remove(test::add_to_process_id_name("test_cond0")); + named_condition::remove(test::add_to_process_id_name("test_cond1")); + named_condition::remove(test::add_to_process_id_name("named_condition")); + named_mutex::remove(test::add_to_process_id_name("named_mutex")); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/named_construct_test.cpp b/src/boost/libs/interprocess/test/named_construct_test.cpp new file mode 100644 index 00000000..834a993f --- /dev/null +++ b/src/boost/libs/interprocess/test/named_construct_test.cpp @@ -0,0 +1,196 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +// intrusive/detail +#include <boost/intrusive/detail/minimal_pair_header.hpp> + +typedef std::pair<double, int> simple_pair; + +using namespace boost::interprocess; + +struct array_pair : public simple_pair +{ + array_pair(double d, int i) + : simple_pair(d, i) {} +}; + +struct array_it_pair : public array_pair +{ + array_it_pair(double d, int i) + : array_pair(d, i) {} +}; + +struct named_name_generator +{ + static const bool searchable = true; + + typedef simple_pair simple_type; + typedef array_pair array_type; + typedef array_it_pair array_it_type; + static const char *get_simple_name() + { return "MyType instance"; } + static const char *get_array_name() + { return "MyType array"; } + static const char *get_array_it_name() + { return "MyType array from it"; } +}; + +struct unique_name_generator +{ + static const bool searchable = true; + + typedef simple_pair simple_type; + typedef array_pair array_type; + typedef array_it_pair array_it_type; + static const ipcdetail::unique_instance_t *get_simple_name() + { return 0; } + static const ipcdetail::unique_instance_t *get_array_name() + { return 0; } + static const ipcdetail::unique_instance_t *get_array_it_name() + { return 0; } +}; + +struct anonymous_name_generator +{ + static const bool searchable = false; + + typedef simple_pair simple_type; + typedef array_pair array_type; + typedef array_it_pair array_it_type; + static const ipcdetail::anonymous_instance_t *get_simple_name() + { return 0; } + static const ipcdetail::anonymous_instance_t *get_array_name() + { return 0; } + static const ipcdetail::anonymous_instance_t *get_array_it_name() + { return 0; } +}; + + +template<class NameGenerator> +int construct_test() +{ + typedef typename NameGenerator::simple_type simple_type; + typedef typename NameGenerator::array_type array_type; + typedef typename NameGenerator::array_it_type array_it_type; + + remove_shared_memory_on_destroy remover("MySharedMemory"); + shared_memory_object::remove("MySharedMemory"); + { + //A special shared memory where we can + //construct objects associated with a name. + //First remove any old shared memory of the same name, create + //the shared memory segment and initialize needed resources + managed_shared_memory segment + //create segment name segment size + (create_only, "MySharedMemory", 65536); + + //Create an object of MyType initialized to {0.0, 0} + simple_type *s = segment.construct<simple_type> + (NameGenerator::get_simple_name())//name of the object + (1.0, 2); //ctor first argument + assert(s->first == 1.0 && s->second == 2); + if(!(s->first == 1.0 && s->second == 2)) + return 1; + + //Create an array of 10 elements of MyType initialized to {0.0, 0} + array_type *a = segment.construct<array_type> + (NameGenerator::get_array_name()) //name of the object + [10] //number of elements + (3.0, 4); //Same two ctor arguments for all objects + assert(a->first == 3.0 && a->second == 4); + if(!(a->first == 3.0 && a->second == 4)) + return 1; + + //Create an array of 3 elements of MyType initializing each one + //to a different value {0.0, 3}, {1.0, 4}, {2.0, 5}... + float float_initializer[3] = { 0.0, 1.0, 2.0 }; + int int_initializer[3] = { 3, 4, 5 }; + + array_it_type *a_it = segment.construct_it<array_it_type> + (NameGenerator::get_array_it_name()) //name of the object + [3] //number of elements + ( &float_initializer[0] //Iterator for the 1st ctor argument + , &int_initializer[0]); //Iterator for the 2nd ctor argument + { + const array_it_type *a_it_ptr = a_it; + for(unsigned int i = 0, max = 3; i != max; ++i, ++a_it_ptr){ + assert(a_it_ptr->first == float_initializer[i]); + if(a_it_ptr->first != float_initializer[i]){ + return 1; + } + assert(a_it_ptr->second == int_initializer[i]); + if(a_it_ptr->second != int_initializer[i]){ + return 1; + } + } + } + + if(NameGenerator::searchable){ + { + std::pair<simple_type*, managed_shared_memory::size_type> res; + //Find the object + res = segment.find<simple_type> (NameGenerator::get_simple_name()); + //Length should be 1 + assert(res.second == 1); + if(res.second != 1) + return 1; + assert(res.first == s); + if(res.first != s) + return 1; + } + { + std::pair<array_type*, managed_shared_memory::size_type> res; + + //Find the array + res = segment.find<array_type> (NameGenerator::get_array_name()); + //Length should be 10 + assert(res.second == 10); + if(res.second != 10) + return 1; + assert(res.first == a); + if(res.first != a) + return 1; + } + { + std::pair<array_it_type*, managed_shared_memory::size_type> res; + //Find the array constructed from iterators + res = segment.find<array_it_type> (NameGenerator::get_array_it_name()); + //Length should be 3 + assert(res.second == 3); + if(res.second != 3) + return 1; + assert(res.first == a_it); + if(res.first != a_it) + return 1; + } + } + //We're done, delete all the objects + segment.destroy_ptr<simple_type>(s); + segment.destroy_ptr<array_type>(a); + segment.destroy_ptr<array_it_type>(a_it); + } + return 0; +} + +int main () +{ + if(0 != construct_test<named_name_generator>()) + return 1; + if(0 != construct_test<unique_name_generator>()) + return 1; + if(0 != construct_test<anonymous_name_generator>()) + return 1; + return 0; +} + +//] +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/named_creation_template.hpp b/src/boost/libs/interprocess/test/named_creation_template.hpp new file mode 100644 index 00000000..1e002991 --- /dev/null +++ b/src/boost/libs/interprocess/test/named_creation_template.hpp @@ -0,0 +1,132 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_NAMED_RESOURCE_TEMPLATE_HEADER +#define BOOST_INTERPROCESS_TEST_NAMED_RESOURCE_TEMPLATE_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/exceptions.hpp> +#include "boost_interprocess_check.hpp" +#include "get_process_id_name.hpp" +#include <iostream> +#include <typeinfo> +#include <boost/interprocess/creation_tags.hpp> + +namespace boost { namespace interprocess { namespace test { + +template <class NamedResource> +inline void create_then_open_then_open_or_create() +{ + try{ + //Create it and open it twice + NamedResource nresource1(create_only); + NamedResource nresource2(open_only); + NamedResource nresource3(open_or_create); + } + catch(...){ + //This shouldn't throw so show the error + BOOST_INTERPROCESS_CHECK( false ); + } +} + +template <class NamedResource> +inline void open_or_create_then_create() +{ + //Create it with open_or_create and try to create it twice + NamedResource nresource1(open_or_create); + try{ + NamedResource nresource2(create_only); + } + catch(interprocess_exception &err){ + BOOST_INTERPROCESS_CHECK(err.get_error_code() == already_exists_error); + } +} + +template <class NamedResource> +inline void dont_create_and_open() +{ + //Try to open it without creating + try{ + NamedResource nresource1(open_only); + } + catch(interprocess_exception &err){ + BOOST_INTERPROCESS_CHECK(err.get_error_code() == not_found_error); + return; + } + //The mutex should not exist + BOOST_INTERPROCESS_CHECK(false); +} + +template <class NamedResource> +inline void test_named_creation() +{ + std::cout << "create_then_open_then_open_or_create<" + << typeid(NamedResource).name() << ">" << std::endl; + create_then_open_then_open_or_create<NamedResource>(); + std::cout << "open_or_create_then_create<" + << typeid(NamedResource).name() << ">" << std::endl; + open_or_create_then_create<NamedResource>(); + std::cout << "dont_create_and_open<" + << typeid(NamedResource).name() << ">" << std::endl; + dont_create_and_open<NamedResource>(); +} + +template<class NamedSync> +class named_sync_wrapper + : public NamedSync +{ + public: + named_sync_wrapper() + : NamedSync(open_or_create, test::get_process_id_ptr_name(this)) + {} + + ~named_sync_wrapper() + { + NamedSync::remove(test::get_process_id_ptr_name(this)); + } +}; + +template<class NamedSync> +struct named_sync_deleter +{ + ~named_sync_deleter() + { NamedSync::remove(test::get_process_id_name()); } +}; + + +//This wrapper is necessary to have a common constructor +//in generic named_creation_template functions +template<class NamedSync> +class named_sync_creation_test_wrapper + : public test::named_sync_deleter<NamedSync>, public NamedSync +{ + public: + named_sync_creation_test_wrapper(create_only_t) + : NamedSync(create_only, test::get_process_id_name()) + {} + + named_sync_creation_test_wrapper(open_only_t) + : NamedSync(open_only, test::get_process_id_name()) + {} + + named_sync_creation_test_wrapper(open_or_create_t) + : NamedSync(open_or_create, test::get_process_id_name()) + {} + + ~named_sync_creation_test_wrapper() + {} +}; + + +}}} //namespace boost { namespace interprocess { namespace test { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_TEST_NAMED_RESOURCE_TEMPLATE_HEADER diff --git a/src/boost/libs/interprocess/test/named_mutex_test.cpp b/src/boost/libs/interprocess/test/named_mutex_test.cpp new file mode 100644 index 00000000..11c7f1c4 --- /dev/null +++ b/src/boost/libs/interprocess/test/named_mutex_test.cpp @@ -0,0 +1,38 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/sync/named_mutex.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include "mutex_test_template.hpp" +#include "named_creation_template.hpp" +#include <string> +#include <boost/interprocess/detail/interprocess_tester.hpp> + +using namespace boost::interprocess; + +int main () +{ + try{ + named_mutex::remove(test::get_process_id_name()); + test::test_named_creation< test::named_sync_creation_test_wrapper<named_mutex> >(); + test::test_all_lock< test::named_sync_wrapper<named_mutex> >(); + test::test_all_mutex<test::named_sync_wrapper<named_mutex> >(); + } + catch(std::exception &ex){ + named_mutex::remove(test::get_process_id_name()); + std::cout << ex.what() << std::endl; + return 1; + } + named_mutex::remove(test::get_process_id_name()); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/named_recursive_mutex_test.cpp b/src/boost/libs/interprocess/test/named_recursive_mutex_test.cpp new file mode 100644 index 00000000..376c1e3c --- /dev/null +++ b/src/boost/libs/interprocess/test/named_recursive_mutex_test.cpp @@ -0,0 +1,41 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/sync/named_recursive_mutex.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include "mutex_test_template.hpp" +#include "named_creation_template.hpp" +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +int main () +{ + try{ + named_recursive_mutex::remove(test::get_process_id_name()); + test::test_named_creation< test::named_sync_creation_test_wrapper<named_recursive_mutex> >(); + test::test_all_lock< test::named_sync_wrapper<named_recursive_mutex> >(); + test::test_all_mutex<test::named_sync_wrapper<named_recursive_mutex> >(); + test::test_all_recursive_lock<test::named_sync_wrapper<named_recursive_mutex> >(); + } + catch(std::exception &ex){ + named_recursive_mutex::remove(test::get_process_id_name()); + std::cout << ex.what() << std::endl; + return 1; + } + named_recursive_mutex::remove(test::get_process_id_name()); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> + diff --git a/src/boost/libs/interprocess/test/named_semaphore_test.cpp b/src/boost/libs/interprocess/test/named_semaphore_test.cpp new file mode 100644 index 00000000..57087977 --- /dev/null +++ b/src/boost/libs/interprocess/test/named_semaphore_test.cpp @@ -0,0 +1,123 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/sync/named_semaphore.hpp> +#include <boost/interprocess/detail/interprocess_tester.hpp> +#include <boost/interprocess/exceptions.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include "named_creation_template.hpp" +#include "mutex_test_template.hpp" +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +static const std::size_t RecSemCount = 100; +static const char * SemName = test::get_process_id_name(); + +//This wrapper is necessary to plug this class +//in lock tests +class lock_test_wrapper + : public named_semaphore +{ + public: + + lock_test_wrapper(create_only_t, const char *name, unsigned int count = 1) + : named_semaphore(create_only, name, count) + {} + + lock_test_wrapper(open_only_t, const char *name) + : named_semaphore(open_only, name) + {} + + lock_test_wrapper(open_or_create_t, const char *name, unsigned int count = 1) + : named_semaphore(open_or_create, name, count) + {} + + ~lock_test_wrapper() + {} + + void lock() + { this->wait(); } + + bool try_lock() + { return this->try_wait(); } + + bool timed_lock(const boost::posix_time::ptime &pt) + { return this->timed_wait(pt); } + + void unlock() + { this->post(); } +}; + +//This wrapper is necessary to plug this class +//in recursive tests +class recursive_test_wrapper + : public lock_test_wrapper +{ + public: + recursive_test_wrapper(create_only_t, const char *name) + : lock_test_wrapper(create_only, name, RecSemCount) + {} + + recursive_test_wrapper(open_only_t, const char *name) + : lock_test_wrapper(open_only, name) + {} + + recursive_test_wrapper(open_or_create_t, const char *name) + : lock_test_wrapper(open_or_create, name, RecSemCount) + {} +}; + +bool test_named_semaphore_specific() +{ + //Test persistance + { + named_semaphore sem(create_only, SemName, 3); + } + { + named_semaphore sem(open_only, SemName); + BOOST_INTERPROCESS_CHECK(sem.try_wait() == true); + BOOST_INTERPROCESS_CHECK(sem.try_wait() == true); + BOOST_INTERPROCESS_CHECK(sem.try_wait() == true); + BOOST_INTERPROCESS_CHECK(sem.try_wait() == false); + sem.post(); + } + { + named_semaphore sem(open_only, SemName); + BOOST_INTERPROCESS_CHECK(sem.try_wait() == true); + BOOST_INTERPROCESS_CHECK(sem.try_wait() == false); + } + + named_semaphore::remove(SemName); + return true; +} + +int main () +{ + try{ + named_semaphore::remove(SemName); + test::test_named_creation< test::named_sync_creation_test_wrapper<lock_test_wrapper> >(); + test::test_all_lock< test::named_sync_wrapper<lock_test_wrapper> >(); + test::test_all_mutex<test::named_sync_wrapper<lock_test_wrapper> >(); + test::test_all_recursive_lock<test::named_sync_wrapper<recursive_test_wrapper> >(); + test_named_semaphore_specific(); + } + catch(std::exception &ex){ + named_semaphore::remove(SemName); + std::cout << ex.what() << std::endl; + return 1; + } + named_semaphore::remove(SemName); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/named_sharable_mutex_test.cpp b/src/boost/libs/interprocess/test/named_sharable_mutex_test.cpp new file mode 100644 index 00000000..9721ab07 --- /dev/null +++ b/src/boost/libs/interprocess/test/named_sharable_mutex_test.cpp @@ -0,0 +1,103 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include "mutex_test_template.hpp" +#include "sharable_mutex_test_template.hpp" +#include "named_creation_template.hpp" +#include <boost/interprocess/sync/named_sharable_mutex.hpp> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +struct mutex_deleter +{ + ~mutex_deleter() + { named_sharable_mutex::remove(test::get_process_id_name()); } +}; + +//This wrapper is necessary to have a default constructor +//in generic mutex_test_template functions +class named_sharable_mutex_lock_test_wrapper + : public named_sharable_mutex +{ + public: + named_sharable_mutex_lock_test_wrapper() + : named_sharable_mutex(open_or_create, test::get_process_id_name()) + { ++count_; } + + ~named_sharable_mutex_lock_test_wrapper() + { + if(--count_){ + ipcdetail::interprocess_tester:: + dont_close_on_destruction(static_cast<named_sharable_mutex&>(*this)); + } + } + + static int count_; +}; + +int named_sharable_mutex_lock_test_wrapper::count_ = 0; + + +//This wrapper is necessary to have a common constructor +//in generic named_creation_template functions +class named_sharable_mutex_creation_test_wrapper + : public mutex_deleter, public named_sharable_mutex +{ + public: + named_sharable_mutex_creation_test_wrapper + (create_only_t) + : named_sharable_mutex(create_only, test::get_process_id_name()) + { ++count_; } + + named_sharable_mutex_creation_test_wrapper + (open_only_t) + : named_sharable_mutex(open_only, test::get_process_id_name()) + { ++count_; } + + named_sharable_mutex_creation_test_wrapper + (open_or_create_t) + : named_sharable_mutex(open_or_create, test::get_process_id_name()) + { ++count_; } + + ~named_sharable_mutex_creation_test_wrapper() + { + if(--count_){ + ipcdetail::interprocess_tester:: + dont_close_on_destruction(static_cast<named_sharable_mutex&>(*this)); + } + } + + static int count_; +}; + +int named_sharable_mutex_creation_test_wrapper::count_ = 0; + +int main () +{ + try{ + named_sharable_mutex::remove(test::get_process_id_name()); + test::test_named_creation< test::named_sync_creation_test_wrapper<named_sharable_mutex> >(); + test::test_all_lock< test::named_sync_wrapper<named_sharable_mutex> >(); + test::test_all_mutex<test::named_sync_wrapper<named_sharable_mutex> >(); + test::test_all_sharable_mutex<test::named_sync_wrapper<named_sharable_mutex> >(); + } + catch(std::exception &ex){ + named_sharable_mutex::remove(test::get_process_id_name()); + std::cout << ex.what() << std::endl; + return 1; + } + named_sharable_mutex::remove(test::get_process_id_name()); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/named_upgradable_mutex_test.cpp b/src/boost/libs/interprocess/test/named_upgradable_mutex_test.cpp new file mode 100644 index 00000000..c0d2bcd0 --- /dev/null +++ b/src/boost/libs/interprocess/test/named_upgradable_mutex_test.cpp @@ -0,0 +1,103 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include "mutex_test_template.hpp" +#include "sharable_mutex_test_template.hpp" +#include "named_creation_template.hpp" +#include <boost/interprocess/sync/named_upgradable_mutex.hpp> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +struct mutex_deleter +{ + ~mutex_deleter() + { named_upgradable_mutex::remove(test::get_process_id_name()); } +}; + +//This wrapper is necessary to have a default constructor +//in generic mutex_test_template functions +class named_upgradable_mutex_lock_test_wrapper + : public named_upgradable_mutex +{ + public: + named_upgradable_mutex_lock_test_wrapper() + : named_upgradable_mutex(open_or_create, test::get_process_id_name()) + { ++count_; } + + ~named_upgradable_mutex_lock_test_wrapper() + { + if(--count_){ + ipcdetail::interprocess_tester:: + dont_close_on_destruction(static_cast<named_upgradable_mutex&>(*this)); + } + } + + static int count_; +}; + +int named_upgradable_mutex_lock_test_wrapper::count_ = 0; + + +//This wrapper is necessary to have a common constructor +//in generic named_creation_template functions +class named_upgradable_mutex_creation_test_wrapper + : public mutex_deleter, public named_upgradable_mutex +{ + public: + named_upgradable_mutex_creation_test_wrapper + (create_only_t) + : named_upgradable_mutex(create_only, test::get_process_id_name()) + { ++count_; } + + named_upgradable_mutex_creation_test_wrapper + (open_only_t) + : named_upgradable_mutex(open_only, test::get_process_id_name()) + { ++count_; } + + named_upgradable_mutex_creation_test_wrapper + (open_or_create_t) + : named_upgradable_mutex(open_or_create, test::get_process_id_name()) + { ++count_; } + + ~named_upgradable_mutex_creation_test_wrapper() + { + if(--count_){ + ipcdetail::interprocess_tester:: + dont_close_on_destruction(static_cast<named_upgradable_mutex&>(*this)); + } + } + + static int count_; +}; + +int named_upgradable_mutex_creation_test_wrapper::count_ = 0; + +int main () +{ + try{ + named_upgradable_mutex::remove(test::get_process_id_name()); + test::test_named_creation< test::named_sync_creation_test_wrapper<named_upgradable_mutex> >(); + test::test_all_lock< test::named_sync_wrapper<named_upgradable_mutex> >(); + test::test_all_mutex<test::named_sync_wrapper<named_upgradable_mutex> >(); + test::test_all_sharable_mutex<test::named_sync_wrapper<named_upgradable_mutex> >(); + } + catch(std::exception &ex){ + named_upgradable_mutex::remove(test::get_process_id_name()); + std::cout << ex.what() << std::endl; + return 1; + } + named_upgradable_mutex::remove(test::get_process_id_name()); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/node_allocator_test.cpp b/src/boost/libs/interprocess/test/node_allocator_test.cpp new file mode 100644 index 00000000..4ff7097e --- /dev/null +++ b/src/boost/libs/interprocess/test/node_allocator_test.cpp @@ -0,0 +1,66 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/allocators/node_allocator.hpp> +#include "print_container.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include "list_test.hpp" +#include "vector_test.hpp" + +using namespace boost::interprocess; + +//We will work with wide characters for shared memory objects +//Alias an integer node allocator type +typedef node_allocator + <int, managed_shared_memory::segment_manager> shmem_node_allocator_t; +typedef ipcdetail::node_allocator_v1 + <int, managed_shared_memory::segment_manager> shmem_node_allocator_v1_t; + +namespace boost { +namespace interprocess { + +//Explicit instantiations to catch compilation errors +template class node_allocator<int, managed_shared_memory::segment_manager>; +template class node_allocator<void, managed_shared_memory::segment_manager>; + +namespace ipcdetail { + +template class ipcdetail::node_allocator_v1<int, managed_shared_memory::segment_manager>; +template class ipcdetail::node_allocator_v1<void, managed_shared_memory::segment_manager>; + +}}} + +//Alias list types +typedef list<int, shmem_node_allocator_t> MyShmList; +typedef list<int, shmem_node_allocator_v1_t> MyShmListV1; + +//Alias vector types +typedef vector<int, shmem_node_allocator_t> MyShmVector; +typedef vector<int, shmem_node_allocator_v1_t> MyShmVectorV1; + +int main () +{ + if(test::list_test<managed_shared_memory, MyShmList, true>()) + return 1; + if(test::list_test<managed_shared_memory, MyShmListV1, true>()) + return 1; + if(test::vector_test<managed_shared_memory, MyShmVector>()) + return 1; + if(test::vector_test<managed_shared_memory, MyShmVectorV1>()) + return 1; + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/node_pool_test.cpp b/src/boost/libs/interprocess/test/node_pool_test.cpp new file mode 100644 index 00000000..149bd7f6 --- /dev/null +++ b/src/boost/libs/interprocess/test/node_pool_test.cpp @@ -0,0 +1,29 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include "node_pool_test.hpp" +#include <boost/interprocess/allocators/detail/node_pool.hpp> + +using namespace boost::interprocess; + +typedef managed_shared_memory::segment_manager segment_manager_t; + +int main () +{ + typedef ipcdetail::private_node_pool + <segment_manager_t, 4, 64> node_pool_t; + + if(!test::test_all_node_pool<node_pool_t>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/node_pool_test.hpp b/src/boost/libs/interprocess/test/node_pool_test.hpp new file mode 100644 index 00000000..52fc8ffa --- /dev/null +++ b/src/boost/libs/interprocess/test/node_pool_test.hpp @@ -0,0 +1,163 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/smart_ptr/unique_ptr.hpp> +#include <boost/interprocess/smart_ptr/deleter.hpp> +#include <boost/interprocess/detail/type_traits.hpp> +#include <vector> +#include <cstddef> +#include <string> +#include "get_process_id_name.hpp" + +namespace boost { +namespace interprocess { +namespace test { + +template <class NodePool> +struct test_node_pool +{ + static bool allocate_then_deallocate(NodePool &pool); + static bool deallocate_free_blocks(NodePool &pool); +}; + +template <class NodePool> +bool test_node_pool<NodePool>::allocate_then_deallocate(NodePool &pool) +{ + const typename NodePool::size_type num_alloc = 1 + 3*pool.get_real_num_node(); + + std::vector<void*> nodes; + + //Precondition, the pool must be empty + if(0 != pool.num_free_nodes()){ + return false; + } + + //First allocate nodes + for(std::size_t i = 0; i < num_alloc; ++i){ + nodes.push_back(pool.allocate_node()); + } + + //Check that the free count is correct + if((pool.get_real_num_node() - 1) != pool.num_free_nodes()){ + return false; + } + + //Now deallocate all and check again + for(std::size_t i = 0; i < num_alloc; ++i){ + pool.deallocate_node(nodes[i]); + } + + //Check that the free count is correct + if(4*pool.get_real_num_node() != pool.num_free_nodes()){ + return false; + } + + pool.deallocate_free_blocks(); + + if(0 != pool.num_free_nodes()){ + return false; + } + + return true; +} + +template <class NodePool> +bool test_node_pool<NodePool>::deallocate_free_blocks(NodePool &pool) +{ + const std::size_t max_blocks = 10; + const std::size_t max_nodes = max_blocks*pool.get_real_num_node(); + const std::size_t nodes_per_block = pool.get_real_num_node(); + + std::vector<void*> nodes; + + //Precondition, the pool must be empty + if(0 != pool.num_free_nodes()){ + return false; + } + + //First allocate nodes + for(std::size_t i = 0; i < max_nodes; ++i){ + nodes.push_back(pool.allocate_node()); + } + + //Check that the free count is correct + if(0 != pool.num_free_nodes()){ + return false; + } + + //Now deallocate one of each block per iteration + for(std::size_t node_i = 0; node_i < nodes_per_block; ++node_i){ + //Deallocate a node per block + for(std::size_t i = 0; i < max_blocks; ++i){ + pool.deallocate_node(nodes[i*nodes_per_block + node_i]); + } + + //Check that the free count is correct + if(max_blocks*(node_i+1) != pool.num_free_nodes()){ + return false; + } + + //Now try to deallocate free blocks + pool.deallocate_free_blocks(); + + //Until we don't deallocate the last node of every block + //no node should be deallocated + if(node_i != (nodes_per_block - 1)){ + if(max_blocks*(node_i+1) != pool.num_free_nodes()){ + return false; + } + } + else{ + //If this is the last iteration, all the memory should + //have been deallocated. + if(0 != pool.num_free_nodes()){ + return false; + } + } + } + + return true; +} + +template<class node_pool_t> +bool test_all_node_pool() +{ + using namespace boost::interprocess; + typedef managed_shared_memory::segment_manager segment_manager; + + typedef boost::interprocess::test::test_node_pool<node_pool_t> test_node_pool_t; + shared_memory_object::remove(test::get_process_id_name()); + { + managed_shared_memory shm(create_only, test::get_process_id_name(), 4*1024*sizeof(segment_manager::void_pointer)); + + typedef deleter<node_pool_t, segment_manager> deleter_t; + typedef unique_ptr<node_pool_t, deleter_t> unique_ptr_t; + + //Delete the pool when the tests end + unique_ptr_t p + (shm.construct<node_pool_t>(anonymous_instance)(shm.get_segment_manager()) + ,deleter_t(shm.get_segment_manager())); + + //Now call each test + if(!test_node_pool_t::allocate_then_deallocate(*p)) + return false; + if(!test_node_pool_t::deallocate_free_blocks(*p)) + return false; + } + shared_memory_object::remove(test::get_process_id_name()); + return true; +} + +} //namespace test { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/null_index_test.cpp b/src/boost/libs/interprocess/test/null_index_test.cpp new file mode 100644 index 00000000..e0f23407 --- /dev/null +++ b/src/boost/libs/interprocess/test/null_index_test.cpp @@ -0,0 +1,51 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/indexes/null_index.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/mem_algo/simple_seq_fit.hpp> +#include <cstddef> +#include <cassert> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; +typedef basic_managed_shared_memory + <char, simple_seq_fit<mutex_family>, null_index> +my_shared_objects_t; + +int main () +{ + //Create shared memory + shared_memory_object::remove(test::get_process_id_name()); + { + my_shared_objects_t segment + (create_only, + test::get_process_id_name(), //segment name + 65536); //segment size in bytes + + //Allocate a portion of the segment + void * shptr = segment.allocate(1024/*bytes to allocate*/); + my_shared_objects_t::handle_t handle = segment.get_handle_from_address(shptr); + if(!segment.belongs_to_segment(shptr)){ + return 1; + } + if(shptr != segment.get_address_from_handle(handle)){ + return 1; + } + + segment.deallocate(shptr); + } + shared_memory_object::remove(test::get_process_id_name()); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/offset_ptr_test.cpp b/src/boost/libs/interprocess/test/offset_ptr_test.cpp new file mode 100644 index 00000000..bece39b0 --- /dev/null +++ b/src/boost/libs/interprocess/test/offset_ptr_test.cpp @@ -0,0 +1,352 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/offset_ptr.hpp> +#include <boost/interprocess/detail/type_traits.hpp> +#include <boost/intrusive/pointer_traits.hpp> +#include <boost/static_assert.hpp> +#include <boost/core/lightweight_test.hpp> + +using namespace boost::interprocess; + +class Base +{}; + +class Derived + : public Base +{}; + +class VirtualDerived + : public virtual Base +{}; + +void test_types_and_conversions() +{ + typedef offset_ptr<int> pint_t; + typedef offset_ptr<const int> pcint_t; + typedef offset_ptr<volatile int> pvint_t; + typedef offset_ptr<const volatile int> pcvint_t; + + BOOST_STATIC_ASSERT((ipcdetail::is_same<pint_t::element_type, int>::value)); + BOOST_STATIC_ASSERT((ipcdetail::is_same<pcint_t::element_type, const int>::value)); + BOOST_STATIC_ASSERT((ipcdetail::is_same<pvint_t::element_type, volatile int>::value)); + BOOST_STATIC_ASSERT((ipcdetail::is_same<pcvint_t::element_type, const volatile int>::value)); + + BOOST_STATIC_ASSERT((ipcdetail::is_same<pint_t::value_type, int>::value)); + BOOST_STATIC_ASSERT((ipcdetail::is_same<pcint_t::value_type, int>::value)); + BOOST_STATIC_ASSERT((ipcdetail::is_same<pvint_t::value_type, int>::value)); + BOOST_STATIC_ASSERT((ipcdetail::is_same<pcvint_t::value_type, int>::value)); + int dummy_int = 9; + + { pint_t pint(&dummy_int); + pcint_t pcint(pint); + BOOST_TEST(pcint.get() == &dummy_int); + } + { pint_t pint(&dummy_int); + pvint_t pvint(pint); + BOOST_TEST(pvint.get() == &dummy_int); + } + { pint_t pint(&dummy_int); + pcvint_t pcvint(pint); + BOOST_TEST(pcvint.get() == &dummy_int); + } + { pcint_t pcint(&dummy_int); + pcvint_t pcvint(pcint); + BOOST_TEST(pcvint.get() == &dummy_int); + } + { pvint_t pvint(&dummy_int); + pcvint_t pcvint(pvint); + BOOST_TEST(pcvint.get() == &dummy_int); + } + + pint_t pint(0); + pcint_t pcint(0); + pvint_t pvint(0); + pcvint_t pcvint(0); + + pint = &dummy_int; + pcint = &dummy_int; + pvint = &dummy_int; + pcvint = &dummy_int; + + { pcint = pint; + BOOST_TEST(pcint.get() == &dummy_int); + } + { pvint = pint; + BOOST_TEST(pvint.get() == &dummy_int); + } + { pcvint = pint; + BOOST_TEST(pcvint.get() == &dummy_int); + } + { pcvint = pcint; + BOOST_TEST(pcvint.get() == &dummy_int); + } + { pcvint = pvint; + BOOST_TEST(pcvint.get() == &dummy_int); + } + + BOOST_TEST(pint); + + pint = 0; + BOOST_TEST(!pint); + + BOOST_TEST(pint == 0); + + BOOST_TEST(0 == pint); + + pint = &dummy_int; + BOOST_TEST(0 != pint); + + pcint = &dummy_int; + + BOOST_TEST( (pcint - pint) == 0); + BOOST_TEST( (pint - pcint) == 0); +} + +template<class BasePtr, class DerivedPtr> +void test_base_derived_impl() +{ + typename DerivedPtr::element_type d; + DerivedPtr pderi(&d); + + BasePtr pbase(pderi); + pbase = pderi; + BOOST_TEST(pbase == pderi); + BOOST_TEST(!(pbase != pderi)); + BOOST_TEST((pbase - pderi) == 0); + BOOST_TEST(!(pbase < pderi)); + BOOST_TEST(!(pbase > pderi)); + BOOST_TEST(pbase <= pderi); + BOOST_TEST((pbase >= pderi)); +} + +void test_base_derived() +{ + typedef offset_ptr<Base> pbase_t; + typedef offset_ptr<const Base> pcbas_t; + typedef offset_ptr<Derived> pderi_t; + typedef offset_ptr<VirtualDerived> pvder_t; + + test_base_derived_impl<pbase_t, pderi_t>(); + test_base_derived_impl<pbase_t, pvder_t>(); + test_base_derived_impl<pcbas_t, pderi_t>(); + test_base_derived_impl<pcbas_t, pvder_t>(); +} + +void test_arithmetic() +{ + typedef offset_ptr<int> pint_t; + const int NumValues = 5; + int values[NumValues]; + + //Initialize p + pint_t p = values; + BOOST_TEST(p.get() == values); + + //Initialize p + NumValues + pint_t pe = &values[NumValues]; + BOOST_TEST(pe != p); + BOOST_TEST(pe.get() == &values[NumValues]); + + //ptr - ptr + BOOST_TEST((pe - p) == NumValues); + + //ptr - integer + BOOST_TEST((pe - NumValues) == p); + + //ptr + integer + BOOST_TEST((p + NumValues) == pe); + + //integer + ptr + BOOST_TEST((NumValues + p) == pe); + + //indexing + BOOST_TEST(pint_t(&p[NumValues]) == pe); + BOOST_TEST(pint_t(&pe[-NumValues]) == p); + + //ptr -= integer + pint_t p0 = pe; + p0-= NumValues; + BOOST_TEST(p == p0); + + //ptr += integer + pint_t penew = p0; + penew += NumValues; + BOOST_TEST(penew == pe); + + //++ptr + penew = p0; + for(int j = 0; j != NumValues; ++j, ++penew); + BOOST_TEST(penew == pe); + + //--ptr + p0 = pe; + for(int j = 0; j != NumValues; ++j, --p0); + BOOST_TEST(p == p0); + + //ptr++ + penew = p0; + for(int j = 0; j != NumValues; ++j){ + pint_t p_new_copy = penew; + BOOST_TEST(p_new_copy == penew++); + } + //ptr-- + p0 = pe; + for(int j = 0; j != NumValues; ++j){ + pint_t p0_copy = p0; + BOOST_TEST(p0_copy == p0--); + } +} + +void test_comparison() +{ + typedef offset_ptr<int> pint_t; + const int NumValues = 5; + int values[NumValues]; + + //Initialize p + pint_t p = values; + BOOST_TEST(p.get() == values); + + //Initialize p + NumValues + pint_t pe = &values[NumValues]; + BOOST_TEST(pe != p); + + BOOST_TEST(pe.get() == &values[NumValues]); + + //operators + BOOST_TEST(p != pe); + BOOST_TEST(p == p); + BOOST_TEST((p < pe)); + BOOST_TEST((p <= pe)); + BOOST_TEST((pe > p)); + BOOST_TEST((pe >= p)); +} + +bool test_pointer_traits() +{ + typedef offset_ptr<int> OInt; + typedef boost::intrusive::pointer_traits< OInt > PTOInt; + BOOST_STATIC_ASSERT((ipcdetail::is_same<PTOInt::element_type, int>::value)); + BOOST_STATIC_ASSERT((ipcdetail::is_same<PTOInt::pointer, OInt >::value)); + BOOST_STATIC_ASSERT((ipcdetail::is_same<PTOInt::difference_type, OInt::difference_type >::value)); + BOOST_STATIC_ASSERT((ipcdetail::is_same<PTOInt::rebind_pointer<double>::type, offset_ptr<double> >::value)); + int dummy; + OInt oi(&dummy); + if(boost::intrusive::pointer_traits<OInt>::pointer_to(dummy) != oi){ + return false; + } + return true; +} + +struct node +{ + offset_ptr<node> next; +}; + +void test_pointer_plus_bits() +{ + BOOST_STATIC_ASSERT((boost::intrusive::max_pointer_plus_bits< offset_ptr<void>, boost::move_detail::alignment_of<node>::value >::value >= 1U)); + typedef boost::intrusive::pointer_plus_bits< offset_ptr<node>, 1u > ptr_plus_bits; + + node n, n2; + offset_ptr<node> pnode(&n); + + BOOST_TEST(ptr_plus_bits::get_pointer(pnode) == &n); + BOOST_TEST(0 == ptr_plus_bits::get_bits(pnode)); + ptr_plus_bits::set_bits(pnode, 1u); + BOOST_TEST(1 == ptr_plus_bits::get_bits(pnode)); + BOOST_TEST(ptr_plus_bits::get_pointer(pnode) == &n); + + ptr_plus_bits::set_pointer(pnode, &n2); + BOOST_TEST(ptr_plus_bits::get_pointer(pnode) == &n2); + BOOST_TEST(1 == ptr_plus_bits::get_bits(pnode)); + ptr_plus_bits::set_bits(pnode, 0u); + BOOST_TEST(0 == ptr_plus_bits::get_bits(pnode)); + BOOST_TEST(ptr_plus_bits::get_pointer(pnode) == &n2); + + ptr_plus_bits::set_pointer(pnode, offset_ptr<node>()); + BOOST_TEST(ptr_plus_bits::get_pointer(pnode) ==0); + BOOST_TEST(0 == ptr_plus_bits::get_bits(pnode)); + ptr_plus_bits::set_bits(pnode, 1u); + BOOST_TEST(1 == ptr_plus_bits::get_bits(pnode)); + BOOST_TEST(ptr_plus_bits::get_pointer(pnode) == 0); +} + +int main() +{ + test_types_and_conversions(); + test_base_derived(); + test_arithmetic(); + test_comparison(); + test_pointer_traits(); + test_pointer_plus_bits(); + return ::boost::report_errors(); +} + +#include <boost/interprocess/detail/config_end.hpp> + +/* +//Offset ptr benchmark +#include <vector> +#include <iostream> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/timer.hpp> +#include <cstddef> + +template<class InIt, + class Ty> inline + Ty accumulate2(InIt First, InIt Last, Ty Val) + { // return sum of Val and all in [First, Last) + for (; First != Last; ++First) //First = First + 1) + Val = Val + *First; + return (Val); + } + +template <typename Vector> +void time_test(const Vector& vec, std::size_t iterations, const char* label) { + // assert(!vec.empty()) + boost::timer t; + typename Vector::const_iterator first = vec.begin(); + typename Vector::value_type result(0); + while (iterations != 0) { + result = accumulate2(first, first + vec.size(), result); + --iterations; + } + std::cout << label << t.elapsed() << " " << result << std::endl; +} + +int main() +{ + using namespace boost::interprocess; + typedef allocator<double, managed_shared_memory::segment_manager> alloc_t; + + std::size_t n = 0x1 << 26; + std::size_t file_size = n * sizeof(double) + 1000000; + + { + shared_memory_object::remove("MyMappedFile"); + managed_shared_memory segment(open_or_create, "MyMappedFile", file_size); + shared_memory_object::remove("MyMappedFile"); + alloc_t alloc_inst(segment.get_segment_manager()); + vector<double, alloc_t> v0(n, double(42.42), alloc_inst); + time_test(v0, 10, "iterator shared: "); + } + { + std::vector<double> v1(n, double(42.42)); + time_test(v1, 10, "iterator non-shared: "); + } + return 0; +} + +*/ diff --git a/src/boost/libs/interprocess/test/print_container.hpp b/src/boost/libs/interprocess/test/print_container.hpp new file mode 100644 index 00000000..b045bb42 --- /dev/null +++ b/src/boost/libs/interprocess/test/print_container.hpp @@ -0,0 +1,56 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_PRINTCONTAINER_HPP +#define BOOST_INTERPROCESS_TEST_PRINTCONTAINER_HPP + +#include <boost/interprocess/detail/config_begin.hpp> +#include <iostream> + +namespace boost{ +namespace interprocess{ +namespace test{ + +template<class Container> +void PrintContents(const Container &cont, const char *contName) +{ + std::cout<< "Printing contents of " << contName << std::endl; + typename Container::iterator b(cont.begin()), e(cont.end()); + for(; b != e; ++b){ + std::cout << *b << " "; + } + std::cout<< std::endl << std::endl; +} + +//Function to dump data +template<class MyShmCont, class MyStdCont> +void PrintContainers(MyShmCont *shmcont, MyStdCont *stdcont) +{ + typename MyShmCont::iterator itshm = shmcont->begin(), itshmend = shmcont->end(); + typename MyStdCont::iterator itstd = stdcont->begin(), itstdend = stdcont->end(); + + std::cout << "MyShmCont" << std::endl; + for(; itshm != itshmend; ++itshm){ + std::cout << *itshm << std::endl; + } + std::cout << "MyStdCont" << std::endl; + + for(; itstd != itstdend; ++itstd){ + std::cout << *itstd << std::endl; + } +} + +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_TEST_PRINTCONTAINER_HPP diff --git a/src/boost/libs/interprocess/test/private_adaptive_pool_test.cpp b/src/boost/libs/interprocess/test/private_adaptive_pool_test.cpp new file mode 100644 index 00000000..55868a0d --- /dev/null +++ b/src/boost/libs/interprocess/test/private_adaptive_pool_test.cpp @@ -0,0 +1,66 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/allocators/private_adaptive_pool.hpp> +#include "print_container.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include "list_test.hpp" +#include "vector_test.hpp" + +using namespace boost::interprocess; + +//We will work with wide characters for shared memory objects +//Alias a private adaptive pool that allocates ints +typedef private_adaptive_pool + <int, managed_shared_memory::segment_manager> priv_node_allocator_t; +typedef ipcdetail::private_adaptive_pool_v1 + <int, managed_shared_memory::segment_manager> priv_node_allocator_v1_t; + +namespace boost { +namespace interprocess { + +//Explicit instantiations to catch compilation errors +template class private_adaptive_pool<int, managed_shared_memory::segment_manager>; +template class private_adaptive_pool<void, managed_shared_memory::segment_manager>; + +namespace ipcdetail { + +template class ipcdetail::private_adaptive_pool_v1<int, managed_shared_memory::segment_manager>; +template class ipcdetail::private_adaptive_pool_v1<void, managed_shared_memory::segment_manager>; + +}}} + +//Alias list types +typedef list<int, priv_node_allocator_t> MyShmList; +typedef list<int, priv_node_allocator_v1_t> MyShmListV1; + +//Alias vector types +typedef vector<int, priv_node_allocator_t> MyShmVector; +typedef vector<int, priv_node_allocator_v1_t> MyShmVectorV1; + +int main () +{ + if(test::list_test<managed_shared_memory, MyShmList, true>(false)) + return 1; + if(test::list_test<managed_shared_memory, MyShmListV1, true>(false)) + return 1; + if(test::vector_test<managed_shared_memory, MyShmVector>()) + return 1; + if(test::vector_test<managed_shared_memory, MyShmVectorV1>()) + return 1; + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/private_node_allocator_test.cpp b/src/boost/libs/interprocess/test/private_node_allocator_test.cpp new file mode 100644 index 00000000..4690f83f --- /dev/null +++ b/src/boost/libs/interprocess/test/private_node_allocator_test.cpp @@ -0,0 +1,66 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/allocators/private_node_allocator.hpp> +#include "print_container.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include "list_test.hpp" +#include "vector_test.hpp" + +using namespace boost::interprocess; + +//We will work with wide characters for shared memory objects +//Alias an integer node allocator type +typedef private_node_allocator + <int, managed_shared_memory::segment_manager> priv_node_allocator_t; +typedef ipcdetail::private_node_allocator_v1 + <int, managed_shared_memory::segment_manager> priv_node_allocator_v1_t; + +namespace boost { +namespace interprocess { + +//Explicit instantiations to catch compilation errors +template class private_node_allocator<int, managed_shared_memory::segment_manager>; +template class private_node_allocator<void, managed_shared_memory::segment_manager>; + +namespace ipcdetail { + +template class ipcdetail::private_node_allocator_v1<int, managed_shared_memory::segment_manager>; +template class ipcdetail::private_node_allocator_v1<void, managed_shared_memory::segment_manager>; + +}}} + +//Alias list types +typedef list<int, priv_node_allocator_t> MyShmList; +typedef list<int, priv_node_allocator_v1_t> MyShmListV1; + +//Alias vector types +typedef vector<int, priv_node_allocator_t> MyShmVector; +typedef vector<int, priv_node_allocator_v1_t> MyShmVectorV1; + +int main () +{ + if(test::list_test<managed_shared_memory, MyShmList, true>(false)) + return 1; + if(test::list_test<managed_shared_memory, MyShmListV1, true>(false)) + return 1; + if(test::vector_test<managed_shared_memory, MyShmVector>()) + return 1; + if(test::vector_test<managed_shared_memory, MyShmVectorV1>()) + return 1; + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/recursive_mutex_test.cpp b/src/boost/libs/interprocess/test/recursive_mutex_test.cpp new file mode 100644 index 00000000..8bec0344 --- /dev/null +++ b/src/boost/libs/interprocess/test/recursive_mutex_test.cpp @@ -0,0 +1,42 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#if defined(BOOST_INTERPROCESS_WINDOWS) +#include <boost/interprocess/sync/windows/recursive_mutex.hpp> +#include <boost/interprocess/sync/spin/recursive_mutex.hpp> +#endif +#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include "mutex_test_template.hpp" + +int main () +{ + using namespace boost::interprocess; + #if defined(BOOST_INTERPROCESS_WINDOWS) + // + test::test_all_lock<ipcdetail::windows_recursive_mutex>(); + test::test_all_mutex<ipcdetail::windows_recursive_mutex>(); + test::test_all_recursive_lock<ipcdetail::windows_recursive_mutex>(); + // + test::test_all_lock<ipcdetail::spin_recursive_mutex>(); + test::test_all_mutex<ipcdetail::spin_recursive_mutex>(); + test::test_all_recursive_lock<ipcdetail::spin_recursive_mutex>(); + #endif + // + test::test_all_lock<interprocess_recursive_mutex>(); + test::test_all_mutex<interprocess_recursive_mutex>(); + test::test_all_recursive_lock<interprocess_recursive_mutex>(); + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/robust_emulation_test.cpp b/src/boost/libs/interprocess/test/robust_emulation_test.cpp new file mode 100644 index 00000000..98a64e0f --- /dev/null +++ b/src/boost/libs/interprocess/test/robust_emulation_test.cpp @@ -0,0 +1,22 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2010-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include "robust_mutex_test.hpp" +#include <boost/interprocess/detail/robust_emulation.hpp> +#include <boost/interprocess/sync/spin/mutex.hpp> + +int main(int argc, char *argv[]) +{ + using namespace boost::interprocess; + return test::robust_mutex_test + < ipcdetail::robust_spin_mutex<ipcdetail::spin_mutex> >(argc, argv); +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/robust_mutex_test.hpp b/src/boost/libs/interprocess/test/robust_mutex_test.hpp new file mode 100644 index 00000000..09688c3d --- /dev/null +++ b/src/boost/libs/interprocess/test/robust_mutex_test.hpp @@ -0,0 +1,208 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2010-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_ROBUST_MUTEX_TEST_HEADER +#define BOOST_INTERPROCESS_TEST_ROBUST_MUTEX_TEST_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include <iostream> +#include <cstdlib> //std::system +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/sync/spin/wait.hpp> +#include "get_process_id_name.hpp" +#include "mutex_test_template.hpp" +#include <iostream> + +namespace boost{ +namespace interprocess{ +namespace test{ + +template<class RobustMutex> +int robust_mutex_test(int argc, char *argv[]) +{ + try{ + if(argc == 1){ //Parent process + //First usual mutex tests + { + // test_all_lock<RobustMutex>(); +// test_all_mutex<true, RobustMutex>(); + } + std::cout << "robust mutex recovery test" << std::endl; + + //Remove shared memory on construction and destruction + class shm_remove + { + public: + shm_remove(){ shared_memory_object::remove + (::boost::interprocess::test::get_process_id_name()); } + ~shm_remove(){ shared_memory_object::remove + (::boost::interprocess::test::get_process_id_name()); } + } remover; + (void)remover; + + //Construct managed shared memory + managed_shared_memory segment(create_only, get_process_id_name(), 65536); + + //Create two robust mutexes + RobustMutex *instance = segment.construct<RobustMutex> + ("robust mutex")[2](); + + //Create a flag to notify that both mutexes are + //locked and the owner is going to die soon. + bool *go_ahead = segment.construct<bool> ("go ahead")(false); + + //Launch child process + std::string s(argv[0]); s += " child "; + s += get_process_id_name(); + std::cout << "... launching child" << std::endl; + if(0 != std::system(s.c_str())) + return 1; + + //Wait until child locks the mutexes and dies + spin_wait swait; + while(!*go_ahead){ + swait.yield(); + } + + std::cout << "... recovering mutex[0]" << std::endl; + //First try to recover lock[0], put into consistent + //state and relock it again + { + //Done, now try to lock it to see if robust + //mutex recovery works + instance[0].lock(); + if(!instance[0].previous_owner_dead()) + return 1; + instance[0].consistent(); + instance[0].unlock(); + //Since it's consistent, locking is possible again + instance[0].lock(); + instance[0].unlock(); + } + //Now with lock[1], but dont' put it in consistent state + //so the mutex is no longer usable + std::cout << "... recovering mutex[1]" << std::endl; + { + //Done, now try to lock it to see if robust + //mutex recovery works + instance[1].lock(); + if(!instance[1].previous_owner_dead()) + return 1; + //Unlock a recovered mutex without putting it into + //into consistent state marks mutex as unusable. + instance[1].unlock(); + //Since it's NOT consistent, locking is NOT possible again + bool exception_thrown = false; + try{ + instance[1].lock(); + } + catch(interprocess_exception &){ + exception_thrown = true; + } + if(!exception_thrown){ + return 1; + } + } + //Now with lock[2], this was locked by child but not + //unlocked + std::cout << "... recovering mutex[2]" << std::endl; + { + //Done, now try to lock it to see if robust + //mutex recovery works + instance[2].lock(); + if(!instance[2].previous_owner_dead()) + return 1; + //Unlock a recovered mutex without putting it into + //into consistent state marks mutex as unusable. + instance[2].unlock(); + //Since it's NOT consistent, locking is NOT possible again + bool exception_thrown = false; + try{ + instance[2].lock(); + } + catch(interprocess_exception &){ + exception_thrown = true; + } + if(!exception_thrown){ + return 1; + } + } + } + else{ + //Open managed shared memory + managed_shared_memory segment(open_only, argv[2]); + //Find mutexes + RobustMutex *instance = segment.find<RobustMutex>("robust mutex").first; + assert(instance); + if(std::string(argv[1]) == std::string("child")){ + std::cout << "launched child" << std::endl; + //Find flag + bool *go_ahead = segment.find<bool>("go ahead").first; + assert(go_ahead); + //Lock, flag and die + bool try_lock_res = instance[0].try_lock() && instance[1].try_lock(); + assert(try_lock_res); + if(!try_lock_res) + return 1; + + bool *go_ahead2 = segment.construct<bool>("go ahead2")(false); + assert(go_ahead2); + //Launch grandchild + std::string s(argv[0]); s += " grandchild "; + s += argv[2]; + std::cout << "... launching grandchild" << std::endl; + if(0 != std::system(s.c_str())){ + std::cout << "launched terminated with error" << std::endl; + return 1; + } + + //Wait until child locks the 2nd mutex and dies + spin_wait swait; + while(!*go_ahead2){ + swait.yield(); + } + + //Done, now try to lock number 3 to see if robust + //mutex recovery works + instance[2].lock(); + if(!instance[2].previous_owner_dead()){ + return 1; + } + *go_ahead = true; + } + else{ + std::cout << "launched grandchild" << std::endl; + //grandchild locks the lock and dies + bool *go_ahead2 = segment.find<bool>("go ahead2").first; + assert(go_ahead2); + //Lock, flag and die + bool try_lock_res = instance[2].try_lock(); + assert(try_lock_res); + if(!try_lock_res){ + return 1; + } + *go_ahead2 = true; + } + } + }catch(...){ + std::cout << "Exception thrown error!" << std::endl; + throw; + } + return 0; +} + +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_TEST_ROBUST_EMULATION_TEST_HEADER diff --git a/src/boost/libs/interprocess/test/robust_recursive_emulation_test.cpp b/src/boost/libs/interprocess/test/robust_recursive_emulation_test.cpp new file mode 100644 index 00000000..bc140769 --- /dev/null +++ b/src/boost/libs/interprocess/test/robust_recursive_emulation_test.cpp @@ -0,0 +1,23 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2010-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include "robust_mutex_test.hpp" +#include <boost/interprocess/detail/robust_emulation.hpp> +#include <boost/interprocess/sync/spin/recursive_mutex.hpp> + +int main(int argc, char *argv[]) +{ + using namespace boost::interprocess; + + return test::robust_mutex_test + < ipcdetail::robust_spin_mutex<ipcdetail::spin_recursive_mutex> >(argc, argv); +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/segment_manager_test.cpp b/src/boost/libs/interprocess/test/segment_manager_test.cpp new file mode 100644 index 00000000..1b42c8c5 --- /dev/null +++ b/src/boost/libs/interprocess/test/segment_manager_test.cpp @@ -0,0 +1,478 @@ +#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; + } + private: + atomic_func_test operator=(const atomic_func_test&); + atomic_func_test(const atomic_func_test&); +}; + +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); + //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; + } + + {//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 != 1/*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; + + 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; + } + {//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; +} diff --git a/src/boost/libs/interprocess/test/semaphore_test.cpp b/src/boost/libs/interprocess/test/semaphore_test.cpp new file mode 100644 index 00000000..54913ce8 --- /dev/null +++ b/src/boost/libs/interprocess/test/semaphore_test.cpp @@ -0,0 +1,70 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/sync/interprocess_semaphore.hpp> +#include <boost/interprocess/exceptions.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include "named_creation_template.hpp" +#include "mutex_test_template.hpp" + +static const std::size_t SemCount = 1; +static const std::size_t RecSemCount = 100; + +//This wrapper is necessary to plug this class +//in named creation tests and interprocess_mutex tests +class semaphore_test_wrapper + : public boost::interprocess::interprocess_semaphore +{ + public: + semaphore_test_wrapper() + : boost::interprocess::interprocess_semaphore(SemCount) + {} + + void lock() + { this->wait(); } + + bool try_lock() + { return this->try_wait(); } + + bool timed_lock(const boost::posix_time::ptime &pt) + { return this->timed_wait(pt); } + + void unlock() + { this->post(); } + + protected: + semaphore_test_wrapper(int initial_count) + : boost::interprocess::interprocess_semaphore(initial_count) + {} +}; + +//This wrapper is necessary to plug this class +//in recursive tests +class recursive_semaphore_test_wrapper + : public semaphore_test_wrapper +{ + public: + recursive_semaphore_test_wrapper() + : semaphore_test_wrapper(RecSemCount) + {} +}; + +int main () +{ + using namespace boost::interprocess; + + test::test_all_lock<semaphore_test_wrapper>(); + test::test_all_recursive_lock<recursive_semaphore_test_wrapper>(); + test::test_all_mutex<semaphore_test_wrapper>(); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/set_test.hpp b/src/boost/libs/interprocess/test/set_test.hpp new file mode 100644 index 00000000..44b0b66e --- /dev/null +++ b/src/boost/libs/interprocess/test/set_test.hpp @@ -0,0 +1,594 @@ +//////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +//////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_SET_TEST_HEADER +#define BOOST_INTERPROCESS_TEST_SET_TEST_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include "check_equal_containers.hpp" +#include "print_container.hpp" +#include <boost/move/utility_core.hpp> +#include "get_process_id_name.hpp" + +#include <functional> + +namespace boost{ +namespace interprocess{ +namespace test{ + +template<class ManagedSharedMemory + ,class MyShmSet + ,class MyStdSet + ,class MyShmMultiSet + ,class MyStdMultiSet> +int set_test () +{ + typedef typename MyShmSet::value_type IntType; + const int memsize = 65536; + const char *const shMemName = test::get_process_id_name(); + const int max = 100; + + try{ + //Create shared memory + shared_memory_object::remove(shMemName); + ManagedSharedMemory segment(create_only, shMemName, memsize); + + segment.reserve_named_objects(100); + + //Shared memory allocator must be always be initialized + //since it has no default constructor + MyShmSet *shmset = + segment.template construct<MyShmSet>("MyShmSet") + (std::less<IntType>(), segment.get_segment_manager()); + + MyStdSet *stdset = new MyStdSet; + + MyShmMultiSet *shmmultiset = + segment.template construct<MyShmMultiSet>("MyShmMultiSet") + (std::less<IntType>(), segment.get_segment_manager()); + + MyStdMultiSet *stdmultiset = new MyStdMultiSet; + + //Test construction from a range + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(i/2); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = i/2; + } + IntType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(i/2); + aux_vect3[i] = boost::move(move_me); + } + + MyShmSet *shmset2 = + segment.template construct<MyShmSet>("MyShmSet2") + ( ::boost::make_move_iterator(&aux_vect[0]) + , ::boost::make_move_iterator(aux_vect + 50) + , std::less<IntType>(), segment.get_segment_manager()); + + MyStdSet *stdset2 = new MyStdSet(aux_vect2, aux_vect2 + 50); + + MyShmMultiSet *shmmultiset2 = + segment.template construct<MyShmMultiSet>("MyShmMultiSet2") + ( ::boost::make_move_iterator(&aux_vect3[0]) + , ::boost::make_move_iterator(aux_vect3 + 50) + , std::less<IntType>(), segment.get_segment_manager()); + + MyStdMultiSet *stdmultiset2 = new MyStdMultiSet(aux_vect2, aux_vect2 + 50); + if(!CheckEqualContainers(shmset2, stdset2)){ + std::cout << "Error in construct<MyShmSet>(MyShmSet2)" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset2, stdmultiset2)){ + std::cout << "Error in construct<MyShmMultiSet>(MyShmMultiSet2)" << std::endl; + return 1; + } + + //ordered range insertion + for(int i = 0; i < 50; ++i){ + IntType move_me(i); + aux_vect[i] = boost::move(move_me); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = i; + } + + for(int i = 0; i < 50; ++i){ + IntType move_me(i); + aux_vect3[i] = boost::move(move_me); + } + + MyShmSet *shmset3 = + segment.template construct<MyShmSet>("MyShmSet3") + ( ordered_unique_range + , ::boost::make_move_iterator(&aux_vect[0]) + , ::boost::make_move_iterator(aux_vect + 50) + , std::less<IntType>(), segment.get_segment_manager()); + + MyStdSet *stdset3 = new MyStdSet(aux_vect2, aux_vect2 + 50); + + MyShmMultiSet *shmmultiset3 = + segment.template construct<MyShmMultiSet>("MyShmMultiSet3") + ( ordered_range + , ::boost::make_move_iterator(&aux_vect3[0]) + , ::boost::make_move_iterator(aux_vect3 + 50) + , std::less<IntType>(), segment.get_segment_manager()); + + MyStdMultiSet *stdmultiset3 = new MyStdMultiSet(aux_vect2, aux_vect2 + 50); + + if(!CheckEqualContainers(shmset3, stdset3)){ + std::cout << "Error in construct<MyShmSet>(MyShmSet3)" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset3, stdmultiset3)){ + std::cout << "Error in construct<MyShmMultiSet>(MyShmMultiSet3)" << std::endl; + return 1; + } + + segment.destroy_ptr(shmset2); + segment.destroy_ptr(shmmultiset2); + delete stdset2; + delete stdmultiset2; + + segment.destroy_ptr(shmset3); + segment.destroy_ptr(shmmultiset3); + delete stdset3; + delete stdmultiset3; + } + + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(boost::move(move_me)" << std::endl; + return 1; + } + + for(int i = 0; i < max/2; ++i){ + IntType move_me(i); + shmset->insert(boost::move(move_me)); + stdset->insert(i); + IntType move_me2(i); + shmmultiset->insert(boost::move(move_me2)); + stdmultiset->insert(i); + + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(boost::move(move_me)" << std::endl; + return 1; + } + // + shmset->insert(IntType(i)); + stdset->insert(i); + shmmultiset->insert(IntType(i)); + stdmultiset->insert(i); + + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(boost::move(move_me)" << std::endl; + return 1; + } + + } + + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(boost::move(move_me)" << std::endl; + return 1; + } + + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->insert(boost::move(move_me)" << std::endl; + return 1; + } + + typename MyShmSet::iterator it; + typename MyShmSet::const_iterator cit = it; + (void)cit; + + shmset->erase(shmset->begin()++); + stdset->erase(stdset->begin()++); + shmmultiset->erase(shmmultiset->begin()++); + stdmultiset->erase(stdmultiset->begin()++); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->erase(shmset->begin()++)" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->erase(shmmultiset->begin()++)" << std::endl; + return 1; + } + + shmset->erase(shmset->begin()); + stdset->erase(stdset->begin()); + shmmultiset->erase(shmmultiset->begin()); + stdmultiset->erase(stdmultiset->begin()); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->erase(shmset->begin())" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->erase(shmmultiset->begin())" << std::endl; + return 1; + } + + //Swapping test + std::less<IntType> lessfunc; + MyShmSet tmpshmeset2 (lessfunc, segment.get_segment_manager()); + MyStdSet tmpstdset2; + MyShmMultiSet tmpshmemultiset2(lessfunc, segment.get_segment_manager()); + MyStdMultiSet tmpstdmultiset2; + shmset->swap(tmpshmeset2); + stdset->swap(tmpstdset2); + shmmultiset->swap(tmpshmemultiset2); + stdmultiset->swap(tmpstdmultiset2); + shmset->swap(tmpshmeset2); + stdset->swap(tmpstdset2); + shmmultiset->swap(tmpshmemultiset2); + stdmultiset->swap(tmpstdmultiset2); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->swap(tmpshmeset2)" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->swap(tmpshmemultiset2)" << std::endl; + return 1; + } + + //Insertion from other container + //Initialize values + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + IntType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect3[i] = boost::move(move_me); + } + + shmset->insert(::boost::make_move_iterator(&aux_vect[0]), ::boost::make_move_iterator(aux_vect + 50)); + stdset->insert(aux_vect2, aux_vect2 + 50); + shmmultiset->insert(::boost::make_move_iterator(&aux_vect3[0]), ::boost::make_move_iterator(aux_vect3 + 50)); + stdmultiset->insert(aux_vect2, aux_vect2 + 50); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(::boost::make_move_iterator(&aux_vect[0])..." << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->insert(::boost::make_move_iterator(&aux_vect3[0]), ..." << std::endl; + return 1; + } + + for(int i = 0, j = static_cast<int>(shmset->size()); i < j; ++i){ + IntType erase_me(i); + shmset->erase(erase_me); + stdset->erase(i); + shmmultiset->erase(erase_me); + stdmultiset->erase(i); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->erase(erase_me)" << shmset->size() << " " << stdset->size() << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->erase(erase_me)" << std::endl; + return 1; + } + } + } + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + IntType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect3[i] = boost::move(move_me); + } + + IntType aux_vect4[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect4[i] = boost::move(move_me); + } + + IntType aux_vect5[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect5[i] = boost::move(move_me); + } + + shmset->insert(::boost::make_move_iterator(&aux_vect[0]), ::boost::make_move_iterator(aux_vect + 50)); + shmset->insert(::boost::make_move_iterator(&aux_vect3[0]), ::boost::make_move_iterator(aux_vect3 + 50)); + stdset->insert(aux_vect2, aux_vect2 + 50); + stdset->insert(aux_vect2, aux_vect2 + 50); + shmmultiset->insert(::boost::make_move_iterator(&aux_vect4[0]), ::boost::make_move_iterator(aux_vect4 + 50)); + shmmultiset->insert(::boost::make_move_iterator(&aux_vect5[0]), ::boost::make_move_iterator(aux_vect5 + 50)); + stdmultiset->insert(aux_vect2, aux_vect2 + 50); + stdmultiset->insert(aux_vect2, aux_vect2 + 50); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(::boost::make_move_iterator(&aux_vect3[0])..." << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->insert(::boost::make_move_iterator(&aux_vect5[0])..." << std::endl; + return 1; + } + + shmset->erase(*shmset->begin()); + stdset->erase(*stdset->begin()); + shmmultiset->erase(*shmmultiset->begin()); + stdmultiset->erase(*stdmultiset->begin()); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->erase(*shmset->begin())" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->erase(*shmmultiset->begin())" << std::endl; + return 1; + } + } + + for(int i = 0; i < max/2; ++i){ + IntType move_me(i); + shmset->insert(shmset->begin(), boost::move(move_me)); + stdset->insert(stdset->begin(), i); + IntType move_me2(i); + shmmultiset->insert(shmmultiset->begin(), boost::move(move_me2)); + stdmultiset->insert(stdmultiset->begin(), i); + // + shmset->insert(shmset->begin(), IntType(i)); + stdset->insert(stdset->begin(), i); + shmmultiset->insert(shmmultiset->begin(), IntType(i)); + stdmultiset->insert(stdmultiset->begin(), i); + } + + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(boost::move(move_me)) try 2" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->insert(boost::move(move_me2)) try 2" << std::endl; + return 1; + } + + for(int i = 0; i < max; ++i){ + { + IntType move_me(i); + shmset->insert(shmset->begin(), boost::move(move_me)); + stdset->insert(stdset->begin(), i); + //PrintContainers(shmset, stdset); + IntType move_me2(i); + shmmultiset->insert(shmmultiset->begin(), boost::move(move_me2)); + stdmultiset->insert(stdmultiset->begin(), i); + //PrintContainers(shmmultiset, stdmultiset); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(shmset->begin(), boost::move(move_me))" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->insert(shmmultiset->begin(), boost::move(move_me2))" << std::endl; + return 1; + } + + IntType move_me3(i); + shmset->insert(shmset->end(), boost::move(move_me3)); + stdset->insert(stdset->end(), i); + IntType move_me4(i); + shmmultiset->insert(shmmultiset->end(), boost::move(move_me4)); + stdmultiset->insert(stdmultiset->end(), i); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(shmset->end(), boost::move(move_me3))" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->insert(shmmultiset->end(), boost::move(move_me4))" << std::endl; + return 1; + } + } + { + IntType move_me(i); + shmset->insert(shmset->upper_bound(move_me), boost::move(move_me)); + stdset->insert(stdset->upper_bound(i), i); + //PrintContainers(shmset, stdset); + IntType move_me2(i); + shmmultiset->insert(shmmultiset->upper_bound(move_me2), boost::move(move_me2)); + stdmultiset->insert(stdmultiset->upper_bound(i), i); + //PrintContainers(shmmultiset, stdmultiset); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(shmset->upper_bound(move_me), boost::move(move_me))" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->insert(shmmultiset->upper_bound(move_me2), boost::move(move_me2))" << std::endl; + return 1; + } + } + { + IntType move_me(i); + IntType move_me2(i); + shmset->insert(shmset->lower_bound(move_me), boost::move(move_me2)); + stdset->insert(stdset->lower_bound(i), i); + //PrintContainers(shmset, stdset); + move_me2 = i; + shmmultiset->insert(shmmultiset->lower_bound(move_me2), boost::move(move_me2)); + stdmultiset->insert(stdmultiset->lower_bound(i), i); + //PrintContainers(shmmultiset, stdmultiset); + if(!CheckEqualContainers(shmset, stdset)){ + std::cout << "Error in shmset->insert(shmset->lower_bound(move_me), boost::move(move_me2))" << std::endl; + return 1; + } + if(!CheckEqualContainers(shmmultiset, stdmultiset)){ + std::cout << "Error in shmmultiset->insert(shmmultiset->lower_bound(move_me2), boost::move(move_me2))" << std::endl; + return 1; + } + } + } + + //Compare count with std containers + for(int i = 0; i < max; ++i){ + IntType count_me(i); + if(shmset->count(count_me) != stdset->count(i)){ + return -1; + } + if(shmmultiset->count(count_me) != stdmultiset->count(i)){ + return -1; + } + } + + //Now do count exercise + shmset->erase(shmset->begin(), shmset->end()); + shmmultiset->erase(shmmultiset->begin(), shmmultiset->end()); + shmset->clear(); + shmmultiset->clear(); + + for(int j = 0; j < 3; ++j) + for(int i = 0; i < 100; ++i){ + IntType move_me(i); + shmset->insert(boost::move(move_me)); + IntType move_me2(i); + shmmultiset->insert(boost::move(move_me2)); + IntType count_me(i); + if(shmset->count(count_me) != typename MyShmMultiSet::size_type(1)){ + std::cout << "Error in shmset->count(count_me)" << std::endl; + return 1; + } + if(shmmultiset->count(count_me) != typename MyShmMultiSet::size_type(j+1)){ + std::cout << "Error in shmmultiset->count(count_me)" << std::endl; + return 1; + } + } + + segment.template destroy<MyShmSet>("MyShmSet"); + delete stdset; + segment.destroy_ptr(shmmultiset); + delete stdmultiset; + segment.shrink_to_fit_indexes(); + + if(!segment.all_memory_deallocated()){ + std::cout << "Error in segment.all_memory_deallocated()" << std::endl; + return 1; + } + } + catch(...){ + shared_memory_object::remove(shMemName); + throw; + } + shared_memory_object::remove(shMemName); + return 0; +} + +template<class ManagedSharedMemory + ,class MyShmSet + ,class MyStdSet + ,class MyShmMultiSet + ,class MyStdMultiSet> +int set_test_copyable () +{ + typedef typename MyShmSet::value_type IntType; + const int memsize = 65536; + const char *const shMemName = test::get_process_id_name(); + const int max = 100; + + try{ + //Create shared memory + shared_memory_object::remove(shMemName); + ManagedSharedMemory segment(create_only, shMemName, memsize); + + segment.reserve_named_objects(100); + + //Shared memory allocator must be always be initialized + //since it has no default constructor + MyShmSet *shmset = + segment.template construct<MyShmSet>("MyShmSet") + (std::less<IntType>(), segment.get_segment_manager()); + + MyStdSet *stdset = new MyStdSet; + + MyShmMultiSet *shmmultiset = + segment.template construct<MyShmMultiSet>("MyShmMultiSet") + (std::less<IntType>(), segment.get_segment_manager()); + + MyStdMultiSet *stdmultiset = new MyStdMultiSet; + + for(int i = 0; i < max; ++i){ + IntType move_me(i); + shmset->insert(boost::move(move_me)); + stdset->insert(i); + IntType move_me2(i); + shmmultiset->insert(boost::move(move_me2)); + stdmultiset->insert(i); + } + if(!CheckEqualContainers(shmset, stdset)) return 1; + if(!CheckEqualContainers(shmmultiset, stdmultiset)) return 1; + + { + //Now, test copy constructor + MyShmSet shmsetcopy(*shmset); + MyStdSet stdsetcopy(*stdset); + + if(!CheckEqualContainers(&shmsetcopy, &stdsetcopy)) + return 1; + + MyShmMultiSet shmmsetcopy(*shmmultiset); + MyStdMultiSet stdmsetcopy(*stdmultiset); + + if(!CheckEqualContainers(&shmmsetcopy, &stdmsetcopy)) + return 1; + + //And now assignment + shmsetcopy = *shmset; + stdsetcopy = *stdset; + + if(!CheckEqualContainers(&shmsetcopy, &stdsetcopy)) + return 1; + + shmmsetcopy = *shmmultiset; + stdmsetcopy = *stdmultiset; + + if(!CheckEqualContainers(&shmmsetcopy, &stdmsetcopy)) + return 1; + } + segment.destroy_ptr(shmset); + segment.destroy_ptr(shmmultiset); + delete stdset; + delete stdmultiset; + segment.shrink_to_fit_indexes(); + if(!segment.all_memory_deallocated()) + return 1; + } + catch(...){ + shared_memory_object::remove(shMemName); + throw; + } + shared_memory_object::remove(shMemName); + return 0; +} + +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif diff --git a/src/boost/libs/interprocess/test/sharable_mutex_test.cpp b/src/boost/libs/interprocess/test/sharable_mutex_test.cpp new file mode 100644 index 00000000..b2731545 --- /dev/null +++ b/src/boost/libs/interprocess/test/sharable_mutex_test.cpp @@ -0,0 +1,31 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include "mutex_test_template.hpp" +#include "sharable_mutex_test_template.hpp" +#include <boost/interprocess/sync/interprocess_sharable_mutex.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/interprocess/sync/sharable_lock.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include "util.hpp" + +int main () +{ + using namespace boost::interprocess; + + test::test_all_lock<interprocess_sharable_mutex>(); + test::test_all_mutex<interprocess_sharable_mutex>(); + test::test_all_sharable_mutex<interprocess_sharable_mutex>(); + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/sharable_mutex_test_template.hpp b/src/boost/libs/interprocess/test/sharable_mutex_test_template.hpp new file mode 100644 index 00000000..3c14c7a7 --- /dev/null +++ b/src/boost/libs/interprocess/test/sharable_mutex_test_template.hpp @@ -0,0 +1,291 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER +#define BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#include <boost/interprocess/detail/os_thread_functions.hpp> +#include "boost_interprocess_check.hpp" +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <boost/interprocess/sync/sharable_lock.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <iostream> +#include <cassert> +#include "util.hpp" + +namespace boost { namespace interprocess { namespace test { + +template<typename SM> +void plain_exclusive(void *arg, SM &sm) +{ + data<SM> *pdata = static_cast<data<SM>*>(arg); + boost::interprocess::scoped_lock<SM> l(sm); + boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds)); + shared_val += 10; + pdata->m_value = shared_val; +} + +template<typename SM> +void plain_shared(void *arg, SM &sm) +{ + data<SM> *pdata = static_cast<data<SM>*>(arg); + boost::interprocess::sharable_lock<SM> l(sm); + if(pdata->m_secs){ + boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds)); + } + pdata->m_value = shared_val; +} + +template<typename SM> +void try_exclusive(void *arg, SM &sm) +{ + data<SM> *pdata = static_cast<data<SM>*>(arg); + boost::interprocess::scoped_lock<SM> l(sm, boost::interprocess::defer_lock); + if (l.try_lock()){ + boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds)); + shared_val += 10; + pdata->m_value = shared_val; + } +} + +template<typename SM> +void try_shared(void *arg, SM &sm) +{ + data<SM> *pdata = static_cast<data<SM>*>(arg); + boost::interprocess::sharable_lock<SM> l(sm, boost::interprocess::defer_lock); + if (l.try_lock()){ + if(pdata->m_secs){ + boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds)); + } + pdata->m_value = shared_val; + } +} + +template<typename SM> +void timed_exclusive(void *arg, SM &sm) +{ + data<SM> *pdata = static_cast<data<SM>*>(arg); + boost::posix_time::ptime pt(delay(pdata->m_secs)); + boost::interprocess::scoped_lock<SM> + l (sm, boost::interprocess::defer_lock); + if (l.timed_lock(pt)){ + boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds)); + shared_val += 10; + pdata->m_value = shared_val; + } +} + +template<typename SM> +void timed_shared(void *arg, SM &sm) +{ + data<SM> *pdata = static_cast<data<SM>*>(arg); + boost::posix_time::ptime pt(delay(pdata->m_secs)); + boost::interprocess::sharable_lock<SM> + l(sm, boost::interprocess::defer_lock); + if (l.timed_lock(pt)){ + if(pdata->m_secs){ + boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds)); + } + pdata->m_value = shared_val; + } +} + +template<typename SM> +void test_plain_sharable_mutex() +{ + { + shared_val = 0; + SM mtx; + data<SM> s1(1); + data<SM> s2(2); + data<SM> e1(1); + data<SM> e2(2); + + // Writer one launches, holds the lock for 3*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tw1; + boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(plain_exclusive, &e1, mtx)); + + // Writer two launches, tries to grab the lock, "clearly" + // after Writer one will already be holding it. + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + boost::interprocess::ipcdetail::OS_thread_t tw2; + boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(plain_exclusive, &e2, mtx)); + + // Reader one launches, "clearly" after writer two, and "clearly" + // while writer 1 still holds the lock + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + boost::interprocess::ipcdetail::OS_thread_t thr1; + boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(plain_shared,&s1, mtx)); + boost::interprocess::ipcdetail::OS_thread_t thr2; + boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter<SM>(plain_shared,&s2, mtx)); + + boost::interprocess::ipcdetail::thread_join(thr2); + boost::interprocess::ipcdetail::thread_join(thr1); + boost::interprocess::ipcdetail::thread_join(tw2); + boost::interprocess::ipcdetail::thread_join(tw1); + + //We can only assure that the writer will be first + BOOST_INTERPROCESS_CHECK(e1.m_value == 10); + //A that we will execute all + BOOST_INTERPROCESS_CHECK(s1.m_value == 20 || s2.m_value == 20 || e2.m_value == 20); + } + + { + shared_val = 0; + SM mtx; + + data<SM> s1(1, 3); + data<SM> s2(2, 3); + data<SM> e1(1); + data<SM> e2(2); + + //We launch 2 readers, that will block for 3*BaseTime seconds + boost::interprocess::ipcdetail::OS_thread_t thr1; + boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(plain_shared,&s1, mtx)); + boost::interprocess::ipcdetail::OS_thread_t thr2; + boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter<SM>(plain_shared,&s2, mtx)); + + //Make sure they try to hold the sharable lock + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + + // We launch two writers, that should block until the readers end + boost::interprocess::ipcdetail::OS_thread_t tw1; + boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(plain_exclusive,&e1, mtx)); + + boost::interprocess::ipcdetail::OS_thread_t tw2; + boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(plain_exclusive,&e2, mtx)); + + boost::interprocess::ipcdetail::thread_join(thr2); + boost::interprocess::ipcdetail::thread_join(thr1); + boost::interprocess::ipcdetail::thread_join(tw2); + boost::interprocess::ipcdetail::thread_join(tw1); + + //We can only assure that the shared will finish first... + BOOST_INTERPROCESS_CHECK(s1.m_value == 0 || s2.m_value == 0); + //...and writers will be mutually excluded after readers + BOOST_INTERPROCESS_CHECK((e1.m_value == 10 && e2.m_value == 20) || + (e1.m_value == 20 && e2.m_value == 10) ); + } +} + +template<typename SM> +void test_try_sharable_mutex() +{ + SM mtx; + + data<SM> s1(1); + data<SM> e1(2); + data<SM> e2(3); + + // We start with some specialized tests for "try" behavior + + shared_val = 0; + + // Writer one launches, holds the lock for 3*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tw1; + boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(try_exclusive,&e1,mtx)); + + // Reader one launches, "clearly" after writer #1 holds the lock + // and before it releases the lock. + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + boost::interprocess::ipcdetail::OS_thread_t thr1; + boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(try_shared,&s1,mtx)); + + // Writer two launches in the same timeframe. + boost::interprocess::ipcdetail::OS_thread_t tw2; + boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(try_exclusive,&e2,mtx)); + + boost::interprocess::ipcdetail::thread_join(tw2); + boost::interprocess::ipcdetail::thread_join(thr1); + boost::interprocess::ipcdetail::thread_join(tw1); + + BOOST_INTERPROCESS_CHECK(e1.m_value == 10); + BOOST_INTERPROCESS_CHECK(s1.m_value == -1); // Try would return w/o waiting + BOOST_INTERPROCESS_CHECK(e2.m_value == -1); // Try would return w/o waiting +} + +template<typename SM> +void test_timed_sharable_mutex() +{ + SM mtx; + data<SM> s1(1,1*BaseSeconds); + data<SM> s2(2,3*BaseSeconds); + data<SM> e1(3,3*BaseSeconds); + data<SM> e2(4,1*BaseSeconds); + + // We begin with some specialized tests for "timed" behavior + + shared_val = 0; + + // Writer one will hold the lock for 3*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tw1; + boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(timed_exclusive,&e1,mtx)); + + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + // Writer two will "clearly" try for the lock after the readers + // have tried for it. Writer will wait up 1*BaseSeconds seconds for the lock. + // This write will fail. + boost::interprocess::ipcdetail::OS_thread_t tw2; + boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(timed_exclusive,&e2,mtx)); + + // Readers one and two will "clearly" try for the lock after writer + // one already holds it. 1st reader will wait 1*BaseSeconds seconds, and will fail + // to get the lock. 2nd reader will wait 3*BaseSeconds seconds, and will get + // the lock. + + boost::interprocess::ipcdetail::OS_thread_t thr1; + boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(timed_shared,&s1,mtx)); + + boost::interprocess::ipcdetail::OS_thread_t thr2; + boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter<SM>(timed_shared,&s2,mtx)); + + boost::interprocess::ipcdetail::thread_join(tw1); + boost::interprocess::ipcdetail::thread_join(thr1); + boost::interprocess::ipcdetail::thread_join(thr2); + boost::interprocess::ipcdetail::thread_join(tw2); + + BOOST_INTERPROCESS_CHECK(e1.m_value == 10); + BOOST_INTERPROCESS_CHECK(s1.m_value == -1); + BOOST_INTERPROCESS_CHECK(s2.m_value == 10); + BOOST_INTERPROCESS_CHECK(e2.m_value == -1); +} + +template<typename SM> +void test_all_sharable_mutex() +{ + std::cout << "test_plain_sharable_mutex<" << typeid(SM).name() << ">" << std::endl; + test_plain_sharable_mutex<SM>(); + + std::cout << "test_try_sharable_mutex<" << typeid(SM).name() << ">" << std::endl; + test_try_sharable_mutex<SM>(); + + std::cout << "test_timed_sharable_mutex<" << typeid(SM).name() << ">" << std::endl; + test_timed_sharable_mutex<SM>(); +} + + +}}} //namespace boost { namespace interprocess { namespace test { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER diff --git a/src/boost/libs/interprocess/test/shared_memory_mapping_test.cpp b/src/boost/libs/interprocess/test/shared_memory_mapping_test.cpp new file mode 100644 index 00000000..a3b0f105 --- /dev/null +++ b/src/boost/libs/interprocess/test/shared_memory_mapping_test.cpp @@ -0,0 +1,239 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <fstream> +#include <iostream> +#include <boost/interprocess/shared_memory_object.hpp> +#include <boost/interprocess/mapped_region.hpp> +#include <boost/interprocess/anonymous_shared_memory.hpp> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +shared_memory_object get_shared_memory_mapping() +{ + shared_memory_object sh; + return shared_memory_object(boost::move(sh)); +} + +int main () +{ + std::string process_id = test::get_process_id_name(); + std::string process_id2(process_id); + process_id2 += "_2"; + try{ + const std::size_t FileSize = 99999*4; + { + //Remove shared memory + shared_memory_object::remove(process_id.c_str()); + shared_memory_object::remove(process_id2.c_str()); + + //Create shared memory and file mapping + shared_memory_object mapping(create_only, process_id.c_str(), read_write); + mapping.truncate(FileSize); + } + + { + //Create a file mapping + shared_memory_object mapping(open_only, process_id.c_str(), read_write); + + //Create two mapped regions, one half of the file each + mapped_region region (mapping + ,read_write + ,0 + ,FileSize/2 + ,0); + + mapped_region region2(mapping + ,read_write + ,FileSize/2 + ,FileSize - FileSize/2 + ,0); + + //Fill two regions with a pattern + unsigned char *filler = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + *filler++ = static_cast<unsigned char>(i); + } + + filler = static_cast<unsigned char*>(region2.get_address()); + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + *filler++ = static_cast<unsigned char>(i); + } + if(!region.flush(0, 0, false)){ + return 1; + } + + if(!region2.flush(0, 0, true)){ + return 1; + } + } + + //See if the pattern is correct in the file using two mapped regions + { + //Create a file mapping + shared_memory_object mapping(open_only, process_id.c_str(), read_write); + mapped_region region(mapping, read_write, 0, FileSize/2, 0); + mapped_region region2(mapping, read_write, FileSize/2, FileSize - FileSize/2, 0); + + unsigned char *checker = static_cast<unsigned char*>(region.get_address()); + //Check pattern + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + if(*checker++ != static_cast<unsigned char>(i)){ + return 1; + } + } + + //Check second half + checker = static_cast<unsigned char *>(region2.get_address()); + + //Check pattern + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + if(*checker++ != static_cast<unsigned char>(i)){ + return 1; + } + } + } + + //Now check the pattern mapping a single read only mapped_region + { + //Create a file mapping + shared_memory_object mapping(open_only, process_id.c_str(), read_only); + + //Create a single regions, mapping all the file + mapped_region region (mapping, read_only); + + //Check pattern + unsigned char *pattern = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + if(*pattern != static_cast<unsigned char>(i)){ + return 1; + } + } + //Now shrink + const std::size_t original_region_size = region.get_size(); + if(!region.shrink_by(region.get_size()/2, false) || region.get_size() != original_region_size/2){ + return 1; + } + const std::size_t shrunk_region_size = region.get_size(); + if(!region.shrink_by(region.get_size()/2, true) || region.get_size() != shrunk_region_size/2){ + return 1; + } + + //Now advise + #if defined(POSIX_MADV_NORMAL) || defined(MADV_NORMAL) + std::cout << "Advice normal" << std::endl; + if(!region.advise(mapped_region::advice_normal)){ + return 1; + } + #endif + + #if defined(POSIX_MADV_SEQUENTIAL) || defined(MADV_SEQUENTIAL) + std::cout << "Advice sequential" << std::endl; + if(!region.advise(mapped_region::advice_sequential)){ + return 1; + } + #endif + + #if defined(POSIX_MADV_RANDOM) || defined(MADV_RANDOM) + std::cout << "Advice random" << std::endl; + if(!region.advise(mapped_region::advice_random)){ + return 1; + } + #endif + + #if defined(POSIX_MADV_WILLNEED) || defined(MADV_WILLNEED) + std::cout << "Advice 'will need'" << std::endl; + if(!region.advise(mapped_region::advice_willneed)){ + return 1; + } + #endif + + #if defined(POSIX_MADV_DONTNEED) || (defined(MADV_DONTNEED) && defined(BOOST_INTERPROCESS_MADV_DONTNEED_HAS_NONDESTRUCTIVE_SEMANTICS)) + std::cout << "Advice 'dont't need'" << std::endl; + if(!region.advise(mapped_region::advice_dontneed)){ + return 1; + } + #endif + + } + { + //Check for busy address space + shared_memory_object mapping(open_only, process_id.c_str(), read_only); + mapped_region region (mapping, read_only); + shared_memory_object mapping2(create_only, process_id2.c_str(), read_write); + mapping2.truncate(FileSize); + try{ + mapped_region region2 (mapping2, read_only, 0, FileSize, region.get_address()); + } + catch(interprocess_exception &e){ + shared_memory_object::remove(process_id2.c_str()); + if(e.get_error_code() != busy_error){ + throw e; + } + } + catch(std::exception &){ + shared_memory_object::remove(process_id2.c_str()); + throw; + } + shared_memory_object::remove(process_id2.c_str()); + } + { + //Now check anonymous mapping + mapped_region region(anonymous_shared_memory(FileSize)); + + //Write pattern + unsigned char *pattern = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + *pattern = static_cast<unsigned char>(i); + } + + //Check pattern + pattern = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + if(*pattern != static_cast<unsigned char>(i)){ + return 1; + } + } + } + { + //Now test move semantics + shared_memory_object mapping(open_only, process_id.c_str(), read_write); + shared_memory_object move_ctor(boost::move(mapping)); + shared_memory_object move_assign; + move_assign = boost::move(move_ctor); + shared_memory_object ret(get_shared_memory_mapping()); + } + } + catch(std::exception &exc){ + shared_memory_object::remove(process_id.c_str()); + shared_memory_object::remove(process_id2.c_str()); + std::cout << "Unhandled exception: " << exc.what() << std::endl; + return 1; + } + shared_memory_object::remove(process_id.c_str()); + return 0; +} diff --git a/src/boost/libs/interprocess/test/shared_memory_test.cpp b/src/boost/libs/interprocess/test/shared_memory_test.cpp new file mode 100644 index 00000000..0723e386 --- /dev/null +++ b/src/boost/libs/interprocess/test/shared_memory_test.cpp @@ -0,0 +1,87 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/shared_memory_object.hpp> +#include <boost/interprocess/detail/managed_open_or_create_impl.hpp> +#include <boost/interprocess/exceptions.hpp> +#include "named_creation_template.hpp" +#include <cstring> //for strcmp, memset +#include <iostream> //for cout +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +static const std::size_t ShmSize = 1000; +static const char * ShmName = test::get_process_id_name(); + +struct eraser +{ + ~eraser() + { + shared_memory_object::remove(ShmName); + } +}; + +typedef ipcdetail::managed_open_or_create_impl<shared_memory_object, 0, true, false> shared_memory; + +//This wrapper is necessary to have a common constructor +//in generic named_creation_template functions +class shared_memory_creation_test_wrapper + : public eraser + , public shared_memory +{ + + public: + shared_memory_creation_test_wrapper(create_only_t) + : shared_memory(create_only, ShmName, ShmSize, read_write, 0, permissions()) + {} + + shared_memory_creation_test_wrapper(open_only_t) + : shared_memory(open_only, ShmName, read_write, 0) + {} + + shared_memory_creation_test_wrapper(open_or_create_t) + : shared_memory(open_or_create, ShmName, ShmSize, read_write, 0, permissions()) + {} +}; + + +int main () +{ + try{ + shared_memory_object::remove(ShmName); + test::test_named_creation<shared_memory_creation_test_wrapper>(); + + //Create and get name, size and address + { + shared_memory_object::remove(ShmName); + shared_memory shm1(create_only, ShmName, ShmSize, read_write, 0, permissions()); + + //Overwrite all memory + std::memset(shm1.get_user_address(), 0, shm1.get_user_size()); + + //Now test move semantics + shared_memory move_ctor(boost::move(shm1)); + shared_memory move_assign; + move_assign = boost::move(move_ctor); + } + } + catch(std::exception &ex){ + shared_memory_object::remove(ShmName); + std::cout << ex.what() << std::endl; + return 1; + } + shared_memory_object::remove(ShmName); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/shared_ptr_test.cpp b/src/boost/libs/interprocess/test/shared_ptr_test.cpp new file mode 100644 index 00000000..17858459 --- /dev/null +++ b/src/boost/libs/interprocess/test/shared_ptr_test.cpp @@ -0,0 +1,615 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Peter Dimov 2002-2005, 2007. +// (C) Copyright Ion Gaztanaga 2006-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/offset_ptr.hpp> +#include <boost/interprocess/smart_ptr/shared_ptr.hpp> +#include <boost/interprocess/smart_ptr/weak_ptr.hpp> +#include <boost/interprocess/smart_ptr/enable_shared_from_this.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/containers/string.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/smart_ptr/deleter.hpp> +#include <boost/interprocess/smart_ptr/scoped_ptr.hpp> +#include <boost/core/lightweight_test.hpp> +#include <string> +#include "get_process_id_name.hpp" + + +#include <boost/interprocess/sync/upgradable_lock.hpp> +#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp> + +using namespace boost::interprocess; + +class base_class +{ + public: + virtual ~base_class() + {} +}; + +class derived_class + : public base_class +{ + public: + virtual ~derived_class() + {} +}; + +int simple_test() +{ + typedef managed_shared_memory::segment_manager segment_mngr_t; + typedef allocator<base_class, segment_mngr_t> base_class_allocator; + typedef deleter<base_class, segment_mngr_t> base_deleter_t; + typedef shared_ptr<base_class, base_class_allocator, base_deleter_t> base_shared_ptr; + + std::string process_name; + test::get_process_id_name(process_name); + + shared_memory_object::remove(process_name.c_str()); + { + managed_shared_memory shmem(create_only, process_name.c_str(), 10000); + + { + base_shared_ptr s_ptr(base_shared_ptr::pointer(0), + base_class_allocator(shmem.get_segment_manager()), + base_deleter_t(shmem.get_segment_manager())); + + base_shared_ptr s_ptr2(shmem.construct<base_class>("base_class")(), + base_class_allocator(shmem.get_segment_manager()), + base_deleter_t(shmem.get_segment_manager())); + + base_shared_ptr s_ptr3(offset_ptr<derived_class>(shmem.construct<derived_class>("derived_class")()), + base_class_allocator(shmem.get_segment_manager()), + base_deleter_t(shmem.get_segment_manager())); + + if(s_ptr3.get_deleter() == 0){ + return 1; + } + //if(s_ptr3.get_allocator() == 0){ + //return 1; + //} + + base_shared_ptr s_ptr_empty; + + if(s_ptr_empty.get_deleter() != 0){ + return 1; + } + //if(s_ptr_empty.get_allocator() != 0){ + //return 1; + //} + } + } + shared_memory_object::remove(process_name.c_str()); + return 0; +} + +int string_shared_ptr_vector_insertion_test() +{ + typedef managed_shared_memory::segment_manager segment_mngr_t; + + //Allocator of chars + typedef allocator<char, segment_mngr_t> char_allocator_t; + + //A shared memory string class + typedef basic_string<char, std::char_traits<char>, char_allocator_t> string_t; + + //A shared memory string allocator + typedef allocator<string_t, segment_mngr_t> string_allocator_t; + + //A deleter for shared_ptr<> that erases a shared memory string + typedef deleter<string_t, segment_mngr_t> string_deleter_t; + + //A shared pointer that points to a shared memory string and its instantiation + typedef shared_ptr<string_t, string_allocator_t, string_deleter_t> string_shared_ptr_t; + + //An allocator for shared pointers to a string in shared memory + typedef allocator<string_shared_ptr_t, segment_mngr_t> string_shared_ptr_allocator_t; + + //A weak pointer that points to a shared memory string and its instantiation + typedef weak_ptr<string_t, string_allocator_t, string_deleter_t> string_weak_ptr_t; + + //An allocator for weak pointers to a string in shared memory + typedef allocator<string_weak_ptr_t, segment_mngr_t > string_weak_ptr_allocator_t; + + //A vector of shared pointers to strings (all in shared memory) and its instantiation + typedef vector<string_shared_ptr_t, string_shared_ptr_allocator_t> + string_shared_ptr_vector_t; + + //A vector of weak pointers to strings (all in shared memory) and its instantiation + typedef vector<string_weak_ptr_t, string_weak_ptr_allocator_t> + string_weak_ptr_vector_t; + + std::string process_name; + test::get_process_id_name(process_name); + + //A shared memory managed memory classes + shared_memory_object::remove(process_name.c_str()); + { + managed_shared_memory shmem(create_only, process_name.c_str(), 20000); + + { + const int NumElements = 100; + //Construct the allocator of strings + string_allocator_t string_allocator(shmem.get_segment_manager()); + //Construct the allocator of a shared_ptr to string + string_shared_ptr_allocator_t string_shared_ptr_allocator(shmem.get_segment_manager()); + //Construct the allocator of a shared_ptr to string + string_weak_ptr_allocator_t string_weak_ptr_allocator(shmem.get_segment_manager()); + //This is a string deleter using destroy_ptr() function of the managed_shared_memory + string_deleter_t deleter(shmem.get_segment_manager()); + //Create a string in shared memory, to avoid leaks with exceptions use + //scoped ptr until we store this pointer in the shared ptr + scoped_ptr<string_t, string_deleter_t> scoped_string + (shmem.construct<string_t>(anonymous_instance)(string_allocator), deleter); + //Now construct a shared pointer to a string + string_shared_ptr_t string_shared_ptr (scoped_string.get(), + string_shared_ptr_allocator, + deleter); + //Check use count is just one + if(!string_shared_ptr.unique()){ + return 1; + } + //We don't need the scoped_ptr anonymous since the raw pointer is in the shared ptr + scoped_string.release(); + //Now fill a shared memory vector of shared_ptrs to a string + string_shared_ptr_vector_t my_sharedptr_vector(string_shared_ptr_allocator); + my_sharedptr_vector.insert(my_sharedptr_vector.begin(), NumElements, string_shared_ptr); + //Insert in the middle to test movability + my_sharedptr_vector.insert(my_sharedptr_vector.begin() + my_sharedptr_vector.size()/2, NumElements, string_shared_ptr); + //Now check the shared count is the objects contained in the + //vector plus string_shared_ptr + if(string_shared_ptr.use_count() != static_cast<long>(my_sharedptr_vector.size()+1)){ + return 1; + } + //Now create a weak ptr from the shared_ptr + string_weak_ptr_t string_weak_ptr (string_shared_ptr); + //Use count should remain the same + if(string_weak_ptr.use_count() != static_cast<long>(my_sharedptr_vector.size()+1)){ + return 1; + } + //Now reset the local shared_ptr and check use count + string_shared_ptr.reset(); + if(string_weak_ptr.use_count() != static_cast<long>(my_sharedptr_vector.size())){ + return 1; + } + //Now reset the local shared_ptr's use count should be zero + if(string_shared_ptr.use_count() != 0){ + return 1; + } + //Now recreate the shared ptr from the weak ptr + //and recheck use count + string_shared_ptr = string_shared_ptr_t(string_weak_ptr); + if(string_shared_ptr.use_count() != static_cast<long>(my_sharedptr_vector.size()+1)){ + return 1; + } + //Now fill a vector of weak_ptr-s + string_weak_ptr_vector_t my_weakptr_vector(string_weak_ptr_allocator); + my_weakptr_vector.insert(my_weakptr_vector.begin(), NumElements, string_weak_ptr); + //The shared count should remain the same + if(string_shared_ptr.use_count() != static_cast<long>(my_sharedptr_vector.size()+1)){ + return 1; + } + //So weak pointers should be fine + string_weak_ptr_vector_t::iterator beg = my_weakptr_vector.begin(), + end = my_weakptr_vector.end(); + for(;beg != end; ++beg){ + if(beg->expired()){ + return 1; + } + //The shared pointer constructed from weak ptr should + //be the same as the original, since all weak pointer + //point the the same object + if(string_shared_ptr_t(*beg) != string_shared_ptr){ + return 1; + } + } + //Now destroy all the shared ptr-s of the shared ptr vector + my_sharedptr_vector.clear(); + //The only alive shared ptr should be the local one + if(string_shared_ptr.use_count() != 1){ + return 1; + } + //Now we invalidate the last alive shared_ptr + string_shared_ptr.reset(); + //Now all weak pointers should have expired + beg = my_weakptr_vector.begin(); + end = my_weakptr_vector.end(); + for(;beg != end; ++beg){ + if(!beg->expired()){ + return 1; + } + bool success = false; + //Now this should throw + try{ + string_shared_ptr_t dummy(*beg); + //We should never reach here + return 1; + } + catch(const boost::interprocess::bad_weak_ptr &){ + success = true; + } + if(!success){ + return 1; + } + } + //Clear weak ptr vector + my_weakptr_vector.clear(); + //Now lock returned shared ptr should return null + if(string_weak_ptr.lock().get()){ + return 1; + } + //Reset weak_ptr + string_weak_ptr.reset(); + } + } + shared_memory_object::remove(process_name.c_str()); + return 0; +} + +// +// This part is taken from shared_ptr_basic_test.cpp +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2006 Ion Gaztanaga +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +static int cnt = 0; + +struct X +{ + X(){ ++cnt; } + // virtual destructor deliberately omitted + virtual ~X(){ --cnt; } + + virtual int id() const + { return 1; } + + private: + X(X const &); + X & operator= (X const &); +}; + +struct Y: public X +{ + Y(){ ++cnt; } + virtual ~Y(){ --cnt; } + + virtual int id() const + { return 2; } + + private: + Y(Y const &); + Y & operator= (Y const &); +}; + +int * get_object() +{ ++cnt; return &cnt; } + +void release_object(int * p) +{ BOOST_TEST(p == &cnt); --cnt; } + +template<class T, class A, class D> +void test_is_X(shared_ptr<T, A, D> const & p) +{ + BOOST_TEST(p->id() == 1); + BOOST_TEST((*p).id() == 1); +} + +template<class T, class A, class D> +void test_is_X(weak_ptr<T, A, D> const & p) +{ + BOOST_TEST(p.get() != 0); + BOOST_TEST(p.get()->id() == 1); +} + +template<class T, class A, class D> +void test_is_Y(shared_ptr<T, A, D> const & p) +{ + BOOST_TEST(p->id() == 2); + BOOST_TEST((*p).id() == 2); +} + +template<class T, class A, class D> +void test_is_Y(weak_ptr<T, A, D> const & p) +{ + shared_ptr<T, A, D> q = p.lock(); + BOOST_TEST(q.get() != 0); + BOOST_TEST(q->id() == 2); +} + +template<class T, class T2> +void test_eq(T const & a, T2 const & b) +{ + BOOST_TEST(a == b); + BOOST_TEST(!(a != b)); + BOOST_TEST(!(a < b)); + BOOST_TEST(!(b < a)); +} + +template<class T, class T2> +void test_ne(T const & a, T2 const & b) +{ + BOOST_TEST(!(a == b)); + BOOST_TEST(a != b); + BOOST_TEST(a < b || b < a); + BOOST_TEST(!(a < b && b < a)); +} + +template<class T, class U, class A, class D, class D2> +void test_shared(weak_ptr<T, A, D> const & a, weak_ptr<U, A, D2> const & b) +{ + BOOST_TEST(!(a < b)); + BOOST_TEST(!(b < a)); +} + +template<class T, class U, class A, class D, class D2> +void test_nonshared(weak_ptr<T, A, D> const & a, weak_ptr<U, A, D2> const & b) +{ + BOOST_TEST(a < b || b < a); + BOOST_TEST(!(a < b && b < a)); +} + +template<class T, class U> +void test_eq2(T const & a, U const & b) +{ + BOOST_TEST(a == b); + BOOST_TEST(!(a != b)); +} + +template<class T, class U> +void test_ne2(T const & a, U const & b) +{ + BOOST_TEST(!(a == b)); + BOOST_TEST(a != b); +} + +template<class T, class A, class D> +void test_is_zero(shared_ptr<T, A, D> const & p) +{ + BOOST_TEST(!p); + BOOST_TEST(p.get() == 0); +} + +template<class T, class A, class D> +void test_is_nonzero(shared_ptr<T, A, D> const & p) +{ + // p? true: false is used to test p in a boolean context. + // BOOST_TEST(p) is not guaranteed to test the conversion, + // as the macro might test !!p instead. + BOOST_TEST(p? true: false); + BOOST_TEST(p.get() != 0); +} + +int basic_shared_ptr_test() +{ + typedef managed_shared_memory::segment_manager segment_mngr_t; + typedef allocator<void, segment_mngr_t> v_allocator_t; + typedef deleter<X, segment_mngr_t> x_deleter_t; + typedef deleter<Y, segment_mngr_t> y_deleter_t; + typedef shared_ptr<X, v_allocator_t, x_deleter_t> x_shared_ptr; + typedef shared_ptr<Y, v_allocator_t, y_deleter_t> y_shared_ptr; + typedef weak_ptr<X, v_allocator_t, x_deleter_t> x_weak_ptr; + typedef weak_ptr<Y, v_allocator_t, y_deleter_t> y_weak_ptr; + + std::string process_name; + test::get_process_id_name(process_name); + + shared_memory_object::remove(process_name.c_str()); + { + managed_shared_memory shmem(create_only, process_name.c_str(), 10000); + { + v_allocator_t v_allocator (shmem.get_segment_manager()); + x_deleter_t x_deleter (shmem.get_segment_manager()); + y_deleter_t y_deleter (shmem.get_segment_manager()); + + y_shared_ptr p (shmem.construct<Y>(anonymous_instance)(), v_allocator, y_deleter); + x_shared_ptr p2(shmem.construct<X>(anonymous_instance)(), v_allocator, x_deleter); + + test_is_nonzero(p); + test_is_nonzero(p2); + test_is_Y(p); + test_is_X(p2); + test_ne(p, p2); + + { + shared_ptr<X, v_allocator_t, y_deleter_t> q(p); + test_eq(p, q); + } + + y_shared_ptr p3 (dynamic_pointer_cast<Y>(p)); + shared_ptr<Y, v_allocator_t, x_deleter_t> p4 (dynamic_pointer_cast<Y>(p2)); + test_is_nonzero(p3); + test_is_zero(p4); + BOOST_TEST(p.use_count() == 2); + BOOST_TEST(p2.use_count() == 1); + BOOST_TEST(p3.use_count() == 2); + test_is_Y(p3); + test_eq2(p, p3); + test_ne2(p2, p4); + + shared_ptr<void, v_allocator_t, y_deleter_t> p5(p); + + test_is_nonzero(p5); + test_eq2(p, p5); + BOOST_TEST(p5.use_count() == 3); + + x_weak_ptr wp1(p2); + + BOOST_TEST(!wp1.expired()); + BOOST_TEST(wp1.use_count() != 0); + + p.reset(); + p2.reset(); + p3.reset(); + p4.reset(); + + test_is_zero(p); + test_is_zero(p2); + test_is_zero(p3); + test_is_zero(p4); + + BOOST_TEST(p5.use_count() == 1); + BOOST_TEST(wp1.expired()); + BOOST_TEST(wp1.use_count() == 0); + + try{ + x_shared_ptr sp1(wp1); + BOOST_ERROR("shared_ptr<X, A, D> sp1(wp1) failed to throw"); + } + catch(boost::interprocess::bad_weak_ptr const &) + {} + + test_is_zero(wp1.lock()); + + weak_ptr<X, v_allocator_t, y_deleter_t> wp2 = static_pointer_cast<X>(p5); + + BOOST_TEST(wp2.use_count() == 1); + test_is_Y(wp2); + test_nonshared(wp1, wp2); + + // Scoped to not affect the subsequent use_count() tests. + { + shared_ptr<X, v_allocator_t, y_deleter_t> sp2(wp2); + test_is_nonzero(wp2.lock()); + } + + y_weak_ptr wp3 = dynamic_pointer_cast<Y>(wp2.lock()); + + BOOST_TEST(wp3.use_count() == 1); + test_shared(wp2, wp3); + + weak_ptr<X, v_allocator_t, y_deleter_t> wp4(wp3); + + BOOST_TEST(wp4.use_count() == 1); + test_shared(wp2, wp4); + + wp1 = p2; + test_is_zero(wp1.lock()); + + wp1 = p4; + + x_weak_ptr wp5; + + bool b1 = wp1 < wp5; + bool b2 = wp5 < wp1; + + y_shared_ptr p6 = static_pointer_cast<Y>(p5); + p5.reset(); + p6.reset(); + + BOOST_TEST(wp1.use_count() == 0); + BOOST_TEST(wp2.use_count() == 0); + BOOST_TEST(wp3.use_count() == 0); + + // Test operator< stability for std::set< weak_ptr<> > + // Thanks to Joe Gottman for pointing this out + BOOST_TEST(b1 == (wp1 < wp5)); + BOOST_TEST(b2 == (wp5 < wp1)); + } + + BOOST_TEST(cnt == 0); + } + shared_memory_object::remove(process_name.c_str()); + return boost::report_errors(); +} + +struct alias_tester +{ + int v_; + + explicit alias_tester( int v ): v_( v ) + { + } + + ~alias_tester() + { + v_ = 0; + } +}; + +void test_alias() +{ + typedef managed_shared_memory::segment_manager segment_mngr_t; + typedef allocator<void, segment_mngr_t> v_allocator_t; + typedef deleter<int, segment_mngr_t> int_deleter_t; + + typedef shared_ptr<int, v_allocator_t, int_deleter_t> int_shared_ptr; + typedef shared_ptr<const int, v_allocator_t, int_deleter_t> const_int_shared_ptr; + + std::string process_name; + test::get_process_id_name(process_name); + + shared_memory_object::remove(process_name.c_str()); + { + managed_shared_memory shmem(create_only, process_name.c_str(), 10000); + + { + int m = 0; + int_shared_ptr p; + int_shared_ptr p2( p, &m ); + + BOOST_TEST( ipcdetail::to_raw_pointer(p2.get()) == &m ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + + p2.reset( p, static_cast<int*>(0) ); + + BOOST_TEST( p2.get() == 0 ); + + BOOST_TEST( p2? false: true ); + BOOST_TEST( !p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + } + + { + int m = 0; + int_shared_ptr p(make_managed_shared_ptr + (shmem.construct<int>(anonymous_instance)(), shmem)); + const_int_shared_ptr p2( p, &m ); + + BOOST_TEST( ipcdetail::to_raw_pointer(p2.get()) == &m ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + int_shared_ptr p_nothrow(make_managed_shared_ptr + (shmem.construct<int>(anonymous_instance)(), shmem, std::nothrow)); + } + } + shared_memory_object::remove(process_name.c_str()); +} + +int main() +{ + if(0 != simple_test()) + return 1; + + if(0 != string_shared_ptr_vector_insertion_test()) + return 1; + + if(0 != basic_shared_ptr_test()) + return 1; + + test_alias(); +} + +#include <boost/interprocess/detail/config_end.hpp> + diff --git a/src/boost/libs/interprocess/test/slist_test.cpp b/src/boost/libs/interprocess/test/slist_test.cpp new file mode 100644 index 00000000..2f207489 --- /dev/null +++ b/src/boost/libs/interprocess/test/slist_test.cpp @@ -0,0 +1,63 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/slist.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/offset_ptr.hpp> +#include "dummy_test_allocator.hpp" +#include "list_test.hpp" +#include "movable_int.hpp" +#include "emplace_test.hpp" + +using namespace boost::interprocess; + +typedef allocator<int, managed_shared_memory::segment_manager> ShmemAllocator; +typedef slist<int, ShmemAllocator> MyList; + +//typedef allocator<volatile int, managed_shared_memory::segment_manager> ShmemVolatileAllocator; +//typedef slist<volatile int, ShmemVolatileAllocator> MyVolatileList; + +typedef allocator<test::movable_int, managed_shared_memory::segment_manager> ShmemMoveAllocator; +typedef slist<test::movable_int, ShmemMoveAllocator> MyMoveList; + +typedef allocator<test::movable_and_copyable_int, managed_shared_memory::segment_manager> ShmemCopyMoveAllocator; +typedef slist<test::movable_and_copyable_int, ShmemCopyMoveAllocator> MyCopyMoveList; + +typedef allocator<test::copyable_int, managed_shared_memory::segment_manager> ShmemCopyAllocator; +typedef slist<test::copyable_int, ShmemCopyAllocator> MyCopyList; + +int main () +{ + if(test::list_test<managed_shared_memory, MyList, false>()) + return 1; + + if(test::list_test<managed_shared_memory, MyMoveList, false>()) + return 1; + + if(test::list_test<managed_shared_memory, MyCopyMoveList, false>()) + return 1; + +// if(test::list_test<managed_shared_memory, MyVolatileList, false>()) +// return 1; + + if(test::list_test<managed_shared_memory, MyCopyList, false>()) + return 1; + + const test::EmplaceOptions Options = (test::EmplaceOptions) + (test::EMPLACE_FRONT | test::EMPLACE_AFTER | test::EMPLACE_BEFORE | test::EMPLACE_AFTER); + + if(!boost::interprocess::test::test_emplace + < slist<test::EmplaceInt>, Options>()) + return 1; +} + +#include <boost/interprocess/detail/config_end.hpp> + diff --git a/src/boost/libs/interprocess/test/stable_vector_test.cpp b/src/boost/libs/interprocess/test/stable_vector_test.cpp new file mode 100644 index 00000000..b341bc0a --- /dev/null +++ b/src/boost/libs/interprocess/test/stable_vector_test.cpp @@ -0,0 +1,72 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/stable_vector.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include "allocator_v1.hpp" +#include "heap_allocator_v1.hpp" +#include "check_equal_containers.hpp" +#include "movable_int.hpp" +#include "expand_bwd_test_allocator.hpp" +#include "expand_bwd_test_template.hpp" +#include "dummy_test_allocator.hpp" +#include "vector_test.hpp" + +using namespace boost::interprocess; + +int main() +{ + typedef allocator<int, managed_shared_memory::segment_manager> ShmemAllocator; + typedef stable_vector<int, ShmemAllocator> MyVector; + + typedef test::allocator_v1<int, managed_shared_memory::segment_manager> ShmemV1Allocator; + typedef stable_vector<int, ShmemV1Allocator> MyV1Vector; + + typedef test::heap_allocator_v1<int, managed_shared_memory::segment_manager> ShmemHeapV1Allocator; + typedef stable_vector<int, ShmemHeapV1Allocator> MyHeapV1Vector; + + typedef allocator<test::movable_int, managed_shared_memory::segment_manager> ShmemMoveAllocator; + typedef stable_vector<test::movable_int, ShmemMoveAllocator> MyMoveVector; + + typedef allocator<test::movable_and_copyable_int, managed_shared_memory::segment_manager> ShmemCopyMoveAllocator; + typedef stable_vector<test::movable_and_copyable_int, ShmemCopyMoveAllocator> MyCopyMoveVector; + + typedef allocator<test::copyable_int, managed_shared_memory::segment_manager> ShmemCopyAllocator; + typedef stable_vector<test::copyable_int, ShmemCopyAllocator> MyCopyVector; + + if(test::vector_test<managed_shared_memory, MyVector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyV1Vector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyHeapV1Vector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyMoveVector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyCopyMoveVector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyCopyVector>()) + return 1; + + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE); + if(!boost::interprocess::test::test_emplace + < stable_vector<test::EmplaceInt>, Options>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/string_test.cpp b/src/boost/libs/interprocess/test/string_test.cpp new file mode 100644 index 00000000..15399be8 --- /dev/null +++ b/src/boost/libs/interprocess/test/string_test.cpp @@ -0,0 +1,289 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/containers/string.hpp> +#include <boost/interprocess/offset_ptr.hpp> +#include <string> +#include <algorithm> +#include <cstring> +#include <cstdio> +#include <cstddef> +#include "dummy_test_allocator.hpp" +#include "check_equal_containers.hpp" +#include "expand_bwd_test_allocator.hpp" +#include "expand_bwd_test_template.hpp" +#include "allocator_v1.hpp" +#include "get_process_id_name.hpp" +#include <new> //std::nothrow + +using namespace boost::interprocess; + +typedef test::dummy_test_allocator<char> DummyCharAllocator; +typedef basic_string<char, std::char_traits<char>, DummyCharAllocator> DummyString; +typedef test::dummy_test_allocator<DummyString> DummyStringAllocator; +typedef test::dummy_test_allocator<wchar_t> DummyWCharAllocator; +typedef basic_string<wchar_t, std::char_traits<wchar_t>, DummyWCharAllocator> DummyWString; +typedef test::dummy_test_allocator<DummyWString> DummyWStringAllocator; + +struct StringEqual +{ + template<class Str1, class Str2> + bool operator ()(const Str1 &string1, const Str2 &string2) const + { + if(string1.size() != string2.size()) + return false; + return std::char_traits<typename Str1::value_type>::compare + (string1.c_str(), string2.c_str(), (std::size_t)string1.size()) == 0; + } +}; + +//Function to check if both lists are equal +template<class StrVector1, class StrVector2> +bool CheckEqualStringVector(StrVector1 *strvect1, StrVector2 *strvect2) +{ + StringEqual comp; + return std::equal(strvect1->begin(), strvect1->end(), + strvect2->begin(), comp); +} + +template<class CharType, template<class T, class SegmentManager> class AllocatorType > +int string_test() +{ + typedef std::allocator<CharType> StdAllocatorChar; + typedef std::basic_string<CharType, std::char_traits<CharType>, StdAllocatorChar> StdString; + typedef std::allocator<StdString> StdStringAllocator; + typedef vector<StdString, StdStringAllocator> StdStringVector; + typedef AllocatorType<CharType, managed_shared_memory::segment_manager> ShmemAllocatorChar; + typedef basic_string<CharType, std::char_traits<CharType>, ShmemAllocatorChar> ShmString; + typedef AllocatorType<ShmString, managed_shared_memory::segment_manager> ShmemStringAllocator; + typedef vector<ShmString, ShmemStringAllocator> ShmStringVector; + + const int MaxSize = 100; + + std::string process_name; + test::get_process_id_name(process_name); + + //Create shared memory + shared_memory_object::remove(process_name.c_str()); + { + managed_shared_memory segment + (create_only, + process_name.c_str(),//segment name + 65536); //segment size in bytes + + ShmemAllocatorChar shmallocator (segment.get_segment_manager()); + + //Initialize vector with a range or iterators and allocator + ShmStringVector *shmStringVect = + segment.construct<ShmStringVector> + (anonymous_instance, std::nothrow) //object name + (shmallocator); + + StdStringVector *stdStringVect = new StdStringVector; + + ShmString auxShmString (segment.get_segment_manager()); + StdString auxStdString(StdString(auxShmString.begin(), auxShmString.end() )); + + CharType buffer [20]; + + //First, push back + for(int i = 0; i < MaxSize; ++i){ + auxShmString = "String"; + auxStdString = "String"; + std::sprintf(buffer, "%i", i); + auxShmString += buffer; + auxStdString += buffer; + shmStringVect->push_back(auxShmString); + stdStringVect->push_back(auxStdString); + } + + if(!CheckEqualStringVector(shmStringVect, stdStringVect)){ + return 1; + } + + //Now push back moving + for(int i = 0; i < MaxSize; ++i){ + auxShmString = "String"; + auxStdString = "String"; + std::sprintf(buffer, "%i", i); + auxShmString += buffer; + auxStdString += buffer; + shmStringVect->push_back(boost::move(auxShmString)); + stdStringVect->push_back(auxStdString); + } + + if(!CheckEqualStringVector(shmStringVect, stdStringVect)){ + return 1; + } + + //push front + for(int i = 0; i < MaxSize; ++i){ + auxShmString = "String"; + auxStdString = "String"; + std::sprintf(buffer, "%i", i); + auxShmString += buffer; + auxStdString += buffer; + shmStringVect->insert(shmStringVect->begin(), auxShmString); + stdStringVect->insert(stdStringVect->begin(), auxStdString); + } + + if(!CheckEqualStringVector(shmStringVect, stdStringVect)){ + return 1; + } + + //Now push front moving + for(int i = 0; i < MaxSize; ++i){ + auxShmString = "String"; + auxStdString = "String"; + std::sprintf(buffer, "%i", i); + auxShmString += buffer; + auxStdString += buffer; + shmStringVect->insert(shmStringVect->begin(), boost::move(auxShmString)); + stdStringVect->insert(stdStringVect->begin(), auxStdString); + } + + if(!CheckEqualStringVector(shmStringVect, stdStringVect)){ + return 1; + } + + //Now test long and short representation swapping + auxShmString = "String"; + auxStdString = "String"; + ShmString shm_swapper(segment.get_segment_manager()); + StdString std_swapper; + shm_swapper.swap(auxShmString); + std_swapper.swap(auxStdString); + if(!StringEqual()(auxShmString, auxStdString)) + return 1; + if(!StringEqual()(shm_swapper, std_swapper)) + return 1; + + shm_swapper.swap(auxShmString); + std_swapper.swap(auxStdString); + if(!StringEqual()(auxShmString, auxStdString)) + return 1; + if(!StringEqual()(shm_swapper, std_swapper)) + return 1; + + auxShmString = "LongLongLongLongLongLongLongLongLongLongLongLongLongString"; + auxStdString = "LongLongLongLongLongLongLongLongLongLongLongLongLongString"; + shm_swapper = ShmString (segment.get_segment_manager()); + std_swapper = StdString (); + shm_swapper.swap(auxShmString); + std_swapper.swap(auxStdString); + if(!StringEqual()(auxShmString, auxStdString)) + return 1; + if(!StringEqual()(shm_swapper, std_swapper)) + return 1; + + shm_swapper.swap(auxShmString); + std_swapper.swap(auxStdString); + if(!StringEqual()(auxShmString, auxStdString)) + return 1; + if(!StringEqual()(shm_swapper, std_swapper)) + return 1; + + //No sort + std::sort(shmStringVect->begin(), shmStringVect->end()); + std::sort(stdStringVect->begin(), stdStringVect->end()); + if(!CheckEqualStringVector(shmStringVect, stdStringVect)) return 1; + + const CharType prefix [] = "Prefix"; + const int prefix_size = sizeof(prefix)/sizeof(prefix[0])-1; + const CharType sufix [] = "Suffix"; + + for(int i = 0; i < MaxSize; ++i){ + (*shmStringVect)[i].append(sufix); + (*stdStringVect)[i].append(sufix); + (*shmStringVect)[i].insert((*shmStringVect)[i].begin(), + prefix, prefix + prefix_size); + (*stdStringVect)[i].insert((*stdStringVect)[i].begin(), + prefix, prefix + prefix_size); + } + + if(!CheckEqualStringVector(shmStringVect, stdStringVect)) return 1; + + for(int i = 0; i < MaxSize; ++i){ + std::reverse((*shmStringVect)[i].begin(), (*shmStringVect)[i].end()); + std::reverse((*stdStringVect)[i].begin(), (*stdStringVect)[i].end()); + } + + if(!CheckEqualStringVector(shmStringVect, stdStringVect)) return 1; + + for(int i = 0; i < MaxSize; ++i){ + std::reverse((*shmStringVect)[i].begin(), (*shmStringVect)[i].end()); + std::reverse((*stdStringVect)[i].begin(), (*stdStringVect)[i].end()); + } + + if(!CheckEqualStringVector(shmStringVect, stdStringVect)) return 1; + + for(int i = 0; i < MaxSize; ++i){ + std::sort(shmStringVect->begin(), shmStringVect->end()); + std::sort(stdStringVect->begin(), stdStringVect->end()); + } + + if(!CheckEqualStringVector(shmStringVect, stdStringVect)) return 1; + + for(int i = 0; i < MaxSize; ++i){ + (*shmStringVect)[i].replace((*shmStringVect)[i].begin(), + (*shmStringVect)[i].end(), + "String"); + (*stdStringVect)[i].replace((*stdStringVect)[i].begin(), + (*stdStringVect)[i].end(), + "String"); + } + + if(!CheckEqualStringVector(shmStringVect, stdStringVect)) return 1; + + shmStringVect->erase(std::unique(shmStringVect->begin(), shmStringVect->end()), + shmStringVect->end()); + stdStringVect->erase(std::unique(stdStringVect->begin(), stdStringVect->end()), + stdStringVect->end()); + if(!CheckEqualStringVector(shmStringVect, stdStringVect)) return 1; + + //When done, delete vector + segment.destroy_ptr(shmStringVect); + delete stdStringVect; + } + shared_memory_object::remove(process_name.c_str()); + return 0; +} + +bool test_expand_bwd() +{ + //Now test all back insertion possibilities + typedef test::expand_bwd_test_allocator<char> + allocator_type; + typedef basic_string<char, std::char_traits<char>, allocator_type> + string_type; + return test::test_all_expand_bwd<string_type>(); +} + +int main() +{ + if(string_test<char, allocator>()){ + return 1; + } + + if(string_test<char, test::allocator_v1>()){ + return 1; + } + + if(!test_expand_bwd()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/tree_test.cpp b/src/boost/libs/interprocess/test/tree_test.cpp new file mode 100644 index 00000000..46190526 --- /dev/null +++ b/src/boost/libs/interprocess/test/tree_test.cpp @@ -0,0 +1,199 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include <boost/interprocess/detail/config_begin.hpp> +#include <set> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/set.hpp> +#include <boost/interprocess/containers/map.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/indexes/map_index.hpp> +#include <boost/interprocess/indexes/iset_index.hpp> +#include <boost/interprocess/mem_algo/simple_seq_fit.hpp> +#include "print_container.hpp" +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" +#include "set_test.hpp" +#include "map_test.hpp" +#include "emplace_test.hpp" + +/////////////////////////////////////////////////////////////////// +// // +// This example repeats the same operations with std::set and // +// shmem_set using the node allocator // +// and compares the values of both containers // +// // +/////////////////////////////////////////////////////////////////// + +using namespace boost::interprocess; + +//Customize managed_shared_memory class +typedef basic_managed_shared_memory + <char, + simple_seq_fit<mutex_family, offset_ptr<void> >, + map_index + > my_managed_shared_memory; + +//We will work with narrow characters for shared memory objects +//Alias an integer node allocator type +typedef allocator<int, my_managed_shared_memory::segment_manager> + shmem_allocator_t; +typedef allocator<std::pair<const int, int>, my_managed_shared_memory::segment_manager> + shmem_node_pair_allocator_t; +typedef allocator<test::movable_int, my_managed_shared_memory::segment_manager> + shmem_movable_allocator_t; +typedef allocator<std::pair<const test::movable_int, test::movable_int>, my_managed_shared_memory::segment_manager> + shmem_movable_node_pair_allocator_t; +typedef allocator<test::movable_and_copyable_int, my_managed_shared_memory::segment_manager> + shmem_move_copy_allocator_t; +typedef allocator<test::copyable_int, my_managed_shared_memory::segment_manager> + shmem_copy_allocator_t; +typedef allocator<std::pair<const test::movable_and_copyable_int, test::movable_and_copyable_int>, my_managed_shared_memory::segment_manager> + shmem_move_copy_node_pair_allocator_t; + +//Alias standard types +typedef std::set<int> MyStdSet; +typedef std::multiset<int> MyStdMultiSet; +typedef std::map<int, int> MyStdMap; +typedef std::multimap<int, int> MyStdMultiMap; + +//Alias non-movable types +typedef set<int, std::less<int>, shmem_allocator_t> MyShmSet; +typedef multiset<int, std::less<int>, shmem_allocator_t> MyShmMultiSet; +typedef map<int, int, std::less<int>, shmem_node_pair_allocator_t> MyShmMap; +typedef multimap<int, int, std::less<int>, shmem_node_pair_allocator_t> MyShmMultiMap; + +//Alias movable types +typedef set<test::movable_int, std::less<test::movable_int> + ,shmem_movable_allocator_t> MyMovableShmSet; +typedef multiset<test::movable_int, + std::less<test::movable_int>, + shmem_movable_allocator_t> MyMovableShmMultiSet; +typedef map<test::movable_int, test::movable_int, + std::less<test::movable_int>, + shmem_movable_node_pair_allocator_t> MyMovableShmMap; +typedef multimap<test::movable_int, test::movable_int, + std::less<test::movable_int>, + shmem_movable_node_pair_allocator_t> MyMovableShmMultiMap; + +typedef set<test::movable_and_copyable_int + ,std::less<test::movable_and_copyable_int> + ,shmem_move_copy_allocator_t> MyMoveCopyShmSet; +typedef multiset<test::movable_and_copyable_int, + std::less<test::movable_and_copyable_int>, + shmem_move_copy_allocator_t> MyMoveCopyShmMultiSet; + +typedef set<test::copyable_int + ,std::less<test::copyable_int> + ,shmem_copy_allocator_t> MyCopyShmSet; +typedef multiset<test::copyable_int, + std::less<test::copyable_int>, + shmem_copy_allocator_t> MyCopyShmMultiSet; + + +typedef map<test::movable_and_copyable_int + ,test::movable_and_copyable_int + ,std::less<test::movable_and_copyable_int> + ,shmem_move_copy_node_pair_allocator_t> MyMoveCopyShmMap; +typedef multimap<test::movable_and_copyable_int + ,test::movable_and_copyable_int + ,std::less<test::movable_and_copyable_int> + ,shmem_move_copy_node_pair_allocator_t> MyMoveCopyShmMultiMap; + +int main () +{ + using namespace boost::interprocess::ipcdetail; + + if(0 != test::set_test<my_managed_shared_memory + ,MyShmSet + ,MyStdSet + ,MyShmMultiSet + ,MyStdMultiSet>()){ + return 1; + } + + if(0 != test::set_test_copyable<my_managed_shared_memory + ,MyShmSet + ,MyStdSet + ,MyShmMultiSet + ,MyStdMultiSet>()){ + return 1; + } + + if(0 != test::set_test<my_managed_shared_memory + ,MyMovableShmSet + ,MyStdSet + ,MyMovableShmMultiSet + ,MyStdMultiSet>()){ + return 1; + } + + if(0 != test::set_test<my_managed_shared_memory + ,MyMoveCopyShmSet + ,MyStdSet + ,MyMoveCopyShmMultiSet + ,MyStdMultiSet>()){ + return 1; + } + + if(0 != test::set_test<my_managed_shared_memory + ,MyCopyShmSet + ,MyStdSet + ,MyCopyShmMultiSet + ,MyStdMultiSet>()){ + return 1; + } + + if (0 != test::map_test<my_managed_shared_memory + ,MyShmMap + ,MyStdMap + ,MyShmMultiMap + ,MyStdMultiMap>()){ + return 1; + } + + if(0 != test::map_test_copyable<my_managed_shared_memory + ,MyShmMap + ,MyStdMap + ,MyShmMultiMap + ,MyStdMultiMap>()){ + return 1; + } + +// if (0 != test::map_test<my_managed_shared_memory +// ,MyMovableShmMap +// ,MyStdMap +// ,MyMovableShmMultiMap +// ,MyStdMultiMap>()){ +// return 1; +// } + + if (0 != test::map_test<my_managed_shared_memory + ,MyMoveCopyShmMap + ,MyStdMap + ,MyMoveCopyShmMultiMap + ,MyStdMultiMap>()){ + return 1; + } + + const test::EmplaceOptions SetOptions = (test::EmplaceOptions)(test::EMPLACE_HINT | test::EMPLACE_ASSOC); + if(!boost::interprocess::test::test_emplace<set<test::EmplaceInt>, SetOptions>()) + return 1; + if(!boost::interprocess::test::test_emplace<multiset<test::EmplaceInt>, SetOptions>()) + return 1; + const test::EmplaceOptions MapOptions = (test::EmplaceOptions)(test::EMPLACE_HINT_PAIR | test::EMPLACE_ASSOC_PAIR); + if(!boost::interprocess::test::test_emplace<map<test::EmplaceInt, test::EmplaceInt>, MapOptions>()) + return 1; + if(!boost::interprocess::test::test_emplace<multimap<test::EmplaceInt, test::EmplaceInt>, MapOptions>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/unique_ptr_test.cpp b/src/boost/libs/interprocess/test/unique_ptr_test.cpp new file mode 100644 index 00000000..b9e24dd2 --- /dev/null +++ b/src/boost/libs/interprocess/test/unique_ptr_test.cpp @@ -0,0 +1,142 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/offset_ptr.hpp> +#include <boost/interprocess/smart_ptr/unique_ptr.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <boost/interprocess/containers/set.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/smart_ptr/deleter.hpp> +#include <stdio.h> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +class MyClass +{ + public: + MyClass() + {} +}; + +typedef managed_unique_ptr<MyClass, managed_shared_memory>::type my_unique_ptr_class; +typedef set <my_unique_ptr_class + ,std::less<my_unique_ptr_class> + ,allocator <my_unique_ptr_class + ,managed_shared_memory::segment_manager> + > MySet; + +typedef list<my_unique_ptr_class + ,allocator <my_unique_ptr_class + ,managed_shared_memory::segment_manager> + > MyList; + +typedef vector <my_unique_ptr_class + ,allocator <my_unique_ptr_class + ,managed_shared_memory::segment_manager> + > MyVector; + +int main() +{ + std::string process_name; + test::get_process_id_name(process_name); + + //Create managed shared memory + shared_memory_object::remove(process_name.c_str()); + { + managed_shared_memory segment(create_only, process_name.c_str(), 10000); + + //Create unique_ptr using dynamic allocation + my_unique_ptr_class my_ptr (segment.construct<MyClass>(anonymous_instance)() + ,segment.get_deleter<MyClass>()); + my_unique_ptr_class my_ptr2(segment.construct<MyClass>(anonymous_instance)() + ,segment.get_deleter<MyClass>()); + + //Backup relative pointers to future tests + offset_ptr<MyClass> ptr1 = my_ptr.get(); + offset_ptr<MyClass> ptr2 = my_ptr2.get(); + + //Test some copy constructors + my_unique_ptr_class my_ptr3(0, segment.get_deleter<MyClass>()); + my_unique_ptr_class my_ptr4(boost::move(my_ptr3)); + + //Construct a list and fill + MyList list(segment.get_segment_manager()); + + //Insert from my_unique_ptr_class + list.push_front(boost::move(my_ptr)); + list.push_back(boost::move(my_ptr2)); + + //Check pointers + assert(my_ptr.get() == 0); + assert(my_ptr2.get() == 0); + assert(list.begin()->get() == ptr1); + assert(list.rbegin()->get() == ptr2); + + //Construct a set and fill + typedef std::less<my_unique_ptr_class> set_less_t; + MySet set(set_less_t(), segment.get_segment_manager()); + + //Insert in set from list passing ownership + set.insert(boost::move(*list.begin())); + set.insert(boost::move(*list.rbegin())); + + //Check pointers + assert(list.begin()->get() == 0); + assert(list.rbegin()->get()== 0); + + //A set is ordered by std::less<my_unique_ptr_class> so + //be careful when comparing pointers + if(ptr1 < ptr2){ + assert(set.begin()->get() == ptr1); + assert(set.rbegin()->get() == ptr2); + } + else{ + assert(set.rbegin()->get() == ptr1); + assert(set.begin()->get() == ptr2); + } + + //Now with vector + MyVector vector(segment.get_segment_manager()); + + //Insert from my_unique_ptr_class + if(ptr1 < ptr2){ + vector.insert(vector.begin(), boost::move(*set.begin())); + vector.insert(vector.end(), boost::move(*set.rbegin())); + } + else{ + vector.insert(vector.begin(), boost::move(*set.rbegin())); + vector.insert(vector.end(), boost::move(*set.begin())); + } + + //Check pointers + assert(my_ptr.get() == 0); + assert(my_ptr2.get() == 0); + assert(vector.begin()->get() == ptr1); + assert(vector.rbegin()->get() == ptr2); + + MyVector vector2(boost::move(vector)); + vector2.swap(vector); + + assert(vector.begin()->get() == ptr1); + assert(vector.rbegin()->get() == ptr2); + + my_unique_ptr_class a(0, segment.get_deleter<MyClass>()), b(0, segment.get_deleter<MyClass>()); + a = boost::move(b); + } + shared_memory_object::remove(process_name.c_str()); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/unordered_test.cpp b/src/boost/libs/interprocess/test/unordered_test.cpp new file mode 100644 index 00000000..e8995e0f --- /dev/null +++ b/src/boost/libs/interprocess/test/unordered_test.cpp @@ -0,0 +1,100 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include "get_process_id_name.hpp" + +//<- +//Shield against external warnings +#include <boost/interprocess/detail/config_external_begin.hpp> +//-> + +#include <boost/unordered_map.hpp> +#include <boost/unordered_set.hpp> + +//<- +#include <boost/interprocess/detail/config_external_end.hpp> +//-> + +#include <functional> //std::equal_to +#include <boost/functional/hash.hpp> //boost::hash + +namespace bip = boost::interprocess; + +typedef bip::allocator<int, bip::managed_shared_memory::segment_manager> ShmemAllocator; +typedef boost::unordered_set<int, boost::hash<int>, std::equal_to<int>, ShmemAllocator> MyUnorderedSet; +typedef boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>, ShmemAllocator> MyUnorderedMultiSet; + +int main() +{ + //Remove any other old shared memory from the system + bip::shared_memory_object::remove(bip::test::get_process_id_name()); + try { + bip::managed_shared_memory shm(bip::create_only, bip::test::get_process_id_name(), 65536); + + //Elements to be inserted in unordered containers + const int elements[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + const int elements_size = sizeof(elements)/sizeof(elements[0]); + + MyUnorderedSet *myset = + shm.construct<MyUnorderedSet>(bip::anonymous_instance) + ( elements_size + , MyUnorderedSet::hasher() + , MyUnorderedSet::key_equal() + , shm.get_allocator<int>()); + MyUnorderedMultiSet *mymset = + shm.construct<MyUnorderedMultiSet>(bip::anonymous_instance) + ( elements_size + , MyUnorderedSet::hasher() + , MyUnorderedSet::key_equal() + , shm.get_allocator<int>()); + + //Insert elements and check sizes + myset->insert((&elements[0]), (&elements[elements_size])); + myset->insert((&elements[0]), (&elements[elements_size])); + mymset->insert((&elements[0]), (&elements[elements_size])); + mymset->insert((&elements[0]), (&elements[elements_size])); + + if(myset->size() != (unsigned int)elements_size) + return 1; + if(mymset->size() != (unsigned int)elements_size*2) + return 1; + + //Destroy elements and check sizes + myset->clear(); + mymset->clear(); + + if(!myset->empty()) + return 1; + if(!mymset->empty()) + return 1; + + //Destroy elements and check if memory has been deallocated + shm.destroy_ptr(myset); + shm.destroy_ptr(mymset); + + shm.shrink_to_fit_indexes(); + if(!shm.all_memory_deallocated()) + return 1; + + } + catch(...){ + //Remove shared memory from the system + bip::shared_memory_object::remove(bip::test::get_process_id_name()); + throw; + } + //Remove shared memory from the system + bip::shared_memory_object::remove(bip::test::get_process_id_name()); + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/upgradable_mutex_test.cpp b/src/boost/libs/interprocess/test/upgradable_mutex_test.cpp new file mode 100644 index 00000000..94bc3155 --- /dev/null +++ b/src/boost/libs/interprocess/test/upgradable_mutex_test.cpp @@ -0,0 +1,173 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include "mutex_test_template.hpp" +#include "sharable_mutex_test_template.hpp" +#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/interprocess/sync/sharable_lock.hpp> +#include <boost/interprocess/sync/upgradable_lock.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include "util.hpp" + +int main () +{ + using namespace boost::interprocess; + + test::test_all_lock<interprocess_upgradable_mutex>(); + test::test_all_mutex<interprocess_upgradable_mutex>(); + test::test_all_sharable_mutex<interprocess_upgradable_mutex>(); + + //Test lock transition + { + typedef interprocess_upgradable_mutex Mutex; + Mutex mut; + Mutex mut2; + + //Conversions to scoped_lock + { + scoped_lock<Mutex> lock(mut); + scoped_lock<Mutex> e_lock(boost::move(lock)); + lock.swap(e_lock); + } + { + scoped_lock<Mutex> lock(mut); + scoped_lock<Mutex> e_lock(mut2); + e_lock = boost::move(lock); + } + { + upgradable_lock<Mutex> u_lock(mut); + //This calls unlock_upgradable_and_lock() + scoped_lock<Mutex> e_lock(boost::move(u_lock)); + } + { + upgradable_lock<Mutex> u_lock(mut); + //This calls unlock_upgradable_and_lock() + scoped_lock<Mutex> e_lock(mut2); + scoped_lock<Mutex> moved(boost::move(u_lock)); + e_lock = boost::move(moved); + } + { + upgradable_lock<Mutex> u_lock(mut); + //This calls try_unlock_upgradable_and_lock() + scoped_lock<Mutex> e_lock(boost::move(u_lock), try_to_lock); + } + { + upgradable_lock<Mutex> u_lock(mut); + //This calls try_unlock_upgradable_and_lock() + scoped_lock<Mutex> e_lock(mut2); + scoped_lock<Mutex> moved(boost::move(u_lock), try_to_lock); + e_lock = boost::move(moved); + } + { + boost::posix_time::ptime t = test::delay(100); + upgradable_lock<Mutex> u_lock(mut); + //This calls timed_unlock_upgradable_and_lock() + scoped_lock<Mutex> e_lock(boost::move(u_lock), t); + } + { + boost::posix_time::ptime t = test::delay(100); + upgradable_lock<Mutex> u_lock(mut); + //This calls timed_unlock_upgradable_and_lock() + scoped_lock<Mutex> e_lock(mut2); + scoped_lock<Mutex> moved(boost::move(u_lock), t); + e_lock = boost::move(moved); + } + { + sharable_lock<Mutex> s_lock(mut); + //This calls try_unlock_sharable_and_lock() + scoped_lock<Mutex> e_lock(boost::move(s_lock), try_to_lock); + } + { + sharable_lock<Mutex> s_lock(mut); + //This calls try_unlock_sharable_and_lock() + scoped_lock<Mutex> e_lock(mut2); + scoped_lock<Mutex> moved(boost::move(s_lock), try_to_lock); + e_lock = boost::move(moved); + } + //Conversions to upgradable_lock + { + upgradable_lock<Mutex> lock(mut); + upgradable_lock<Mutex> u_lock(boost::move(lock)); + lock.swap(u_lock); + } + { + upgradable_lock<Mutex> lock(mut); + upgradable_lock<Mutex> u_lock(mut2); + upgradable_lock<Mutex> moved(boost::move(lock)); + u_lock = boost::move(moved); + } + { + sharable_lock<Mutex> s_lock(mut); + //This calls unlock_sharable_and_lock_upgradable() + upgradable_lock<Mutex> u_lock(boost::move(s_lock), try_to_lock); + } + { + sharable_lock<Mutex> s_lock(mut); + //This calls unlock_sharable_and_lock_upgradable() + upgradable_lock<Mutex> u_lock(mut2); + upgradable_lock<Mutex> moved(boost::move(s_lock), try_to_lock); + u_lock = boost::move(moved); + } + { + scoped_lock<Mutex> e_lock(mut); + //This calls unlock_and_lock_upgradable() + upgradable_lock<Mutex> u_lock(boost::move(e_lock)); + } + { + scoped_lock<Mutex> e_lock(mut); + //This calls unlock_and_lock_upgradable() + upgradable_lock<Mutex> u_lock(mut2); + upgradable_lock<Mutex> moved(boost::move(e_lock)); + u_lock = boost::move(moved); + } + //Conversions to sharable_lock + { + sharable_lock<Mutex> lock(mut); + sharable_lock<Mutex> s_lock(boost::move(lock)); + lock.swap(s_lock); + } + { + sharable_lock<Mutex> lock(mut); + sharable_lock<Mutex> s_lock(mut2); + sharable_lock<Mutex> moved(boost::move(lock)); + s_lock = boost::move(moved); + } + { + upgradable_lock<Mutex> u_lock(mut); + //This calls unlock_upgradable_and_lock_sharable() + sharable_lock<Mutex> s_lock(boost::move(u_lock)); + } + { + upgradable_lock<Mutex> u_lock(mut); + //This calls unlock_upgradable_and_lock_sharable() + sharable_lock<Mutex> s_lock(mut2); + sharable_lock<Mutex> moved(boost::move(u_lock)); + s_lock = boost::move(moved); + } + { + scoped_lock<Mutex> e_lock(mut); + //This calls unlock_and_lock_sharable() + sharable_lock<Mutex> s_lock(boost::move(e_lock)); + } + { + scoped_lock<Mutex> e_lock(mut); + //This calls unlock_and_lock_sharable() + sharable_lock<Mutex> s_lock(mut2); + sharable_lock<Mutex> moved(boost::move(e_lock)); + s_lock = boost::move(moved); + } + } + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/user_buffer_test.cpp b/src/boost/libs/interprocess/test/user_buffer_test.cpp new file mode 100644 index 00000000..32670af5 --- /dev/null +++ b/src/boost/libs/interprocess/test/user_buffer_test.cpp @@ -0,0 +1,259 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <algorithm> +#include <vector> +#include <list> +#include <iostream> +#include <functional> +#include <boost/interprocess/managed_external_buffer.hpp> +#include <boost/interprocess/managed_heap_memory.hpp> +#include <boost/interprocess/containers/list.hpp> +#include <boost/interprocess/detail/type_traits.hpp> +#include <boost/move/detail/type_traits.hpp> +#include <boost/interprocess/allocators/node_allocator.hpp> +#include "print_container.hpp" + +/******************************************************************************/ +/* */ +/* This example constructs repeats the same operations with std::list, */ +/* shmem_list in user provided buffer, and shmem_list in heap memory */ +/* */ +/******************************************************************************/ + +using namespace boost::interprocess; + +//We will work with wide characters for user memory objects +//Alias <integer> node allocator type +typedef node_allocator + <int, wmanaged_external_buffer::segment_manager> user_node_allocator_t; +typedef node_allocator + <int, wmanaged_heap_memory::segment_manager> heap_node_allocator_t; + +//Alias list types +typedef list<int, user_node_allocator_t> MyUserList; +typedef list<int, heap_node_allocator_t> MyHeapList; +typedef std::list<int> MyStdList; + +//Function to check if both lists are equal +bool CheckEqual(MyUserList *userlist, MyStdList *stdlist, MyHeapList *heaplist) +{ + return std::equal(userlist->begin(), userlist->end(), stdlist->begin()) && + std::equal(heaplist->begin(), heaplist->end(), stdlist->begin()); +} + +int main () +{ + //Create the user memory who will store all objects + const int size_aligner = sizeof(::boost::container::dtl::max_align_t); + const int memsize = 65536/size_aligner*size_aligner; + static ::boost::container::dtl::max_align_t static_buffer[memsize/size_aligner]; + + { + //Now test move semantics + managed_heap_memory original(memsize); + managed_heap_memory move_ctor(boost::move(original)); + managed_heap_memory move_assign; + move_assign = boost::move(move_ctor); + original.swap(move_assign); + } + { + //Now test move semantics + managed_external_buffer original(create_only, static_buffer, memsize); + managed_external_buffer move_ctor(boost::move(original)); + managed_external_buffer move_assign; + move_assign = boost::move(move_ctor); + original.swap(move_assign); + } + + //Named new capable user mem allocator + wmanaged_external_buffer user_buffer(create_only, static_buffer, memsize); + + //Named new capable heap mem allocator + wmanaged_heap_memory heap_buffer(memsize); + + //Test move semantics + { + wmanaged_external_buffer user_default; + wmanaged_external_buffer temp_external(boost::move(user_buffer)); + user_default = boost::move(temp_external); + user_buffer = boost::move(user_default); + wmanaged_heap_memory heap_default; + wmanaged_heap_memory temp_heap(boost::move(heap_buffer)); + heap_default = boost::move(temp_heap); + heap_buffer = boost::move(heap_default); + } + + //Initialize memory + user_buffer.reserve_named_objects(100); + heap_buffer.reserve_named_objects(100); + + //User memory allocator must be always be initialized + //since it has no default constructor + MyUserList *userlist = user_buffer.construct<MyUserList>(L"MyUserList") + (user_buffer.get_segment_manager()); + + MyHeapList *heaplist = heap_buffer.construct<MyHeapList>(L"MyHeapList") + (heap_buffer.get_segment_manager()); + + //Alias heap list + MyStdList *stdlist = new MyStdList; + + int i; + const int max = 100; + for(i = 0; i < max; ++i){ + userlist->push_back(i); + heaplist->push_back(i); + stdlist->push_back(i); + } + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + userlist->erase(userlist->begin()++); + heaplist->erase(heaplist->begin()++); + stdlist->erase(stdlist->begin()++); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + userlist->pop_back(); + heaplist->pop_back(); + stdlist->pop_back(); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + userlist->pop_front(); + heaplist->pop_front(); + stdlist->pop_front(); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + std::vector<int> aux_vect; + #if !BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) + aux_vect.assign(50, -1); + userlist->assign(aux_vect.begin(), aux_vect.end()); + heaplist->assign(aux_vect.begin(), aux_vect.end()); + stdlist->assign(aux_vect.begin(), aux_vect.end()); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + #endif + + userlist->sort(); + heaplist->sort(); + stdlist->sort(); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + #if !BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) + aux_vect.assign(50, 0); + #endif + userlist->insert(userlist->begin(), aux_vect.begin(), aux_vect.end()); + heaplist->insert(heaplist->begin(), aux_vect.begin(), aux_vect.end()); + stdlist->insert(stdlist->begin(), aux_vect.begin(), aux_vect.end()); + + userlist->unique(); + heaplist->unique(); + stdlist->unique(); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + userlist->sort(std::greater<int>()); + heaplist->sort(std::greater<int>()); + stdlist->sort(std::greater<int>()); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + userlist->resize(userlist->size()/2); + heaplist->resize(heaplist->size()/2); + stdlist->resize(stdlist->size()/2); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + userlist->remove(*userlist->begin()); + heaplist->remove(*heaplist->begin()); + stdlist->remove(*stdlist->begin()); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + for(i = 0; i < max; ++i){ + userlist->push_back(i); + heaplist->push_back(i); + stdlist->push_back(i); + } + + MyUserList otheruserlist(*userlist); + MyHeapList otherheaplist(*heaplist); + MyStdList otherstdlist(*stdlist); + userlist->splice(userlist->begin(), otheruserlist); + heaplist->splice(heaplist->begin(), otherheaplist); + stdlist->splice(stdlist->begin(), otherstdlist); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + otheruserlist = *userlist; + otherheaplist = *heaplist; + otherstdlist = *stdlist; + + userlist->sort(std::greater<int>()); + heaplist->sort(std::greater<int>()); + stdlist->sort(std::greater<int>()); + otheruserlist.sort(std::greater<int>()); + otherheaplist.sort(std::greater<int>()); + otherstdlist.sort(std::greater<int>()); + userlist->merge(otheruserlist, std::greater<int>()); + heaplist->merge(otherheaplist, std::greater<int>()); + stdlist->merge(otherstdlist, std::greater<int>()); + if(!CheckEqual(userlist, stdlist, heaplist)) return 1; + + user_buffer.destroy<MyUserList>(L"MyUserList"); + delete stdlist; + + //Fill heap buffer until is full + try{ + while(1){ + heaplist->insert(heaplist->end(), 0); + } + } + catch(boost::interprocess::bad_alloc &){} + + MyHeapList::size_type heap_list_size = heaplist->size(); + + //Copy heap buffer to another + const char *insert_beg = static_cast<char*>(heap_buffer.get_address()); + const char *insert_end = insert_beg + heap_buffer.get_size(); + std::vector<char> grow_copy (insert_beg, insert_end); + + //Destroy old list + heap_buffer.destroy<MyHeapList>(L"MyHeapList"); + + //Resize copy buffer + grow_copy.resize(memsize*2); + + //Open Interprocess machinery in the new managed external buffer + wmanaged_external_buffer user_buffer2(open_only, &grow_copy[0], memsize); + + //Expand old Interprocess machinery to the new size + user_buffer2.grow(memsize); + + //Get a pointer to the full list + userlist = user_buffer2.find<MyUserList>(L"MyHeapList").first; + if(!userlist){ + return 1; + } + + //Fill user buffer until is full + try{ + while(1){ + userlist->insert(userlist->end(), 0); + } + } + catch(boost::interprocess::bad_alloc &){} + + MyUserList::size_type user_list_size = userlist->size(); + + if(user_list_size <= heap_list_size){ + return 1; + } + + user_buffer2.destroy_ptr(userlist); + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/util.hpp b/src/boost/libs/interprocess/test/util.hpp new file mode 100644 index 00000000..c4e8229f --- /dev/null +++ b/src/boost/libs/interprocess/test/util.hpp @@ -0,0 +1,95 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. + +#ifndef BOOST_INTERPROCESS_TEST_UTIL_HEADER +#define BOOST_INTERPROCESS_TEST_UTIL_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/sync/scoped_lock.hpp> +#include <boost/interprocess/detail/os_thread_functions.hpp> + +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <boost/version.hpp> + +namespace boost { +namespace interprocess { +namespace test { + +inline void sleep(const boost::posix_time::ptime &xt) +{ + boost::interprocess::ipcdetail::thread_sleep + ((xt - microsec_clock::universal_time()).total_milliseconds()); +} + +inline boost::posix_time::ptime delay(int secs, int msecs=0, int nsecs = 0) +{ + (void)msecs; + using namespace boost::posix_time; + int count = static_cast<int>(double(nsecs)* + (double(time_duration::ticks_per_second())/double(1000000000.0))); + count += static_cast<int>(double(msecs)* + (double(time_duration::ticks_per_second())/double(1000.0))); + boost::posix_time::ptime cur = microsec_clock::universal_time(); + return cur += boost::posix_time::time_duration(0, 0, secs, count); +} + +inline bool in_range(const boost::posix_time::ptime& xt, int secs=1) +{ + boost::posix_time::ptime min = delay(-secs); + boost::posix_time::ptime max = delay(0); + return (xt > min) && (max > xt); +} + +template <typename P> +class thread_adapter +{ + public: + thread_adapter(void (*func)(void*, P &), void* param1, P ¶m2) + : func_(func), param1_(param1) ,param2_(param2){ } + void operator()() const { func_(param1_, param2_); } + + private: + void (*func_)(void*, P &); + void* param1_; + P& param2_; +}; + +template <typename P> +struct data +{ + explicit data(int id, int secs=0) + : m_id(id), m_value(-1), m_secs(secs), m_error(no_error) + {} + int m_id; + int m_value; + int m_secs; + error_code_t m_error; +}; + +static int shared_val = 0; +static const int BaseSeconds = 1; + +} //namespace test { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_TEST_UTIL_HEADER diff --git a/src/boost/libs/interprocess/test/vector_test.cpp b/src/boost/libs/interprocess/test/vector_test.cpp new file mode 100644 index 00000000..6a3931c2 --- /dev/null +++ b/src/boost/libs/interprocess/test/vector_test.cpp @@ -0,0 +1,103 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/allocators/allocator.hpp> +#include "allocator_v1.hpp" +#include "check_equal_containers.hpp" +#include "movable_int.hpp" +#include "expand_bwd_test_allocator.hpp" +#include "expand_bwd_test_template.hpp" +#include "dummy_test_allocator.hpp" +#include "vector_test.hpp" + +using namespace boost::interprocess; + +int test_expand_bwd() +{ + //Now test all back insertion possibilities + + //First raw ints + typedef test::expand_bwd_test_allocator<int> + int_allocator_type; + typedef vector<int, int_allocator_type> + int_vector; + + if(!test::test_all_expand_bwd<int_vector>()) + return 1; + + //Now user defined wrapped int + typedef test::expand_bwd_test_allocator<test::int_holder> + int_holder_allocator_type; + typedef vector<test::int_holder, int_holder_allocator_type> + int_holder_vector; + + if(!test::test_all_expand_bwd<int_holder_vector>()) + return 1; + + //Now user defined bigger wrapped int + typedef test::expand_bwd_test_allocator<test::triple_int_holder> + triple_int_holder_allocator_type; + + typedef vector<test::triple_int_holder, triple_int_holder_allocator_type> + triple_int_holder_vector; + + if(!test::test_all_expand_bwd<triple_int_holder_vector>()) + return 1; + + return 0; +} + +int main() +{ + typedef allocator<int, managed_shared_memory::segment_manager> ShmemAllocator; + typedef vector<int, ShmemAllocator> MyVector; + + typedef test::allocator_v1<int, managed_shared_memory::segment_manager> ShmemV1Allocator; + typedef vector<int, ShmemV1Allocator> MyV1Vector; + + typedef allocator<test::movable_int, managed_shared_memory::segment_manager> ShmemMoveAllocator; + typedef vector<test::movable_int, ShmemMoveAllocator> MyMoveVector; + + typedef allocator<test::movable_and_copyable_int, managed_shared_memory::segment_manager> ShmemCopyMoveAllocator; + typedef vector<test::movable_and_copyable_int, ShmemCopyMoveAllocator> MyCopyMoveVector; + + typedef allocator<test::copyable_int, managed_shared_memory::segment_manager> ShmemCopyAllocator; + typedef vector<test::copyable_int, ShmemCopyAllocator> MyCopyVector; + + if(test::vector_test<managed_shared_memory, MyVector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyV1Vector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyMoveVector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyCopyMoveVector>()) + return 1; + + if(test::vector_test<managed_shared_memory, MyCopyVector>()) + return 1; + + if(test_expand_bwd()) + return 1; + + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE); + if(!boost::interprocess::test::test_emplace + < vector<test::EmplaceInt>, Options>()) + return 1; + + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/vector_test.hpp b/src/boost/libs/interprocess/test/vector_test.hpp new file mode 100644 index 00000000..4875b336 --- /dev/null +++ b/src/boost/libs/interprocess/test/vector_test.hpp @@ -0,0 +1,254 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_TEST_VECTOR_TEST_HEADER +#define BOOST_INTERPROCESS_TEST_VECTOR_TEST_HEADER + +#include <boost/interprocess/detail/config_begin.hpp> + +#include <boost/interprocess/exceptions.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/interprocess/detail/mpl.hpp> +#include "print_container.hpp" +#include "check_equal_containers.hpp" +#include "movable_int.hpp" + +#include "get_process_id_name.hpp" +#include "emplace_test.hpp" + +#include <vector> +#include <list> +#include <string> +#include <iostream> +#include <cstddef> + + +namespace boost{ +namespace interprocess{ +namespace test{ + +template<class V1, class V2> +bool copyable_only(V1 *, V2 *, boost::interprocess::ipcdetail::false_type) +{ + return true; +} + +//Function to check if both sets are equal +template<class V1, class V2> +bool copyable_only(V1 *shmvector, V2 *stdvector, boost::interprocess::ipcdetail::true_type) +{ + typedef typename V1::value_type IntType; + std::size_t size = shmvector->size(); + stdvector->insert(stdvector->end(), 50, 1); + shmvector->insert(shmvector->end(), 50, IntType(1)); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + + { + IntType move_me(1); + stdvector->insert(stdvector->begin()+size/2, 50, 1); + shmvector->insert(shmvector->begin()+size/2, 50, boost::move(move_me)); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + } + { + IntType move_me(2); + shmvector->assign(shmvector->size()/2, boost::move(move_me)); + stdvector->assign(stdvector->size()/2, 2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + } + { + IntType move_me(3); + shmvector->assign(shmvector->size()*3-1, boost::move(move_me)); + stdvector->assign(stdvector->size()*3-1, 3); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + } + return true; +} + +template<class ManagedSharedMemory + ,class MyShmVector> +int vector_test() +{ + typedef std::vector<int> MyStdVector; + typedef typename MyShmVector::value_type IntType; + + std::string process_name; + test::get_process_id_name(process_name); + + const int Memsize = 65536; + const char *const shMemName = process_name.c_str(); + const int max = 100; + + { + //Compare several shared memory vector operations with std::vector + //Create shared memory + shared_memory_object::remove(shMemName); + try{ + ManagedSharedMemory segment(create_only, shMemName, Memsize); + + segment.reserve_named_objects(100); + + //Shared memory allocator must be always be initialized + //since it has no default constructor + MyShmVector *shmvector = segment.template construct<MyShmVector>("MyShmVector") + (segment.get_segment_manager()); + MyStdVector *stdvector = new MyStdVector; + + shmvector->resize(100); + stdvector->resize(100); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + shmvector->resize(200); + stdvector->resize(200); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + shmvector->resize(0); + stdvector->resize(0); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + for(int i = 0; i < max; ++i){ + IntType new_int(i); + shmvector->insert(shmvector->end(), boost::move(new_int)); + stdvector->insert(stdvector->end(), i); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + } + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + typename MyShmVector::iterator shmit(shmvector->begin()); + typename MyStdVector::iterator stdit(stdvector->begin()); + typename MyShmVector::const_iterator cshmit = shmit; + (void)cshmit; + ++shmit; ++stdit; + shmvector->erase(shmit); + stdvector->erase(stdit); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + shmvector->erase(shmvector->begin()); + stdvector->erase(stdvector->begin()); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + { + //Initialize values + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType new_int(-1); + //BOOST_STATIC_ASSERT((::boost::move_ipcdetail::is_copy_constructible<boost::interprocess::test::movable_int>::value == false)); + aux_vect[i] = boost::move(new_int); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + + shmvector->insert(shmvector->end() + ,::boost::make_move_iterator(&aux_vect[0]) + ,::boost::make_move_iterator(aux_vect + 50)); + stdvector->insert(stdvector->end(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + for(int i = 0, j = static_cast<int>(shmvector->size()); i < j; ++i){ + shmvector->erase(shmvector->begin()); + stdvector->erase(stdvector->begin()); + } + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + } + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType new_int(-1); + aux_vect[i] = boost::move(new_int); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + shmvector->insert(shmvector->begin() + ,::boost::make_move_iterator(&aux_vect[0]) + ,::boost::make_move_iterator(aux_vect + 50)); + stdvector->insert(stdvector->begin(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + } + + shmvector->reserve(shmvector->size()*2); + stdvector->reserve(stdvector->size()*2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + IntType push_back_this(1); + shmvector->push_back(boost::move(push_back_this)); + stdvector->push_back(int(1)); + shmvector->push_back(IntType(1)); + stdvector->push_back(int(1)); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + if(!copyable_only(shmvector, stdvector + ,ipcdetail::bool_<!ipcdetail::is_same<IntType, test::movable_int>::value>())){ + return 1; + } + + shmvector->erase(shmvector->begin()); + stdvector->erase(stdvector->begin()); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + for(int i = 0; i < max; ++i){ + IntType insert_this(i); + shmvector->insert(shmvector->begin(), boost::move(insert_this)); + stdvector->insert(stdvector->begin(), i); + shmvector->insert(shmvector->begin(), IntType(i)); + stdvector->insert(stdvector->begin(), int(i)); + } + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + //Test insertion from list + { + std::list<int> l(50, int(1)); + shmvector->insert(shmvector->begin(), l.begin(), l.end()); + stdvector->insert(stdvector->begin(), l.begin(), l.end()); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + shmvector->assign(l.begin(), l.end()); + stdvector->assign(l.begin(), l.end()); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + } +/* + std::size_t cap = shmvector->capacity(); + shmvector->reserve(cap*2); + stdvector->reserve(cap*2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + shmvector->resize(0); + stdvector->resize(0); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + shmvector->resize(cap*2); + stdvector->resize(cap*2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; +*/ + + delete stdvector; + segment.template destroy<MyShmVector>("MyShmVector"); + segment.shrink_to_fit_indexes(); + + if(!segment.all_memory_deallocated()) + return 1; + } + catch(std::exception &ex){ + shared_memory_object::remove(shMemName); + std::cout << ex.what() << std::endl; + return 1; + } + } + shared_memory_object::remove(shMemName); + std::cout << std::endl << "Test OK!" << std::endl; + return 0; +} + +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#include <boost/interprocess/detail/config_end.hpp> + +#endif diff --git a/src/boost/libs/interprocess/test/vectorstream_test.cpp b/src/boost/libs/interprocess/test/vectorstream_test.cpp new file mode 100644 index 00000000..d20b82ac --- /dev/null +++ b/src/boost/libs/interprocess/test/vectorstream_test.cpp @@ -0,0 +1,185 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/containers/string.hpp> +#include <boost/interprocess/containers/vector.hpp> +#include <boost/interprocess/streams/vectorstream.hpp> +#include <boost/interprocess/streams/bufferstream.hpp> +#include <sstream> +#include <cstring> +#include <vector> +#include <iostream> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <stdio.h> + +namespace boost { +namespace interprocess { + +//Force instantiations to catch compile-time errors +typedef basic_string<char> my_string; +typedef basic_vectorstream<my_string > my_stringstream_t; +typedef vector<char> my_vector; +typedef basic_vectorstream<my_vector> my_vectorstream_t; +template class basic_vectorstream<my_string>; +template class basic_vectorstream<std::vector<char> >; + +}} + +using namespace boost::interprocess; + +static int vectorstream_test() +{ + { //Test high watermarking initialization + my_stringstream_t my_stringstream; + + if(my_stringstream.tellg() != std::streampos(0)){ + return 1; + } + if(my_stringstream.tellp() != std::streampos(0)){ + return 1; + } + + int a (0); + my_stringstream << 11; + my_stringstream >> a; + if(a != 11) + return 1; + } + { //Test high watermarking initialization + my_vectorstream_t my_stringstream; + int a (0); + my_stringstream << 13; + my_stringstream >> a; + if(a != 13) + return 1; + } + + //Pre-reserved string + { + my_stringstream_t my_stringstream; + std::stringstream std_stringstream; + std::string str1, str2, str3("testline:"); + int number1, number2; + + my_stringstream.reserve(10000); + for(int i = 0; i < 100; ++i){ + my_stringstream << "testline: " << i << std::endl; + std_stringstream << "testline: " << i << std::endl; + } + + if(std::strcmp(my_stringstream.vector().c_str(), std_stringstream.str().c_str()) != 0){ + return 1; + } + + for(int i = 0; i < 100; ++i){ + my_stringstream >> str1 >> number1; + std_stringstream >> str2 >> number2; + if((str1 != str2) || (str1 != str3)){ + assert(0); return 1; + } + if((number1 != number2) || (number1 != i)){ + assert(0); return 1; + } + } + } + //Pre-reserved vector + { + basic_vectorstream<std::vector<char> > my_vectorstream; + std::vector<char> myvector; + std::stringstream std_stringstream; + std::string str1, str2, str3("testline:"); + int number1, number2; + + my_vectorstream.reserve(10000); + for(int i = 0; i < 100; ++i){ + my_vectorstream << "testline: " << i << std::endl; + std_stringstream << "testline: " << i << std::endl; + } + //Add final null to form a c string + myvector.push_back(0); + if(std::strcmp(&(my_vectorstream.vector()[0]), std_stringstream.str().c_str()) != 0){ + return 1; + } + myvector.pop_back(); + for(int i = 0; i < 100; ++i){ + my_vectorstream >> str1 >> number1; + std_stringstream >> str2 >> number2; + if((str1 != str2) || (str1 != str3)){ + assert(0); return 1; + } + if((number1 != number2) || (number1 != i)){ + assert(0); return 1; + } + } + } + + //No pre-reserved or pre-reserved string + { + my_stringstream_t my_stringstream; + std::stringstream std_stringstream; + std::string str1, str2, str3("testline:"); + int number1, number2; + + for(int i = 0; i < 100; ++i){ + my_stringstream << "testline: " << i << std::endl; + std_stringstream << "testline: " << i << std::endl; + } + if(std::strcmp(my_stringstream.vector().c_str(), std_stringstream.str().c_str()) != 0){ + assert(0); return 1; + } + for(int i = 0; i < 100; ++i){ + my_stringstream >> str1 >> number1; + std_stringstream >> str2 >> number2; + if((str1 != str2) || (str1 != str3)){ + assert(0); return 1; + } + if((number1 != number2) || (number1 != i)){ + assert(0); return 1; + } + } + } + + //Test seek + { + my_stringstream_t my_stringstream; + my_stringstream << "ABCDEFGHIJKLM"; + my_stringstream.seekp(0); + my_stringstream << "PQRST"; + string s("PQRSTFGHIJKLM"); + if(s != my_stringstream.vector()){ + return 1; + } + my_stringstream.seekp(0, std::ios_base::end); + my_stringstream << "NOPQRST"; + s ="PQRSTFGHIJKLMNOPQRST"; + if(s != my_stringstream.vector()){ + return 1; + } + int size = static_cast<int>(my_stringstream.vector().size()); + my_stringstream.seekp(-size, std::ios_base::cur); + my_stringstream << "ABCDE"; + s ="ABCDEFGHIJKLMNOPQRST"; + if(s != my_stringstream.vector()){ + return 1; + } + } + return 0; +} + +int main () +{ + if(vectorstream_test()){ + return 1; + } + return 0; +} + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/windows_shared_dir_func.cpp b/src/boost/libs/interprocess/test/windows_shared_dir_func.cpp new file mode 100644 index 00000000..135f2460 --- /dev/null +++ b/src/boost/libs/interprocess/test/windows_shared_dir_func.cpp @@ -0,0 +1,84 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#ifdef BOOST_INTERPROCESS_WINDOWS + +#define BOOST_INTERPROCESS_WINDOWS + +//Force user-defined get_shared_dir +#define BOOST_INTERPROCESS_SHARED_DIR_FUNC +#include <boost/interprocess/detail/shared_dir_helpers.hpp> +#include <string> + +#include "get_process_id_name.hpp" + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +static bool dir_created = false; + +inline void get_shared_dir(std::string &shared_dir) +{ + shared_dir = boost::interprocess::ipcdetail::get_temporary_path(); + shared_dir += "/boostipctest_"; + shared_dir += boost::interprocess::test::get_process_id_name(); + if(!dir_created) + ipcdetail::create_directory(shared_dir.c_str()); + dir_created = true; +} + +}}} //namespace boost::interprocess::ipcdetail + +#include <boost/interprocess/shared_memory_object.hpp> +#include <iostream> + +int main () +{ + using namespace boost::interprocess; + const char *const shm_name = "test_shm"; + std::string shared_dir; + ipcdetail::get_shared_dir(shared_dir); + + std::string shm_path(shared_dir); + shm_path += shm_name; + + int ret = 0; + shared_memory_object::remove(shm_name); + { + shared_memory_object shm(create_only, shm_name, read_write); + + shm_path += shm_name; + int ret = ipcdetail::invalid_file() == ipcdetail::open_existing_file(shm_path.c_str(), read_only) ? + 1 : 0; + if(ret) + { + std::cerr << "Error opening user get_shared_dir()/shm file" << std::endl; + } + } + shared_memory_object::remove(shm_name); + ipcdetail::remove_directory(shared_dir.c_str()); + + return ret; +} + +#else + +int main() +{ + return 0; +} + +#endif //#ifdef BOOST_INTERPROCESS_WINDOWS + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/windows_shared_memory_mapping_test.cpp b/src/boost/libs/interprocess/test/windows_shared_memory_mapping_test.cpp new file mode 100644 index 00000000..582b2ba3 --- /dev/null +++ b/src/boost/libs/interprocess/test/windows_shared_memory_mapping_test.cpp @@ -0,0 +1,138 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#ifdef BOOST_INTERPROCESS_WINDOWS + +#include <fstream> +#include <iostream> +#include <boost/interprocess/windows_shared_memory.hpp> +#include <boost/interprocess/mapped_region.hpp> +#include <string> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +int main () +{ + try{ + const char *names[2] = { test::get_process_id_name(), 0 }; + for(unsigned int i_name = 0; i_name < sizeof(names)/sizeof(names[0]); ++i_name) + { + const std::size_t FileSize = 99999*2; + //Create a file mapping + windows_shared_memory mapping + (create_only, names[i_name], read_write, FileSize); + if(static_cast<std::size_t>(mapping.get_size()) < FileSize) + return 1; + { + + //Create two mapped regions, one half of the file each + mapped_region region (mapping + ,read_write + ,0 + ,FileSize/2 + ,0); + + mapped_region region2(mapping + ,read_write + ,FileSize/2 + ,FileSize - FileSize/2 + ,0); + + //Fill two regions with a pattern + unsigned char *filler = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + *filler++ = static_cast<unsigned char>(i); + } + + filler = static_cast<unsigned char*>(region2.get_address()); + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + *filler++ = static_cast<unsigned char>(i); + } + if(!region.flush(0, 0, false)){ + return 1; + } + + if(!region2.flush(0, 0, true)){ + return 1; + } + } + + //See if the pattern is correct in the file using two mapped regions + { + mapped_region region (mapping, read_only, 0, FileSize/2, 0); + mapped_region region2(mapping, read_only, FileSize/2, FileSize - FileSize/2, 0); + + unsigned char *checker = static_cast<unsigned char*>(region.get_address()); + //Check pattern + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + if(*checker++ != static_cast<unsigned char>(i)){ + return 1; + } + } + + //Check second half + checker = static_cast<unsigned char *>(region2.get_address()); + + //Check pattern + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + if(*checker++ != static_cast<unsigned char>(i)){ + return 1; + } + } + } + + //Now check the pattern mapping a single read only mapped_region + { + //Create a single regions, mapping all the file + mapped_region region (mapping, read_only); + + //Check pattern + unsigned char *pattern = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + if(*pattern != static_cast<unsigned char>(i)){ + return 1; + } + } + } + } + } + catch(std::exception &exc){ + //shared_memory_object::remove(test::get_process_id_name()); + std::cout << "Unhandled exception: " << exc.what() << std::endl; + return 1; + } + + return 0; +} + +#else + +int main() +{ + return 0; +} + +#endif + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/windows_shared_memory_test.cpp b/src/boost/libs/interprocess/test/windows_shared_memory_test.cpp new file mode 100644 index 00000000..6a235bb1 --- /dev/null +++ b/src/boost/libs/interprocess/test/windows_shared_memory_test.cpp @@ -0,0 +1,80 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#ifdef BOOST_INTERPROCESS_WINDOWS + +#include <boost/interprocess/windows_shared_memory.hpp> +#include <boost/interprocess/detail/managed_open_or_create_impl.hpp> +#include <boost/interprocess/exceptions.hpp> +#include "named_creation_template.hpp" +#include <cstring> //for strcmp, memset +#include <iostream> //for cout +#include <string> //for string +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +static const char *name_initialization_routine() +{ + static std::string process_name; + test::get_process_id_name(process_name); + return process_name.c_str(); +} + +static const std::size_t ShmSize = 1000; +typedef ipcdetail::managed_open_or_create_impl + <windows_shared_memory, 0, false, false> windows_shared_memory_t; + +//This wrapper is necessary to have a common constructor +//in generic named_creation_template functions +class shared_memory_creation_test_wrapper + : public windows_shared_memory_t +{ + public: + shared_memory_creation_test_wrapper(create_only_t) + : windows_shared_memory_t(create_only, name_initialization_routine(), ShmSize, read_write, 0, permissions()) + {} + + shared_memory_creation_test_wrapper(open_only_t) + : windows_shared_memory_t(open_only, name_initialization_routine(), read_write, 0) + {} + + shared_memory_creation_test_wrapper(open_or_create_t) + : windows_shared_memory_t(open_or_create, name_initialization_routine(), ShmSize, read_write, 0, permissions()) + {} +}; + + +int main () +{ + try{ + test::test_named_creation<shared_memory_creation_test_wrapper>(); + } + catch(std::exception &ex){ + std::cout << ex.what() << std::endl; + return 1; + } + + return 0; +} + +#else + +int main() +{ + return 0; +} + +#endif //#ifdef BOOST_INTERPROCESS_WINDOWS + +#include <boost/interprocess/detail/config_end.hpp> diff --git a/src/boost/libs/interprocess/test/xsi_shared_memory_mapping_test.cpp b/src/boost/libs/interprocess/test/xsi_shared_memory_mapping_test.cpp new file mode 100644 index 00000000..24d0df08 --- /dev/null +++ b/src/boost/libs/interprocess/test/xsi_shared_memory_mapping_test.cpp @@ -0,0 +1,139 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) + +#include <fstream> +#include <iostream> +#include <boost/interprocess/xsi_shared_memory.hpp> +#include <boost/interprocess/mapped_region.hpp> +#include <boost/interprocess/file_mapping.hpp> +#include <boost/interprocess/detail/file_wrapper.hpp> +#include <string> +#include <iostream> +#include "get_process_id_name.hpp" + +using namespace boost::interprocess; + +void remove_shared_memory(const xsi_key &key) +{ + try{ + xsi_shared_memory xsi(open_only, key); + xsi_shared_memory::remove(xsi.get_shmid()); + } + catch(interprocess_exception &e){ + if(e.get_error_code() != not_found_error) + throw; + } +} + +class xsi_shared_memory_remover +{ + public: + xsi_shared_memory_remover(xsi_shared_memory &xsi_shm) + : xsi_shm_(xsi_shm) + {} + + ~xsi_shared_memory_remover() + { xsi_shared_memory::remove(xsi_shm_.get_shmid()); } + private: + xsi_shared_memory & xsi_shm_; +}; + +inline std::string get_filename() +{ + std::string ret (ipcdetail::get_temporary_path()); + ret += "/"; + ret += test::get_process_id_name(); + return ret; +} + +int main () +{ + std::string filename(get_filename()); + const char *names[2] = { filename.c_str(), 0 }; + + file_mapping::remove(names[0]); + { ipcdetail::file_wrapper(create_only, names[0], read_write); } + xsi_key key(names[0], 1); + file_mapping::remove(names[0]); + remove_shared_memory(key); + + unsigned int i; + try{ + for(i = 0; i < sizeof(names)/sizeof(names[0]); ++i) + { + const std::size_t FileSize = 99999*2; + //Create a file mapping + xsi_shared_memory mapping (create_only, names[i] ? key : xsi_key(), FileSize); + xsi_shared_memory_remover rem(mapping); + try{ + { + //Partial mapping should fail fox XSI shared memory + bool thrown = false; + try{ + mapped_region region2(mapping, read_write, FileSize/2, FileSize - FileSize/2, 0); + } + catch(...){ + thrown = true; + } + if(thrown == false){ + return 1; + } + //Create a mapped region + mapped_region region (mapping, read_write, 0, FileSize, 0); + + //Fill two regions with a pattern + unsigned char *filler = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0; i < FileSize; ++i){ + *filler++ = static_cast<unsigned char>(i); + } + } + + //Now check the pattern mapping a single read only mapped_region + { + //Create a single region, mapping all the file + mapped_region region (mapping, read_only); + + //Check pattern + unsigned char *pattern = static_cast<unsigned char*>(region.get_address()); + for(std::size_t i = 0; i < FileSize; ++i, ++pattern){ + if(*pattern != static_cast<unsigned char>(i)){ + return 1; + } + } + } + } + catch(std::exception &exc){ + std::cout << "Unhandled exception: " << exc.what() << std::endl; + return 1; + } + } + } + catch(std::exception &exc){ + std::cout << "Unhandled exception: " << exc.what() << std::endl; + return 1; + } + return 0; +} + +#else + +int main() +{ + return 0; +} + +#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + +#include <boost/interprocess/detail/config_end.hpp> |