diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index eed8e52..0b6096c 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -58,6 +58,15 @@ separate compilation. However, the subset used by [*Boost.Interprocess] does not need any separate compilation so the user can define `BOOST_DATE_TIME_NO_LIB` to avoid Boost from trying to automatically link the [*Boost.DateTime]. +In POSIX systems, [*Boost.Interprocess] uses pthread system calls to implement +classes like mutexes, condition variables, etc... In some operating systems, +these POSIX calls are implemented in separate libraries that are not automatically +linked by the compiler. For example, in some Linux systems POSIX pthread functions +are implemented in `librt.a` library, so you might need to add that library +when linking an executable or shared library that uses [*Boost.Interprocess]. +If you obtain linking errors related to those pthread functions, please revise +your system's documentation to know which library implements them. + [endsect] [section:tested_compilers Tested compilers] @@ -551,6 +560,30 @@ behavior as the standard C (stdio.h) `int remove(const char *path)` function. [endsect] +[section:anonymous_shared_memory Anonymous shared memory for UNIX systems] + +Creating a shared memory segment and mapping it can be a bit tedious when several +processes are involved. When processes are related via `fork()` operating system +call in UNIX sytems a simpler method is available using anonymous shared memory. + +This feature has been implemented in UNIX systems mapping the device `\dev\zero` or +just using the `MAP_ANONYMOUS` in a POSIX conformant `mmap` system call. + +This feature is wrapped in [*Boost.Interprocess] using the `anonymous_shared_memory()` +function, which returns a `mapped_region` object holding an anonymous shared memory +segment that can be shared by related processes. + +Here's is an example: + +[import ../example/doc_anonymous_shared_memory.cpp] +[doc_anonymous_shared_memory] + +Once the segment is created, a `fork()` call can +be used so that `region` is used to communicate two related processes. + +[endsect] + + [section:windows_shared_memory Native windows shared memory] Windows operating system also offers shared memory, but the lifetime of this @@ -1298,7 +1331,7 @@ All the mutex types from [*Boost.Interprocess] implement the following operation [blurb ['[*void lock()]]] [*Effects:] - The calling thread tries to obtain ownership of the mutex, and if another thread has ownership of the mutex, it waits until it can obtain the ownership. If a thread takes ownership of the mutex the mutex must be unlocked by the same mutex. If the mutex supports recursive locking, the mutex must be unlocked the same number of times it is locked. + The calling thread tries to obtain ownership of the mutex, and if another thread has ownership of the mutex, it waits until it can obtain the ownership. If a thread takes ownership of the mutex the mutex must be unlocked by the same thread. If the mutex supports recursive locking, the mutex must be unlocked the same number of times it is locked. [*Throws:] *interprocess_exception* on error. @@ -4935,6 +4968,41 @@ Boost.Interprocess containers: [endsect] +[section:additional_containers Boost containers compatible with Boost.Interprocess] + +As mentioned, container developers might need to change their implementation to make them +compatible with Boost.Interprocess, because implementation usually ignore allocators with +smart pointers. Hopefully several Boost containers are compatible with [*Interprocess]. + +[section:unordered Boost unordered containers] + +[*Boost.Unordered] containers are compatible with Interprocess, so programmers can store +hash containers in shared memory and memory mapped files. Here's an small example storing +`unordered_map` in shared memory: + +[import ../example/doc_unordered_map.cpp] +[doc_unordered_map] + +[endsect] + +[section:multi_index Boost.MultiIndex containers] + +The widely used [*Boost.MultiIndex] library is compatible with [*Boost.Interprocess] so +we can construct pretty good databases in shared memory. Constructing databases in shared +memory is a bit tougher than in normal memory, usually because those databases contain strings +and those strings need to be placed in shared memory. Shared memory strings require +an allocator in their constructors so this usually makes object insertion a bit more +complicated. + +Here's is an example that shows how to put a multi index container in shared memory: + +[import ../example/doc_multi_index.cpp] +[doc_multi_index] + +[endsect] + +[endsect] + [section:memory_algorithms Memory allocation algorithms] [section:simple_seq_fit simple_seq_fit: A simple shared memory management algorithm] @@ -6262,7 +6330,7 @@ will manage the index. `segment_manager` will define interesting internal types For example, the index type `flat_map_index` based in `boost::interprocess::flat_map` is just defined as: -[import ../../../boost/interprocess/indexes/flat_map_index.hpp] +[import ../../boost/interprocess/indexes/flat_map_index.hpp] [flat_map_index] @@ -6385,6 +6453,12 @@ warranty. [section:release_notes Release Notes] +[section:release_notes_boost_1_36_00 Boost 1.36 Release] + +* Added anonymous shared memory for UNIX systems. + +[endsect] + [section:release_notes_boost_1_35_00 Boost 1.35 Release] * Added auxiliary utilities to ease the definition and construction of @@ -6654,20 +6728,6 @@ But the work to implement PF_UNIX-like sockets and doors would be huge [endsect] -[section:future_containers Unordered associative containers and other containers] - -We should be able to construct boost::unordered_xxx family in managed memory segments, -so that there is no code duplication in boost. So [*Boost.Interprocess] should cooperate -with boost container developers instead of duplicating effort writing it's own containers. - -A very interesting project is making [*boost::multi_index] compatible with -[*Boost.Interprocess] ready for shared memory. This could be a good basis for memory -mapped data-bases. The work to achieve this, however, can be huge. It would be -interesting a collaboration with [*Intrusive] library to achieve shared memory -intrusive containers. - -[endsect] - [endsect] [endsect] diff --git a/example/doc_anonymous_shared_memory.cpp b/example/doc_anonymous_shared_memory.cpp new file mode 100644 index 0000000..b0dbcf2 --- /dev/null +++ b/example/doc_anonymous_shared_memory.cpp @@ -0,0 +1,36 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007. 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 +//[doc_anonymous_shared_memory +#include +#include +#include +#include + +int main () +{ + using namespace boost::interprocess; + try{ + //Create an anonymous shared memory segment with size 1000 + mapped_region region(anonymous_shared_memory(1000)); + + //Write all the memory to 1 + std::memset(region.get_address(), 1, region.get_size()); + + //The segment is unmapped when "region" goes out of scope + } + catch(interprocess_exception &ex){ + std::cout << ex.what() << std::endl; + return 1; + } + return 0; +} +//] +#include diff --git a/example/doc_multi_index.cpp b/example/doc_multi_index.cpp new file mode 100644 index 0000000..24cbd63 --- /dev/null +++ b/example/doc_multi_index.cpp @@ -0,0 +1,91 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007. 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 +#include +//[doc_multi_index +#include +#include +#include + +#include +#include +#include + +using namespace boost::interprocess; +namespace bmi = boost::multi_index; + +typedef managed_shared_memory::allocator::type char_allocator; +typedef basic_string, char_allocator>shm_string; + +//Data to insert in shared memory +struct employee +{ + int id; + int age; + shm_string name; + employee( int id_ + , int age_ + , const char *name_ + , const char_allocator &a) + : id(id_), age(age_), name(name_, a) + {} +}; + +//Tags +struct id{}; +struct age{}; +struct name{}; + +// Define a multi_index_container of employees with following indices: +// - a unique index sorted by employee::int, +// - a non-unique index sorted by employee::name, +// - a non-unique index sorted by employee::age. +typedef bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + managed_shared_memory::allocator::type +> employee_set; + +int main () +{ + //Erase previous shared memory with the name + shared_memory_object::remove("MySharedMemory"); + + try{ + //Create shared memory + managed_shared_memory segment(create_only,"MySharedMemory", 65536); + + //Construct the multi_index in shared memory + employee_set *es = segment.construct + ("My MultiIndex Container") //Container's name in shared memory + ( employee_set::ctor_args_list() + , segment.get_allocator()); //Ctor parameters + + //Now insert elements + char_allocator ca(segment.get_allocator()); + es->insert(employee(0,31, "Joe", ca)); + es->insert(employee(1,27, "Robert", ca)); + es->insert(employee(2,40, "John", ca)); + } + catch(...){ + shared_memory_object::remove("MySharedMemory"); + throw; + } + shared_memory_object::remove("MySharedMemory"); + return 0; +} +//] +#include diff --git a/example/doc_unordered_map.cpp b/example/doc_unordered_map.cpp new file mode 100644 index 0000000..3839c6f --- /dev/null +++ b/example/doc_unordered_map.cpp @@ -0,0 +1,66 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007. 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 +#include +//[doc_unordered_map +#include +#include + +#include //boost::unordered_map +#include //std::equal_to +#include //boost::hash + +int main () +{ + using namespace boost::interprocess; + //Erase previous shared memory with the name + shared_memory_object::remove("MySharedMemory"); + + try{ + //Create shared memory + managed_shared_memory segment(create_only ,"MySharedMemory" ,65536); + + //Note that unordered_map's value_type is std::pair, + //so the allocator must allocate that pair. + typedef int KeyType; + typedef float MappedType; + typedef std::pair ValueType; + + //Typedef the allocator + typedef allocator ShmemAllocator; + + //Alias an unordered_map of ints that uses the previous STL-like allocator. + typedef boost::unordered_map + < KeyType , MappedType + , boost::hash ,std::equal_to + , ShmemAllocator> + MyHashMap; + + //Construct a shared memory hash map. + //Note that the first parameter is the initial bucket count and + //after that, the hash function, the equality function and the allocator + MyHashMap *myhashmap = segment.construct("MyHashMap") //object name + ( 3, boost::hash(), std::equal_to() // + , segment.get_allocator()); //allocator instance + + //Insert data in the hash map + for(int i = 0; i < 100; ++i){ + myhashmap->insert(ValueType(i, (float)i)); + } + } + catch(...){ + shared_memory_object::remove("MySharedMemory"); + throw; + } + shared_memory_object::remove("MySharedMemory"); + return 0; +} +//] +#include diff --git a/include/boost/interprocess/allocators/adaptive_pool.hpp b/include/boost/interprocess/allocators/adaptive_pool.hpp index 0c00006..01b2b06 100644 --- a/include/boost/interprocess/allocators/adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/adaptive_pool.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,7 @@ namespace interprocess { /// @cond namespace detail{ - +/* template < unsigned int Version , class T , class SegmentManager @@ -61,8 +62,9 @@ class adaptive_pool_base typedef SegmentManager segment_manager; typedef adaptive_pool_base self_t; + static const std::size_t SizeOfT = sizeof(detail::if_c::value, int, T>::type); typedef detail::shared_adaptive_node_pool - < SegmentManager, sizeof(T), NodesPerChunk, MaxFreeChunks, OverheadPercent> node_pool_t; + < SegmentManager, SizeOfT, NodesPerChunk, MaxFreeChunks, OverheadPercent> node_pool_t; typedef typename detail:: pointer_to_other::type node_pool_ptr; @@ -157,19 +159,153 @@ class adaptive_pool_base node_pool_ptr mp_node_pool; /// @endcond }; +*/ + +template < unsigned int Version + , class T + , class SegmentManager + , std::size_t NodesPerChunk + , std::size_t MaxFreeChunks + , unsigned char OverheadPercent + > +class adaptive_pool_base + : public node_pool_allocation_impl + < adaptive_pool_base + < Version, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> + , Version + , T + , SegmentManager + > +{ + public: + typedef typename SegmentManager::void_pointer void_pointer; + typedef SegmentManager segment_manager; + typedef adaptive_pool_base + self_t; + + /// @cond + + template + struct node_pool + { + typedef detail::shared_adaptive_node_pool + < SegmentManager, sizeof(T), NodesPerChunk, MaxFreeChunks, OverheadPercent> type; + + static type *get(void *p) + { return static_cast(p); } + }; + /// @endcond + + BOOST_STATIC_ASSERT((Version <=2)); + + public: + //------- + typedef typename detail:: + pointer_to_other::type pointer; + typedef typename detail:: + pointer_to_other::type const_pointer; + typedef T value_type; + typedef typename detail::add_reference + ::type reference; + typedef typename detail::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef detail::version_type version; + typedef transform_iterator + < typename SegmentManager:: + multiallocation_iterator + , detail::cast_functor > multiallocation_iterator; + typedef typename SegmentManager:: + multiallocation_chain multiallocation_chain; + + //!Obtains adaptive_pool_base from + //!adaptive_pool_base + template + struct rebind + { + typedef adaptive_pool_base other; + }; + + /// @cond + private: + //!Not assignable from related adaptive_pool_base + template + adaptive_pool_base& operator= + (const adaptive_pool_base&); + + /// @endcond + + public: + //!Constructor from a segment manager. If not present, constructs a node + //!pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + adaptive_pool_base(segment_manager *segment_mngr) + : mp_node_pool(detail::get_or_create_node_pool::type>(segment_mngr)) { } + + //!Copy constructor from other adaptive_pool_base. Increments the reference + //!count of the associated node pool. Never throws + adaptive_pool_base(const adaptive_pool_base &other) + : mp_node_pool(other.get_node_pool()) + { + node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count(); + } + + //!Assignment from other adaptive_pool_base + adaptive_pool_base& operator=(const adaptive_pool_base &other) + { + adaptive_pool_base c(other); + swap(*this, c); + return *this; + } + + //!Copy constructor from related adaptive_pool_base. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + adaptive_pool_base + (const adaptive_pool_base &other) + : mp_node_pool(detail::get_or_create_node_pool::type>(other.get_segment_manager())) { } + + //!Destructor, removes node_pool_t from memory + //!if its reference count reaches to zero. Never throws + ~adaptive_pool_base() + { detail::destroy_node_pool_if_last_link(node_pool<0>::get(detail::get_pointer(mp_node_pool))); } + + //!Returns a pointer to the node pool. + //!Never throws + void* get_node_pool() const + { return detail::get_pointer(mp_node_pool); } + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const + { return node_pool<0>::get(detail::get_pointer(mp_node_pool))->get_segment_manager(); } + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2) + { detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); } + + /// @cond + private: + void_pointer mp_node_pool; + /// @endcond +}; //!Equality test for same type //!of adaptive_pool_base -template inline -bool operator==(const adaptive_pool_base &alloc1, - const adaptive_pool_base &alloc2) +template inline +bool operator==(const adaptive_pool_base &alloc1, + const adaptive_pool_base &alloc2) { return alloc1.get_node_pool() == alloc2.get_node_pool(); } //!Inequality test for same type //!of adaptive_pool_base -template inline -bool operator!=(const adaptive_pool_base &alloc1, - const adaptive_pool_base &alloc2) +template inline +bool operator!=(const adaptive_pool_base &alloc1, + const adaptive_pool_base &alloc2) { return alloc1.get_node_pool() != alloc2.get_node_pool(); } template < class T @@ -299,7 +435,7 @@ class adaptive_pool //!Not assignable from //!other adaptive_pool - adaptive_pool& operator=(const adaptive_pool&); + //adaptive_pool& operator=(const adaptive_pool&); public: //!Constructor from a segment manager. If not present, constructs a node @@ -324,7 +460,7 @@ class adaptive_pool //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const; + void* get_node_pool() const; //!Returns the segment manager. //!Never throws @@ -358,9 +494,9 @@ class adaptive_pool //!Never throws const_pointer address(const_reference value) const; - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr); + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index 08136dc..f5cbbb1 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -106,8 +106,6 @@ class allocator multiallocation_chain; -// typedef typename SegmentManager:: -// multiallocation_chain multiallocation_chain; /// @endcond @@ -153,7 +151,7 @@ class allocator //!Deallocates memory previously allocated. //!Never throws void deallocate(const pointer &ptr, size_type) - { mp_mngr->deallocate(detail::get_pointer(ptr)); } + { mp_mngr->deallocate((void*)detail::get_pointer(ptr)); } //!Returns the number of elements that could be allocated. //!Never throws @@ -253,10 +251,15 @@ class allocator const_pointer address(const_reference value) const { return const_pointer(boost::addressof(value)); } + //!Copy construct an object + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v) + { new((void*)detail::get_pointer(ptr)) value_type(v); } + //!Default construct an object. //!Throws if T's default constructor throws void construct(const pointer &ptr) - { new(detail::get_pointer(ptr)) value_type; } + { new((void*)detail::get_pointer(ptr)) value_type; } //!Destroys object. Throws if object's //!destructor throws diff --git a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp index ec75948..0b31f0a 100644 --- a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -119,7 +119,7 @@ class cached_adaptive_pool < T , detail::shared_adaptive_node_pool < SegmentManager - , sizeof(T) + , sizeof(typename detail::if_c::value, int, T>::type) , NodesPerChunk , MaxFreeChunks , OverheadPercent @@ -252,9 +252,9 @@ class cached_adaptive_pool //!Never throws const_pointer address(const_reference value) const; - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr); + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp index 4ee4767..6d470de 100644 --- a/include/boost/interprocess/allocators/cached_node_allocator.hpp +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -225,7 +225,7 @@ class cached_node_allocator //!Default construct an object. //!Throws if T's default constructor throws - void construct(const pointer &ptr); + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws @@ -302,15 +302,15 @@ class cached_node_allocator //!Equality test for same type //!of cached_node_allocator -template inline -bool operator==(const cached_node_allocator &alloc1, - const cached_node_allocator &alloc2); +template inline +bool operator==(const cached_node_allocator &alloc1, + const cached_node_allocator &alloc2); //!Inequality test for same type //!of cached_node_allocator -template inline -bool operator!=(const cached_node_allocator &alloc1, - const cached_node_allocator &alloc2); +template inline +bool operator!=(const cached_node_allocator &alloc1, + const cached_node_allocator &alloc2); #endif diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index 87fea06..0495f41 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -49,7 +49,7 @@ class private_adaptive_node_pool_impl private_adaptive_node_pool_impl &operator=(const private_adaptive_node_pool_impl &); typedef typename SegmentManagerBase::void_pointer void_pointer; - + static const std::size_t PayloadPerAllocation = SegmentManagerBase::PayloadPerAllocation; public: typedef typename node_slist::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; @@ -106,9 +106,11 @@ class private_adaptive_node_pool_impl std::size_t candidate_power_of_2 = upper_power_of_2(elements_per_subchunk*real_node_size + HdrOffsetSize); bool overhead_satisfied = false; + //Now calculate the wors-case overhead for a subchunk + const std::size_t max_subchunk_overhead = HdrSize + PayloadPerAllocation; while(!overhead_satisfied){ - elements_per_subchunk = (candidate_power_of_2 - HdrOffsetSize)/real_node_size; - std::size_t overhead_size = candidate_power_of_2 - elements_per_subchunk*real_node_size; + elements_per_subchunk = (candidate_power_of_2 - max_subchunk_overhead)/real_node_size; + const std::size_t overhead_size = candidate_power_of_2 - elements_per_subchunk*real_node_size; if(overhead_size*100/candidate_power_of_2 < overhead_percent){ overhead_satisfied = true; } @@ -121,14 +123,26 @@ class private_adaptive_node_pool_impl static void calculate_num_subchunks (std::size_t alignment, std::size_t real_node_size, std::size_t elements_per_chunk - ,std::size_t &num_subchunks, std::size_t &real_num_node) + ,std::size_t &num_subchunks, std::size_t &real_num_node, std::size_t overhead_percent) { std::size_t elements_per_subchunk = (alignment - HdrOffsetSize)/real_node_size; std::size_t possible_num_subchunk = (elements_per_chunk - 1)/elements_per_subchunk + 1; - std::size_t hdr_subchunk_elements = (alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/real_node_size; + std::size_t hdr_subchunk_elements = (alignment - HdrSize - PayloadPerAllocation)/real_node_size; while(((possible_num_subchunk-1)*elements_per_subchunk + hdr_subchunk_elements) < elements_per_chunk){ ++possible_num_subchunk; } + elements_per_subchunk = (alignment - HdrOffsetSize)/real_node_size; + bool overhead_satisfied = false; + while(!overhead_satisfied){ + const std::size_t total_data = (elements_per_subchunk*(possible_num_subchunk-1) + hdr_subchunk_elements)*real_node_size; + const std::size_t total_size = alignment*possible_num_subchunk; + if((total_size - total_data)*100/total_size < overhead_percent){ + overhead_satisfied = true; + } + else{ + ++possible_num_subchunk; + } + } num_subchunks = possible_num_subchunk; real_num_node = (possible_num_subchunk-1)*elements_per_subchunk + hdr_subchunk_elements; } @@ -157,7 +171,7 @@ class private_adaptive_node_pool_impl , m_chunk_multiset() , m_totally_free_chunks(0) { - calculate_num_subchunks(m_real_chunk_alignment, m_real_node_size, nodes_per_chunk, m_num_subchunks, m_real_num_node); + calculate_num_subchunks(m_real_chunk_alignment, m_real_node_size, nodes_per_chunk, m_num_subchunks, m_real_num_node, overhead_percent); } //!Destructor. Deallocates all allocated chunks. Never throws diff --git a/include/boost/interprocess/allocators/detail/allocator_common.hpp b/include/boost/interprocess/allocators/detail/allocator_common.hpp index da18fc9..bd64f3c 100644 --- a/include/boost/interprocess/allocators/detail/allocator_common.hpp +++ b/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -342,7 +342,12 @@ class array_allocation_impl //!Default construct an object. //!Throws if T's default constructor throws void construct(const pointer &ptr) - { new(detail::get_pointer(ptr)) value_type; } + { new((void*)detail::get_pointer(ptr)) value_type; } + + //!Copy construct an object + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v) + { new((void*)detail::get_pointer(ptr)) value_type(v); } //!Destroys object. Throws if object's //!destructor throws @@ -386,36 +391,53 @@ class node_pool_allocation_impl typedef typename SegmentManager:: multiallocation_chain multiallocation_chain; + template + struct node_pool + { + typedef typename Derived::template node_pool<0>::type type; + static type *get(void *p) + { return static_cast(p); } + }; + public: //!Allocate memory for an array of count elements. //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate(size_type count, cvoid_pointer hint = 0) { (void)hint; + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); if(count > this->max_size()) throw bad_alloc(); else if(Version == 1 && count == 1) - return pointer(static_cast(this->derived()->get_node_pool()->allocate_node())); + return pointer(static_cast + (pool->allocate_node())); else return pointer(static_cast - (this->derived()->get_node_pool()->get_segment_manager()->allocate(sizeof(T)*count))); + (pool->get_segment_manager()->allocate(sizeof(T)*count))); } //!Deallocate allocated memory. Never throws void deallocate(const pointer &ptr, size_type count) { (void)count; + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); if(Version == 1 && count == 1) - this->derived()->get_node_pool()->deallocate_node(detail::get_pointer(ptr)); + pool->deallocate_node(detail::get_pointer(ptr)); else - this->derived()->get_node_pool()->get_segment_manager()->deallocate(detail::get_pointer(ptr)); + pool->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr)); } //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one() - { return pointer(static_cast(this->derived()->get_node_pool()->allocate_node())); } + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + return pointer(static_cast(pool->allocate_node())); + } //!Allocates many elements of size == 1 in a contiguous chunk //!of memory. The minimum number to be allocated is min_elements, @@ -424,13 +446,21 @@ class node_pool_allocation_impl //!will be assigned to received_size. Memory allocated with this function //!must be deallocated only with deallocate_one(). multiallocation_iterator allocate_individual(std::size_t num_elements) - { return multiallocation_iterator(this->derived()->get_node_pool()->allocate_nodes(num_elements)); } + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + return multiallocation_iterator(pool->allocate_nodes(num_elements)); + } //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p) - { this->derived()->get_node_pool()->deallocate_node(detail::get_pointer(p)); } + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + pool->deallocate_node(detail::get_pointer(p)); + } //!Allocates many elements of size == 1 in a contiguous chunk //!of memory. The minimum number to be allocated is min_elements, @@ -439,11 +469,11 @@ class node_pool_allocation_impl //!will be assigned to received_size. Memory allocated with this function //!must be deallocated only with deallocate_one(). void deallocate_individual(multiallocation_iterator it) - { this->derived()->get_node_pool()->deallocate_nodes(it.base()); } + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes(it.base()); } //!Deallocates all free chunks of the pool void deallocate_free_chunks() - { this->derived()->get_node_pool()->deallocate_free_chunks(); } + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_chunks(); } }; template @@ -536,7 +566,7 @@ class cached_allocator_impl m_cache.cached_deallocation(detail::get_pointer(ptr)); } else{ - this->get_segment_manager()->deallocate(detail::get_pointer(ptr)); + this->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr)); } } diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index cfcbcf8..3418d9f 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -253,7 +253,7 @@ class private_node_pool_impl while(!m_chunklist.empty()){ void *addr = get_chunk_from_hook(&m_chunklist.front(), blocksize); m_chunklist.pop_front(); - mp_segment_mngr_base->deallocate(addr); + mp_segment_mngr_base->deallocate((void*)addr); } //Just clear free node list m_freelist.clear(); diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp index eed6e9e..fabc3af 100644 --- a/include/boost/interprocess/allocators/node_allocator.hpp +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -59,10 +59,19 @@ class node_allocator_base typedef SegmentManager segment_manager; typedef node_allocator_base self_t; - typedef detail::shared_node_pool - < SegmentManager, sizeof(T), NodesPerChunk> node_pool_t; - typedef typename detail:: - pointer_to_other::type node_pool_ptr; + + /// @cond + + template + struct node_pool + { + typedef detail::shared_node_pool + < SegmentManager, sizeof(T), NodesPerChunk> type; + + static type *get(void *p) + { return static_cast(p); } + }; + /// @endcond BOOST_STATIC_ASSERT((Version <=2)); @@ -104,7 +113,7 @@ class node_allocator_base (const node_allocator_base&); //!Not assignable from other node_allocator_base - node_allocator_base& operator=(const node_allocator_base&); + //node_allocator_base& operator=(const node_allocator_base&); /// @endcond public: @@ -112,14 +121,14 @@ class node_allocator_base //!pool. Increments the reference count of the associated node pool. //!Can throw boost::interprocess::bad_alloc node_allocator_base(segment_manager *segment_mngr) - : mp_node_pool(detail::get_or_create_node_pool(segment_mngr)) { } + : mp_node_pool(detail::get_or_create_node_pool::type>(segment_mngr)) { } //!Copy constructor from other node_allocator_base. Increments the reference //!count of the associated node pool. Never throws node_allocator_base(const node_allocator_base &other) : mp_node_pool(other.get_node_pool()) { - mp_node_pool->inc_ref_count(); + node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count(); } //!Copy constructor from related node_allocator_base. If not present, constructs @@ -128,22 +137,30 @@ class node_allocator_base template node_allocator_base (const node_allocator_base &other) - : mp_node_pool(detail::get_or_create_node_pool(other.get_segment_manager())) { } + : mp_node_pool(detail::get_or_create_node_pool::type>(other.get_segment_manager())) { } + + //!Assignment from other node_allocator_base + node_allocator_base& operator=(const node_allocator_base &other) + { + node_allocator_base c(other); + swap(*this, c); + return *this; + } //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws ~node_allocator_base() - { detail::destroy_node_pool_if_last_link(detail::get_pointer(mp_node_pool)); } + { detail::destroy_node_pool_if_last_link(node_pool<0>::get(detail::get_pointer(mp_node_pool))); } //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const + void* get_node_pool() const { return detail::get_pointer(mp_node_pool); } //!Returns the segment manager. //!Never throws segment_manager* get_segment_manager()const - { return mp_node_pool->get_segment_manager(); } + { return node_pool<0>::get(detail::get_pointer(mp_node_pool))->get_segment_manager(); } //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -152,22 +169,22 @@ class node_allocator_base /// @cond private: - node_pool_ptr mp_node_pool; + void_pointer mp_node_pool; /// @endcond }; //!Equality test for same type //!of node_allocator_base -template inline -bool operator==(const node_allocator_base &alloc1, - const node_allocator_base &alloc2) +template inline +bool operator==(const node_allocator_base &alloc1, + const node_allocator_base &alloc2) { return alloc1.get_node_pool() == alloc2.get_node_pool(); } //!Inequality test for same type //!of node_allocator_base -template inline -bool operator!=(const node_allocator_base &alloc1, - const node_allocator_base &alloc2) +template inline +bool operator!=(const node_allocator_base &alloc1, + const node_allocator_base &alloc2) { return alloc1.get_node_pool() != alloc2.get_node_pool(); } template < class T @@ -283,7 +300,7 @@ class node_allocator //!Not assignable from //!other node_allocator - node_allocator& operator=(const node_allocator&); + //node_allocator& operator=(const node_allocator&); public: //!Constructor from a segment manager. If not present, constructs a node @@ -308,7 +325,7 @@ class node_allocator //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const; + void* get_node_pool() const; //!Returns the segment manager. //!Never throws @@ -342,9 +359,9 @@ class node_allocator //!Never throws const_pointer address(const_reference value) const; - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr); + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws @@ -414,15 +431,15 @@ class node_allocator //!Equality test for same type //!of node_allocator -template inline -bool operator==(const node_allocator &alloc1, - const node_allocator &alloc2); +template inline +bool operator==(const node_allocator &alloc1, + const node_allocator &alloc2); //!Inequality test for same type //!of node_allocator -template inline -bool operator!=(const node_allocator &alloc1, - const node_allocator &alloc2); +template inline +bool operator!=(const node_allocator &alloc1, + const node_allocator &alloc2); #endif diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index 5552348..0e34ba4 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -104,6 +104,22 @@ class private_adaptive_pool_base }; /// @cond + + template + struct node_pool + { + typedef detail::private_adaptive_node_pool + type; + + static type *get(void *p) + { return static_cast(p); } + }; + private: //!Not assignable from related private_adaptive_pool_base template @@ -355,9 +371,9 @@ class private_adaptive_pool //!Never throws const_pointer address(const_reference value) const; - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr); + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index 608bacc..9db03a6 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -7,201 +7,6 @@ // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// -/* -#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP -#define BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP - -#if (defined _MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//!\file -//!Describes private_node_allocator pooled shared memory STL compatible allocator - -namespace boost { -namespace interprocess { - -//!An STL node allocator that uses a segment manager as memory -//!source. The internal pointer type will of the same type (raw, smart) as -//!"typename SegmentManager::void_pointer" type. This allows -//!placing the allocator in shared memory, memory mapped-files, etc... -//!This allocator has its own node pool. NodesPerChunk is the number of nodes allocated -//!at once when the allocator needs runs out of nodes -template -class private_node_allocator -{ - /// @cond - private: - typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: - pointer_to_other::type cvoid_pointer; - typedef SegmentManager segment_manager; - typedef typename detail::pointer_to_other - ::type segment_mngr_ptr_t; - typedef private_node_allocator - self_t; - typedef detail::private_node_pool - priv_node_pool_t; - /// @endcond - - public: - //------- - typedef typename detail:: - pointer_to_other::type pointer; - typedef typename detail:: - pointer_to_other::type const_pointer; - typedef T value_type; - typedef typename detail::add_reference - ::type reference; - typedef typename detail::add_reference - ::type const_reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - //!Obtains node_allocator from other node_allocator - template - struct rebind - { - typedef private_node_allocator other; - }; - - /// @cond - private: - //!Not assignable from related private_node_allocator - template - private_node_allocator& operator= - (const private_node_allocator&); - - //!Not assignable from other private_node_allocator - private_node_allocator& operator=(const private_node_allocator&); - /// @endcond - - public: - - //!Constructor from a segment manager - private_node_allocator(segment_manager *segment_mngr) - : m_node_pool(segment_mngr){} - - //!Copy constructor from other private_node_allocator. Never throws - private_node_allocator(const private_node_allocator &other) - : m_node_pool(other.get_segment_manager()){} - - //!Copy constructor from related private_node_allocator. Never throws. - template - private_node_allocator - (const private_node_allocator &other) - : m_node_pool(other.get_segment_manager()) - {} - - //!Destructor, frees all used memory. Never throws - ~private_node_allocator() - {} - - //!Returns the segment manager. Never throws - segment_manager* get_segment_manager()const - { return m_node_pool.get_segment_manager(); } - - //!Returns the number of elements that could be allocated. Never throws - size_type max_size() const - { return this->get_segment_manager()->get_size()/sizeof(value_type); } - - //!Allocate memory for an array of count elements. - //!Throws boost::interprocess::bad_alloc if there is no enough memory - pointer allocate(size_type count, cvoid_pointer hint = 0) - { - (void)hint; - if(count > this->max_size()) - throw bad_alloc(); - else if(count == 1) - return pointer(static_cast(m_node_pool.allocate_node())); - else - return pointer(static_cast - (m_node_pool.get_segment_manager()->allocate(sizeof(T)*count))); - } - - //!Deallocate allocated memory. Never throws - void deallocate(const pointer &ptr, size_type count) - { - if(count == 1) - m_node_pool.deallocate_node(detail::get_pointer(ptr)); - else - m_node_pool.get_segment_manager()->deallocate(detail::get_pointer(ptr)); - } - - //!Deallocates all free chunks of the pool - void deallocate_free_chunks() - { m_node_pool.deallocate_free_chunks(); } - - //!Swaps allocators. Does not throw. If each allocator is placed in a - //!different shared memory segments, the result is undefined. - friend void swap(self_t &alloc1,self_t &alloc2) - { alloc1.m_node_pool.swap(alloc2.m_node_pool); } - - //These functions are obsolete. These are here to conserve - //backwards compatibility with containers using them... - - //!Returns address of mutable object. - //!Never throws - pointer address(reference value) const - { return pointer(boost::addressof(value)); } - - //!Returns address of non mutable object. - //!Never throws - const_pointer address(const_reference value) const - { return const_pointer(boost::addressof(value)); } - - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr) - { new(detail::get_pointer(ptr)) value_type; } - - //!Destroys object. Throws if object's - //!destructor throws - void destroy(const pointer &ptr) - { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } - - /// @cond - private: - priv_node_pool_t m_node_pool; - /// @endcond -}; - -//!Equality test for same type of private_node_allocator -template inline -bool operator==(const private_node_allocator &alloc1, - const private_node_allocator &alloc2) -{ return &alloc1 == &alloc2; } - -//!Inequality test for same type of private_node_allocator -template inline -bool operator!=(const private_node_allocator &alloc1, - const private_node_allocator &alloc2) -{ - return &alloc1 != &alloc2; -} - -} //namespace interprocess { -} //namespace boost { - -#include - -#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP - -*/ ////////////////////////////////////////////////////////////////////////////// // @@ -303,6 +108,19 @@ class private_node_allocator_base }; /// @cond + template + struct node_pool + { + typedef detail::private_node_pool + type; + + static type *get(void *p) + { return static_cast(p); } + }; + private: //!Not assignable from related private_node_allocator_base template @@ -356,15 +174,15 @@ class private_node_allocator_base }; //!Equality test for same type of private_node_allocator_base -template inline -bool operator==(const private_node_allocator_base &alloc1, - const private_node_allocator_base &alloc2) +template inline +bool operator==(const private_node_allocator_base &alloc1, + const private_node_allocator_base &alloc2) { return &alloc1 == &alloc2; } //!Inequality test for same type of private_node_allocator_base -template inline -bool operator!=(const private_node_allocator_base &alloc1, - const private_node_allocator_base &alloc2) +template inline +bool operator!=(const private_node_allocator_base &alloc1, + const private_node_allocator_base &alloc2) { return &alloc1 != &alloc2; } template < class T @@ -539,9 +357,9 @@ class private_node_allocator //!Never throws const_pointer address(const_reference value) const; - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr); + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp index 0b7183d..9359db3 100644 --- a/include/boost/interprocess/containers/deque.hpp +++ b/include/boost/interprocess/containers/deque.hpp @@ -658,7 +658,7 @@ class deque : protected deque_base void push_back(const value_type& t) { if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); ++this->members_.m_finish.m_cur; } else @@ -669,7 +669,7 @@ class deque : protected deque_base void push_back(const detail::moved_object &mt) { if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); ++this->members_.m_finish.m_cur; } else @@ -679,7 +679,7 @@ class deque : protected deque_base void push_back(value_type &&mt) { if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); ++this->members_.m_finish.m_cur; } else @@ -690,7 +690,7 @@ class deque : protected deque_base void push_front(const value_type& t) { if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new(detail::get_pointer(this->members_.m_start.m_cur)- 1)value_type(t); + new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(t); --this->members_.m_start.m_cur; } else @@ -701,7 +701,7 @@ class deque : protected deque_base void push_front(const detail::moved_object &mt) { if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new(detail::get_pointer(this->members_.m_start.m_cur)- 1)value_type(mt); + new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(mt); --this->members_.m_start.m_cur; } else @@ -711,7 +711,7 @@ class deque : protected deque_base void push_front(value_type &&mt) { if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new(detail::get_pointer(this->members_.m_start.m_cur)- 1)value_type(move(mt)); + new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(move(mt)); --this->members_.m_start.m_cur; } else @@ -1217,7 +1217,7 @@ class deque : protected deque_base this->priv_reserve_map_at_back(); *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); BOOST_TRY { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node + 1); this->members_.m_finish.m_cur = this->members_.m_finish.m_first; } @@ -1235,7 +1235,7 @@ class deque : protected deque_base this->priv_reserve_map_at_back(); *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); BOOST_TRY { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node + 1); this->members_.m_finish.m_cur = this->members_.m_finish.m_first; } @@ -1251,7 +1251,7 @@ class deque : protected deque_base this->priv_reserve_map_at_back(); *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); BOOST_TRY { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node + 1); this->members_.m_finish.m_cur = this->members_.m_finish.m_first; } @@ -1271,7 +1271,7 @@ class deque : protected deque_base BOOST_TRY { this->members_.m_start.priv_set_node(this->members_.m_start.m_node - 1); this->members_.m_start.m_cur = this->members_.m_start.m_last - 1; - new(detail::get_pointer(this->members_.m_start.m_cur))value_type(t); + new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(t); } BOOST_CATCH(...){ ++this->members_.m_start; @@ -1289,7 +1289,7 @@ class deque : protected deque_base BOOST_TRY { this->members_.m_start.priv_set_node(this->members_.m_start.m_node - 1); this->members_.m_start.m_cur = this->members_.m_start.m_last - 1; - new(detail::get_pointer(this->members_.m_start.m_cur))value_type(mt); + new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(mt); } BOOST_CATCH(...){ ++this->members_.m_start; @@ -1306,7 +1306,7 @@ class deque : protected deque_base BOOST_TRY { this->members_.m_start.priv_set_node(this->members_.m_start.m_node - 1); this->members_.m_start.m_cur = this->members_.m_start.m_last - 1; - new(detail::get_pointer(this->members_.m_start.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(move(mt)); } BOOST_CATCH(...){ ++this->members_.m_start; diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp index 19901ca..2f9f73a 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp @@ -145,15 +145,15 @@ struct node_alloc_holder #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template static void construct(const NodePtr &ptr, const Convertible &value) - { new(detail::get_pointer(ptr)) Node(value); } + { new((void*)detail::get_pointer(ptr)) Node(value); } #else template static void construct(const NodePtr &ptr, Convertible &&value) - { new(detail::get_pointer(ptr)) Node(forward(value)); } + { new((void*)detail::get_pointer(ptr)) Node(forward(value)); } #endif static void construct(const NodePtr &ptr) - { new(detail::get_pointer(ptr)) Node(); } + { new((void*)detail::get_pointer(ptr)) Node(); } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index 1c83a75..c1d0c90 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -308,7 +308,7 @@ class basic_string_base } void construct(pointer p, const value_type &value = value_type()) - { new(detail::get_pointer(p)) value_type(value); } + { new((void*)detail::get_pointer(p)) value_type(value); } void destroy(pointer p, size_type n) { diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index f1af804..561c87d 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -301,8 +301,8 @@ struct vector_alloc_holder const pointer &reuse, allocator_v2) { - return this->alloc().allocation_command(command, limit_size, preferred_size, - received_size, reuse); + return this->alloc().allocation_command + (command, limit_size, preferred_size, received_size, reuse); } size_type next_capacity(size_type additional_objects) const @@ -434,7 +434,7 @@ class vector : private detail::vector_alloc_holder //This is the optimized move iterator for copy constructors //so that std::copy and similar can use memcpy typedef typename detail::if_c - ::value ,T* ,detail::move_iterator >::type copy_move_it; @@ -442,7 +442,7 @@ class vector : private detail::vector_alloc_holder //This is the optimized move iterator for assignments //so that std::uninitialized_copy and similar can use memcpy typedef typename detail::if_c - ::value ,T* ,detail::move_iterator >::type assign_move_it; @@ -859,7 +859,7 @@ class vector : private detail::vector_alloc_holder { if (this->members_.m_size < this->members_.m_capacity){ //There is more memory, just construct a new object at the end - new(detail::get_pointer(this->members_.m_start) + this->members_.m_size)value_type(x); + new((void*)(detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x); ++this->members_.m_size; } else{ @@ -878,7 +878,7 @@ class vector : private detail::vector_alloc_holder { if (this->members_.m_size < this->members_.m_capacity){ //There is more memory, just construct a new object at the end - new(detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(mx); + new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(mx); ++this->members_.m_size; } else{ @@ -890,7 +890,7 @@ class vector : private detail::vector_alloc_holder { if (this->members_.m_size < this->members_.m_capacity){ //There is more memory, just construct a new object at the end - new(detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(move(mx)); + new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(move(mx)); ++this->members_.m_size; } else{ @@ -1101,7 +1101,7 @@ class vector : private detail::vector_alloc_holder T *ptr = detail::get_pointer(this->members_.m_start + this->members_.m_size); while(n--){ //Default construct - new(ptr++)T(); + new((void*)ptr++)T(); ++this->members_.m_size; } } @@ -1241,9 +1241,9 @@ class vector : private detail::vector_alloc_holder std::uninitialized_copy(copy_move_it(old_finish - n), copy_move_it(old_finish), old_finish); this->members_.m_size += n; //Copy previous to last objects to the initialized end - std::copy_backward(assign_move_it(detail::get_pointer(pos)), assign_move_it(old_finish - n), old_finish); + std::copy_backward(assign_move_it(pos), assign_move_it(old_finish - n), old_finish); //Insert new objects in the pos - std::copy(first, last, detail::get_pointer(pos)); + std::copy(first, last, pos); } else { //The new elements don't fit in the [pos, end()) range. Copy @@ -1254,12 +1254,12 @@ class vector : private detail::vector_alloc_holder this->members_.m_size += n - elems_after; //Copy old [pos, end()) elements to the uninitialized memory std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) + ( copy_move_it(pos) , copy_move_it(old_finish) , detail::get_pointer(this->members_.m_start) + this->members_.m_size); this->members_.m_size += elems_after; //Copy first new elements in pos - std::copy(first, mid, detail::get_pointer(pos)); + std::copy(first, mid, pos); } } @@ -1277,7 +1277,7 @@ class vector : private detail::vector_alloc_holder //the start of the new buffer new_finish = std::uninitialized_copy ( copy_move_it(detail::get_pointer(this->members_.m_start)) - , copy_move_it(detail::get_pointer(pos)) + , copy_move_it(pos) , old_finish = new_finish); construted_values_destroyer.increment_size(new_finish - old_finish); //Initialize new objects, starting from previous point @@ -1287,9 +1287,9 @@ class vector : private detail::vector_alloc_holder //Initialize from the rest of the old buffer, //starting from previous point new_finish = std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) + ( copy_move_it(pos) , copy_move_it(detail::get_pointer(this->members_.m_start) + this->members_.m_size) - , detail::get_pointer(new_finish)); + , new_finish); //All construction successful, disable rollbacks construted_values_destroyer.release(); @@ -1345,13 +1345,11 @@ class vector : private detail::vector_alloc_holder //Copy first old values before pos, after that the //new objects boost::interprocess::uninitialized_copy_copy - (copy_move_it(old_start), copy_move_it(detail::get_pointer(pos)), first, last, detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(pos), first, last, new_start); UCopiedArrayDestructor new_values_destroyer(new_start, elemsbefore); //Now initialize the rest of memory with the last old values std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) - , copy_move_it(old_finish) - , detail::get_pointer(new_start) + elemsbefore + n); + (copy_move_it(pos), copy_move_it(old_finish), new_start + elemsbefore + n); //All new elements correctly constructed, avoid new element destruction new_values_destroyer.release(); this->members_.m_size = old_size + n; @@ -1376,17 +1374,13 @@ class vector : private detail::vector_alloc_holder //Copy first old values before pos, after that the //new objects boost::interprocess::uninitialized_copy_copy - ( copy_move_it(old_start) - , copy_move_it(detail::get_pointer(pos)) - , first, last, detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(pos), first, last, new_start); UCopiedArrayDestructor new_values_destroyer(new_start, elemsbefore); size_type raw_gap = s_before - (elemsbefore + n); //Now initialize the rest of s_before memory with the //first of elements after new values std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) - , copy_move_it(detail::get_pointer(pos) + raw_gap) - , detail::get_pointer(new_start) + elemsbefore + n); + (copy_move_it(pos), copy_move_it(pos + raw_gap), new_start + elemsbefore + n); //All new elements correctly constructed, avoid new element destruction new_values_destroyer.release(); //All new elements correctly constructed, avoid old element destruction @@ -1394,7 +1388,7 @@ class vector : private detail::vector_alloc_holder //Update size since we have a contiguous buffer this->members_.m_size = old_size + s_before; //Now copy remaining last objects in the old buffer begin - T *to_destroy = std::copy(assign_move_it(detail::get_pointer(pos) + raw_gap), assign_move_it(old_finish), old_start); + T *to_destroy = std::copy(assign_move_it(pos + raw_gap), assign_move_it(old_finish), old_start); //Now destroy redundant elements except if they were moved and //they have trivial destructor after move size_type n_destroy = old_finish - to_destroy; @@ -1460,24 +1454,22 @@ class vector : private detail::vector_alloc_holder //Copy the first part of old_begin to raw_mem T *start_n = old_start + difference_type(s_before); std::uninitialized_copy - ( copy_move_it(old_start) - , copy_move_it(start_n) - , detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(start_n), new_start); //The buffer is all constructed until old_end, //release destroyer and update size old_values_destroyer.release(); this->members_.m_size = old_size + s_before; //Now copy the second part of old_begin overwriting himself - T* next = std::copy(assign_move_it(start_n), assign_move_it(detail::get_pointer(pos)), old_start); + T* next = std::copy(assign_move_it(start_n), assign_move_it(pos), old_start); if(do_after){ //Now copy the new_beg elements - std::copy(first, before_end, detail::get_pointer(next)); + std::copy(first, before_end, next); } else{ //Now copy the all the new elements - T* move_start = std::copy(first, last, detail::get_pointer(next)); + T* move_start = std::copy(first, last, next); //Now displace old_end elements - T* move_end = std::copy(assign_move_it(detail::get_pointer(pos)), assign_move_it(old_finish), detail::get_pointer(move_start)); + T* move_end = std::copy(assign_move_it(pos), assign_move_it(old_finish), move_start); //Destroy remaining moved elements from old_end except if //they have trivial destructor after being moved difference_type n_destroy = s_before - n; @@ -1513,9 +1505,7 @@ class vector : private detail::vector_alloc_holder size_type n_new_init = difference_type(s_before) - elemsbefore; std::advance(mid, n_new_init); boost::interprocess::uninitialized_copy_copy - ( copy_move_it(old_start) - , copy_move_it(detail::get_pointer(pos)) - , first, mid, detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(pos), first, mid, new_start); //The buffer is all constructed until old_end, //release destroyer and update size old_values_destroyer.release(); @@ -1529,7 +1519,7 @@ class vector : private detail::vector_alloc_holder //Copy all new elements T* move_start = std::copy(mid, last, old_start); //Displace old_end - T* move_end = std::copy(copy_move_it(detail::get_pointer(pos)), copy_move_it(old_finish), detail::get_pointer(move_start)); + T* move_end = std::copy(copy_move_it(pos), copy_move_it(old_finish), move_start); //Destroy remaining moved elements from old_end except if they //have trivial destructor after being moved difference_type n_destroy = s_before - n; @@ -1584,14 +1574,12 @@ class vector : private detail::vector_alloc_holder //First copy the part of old_end raw_mem T* finish_n = old_finish - difference_type(n_after); std::uninitialized_copy - ( copy_move_it(detail::get_pointer(finish_n)) - , copy_move_it(old_finish) - , old_finish); + (copy_move_it(finish_n), copy_move_it(old_finish), old_finish); this->members_.m_size += n_after; //Displace the rest of old_end to the new position - std::copy_backward(assign_move_it(detail::get_pointer(pos)), assign_move_it(detail::get_pointer(finish_n)), old_finish); + std::copy_backward(assign_move_it(pos), assign_move_it(finish_n), old_finish); //Now overwrite with new_end - std::copy(first, last, detail::get_pointer(pos)); + std::copy(first, last, pos); } else { //The raw_mem from end will divide new_end part @@ -1610,13 +1598,10 @@ class vector : private detail::vector_alloc_holder std::advance(mid, elemsafter); //First initialize data in raw memory boost::interprocess::uninitialized_copy_copy - ( mid, last - , copy_move_it(detail::get_pointer(pos)) - , copy_move_it(old_finish) - , old_finish); + ( mid, last, copy_move_it(pos), copy_move_it(old_finish), old_finish); this->members_.m_size += n_after; //Now copy the part of new_end over constructed elements - std::copy(first, mid, detail::get_pointer(pos)); + std::copy(first, mid, pos); } } } diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/detail/algorithms.hpp index 233080d..ed61264 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/detail/algorithms.hpp @@ -43,7 +43,7 @@ inline void construct_in_place_impl(T* dest, const InpIt &source, detail::true_) template inline void construct_in_place_impl(T* dest, const InpIt &source, detail::false_) { - new(dest)T(*source); + new((void*)dest)T(*source); } } //namespace detail { @@ -58,7 +58,7 @@ inline void construct_in_place(T* dest, InpIt source) template inline void construct_in_place(T *dest, default_construct_iterator) { - new(dest)T(); + new((void*)dest)T(); } template diff --git a/include/boost/interprocess/detail/config_begin.hpp b/include/boost/interprocess/detail/config_begin.hpp index 4db523a..e872b53 100644 --- a/include/boost/interprocess/detail/config_begin.hpp +++ b/include/boost/interprocess/detail/config_begin.hpp @@ -30,4 +30,5 @@ #pragma warning (disable : 4711) // function selected for automatic inline expansion #pragma warning (disable : 4786) // identifier truncated in debug info #pragma warning (disable : 4996) // 'function': was declared deprecated + #pragma warning (disable : 4197) // top-level volatile in cast is ignored #endif diff --git a/include/boost/interprocess/detail/move.hpp b/include/boost/interprocess/detail/move.hpp index aab0455..7e0c549 100644 --- a/include/boost/interprocess/detail/move.hpp +++ b/include/boost/interprocess/detail/move.hpp @@ -79,7 +79,7 @@ class move_return public: typedef T type; - move_return(T& returned) + move_return(const T& returned) : m_moved(moved_object(returned)) {} diff --git a/include/boost/interprocess/detail/mpl.hpp b/include/boost/interprocess/detail/mpl.hpp index 0ae2392..1c100c5 100644 --- a/include/boost/interprocess/detail/mpl.hpp +++ b/include/boost/interprocess/detail/mpl.hpp @@ -17,7 +17,7 @@ # pragma once #endif -//#include +#include namespace boost { namespace interprocess { @@ -121,6 +121,24 @@ struct identity { return x; } }; +template +struct ls_zeros +{ + static const std::size_t value = (S & std::size_t(1)) ? 0 : (1u + ls_zeros<(S >> 1u)>::value); +}; + +template<> +struct ls_zeros<0> +{ + static const std::size_t value = 0; +}; + +template<> +struct ls_zeros<1> +{ + static const std::size_t value = 0; +}; + } //namespace detail { } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/detail/named_proxy.hpp b/include/boost/interprocess/detail/named_proxy.hpp index 98a28ee..be6ee84 100644 --- a/include/boost/interprocess/detail/named_proxy.hpp +++ b/include/boost/interprocess/detail/named_proxy.hpp @@ -48,13 +48,13 @@ struct Ctor0Arg : public placement_destroy self_t operator++(int) { return *this; } void construct(void *mem) - { new(mem)T; } + { new((void*)mem)T; } virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) { - T* memory = static_cast(mem); + T* memory = (T*)(mem); for(constructed = 0; constructed < num; ++constructed) - new(memory++)T; + new((void*)memory++)T; } }; @@ -88,13 +88,13 @@ struct Ctor0Arg : public placement_destroy // : p1((P1 &)p_1), p2((P2 &)p_2) {} // // void construct(void *mem) -// { new(object)T(m_p1, m_p2); } +// { new((void*)object)T(m_p1, m_p2); } // // virtual void construct_n(void *mem // , std::size_t num // , std::size_t &constructed) // { -// T* memory = static_cast(mem); +// T* memory = (T*)(mem); // for(constructed = 0; constructed < num; ++constructed){ // this->construct(memory++, IsIterator()); // this->do_increment(IsIterator()); @@ -103,10 +103,10 @@ struct Ctor0Arg : public placement_destroy // // private: // void construct(void *mem, detail::true_) -// { new(mem)T(*m_p1, *m_p2); } +// { new((void*)mem)T(*m_p1, *m_p2); } // // void construct(void *mem, detail::false_) -// { new(mem)T(m_p1, m_p2); } +// { new((void*)mem)T(m_p1, m_p2); } // // P1 &m_p1; P2 &m_p2; // }; @@ -163,7 +163,7 @@ struct Ctor0Arg : public placement_destroy , std::size_t num \ , std::size_t &constructed) \ { \ - T* memory = static_cast(mem); \ + T* memory = (T*)(mem); \ for(constructed = 0; constructed < num; ++constructed){ \ this->construct(memory++, IsIterator()); \ this->do_increment(IsIterator()); \ @@ -172,10 +172,10 @@ struct Ctor0Arg : public placement_destroy \ private: \ void construct(void *mem, detail::true_) \ - { new(mem)T(BOOST_PP_ENUM_PARAMS(n, *m_p)); } \ + { new((void*)mem)T(BOOST_PP_ENUM_PARAMS(n, *m_p)); } \ \ void construct(void *mem, detail::false_) \ - { new(mem)T(BOOST_PP_ENUM_PARAMS(n, m_p)); } \ + { new((void*)mem)T(BOOST_PP_ENUM_PARAMS(n, m_p)); } \ \ BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_AUX_PARAM_DEFINE, _) \ }; \ diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index 7cb2eef..a72e738 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -373,11 +373,24 @@ inline std::size_t get_rounded_size(std::size_t orig_size, std::size_t round_to) return ((orig_size-1)/round_to+1)*round_to; } +//Truncates "orig_size" to a multiple of "multiple" bytes. inline std::size_t get_truncated_size(std::size_t orig_size, std::size_t multiple) { return orig_size/multiple*multiple; } - + +//Rounds "orig_size" by excess to round_to bytes. round_to must be power of two +inline std::size_t get_rounded_size_po2(std::size_t orig_size, std::size_t round_to) +{ + return ((orig_size-1)&(~(round_to-1))) + round_to; +} + +//Truncates "orig_size" to a multiple of "multiple" bytes. multiple must be power of two +inline std::size_t get_truncated_size_po2(std::size_t orig_size, std::size_t multiple) +{ + return (orig_size & (~(multiple-1))); +} + template struct ct_rounded_size { diff --git a/include/boost/interprocess/ipc/message_queue.hpp b/include/boost/interprocess/ipc/message_queue.hpp index b28ba68..4a48b5d 100644 --- a/include/boost/interprocess/ipc/message_queue.hpp +++ b/include/boost/interprocess/ipc/message_queue.hpp @@ -98,7 +98,7 @@ class message_queue //!Sends a message stored in buffer "buffer" with size "buffer_size" in the //!message queue with priority "priority". If the message queue is full - //!the sender is retries until time "abs_time" is reached. Returns true if + //!the sender retries until time "abs_time" is reached. Returns true if //!the message has been successfully sent. Returns false if timeout is reached. //!Throws interprocess_error on error. bool timed_send (const void *buffer, std::size_t buffer_size, @@ -106,23 +106,23 @@ class message_queue //!Receives a message from the message queue. The message is stored in buffer //!"buffer", which has size "buffer_size". The received message has size - //!"recvd_size" and priority "priority". If the message queue is full - //!the sender is blocked. Throws interprocess_error on error. + //!"recvd_size" and priority "priority". If the message queue is empty + //!the receiver is blocked. Throws interprocess_error on error. void receive (void *buffer, std::size_t buffer_size, std::size_t &recvd_size,unsigned int &priority); //!Receives a message from the message queue. The message is stored in buffer //!"buffer", which has size "buffer_size". The received message has size - //!"recvd_size" and priority "priority". If the message queue is full - //!the sender is not blocked and returns false, otherwise returns true. + //!"recvd_size" and priority "priority". If the message queue is empty + //!the receiver is not blocked and returns false, otherwise returns true. //!Throws interprocess_error on error. bool try_receive (void *buffer, std::size_t buffer_size, std::size_t &recvd_size,unsigned int &priority); //!Receives a message from the message queue. The message is stored in buffer //!"buffer", which has size "buffer_size". The received message has size - //!"recvd_size" and priority "priority". If the message queue is full - //!the sender is retries until time "abs_time" is reached. Returns true if + //!"recvd_size" and priority "priority". If the message queue is empty + //!the receiver retries until time "abs_time" is reached. Returns true if //!the message has been successfully sent. Returns false if timeout is reached. //!Throws interprocess_error on error. bool timed_receive (void *buffer, std::size_t buffer_size, diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index 71a28fb..0e45ab4 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -45,6 +45,8 @@ namespace interprocess { /// @cond namespace detail{ class interprocess_tester; } +namespace detail{ class raw_mapped_region_creator; } + /// @endcond //!The mapped_region class represents a portion or region created from a @@ -140,6 +142,7 @@ class mapped_region #endif friend class detail::interprocess_tester; + friend class detail::raw_mapped_region_creator; void dont_close_on_destruction(); /// @endcond }; @@ -362,9 +365,9 @@ inline void mapped_region::priv_close() m_base = 0; } #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) - if(m_file_mapping_hnd){ + if(m_file_mapping_hnd != detail::invalid_file()){ winapi::close_handle(m_file_mapping_hnd); - m_file_mapping_hnd = 0; + m_file_mapping_hnd = detail::invalid_file(); } #endif } diff --git a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index c98ec06..bc8b68d 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -281,6 +283,101 @@ class memory_algorithm_common return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0); } + static bool calculate_lcm_and_needs_backwards_lcmed + (std::size_t backwards_multiple, std::size_t received_size, std::size_t size_to_achieve, + std::size_t &lcm_out, std::size_t &needs_backwards_lcmed_out) + { + // Now calculate lcm + std::size_t max = backwards_multiple; + std::size_t min = Alignment; + std::size_t needs_backwards; + std::size_t needs_backwards_lcmed; + std::size_t lcm; + std::size_t current_forward; + //Swap if necessary + if(max < min){ + std::size_t tmp = min; + min = max; + max = tmp; + } + //Check if it's power of two + if((backwards_multiple & (backwards_multiple-1)) == 0){ + if(0 != (size_to_achieve & ((backwards_multiple-1)))){ + return false; + } + + lcm = max; + //If we want to use minbytes data to get a buffer between maxbytes + //and minbytes if maxbytes can't be achieved, calculate the + //biggest of all possibilities + current_forward = detail::get_truncated_size_po2(received_size, backwards_multiple); + needs_backwards = size_to_achieve - current_forward; + assert((needs_backwards % backwards_multiple) == 0); + needs_backwards_lcmed = detail::get_rounded_size_po2(needs_backwards, lcm); + lcm_out = lcm; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of alignment + else if((backwards_multiple & (Alignment - 1u)) == 0){ + lcm = backwards_multiple; + current_forward = detail::get_truncated_size(received_size, backwards_multiple); + //No need to round needs_backwards because backwards_multiple == lcm + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + assert((needs_backwards_lcmed & (Alignment - 1u)) == 0); + lcm_out = lcm; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of the half of the alignmment + else if((backwards_multiple & ((Alignment/2u) - 1u)) == 0){ + lcm = backwards_multiple*2u; + current_forward = detail::get_truncated_size(received_size, backwards_multiple); + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + if(0 != (needs_backwards_lcmed & (Alignment-1))) + //while(0 != (needs_backwards_lcmed & (Alignment-1))) + needs_backwards_lcmed += backwards_multiple; + assert((needs_backwards_lcmed % lcm) == 0); + lcm_out = lcm; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of the half of the alignmment + else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){ + std::size_t remainder; + lcm = backwards_multiple*4u; + current_forward = detail::get_truncated_size(received_size, backwards_multiple); + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + //while(0 != (needs_backwards_lcmed & (Alignment-1))) + //needs_backwards_lcmed += backwards_multiple; + if(0 != (remainder = ((needs_backwards_lcmed & (Alignment-1))>>(Alignment/8u)))){ + if(backwards_multiple & Alignment/2u){ + needs_backwards_lcmed += (remainder)*backwards_multiple; + } + else{ + needs_backwards_lcmed += (4-remainder)*backwards_multiple; + } + } + assert((needs_backwards_lcmed % lcm) == 0); + lcm_out = lcm; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + else{ + lcm = detail::lcm(max, min); + } + //If we want to use minbytes data to get a buffer between maxbytes + //and minbytes if maxbytes can't be achieved, calculate the + //biggest of all possibilities + current_forward = detail::get_truncated_size(received_size, backwards_multiple); + needs_backwards = size_to_achieve - current_forward; + assert((needs_backwards % backwards_multiple) == 0); + needs_backwards_lcmed = detail::get_rounded_size(needs_backwards, lcm); + lcm_out = lcm; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + static multiallocation_iterator allocate_many ( MemoryAlgorithm *memory_algo , const std::size_t *elem_sizes diff --git a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp index 88394ff..f011528 100644 --- a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp @@ -564,7 +564,7 @@ inline std::pair simple_seq_fit_impl:: T *reuse_ptr) { std::pair ret = priv_allocation_command - (command, limit_size, preferred_size, received_size, reuse_ptr, sizeof(T)); + (command, limit_size, preferred_size, received_size, (void*)reuse_ptr, sizeof(T)); BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of::value)); return std::pair(static_cast(ret.first), ret.second); diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index f675f1d..639032e 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -651,7 +651,7 @@ inline std::pair rbtree_best_fit ret = priv_allocation_command - (command, limit_size, preferred_size, received_size, reuse_ptr, sizeof(T)); + (command, limit_size, preferred_size, received_size, (void*)reuse_ptr, sizeof(T)); BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of::value)); return std::pair(static_cast(ret.first), ret.second); @@ -776,26 +776,16 @@ void* rbtree_best_fit:: assert(prev_block->m_size == reuse->m_prev_size); algo_impl_t::assert_alignment(prev_block); - //Let's calculate the number of extra bytes of data before the current - //block's begin. The value is a multiple of backwards_multiple - std::size_t needs_backwards = preferred_size - - detail::get_truncated_size(received_size, backwards_multiple); - - const std::size_t lcm = detail::lcm(max_value(backwards_multiple, (std::size_t)Alignment) - ,min_value(backwards_multiple, (std::size_t)Alignment)); - - //If we want to use min_size data to get a buffer between preferred_size - //and min_size if preferred_size can't be achieved, calculate the - //biggest of all possibilities - if(!only_preferred_backwards){ - needs_backwards = min_size - detail::get_truncated_size(received_size, backwards_multiple); + std::size_t needs_backwards_aligned; + std::size_t lcm; + if(!algo_impl_t::calculate_lcm_and_needs_backwards_lcmed + ( backwards_multiple + , received_size + , only_preferred_backwards ? preferred_size : min_size + , lcm, needs_backwards_aligned)){ + return 0; } - assert((needs_backwards % backwards_multiple) == 0); - - const std::size_t needs_backwards_aligned = - detail::get_rounded_size(needs_backwards, lcm); - //Check if previous block has enough size if(std::size_t(prev_block->m_size*Alignment) >= needs_backwards_aligned){ //Now take all next space. This will succeed @@ -857,10 +847,8 @@ void* rbtree_best_fit:: m_header.m_imultiset.erase(Imultiset::s_iterator_to(*prev_block)); //Just merge the whole previous block - needs_backwards = detail::get_truncated_size - (prev_block->m_size*Alignment, backwards_multiple); - //received_size = received_size/backwards_multiple*backwards_multiple + needs_backwards; - received_size = received_size + needs_backwards; + //prev_block->m_size*Alignment is multiple of lcm (and backwards_multiple) + received_size = received_size + prev_block->m_size*Alignment; m_header.m_allocated += prev_block->m_size*Alignment; //Now update sizes diff --git a/include/boost/interprocess/offset_ptr.hpp b/include/boost/interprocess/offset_ptr.hpp index c3853a1..627c440 100644 --- a/include/boost/interprocess/offset_ptr.hpp +++ b/include/boost/interprocess/offset_ptr.hpp @@ -53,9 +53,6 @@ class offset_ptr { /// @cond typedef offset_ptr self_t; - typedef const PointedType * const_pointer_t; - typedef typename detail::add_reference - ::type const_reference_t; void unspecified_bool_type_func() const {} typedef void (self_t::*unspecified_bool_type)() const; @@ -64,6 +61,9 @@ class offset_ptr __declspec(noinline) //this workaround is needed for msvc-8.0 and msvc-9.0 #endif void set_offset(const volatile void *ptr) + { set_offset((const void*)ptr); } + + void set_offset(const void *ptr) { const char *p = static_cast(const_cast(ptr)); //offset == 1 && ptr != 0 is not legal for this pointer @@ -402,68 +402,44 @@ namespace intrusive { //Predeclaration to avoid including header template -struct has_pointer_plus_bit; +struct max_pointer_plus_bits; -template -struct has_pointer_plus_bit, N> +template +struct max_pointer_plus_bits, Alignment> { - static const bool value = (N % 4u == 0); + //The offset ptr can embed one bit less than the alignment since it + //uses offset == 1 to store the null pointer. + static const std::size_t value = ::boost::interprocess::detail::ls_zeros::value - 1; }; //Predeclaration -template -struct pointer_plus_bit; +template +struct pointer_plus_bits; -//Specialization -template -struct pointer_plus_bit > +template +struct pointer_plus_bits, NumBits> { typedef boost::interprocess::offset_ptr pointer; + //Bits are stored in the lower bits of the pointer except the LSB, + //because this bit is used to represent the null pointer. + static const std::size_t Mask = ((std::size_t(1) << NumBits)-1)<<1u; static pointer get_pointer(const pointer &n) - { return (T*)(std::size_t(n.get()) & ~std::size_t(2u)); } + { return (T*)(std::size_t(n.get()) & ~std::size_t(Mask)); } static void set_pointer(pointer &n, pointer p) - { n = (T*)(std::size_t(p.get()) | (std::size_t(n.get()) & std::size_t(2u))); } - - static bool get_bit(const pointer &n) - { return 0 != (std::size_t(n.get()) & std::size_t(2u)); } - - static void set_bit(pointer &n, bool c) - { n = (T*)(std::size_t(get_pointer(n).get()) | (std::size_t(c) << 1u)); } -}; - -//Predeclaration to avoid including header -template -struct has_pointer_plus_2_bits; - -template -struct has_pointer_plus_2_bits, N> -{ - static const bool value = (N % 8u == 0); -}; - -//Predeclaration -template -struct pointer_plus_2_bits; - -template -struct pointer_plus_2_bits > -{ - typedef boost::interprocess::offset_ptr pointer; - - static pointer get_pointer(const pointer &n) - { return (T*)(std::size_t(n.get()) & ~std::size_t(6u)); } - - static void set_pointer(pointer &n, pointer p) - { n = (T*)(std::size_t(p.get()) | (std::size_t(n.get()) & std::size_t(6u))); } + { + std::size_t pint = std::size_t(p.get()); + assert(0 == (std::size_t(pint) & Mask)); + n = (T*)(pint | (std::size_t(n.get()) & std::size_t(Mask))); + } static std::size_t get_bits(const pointer &n) - { return(std::size_t(n.get()) & std::size_t(6u)) >> 1u; } + { return(std::size_t(n.get()) & std::size_t(Mask)) >> 1u; } static void set_bits(pointer &n, std::size_t b) { - assert(b < 4); + assert(b < (std::size_t(1) << NumBits)); n = (T*)(std::size_t(get_pointer(n).get()) | (b << 1u)); } }; diff --git a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp index d967809..bc3306c 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp @@ -86,11 +86,23 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, if(now >= abs_time) return false; } + typedef boost::interprocess::scoped_lock InternalLock; //The enter interprocess_mutex guarantees that while executing a notification, //no other thread can execute the do_timed_wait method. { //--------------------------------------------------------------- - boost::interprocess::scoped_lock lock(m_enter_mut); + InternalLock lock; + if(tout_enabled){ + InternalLock dummy(m_enter_mut, abs_time); + lock = move(dummy); + } + else{ + InternalLock dummy(m_enter_mut); + lock = move(dummy); + } + + if(!lock) + return false; //--------------------------------------------------------------- //We increment the waiting thread count protected so that it will be //always constant when another thread enters the notification logic. @@ -146,7 +158,18 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, //Notification occurred, we will lock the checking interprocess_mutex so that //if a notify_one notification occurs, only one thread can exit //--------------------------------------------------------------- - boost::interprocess::scoped_lock lock(m_check_mut); + InternalLock lock; + if(tout_enabled){ + InternalLock dummy(m_check_mut, abs_time); + lock = move(dummy); + } + else{ + InternalLock dummy(m_check_mut); + lock = move(dummy); + } + + if(!lock) + return false; //--------------------------------------------------------------- boost::uint32_t result = detail::atomic_cas32 ((boost::uint32_t*)&m_command, SLEEP, NOTIFY_ONE); diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index d9ef89f..ae3597a 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include //!\file @@ -106,62 +107,6 @@ class file_lock private: file_handle_t m_file_hnd; - bool timed_acquire_file_lock - (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time) - { - //Obtain current count and target time - boost::posix_time::ptime now = microsec_clock::universal_time(); - using namespace boost::detail; - - if(now >= abs_time) return false; - - do{ - if(!try_acquire_file_lock(hnd, acquired)) - return false; - - if(acquired) - return true; - else{ - now = microsec_clock::universal_time(); - - if(now >= abs_time){ - acquired = false; - return true; - } - // relinquish current time slice - winapi::sched_yield(); - } - }while (true); - } - - bool timed_acquire_file_lock_sharable - (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time) - { - //Obtain current count and target time - boost::posix_time::ptime now = microsec_clock::universal_time(); - using namespace boost::detail; - - if(now >= abs_time) return false; - - do{ - if(!try_acquire_file_lock_sharable(hnd, acquired)) - return false; - - if(acquired) - return true; - else{ - now = microsec_clock::universal_time(); - - if(now >= abs_time){ - acquired = false; - return true; - } - // relinquish current time slice - winapi::sched_yield(); - } - }while (true); - } - bool timed_acquire_file_lock (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time) { @@ -172,7 +117,7 @@ class file_lock if(now >= abs_time) return false; do{ - if(!try_acquire_file_lock(hnd, acquired)) + if(!detail::try_acquire_file_lock(hnd, acquired)) return false; if(acquired) @@ -185,7 +130,7 @@ class file_lock return true; } // relinquish current time slice - sleep(0); + detail::thread_yield(); } }while (true); } @@ -200,7 +145,7 @@ class file_lock if(now >= abs_time) return false; do{ - if(!try_acquire_file_lock_sharable(hnd, acquired)) + if(!detail::try_acquire_file_lock_sharable(hnd, acquired)) return false; if(acquired) @@ -213,7 +158,7 @@ class file_lock return true; } // relinquish current time slice - ::sleep(0); + detail::thread_yield(); } }while (true); } @@ -259,7 +204,7 @@ inline bool file_lock::try_lock() inline bool file_lock::timed_lock(const boost::posix_time::ptime &abs_time) { bool result; - if(!detail::timed_acquire_file_lock(m_file_hnd, result, abs_time)){ + if(!this->timed_acquire_file_lock(m_file_hnd, result, abs_time)){ error_info err(system_error_code()); throw interprocess_exception(err); } @@ -295,7 +240,7 @@ inline bool file_lock::try_lock_sharable() inline bool file_lock::timed_lock_sharable(const boost::posix_time::ptime &abs_time) { bool result; - if(!detail::timed_acquire_file_lock_sharable(m_file_hnd, result, abs_time)){ + if(!this->timed_acquire_file_lock_sharable(m_file_hnd, result, abs_time)){ error_info err(system_error_code()); throw interprocess_exception(err); } diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index cfdbe13..c1d3c31 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -159,7 +159,9 @@ class named_condition //unlock internal first to avoid deadlock with near simultaneous waits lock_inverter inverted_lock(lock); scoped_lock > external_unlock(inverted_lock); - scoped_lock internal_lock(*this->mutex()); + if(!external_unlock) return false; + scoped_lock internal_lock(*this->mutex(), abs_time); + if(!internal_lock) return false; return this->condition()->timed_wait(internal_lock, abs_time); } #endif diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index c8b3c1a..912411a 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -169,7 +169,7 @@ inline mode_t windows_shared_memory::get_mode() const inline bool windows_shared_memory::priv_open_or_create (detail::create_enum_t type, const char *filename, mode_t mode, std::size_t size) { - m_name = filename; + m_name = filename ? filename : ""; unsigned long file_map_access = 0; unsigned long map_access = 0; diff --git a/proj/to-do.txt b/proj/to-do.txt new file mode 100644 index 0000000..dc977b4 --- /dev/null +++ b/proj/to-do.txt @@ -0,0 +1,54 @@ +-> Implement zero_memory flag for allocation_command + +-> The general allocation funtion can be improved with some fixed size allocation bins. + +-> Adapt error reporting to TR1 system exceptions + +-> Improve exception messages + +-> Movability of containers should depend on the no-throw guarantee of allocators copy constructor + +-> Check self-assignment for vectors + +-> Update writing a new memory allocator explaining new functions (like alignment) + +-> private node allocators could take the number of nodes as a runtime parameter. + +-> Explain how to build intrusive indexes. + +-> Add intrusive index types as available indexes. + +-> Add maximum alignment allocation limit in PageSize bytes. Otherwise, we can't + guarantee alignment for process-shared allocations. + +-> Add default algorithm and index types. The user does not need to know how are + they implemented. + +-> Add private mapping to managed classes. + +-> Add unique_ptr documentation. + +-> Pass max size check in allocation to node pools + +-> Add atomic_func explanation in docs + +-> Once shrink to fit indexes is implemented test all memory has been deallocated + in tests to detect leaks/implementation failures. + +-> Improve allocate_many functions to allocate all the nodes forming a singly + linked list of nodes. + +-> Use in-place expansion capabilities to shrink_to_fit and reserve functions + from iunordered_index. + +-> Optimize copy_n with std::copy in vector. Revise other functions to improve optimizations + +-> Keep an eye on container iterator constness issue to bring Interprocess containers up-to-date. + +-> change unique_ptr to avoid using compressed_pair + +-> Improve unique_ptr test to test move assignment and other goodies like assigment from null + +-> barrier_test fails on MacOS X on PowerPC. + +-> void allocator instantiations fail. diff --git a/proj/vc7ide/Interprocess.sln b/proj/vc7ide/Interprocess.sln index 4758668..eed8eda 100644 --- a/proj/vc7ide/Interprocess.sln +++ b/proj/vc7ide/Interprocess.sln @@ -415,6 +415,34 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "offset_ptr_test", "offset_p ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_shared_memory", "doc_anonymous_shared_memory.vcproj", "{6DE178C3-12FE-6032-4FC7-879B63B9F651}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "anonymous_shared_memory_test", "anonymous_shared_memory_test.vcproj", "{58DE8A13-4FA7-6252-36FE-B3A0A6D92812}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_unordered_map", "doc_unordered_map.vcproj", "{9C185DF3-B75F-1928-8F6D-735108AABE62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_multi_index", "doc_multi_index.vcproj", "{918C5DF3-1928-B73F-F626-7358518CBE62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unordered_test", "unordered_test.vcproj", "{C3CE1183-09F2-A46A-4FE6-D06BA7923A02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_index_test", "multi_index_test.vcproj", "{9285DFD3-1928-F662-CB73-73518CB53A62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_lock_test", "file_lock_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792639}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -839,6 +867,34 @@ Global {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Debug.ActiveCfg = Debug|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Debug.Build.0 = Debug|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Release.ActiveCfg = Release|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Release.Build.0 = Release|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Debug.ActiveCfg = Debug|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Debug.Build.0 = Debug|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Release.ActiveCfg = Release|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Release.Build.0 = Release|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Debug.ActiveCfg = Debug|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Debug.Build.0 = Debug|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Release.ActiveCfg = Release|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Release.Build.0 = Release|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Debug.ActiveCfg = Debug|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Debug.Build.0 = Debug|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Release.ActiveCfg = Release|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Release.Build.0 = Release|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Debug.ActiveCfg = Debug|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Debug.Build.0 = Debug|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Release.ActiveCfg = Release|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Release.Build.0 = Release|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Debug.ActiveCfg = Debug|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Debug.Build.0 = Debug|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Release.ActiveCfg = Release|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/anonymous_shared_memory_test.vcproj b/proj/vc7ide/anonymous_shared_memory_test.vcproj new file mode 100644 index 0000000..4b81afc --- /dev/null +++ b/proj/vc7ide/anonymous_shared_memory_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_anonymous_shared_memory.vcproj b/proj/vc7ide/doc_anonymous_shared_memory.vcproj new file mode 100644 index 0000000..cd5d7a4 --- /dev/null +++ b/proj/vc7ide/doc_anonymous_shared_memory.vcproj @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_multi_index.vcproj b/proj/vc7ide/doc_multi_index.vcproj new file mode 100644 index 0000000..5a29cee --- /dev/null +++ b/proj/vc7ide/doc_multi_index.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_unordered_map.vcproj b/proj/vc7ide/doc_unordered_map.vcproj new file mode 100644 index 0000000..a08a8ea --- /dev/null +++ b/proj/vc7ide/doc_unordered_map.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/file_lock_test.vcproj b/proj/vc7ide/file_lock_test.vcproj new file mode 100644 index 0000000..3e311dc --- /dev/null +++ b/proj/vc7ide/file_lock_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/interprocesslib.vcproj b/proj/vc7ide/interprocesslib.vcproj index 5ccbb82..0f79970 100644 --- a/proj/vc7ide/interprocesslib.vcproj +++ b/proj/vc7ide/interprocesslib.vcproj @@ -315,6 +315,9 @@ Name="Managed Memory Classes" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + + diff --git a/proj/vc7ide/multi_index_test.vcproj b/proj/vc7ide/multi_index_test.vcproj new file mode 100644 index 0000000..5d2a807 --- /dev/null +++ b/proj/vc7ide/multi_index_test.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/unordered_test.vcproj b/proj/vc7ide/unordered_test.vcproj new file mode 100644 index 0000000..6c91a73 --- /dev/null +++ b/proj/vc7ide/unordered_test.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/adaptive_node_pool_test.cpp b/test/adaptive_node_pool_test.cpp index 866b8f3..11ce510 100644 --- a/test/adaptive_node_pool_test.cpp +++ b/test/adaptive_node_pool_test.cpp @@ -11,6 +11,8 @@ #include "node_pool_test.hpp" #include +#include + int main () { using namespace boost::interprocess; diff --git a/test/adaptive_pool_test.cpp b/test/adaptive_pool_test.cpp index 7b36131..196d0d5 100644 --- a/test/adaptive_pool_test.cpp +++ b/test/adaptive_pool_test.cpp @@ -41,7 +41,6 @@ typedef list MyShmListV1; typedef vector MyShmVector; typedef vector MyShmVectorV1; - int main () { if(test::list_test()) diff --git a/test/allocator_v1.hpp b/test/allocator_v1.hpp index 6504df9..b46c3c4 100644 --- a/test/allocator_v1.hpp +++ b/test/allocator_v1.hpp @@ -114,17 +114,17 @@ class allocator_v1 //!Deallocates memory previously allocated. Never throws void deallocate(const pointer &ptr, size_type) - { mp_mngr->deallocate(detail::get_pointer(ptr)); } -/* + { mp_mngr->deallocate((void*)detail::get_pointer(ptr)); } + //!Construct object, calling constructor. //!Throws if T(const T&) throws void construct(const pointer &ptr, const_reference value) - { new(detail::get_pointer(ptr)) value_type(value); } + { new((void*)detail::get_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(); } diff --git a/test/anonymous_shared_memory_test.cpp b/test/anonymous_shared_memory_test.cpp new file mode 100644 index 0000000..43ac48b --- /dev/null +++ b/test/anonymous_shared_memory_test.cpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2007. 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 +#include +#include +#include +#include +#include + +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(region.get_address()); + for(std::size_t i = 0 + ;i < MemSize + ;++i, ++pattern){ + *pattern = static_cast(i); + } + + //Check pattern + pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < MemSize + ;++i, ++pattern){ + if(*pattern != static_cast(i)){ + return 1; + } + } + } + } + catch(std::exception &exc){ + std::cout << "Unhandled exception: " << exc.what() << std::endl; + return 1; + } + return 0; +} + +#include diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index af691f9..7c66735 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -82,26 +82,26 @@ class dummy_test_allocator template dummy_test_allocator(const dummy_test_allocator &) {} -/* + 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 void construct(pointer, const Convertible &) {} void destroy(pointer) {} -*/ + size_type max_size() const { return 0; } diff --git a/test/expand_bwd_test_allocator.hpp b/test/expand_bwd_test_allocator.hpp index 840a45e..0a62b33 100644 --- a/test/expand_bwd_test_allocator.hpp +++ b/test/expand_bwd_test_allocator.hpp @@ -85,26 +85,26 @@ class expand_bwd_test_allocator 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){ } -/* + 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 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; } diff --git a/test/expand_bwd_test_template.hpp b/test/expand_bwd_test_template.hpp index 4ccf0ca..4a61d92 100644 --- a/test/expand_bwd_test_template.hpp +++ b/test/expand_bwd_test_template.hpp @@ -15,6 +15,7 @@ #include #include "expand_bwd_test_allocator.hpp" #include +#include namespace boost { namespace interprocess { namespace test { @@ -107,7 +108,8 @@ template bool test_insert_with_expand_bwd() { typedef typename VectorWithExpandBwdAllocator::value_type value_type; - typedef std::vector Vect; + typedef typename boost::remove_volatile::type non_volatile_value_type; + typedef std::vector Vect; const int MemorySize = 1000; //Distance old and new buffer @@ -131,37 +133,42 @@ bool test_insert_with_expand_bwd() for(int iteration = 0; iteration < Iterations; ++iteration) { - Vect memory; - memory.resize(MemorySize); + value_type *memory = new value_type[MemorySize]; + try { + std::vector initial_data; + initial_data.resize(InitialSize[iteration]); + for(int i = 0; i < InitialSize[iteration]; ++i){ + initial_data[i] = i; + } - Vect initial_data; - initial_data.resize(InitialSize[iteration]); - for(int i = 0; i < InitialSize[iteration]; ++i){ - initial_data[i] = value_type(i); - } + Vect data_to_insert; + data_to_insert.resize(InsertSize[iteration]); + for(int i = 0; i < InsertSize[iteration]; ++i){ + data_to_insert[i] = -i; + } - Vect data_to_insert; - data_to_insert.resize(InsertSize[iteration]); - for(int i = 0; i < InsertSize[iteration]; ++i){ - data_to_insert[i] = value_type(-i); + expand_bwd_test_allocator alloc + ((value_type*)&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; + } } - - expand_bwd_test_allocator alloc - (&memory[0], memory.size(), 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 []((non_volatile_value_type*)memory); + throw; } + delete []((non_volatile_value_type*)memory); } return true; @@ -173,7 +180,8 @@ template bool test_assign_with_expand_bwd() { typedef typename VectorWithExpandBwdAllocator::value_type value_type; - typedef std::vector Vect; + typedef typename boost::remove_volatile::type non_volatile_value_type; + typedef std::vector Vect; const int MemorySize = 200; const int Offset[] = { 50, 50, 50}; @@ -183,41 +191,46 @@ bool test_assign_with_expand_bwd() for(int iteration = 0; iteration initial_data; + initial_data.resize(InitialSize[iteration]); + for(int i = 0; i < InitialSize[iteration]; ++i){ + initial_data[i] = i; + } - //Create initial data - Vect initial_data; - initial_data.resize(InitialSize[iteration]); - for(int i = 0; i < InitialSize[iteration]; ++i){ - initial_data[i] = i; + //Create data to assign + std::vector data_to_assign; + data_to_assign.resize(AssignSize[iteration]); + for(int i = 0; i < AssignSize[iteration]; ++i){ + data_to_assign[i] = -i; + } + + //Insert initial data to the vector to test + expand_bwd_test_allocator alloc + (&memory[0], MemorySize, Offset[iteration]); + VectorWithExpandBwdAllocator vector(alloc); + vector.insert( vector.begin() + , initial_data.begin(), initial_data.end()); + + //Assign data + vector.assign(data_to_assign.begin(), data_to_assign.end()); + initial_data.assign(data_to_assign.begin(), data_to_assign.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; + } } - - //Create data to assign - Vect data_to_assign; - data_to_assign.resize(AssignSize[iteration]); - for(int i = 0; i < AssignSize[iteration]; ++i){ - data_to_assign[i] = -i; - } - - //Insert initial data to the vector to test - expand_bwd_test_allocator alloc - (&memory[0], memory.size(), Offset[iteration]); - VectorWithExpandBwdAllocator vector(alloc); - vector.insert( vector.begin() - , initial_data.begin(), initial_data.end()); - - //Assign data - vector.assign(data_to_assign.begin(), data_to_assign.end()); - initial_data.assign(data_to_assign.begin(), data_to_assign.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 []((typename boost::remove_volatile::type*)memory); + throw; } + delete []((typename boost::remove_volatile::type*)memory); } return true; diff --git a/test/file_lock_test.cpp b/test/file_lock_test.cpp new file mode 100644 index 0000000..be0311c --- /dev/null +++ b/test/file_lock_test.cpp @@ -0,0 +1,62 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include "mutex_test_template.hpp" +#include "sharable_mutex_test_template.hpp" +#include "get_process_id_name.hpp" +#include +#include + +using namespace boost::interprocess; +//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(test::get_process_id_name()) + {} +}; + +int main () +{ + //Destroy and create file + { + std::remove(test::get_process_id_name()); + std::ofstream file(test::get_process_id_name()); + if(!file){ + return 1; + } + file_lock flock(test::get_process_id_name()); + { + scoped_lock sl(flock); + } + { + scoped_lock sl(flock, try_to_lock); + } + { + scoped_lock sl(flock, test::delay(1)); + } + } + + //test::test_all_lock(); + //test::test_all_mutex(); + //test::test_all_sharable_mutex(); + std::remove(test::get_process_id_name()); + + return 0; +} + +#include diff --git a/test/list_test.cpp b/test/list_test.cpp index a083d91..e2073fe 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -26,6 +26,9 @@ template class boost::interprocess::list ShmemAllocator; typedef list MyList; +typedef allocator ShmemVolatileAllocator; +typedef list MyVolatileList; + typedef allocator ShmemMoveAllocator; typedef list MyMoveList; @@ -37,6 +40,9 @@ int main () if(test::list_test()) return 1; + if(test::list_test()) + return 1; + if(test::list_test()) return 1; diff --git a/test/multi_index_test.cpp b/test/multi_index_test.cpp new file mode 100644 index 0000000..40ce912 --- /dev/null +++ b/test/multi_index_test.cpp @@ -0,0 +1,149 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007. 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace boost::interprocess; +namespace bmi = boost::multi_index; + +typedef managed_shared_memory::allocator::type char_allocator; +typedef basic_string, char_allocator>shm_string; + +//Data to insert in shared memory +struct employee +{ + int id; + int age; + shm_string name; + employee( int id_ + , int age_ + , const char *name_ + , const char_allocator &a) + : id(id_), age(age_), name(name_, a) + {} +}; + +//Tags +struct id{}; +struct age{}; +struct name{}; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + allocator +>; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + adaptive_pool +>; +/* +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + cached_adaptive_pool +>; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + private_adaptive_pool +>; +*/ +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + node_allocator +>; +/* +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + cached_node_allocator +>; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + private_node_allocator +>; +*/ +int main () +{ + return 0; +} + +#include diff --git a/test/shared_memory_mapping_test.cpp b/test/shared_memory_mapping_test.cpp index 723659c..036adb7 100644 --- a/test/shared_memory_mapping_test.cpp +++ b/test/shared_memory_mapping_test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "get_process_id_name.hpp" @@ -113,6 +114,28 @@ int main () } } } + { + //Now check anonymous mapping + mapped_region region(anonymous_shared_memory(FileSize)); + + //Write pattern + unsigned char *pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + *pattern = static_cast(i); + } + + //Check pattern + pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + if(*pattern != static_cast(i)){ + return 1; + } + } + } } catch(std::exception &exc){ shared_memory_object::remove(test::get_process_id_name()); diff --git a/test/tree_test.cpp b/test/tree_test.cpp index eea66a1..2535ec6 100644 --- a/test/tree_test.cpp +++ b/test/tree_test.cpp @@ -61,7 +61,7 @@ template class boost::interprocess::multimap //Customize managed_shared_memory class typedef basic_managed_shared_memory , + simple_seq_fit >, map_index > my_managed_shared_memory; diff --git a/test/unordered_test.cpp b/test/unordered_test.cpp new file mode 100644 index 0000000..9604a32 --- /dev/null +++ b/test/unordered_test.cpp @@ -0,0 +1,94 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "get_process_id_name.hpp" +#include +#include + +#include //std::equal_to +#include //boost::hash + +namespace bip = boost::interprocess; + +typedef bip::allocator ShmemAllocator; +typedef boost::unordered_set, std::equal_to, ShmemAllocator> MyUnorderedSet; +typedef boost::unordered_multiset, std::equal_to, ShmemAllocator> MyUnorderedMultiSet; + +//Explicit instantiation to catch compile-time errors +template class boost::unordered_set, std::equal_to, ShmemAllocator>; +template class boost::unordered_multiset, std::equal_to, ShmemAllocator>; + +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(bip::anonymous_instance) + ( elements_size + , MyUnorderedSet::hasher() + , MyUnorderedSet::key_equal() + , shm.get_allocator()); + MyUnorderedMultiSet *mymset = + shm.construct(bip::anonymous_instance) + ( elements_size + , MyUnorderedSet::hasher() + , MyUnorderedSet::key_equal() + , shm.get_allocator()); + + //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 diff --git a/test/vector_test.cpp b/test/vector_test.cpp index 0e76115..206b0d0 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -44,7 +44,16 @@ int test_expand_bwd() if(!test::test_all_expand_bwd()) return 1; +/* + //First raw volatile ints + typedef test::expand_bwd_test_allocator + volatile_int_allocator_type; + typedef vector + volatile_int_vector; + if(!test::test_all_expand_bwd()) + return 1; +*/ //Now user defined wrapped int typedef test::expand_bwd_test_allocator int_holder_allocator_type; @@ -72,6 +81,9 @@ int main() typedef allocator ShmemAllocator; typedef vector MyVector; + //typedef allocator ShmemVolatileAllocator; + //typedef vector MyVolatileVector; + typedef allocator ShmemMoveAllocator; typedef vector MyMoveVector; @@ -81,6 +93,9 @@ int main() if(test::vector_test()) return 1; + //if(test::vector_test()) + //return 1; + if(test::vector_test()) return 1; diff --git a/test/windows_shared_memory_mapping_test.cpp b/test/windows_shared_memory_mapping_test.cpp index 6358e41..a5a20ab 100644 --- a/test/windows_shared_memory_mapping_test.cpp +++ b/test/windows_shared_memory_mapping_test.cpp @@ -23,98 +23,93 @@ using namespace boost::interprocess; int main () { - std::string process_name; - test::get_process_id_name(process_name); - try{ - const std::size_t FileSize = 99999*2; - //Create shared memory and file mapping - windows_shared_memory mapping(create_only, process_name.c_str(), read_write, FileSize); - + const char *names[2] = { test::get_process_id_name(), 0 }; + for(unsigned int i = 0; i < sizeof(names)/sizeof(names[0]); ++i) { + const std::size_t FileSize = 99999*2; //Create a file mapping - windows_shared_memory mapping(open_only, process_name.c_str(), read_write); + windows_shared_memory mapping + (create_only, names[i], read_write, FileSize); - //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); + //Create two mapped regions, one half of the file each + mapped_region region (mapping + ,read_write + ,0 + ,FileSize/2 + ,0); - //Fill two regions with a pattern - unsigned char *filler = static_cast(region.get_address()); - for(std::size_t i = 0 - ;i < FileSize/2 - ;++i){ - *filler++ = static_cast(i); - } + mapped_region region2(mapping + ,read_write + ,FileSize/2 + ,FileSize - FileSize/2 + ,0); - filler = static_cast(region2.get_address()); - for(std::size_t i = FileSize/2 - ;i < FileSize - ;++i){ - *filler++ = static_cast(i); - } - } + //Fill two regions with a pattern + unsigned char *filler = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + *filler++ = static_cast(i); + } - //See if the pattern is correct in the file using two mapped regions - { - //Create a file mapping - windows_shared_memory mapping(open_only, process_name.c_str(), read_write); - mapped_region region(mapping, read_write, 0, FileSize/2, 0); - mapped_region region2(mapping, read_write, FileSize/2, 0/*FileSize - FileSize/2*/, 0); - - unsigned char *checker = (unsigned char*)region.get_address(); - //Check pattern - for(std::size_t i = 0 - ;i < FileSize/2 - ;++i){ - if(*checker++ != static_cast(i)){ - return 1; + filler = static_cast(region2.get_address()); + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + *filler++ = static_cast(i); } } - //Check second half - checker = (unsigned char *)region2.get_address(); + //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); - //Check pattern - for(std::size_t i = FileSize/2 - ;i < FileSize - ;++i){ - if(*checker++ != static_cast(i)){ - return 1; + unsigned char *checker = (unsigned char*)region.get_address(); + //Check pattern + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + if(*checker++ != static_cast(i)){ + return 1; + } + } + + //Check second half + checker = (unsigned char *)region2.get_address(); + + //Check pattern + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + if(*checker++ != static_cast(i)){ + return 1; + } } } - } - //Now check the pattern mapping a single read only mapped_region - { - //Create a file mapping - windows_shared_memory mapping(open_only, process_name.c_str(), read_only); + //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); - //Create a single regions, mapping all the file - mapped_region region (mapping - ,read_only); - - //Check pattern - unsigned char *pattern = static_cast(region.get_address()); - for(std::size_t i = 0 - ;i < FileSize - ;++i, ++pattern){ - if(*pattern != static_cast(i)){ - return 1; + //Check pattern + unsigned char *pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + if(*pattern != static_cast(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; } diff --git a/test/windows_shared_memory_test.cpp b/test/windows_shared_memory_test.cpp index 4250241..2f8512e 100644 --- a/test/windows_shared_memory_test.cpp +++ b/test/windows_shared_memory_test.cpp @@ -68,6 +68,7 @@ int main () std::cout << ex.what() << std::endl; return 1; } + return 0; }