diff options
Diffstat (limited to 'boost/interprocess/mem_algo/detail/mem_algo_common.hpp')
-rw-r--r-- | boost/interprocess/mem_algo/detail/mem_algo_common.hpp | 244 |
1 files changed, 140 insertions, 104 deletions
diff --git a/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index 91d798145b..8af256aab9 100644 --- a/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2011. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -11,7 +11,7 @@ #ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP #define BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined(_MSC_VER) # pragma once #endif @@ -24,8 +24,9 @@ #include <boost/interprocess/detail/type_traits.hpp> #include <boost/interprocess/detail/math_functions.hpp> #include <boost/interprocess/detail/utilities.hpp> -#include <boost/move/move.hpp> +#include <boost/move/utility_core.hpp> #include <boost/interprocess/detail/min_max.hpp> +#include <boost/container/detail/multiallocation_chain.hpp> #include <boost/assert.hpp> #include <boost/static_assert.hpp> #include <algorithm> @@ -40,6 +41,37 @@ namespace boost { namespace interprocess { namespace ipcdetail { +template<class VoidPointer> +class basic_multiallocation_chain + : public boost::container::container_detail:: + basic_multiallocation_chain<VoidPointer> +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_multiallocation_chain) + typedef boost::container::container_detail:: + basic_multiallocation_chain<VoidPointer> base_t; + public: + + basic_multiallocation_chain() + : base_t() + {} + + basic_multiallocation_chain(BOOST_RV_REF(basic_multiallocation_chain) other) + : base_t(::boost::move(static_cast<base_t&>(other))) + {} + + basic_multiallocation_chain& operator=(BOOST_RV_REF(basic_multiallocation_chain) other) + { + this->base_t::operator=(::boost::move(static_cast<base_t&>(other))); + return *this; + } + + void *pop_front() + { + return boost::interprocess::ipcdetail::to_raw_pointer(this->base_t::pop_front()); + } +}; + + //!This class implements several allocation functions shared by different algorithms //!(aligned allocation, multiple allocation...). template<class MemoryAlgorithm> @@ -81,15 +113,15 @@ class memory_algorithm_common static size_type multiple_of_units(size_type size) { return get_rounded_size(size, Alignment); } - static multiallocation_chain allocate_many - (MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements) + static void allocate_many + (MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) { - return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0); + return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0, chain); } - static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain) + static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain) { - return this_type::priv_deallocate_many(memory_algo, boost::move(chain)); + return this_type::priv_deallocate_many(memory_algo, chain); } static bool calculate_lcm_and_needs_backwards_lcmed @@ -187,19 +219,20 @@ class memory_algorithm_common return true; } - static multiallocation_chain allocate_many + static void allocate_many ( MemoryAlgorithm *memory_algo , const size_type *elem_sizes , size_type n_elements - , size_type sizeof_element) + , size_type sizeof_element + , multiallocation_chain &chain) { - return this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element); + this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, chain); } static void* allocate_aligned (MemoryAlgorithm *memory_algo, size_type nbytes, size_type alignment) { - + //Ensure power of 2 if ((alignment & (alignment - size_type(1u))) != 0){ //Alignment is not power of two @@ -215,7 +248,7 @@ class memory_algorithm_common if(nbytes > UsableByPreviousChunk) nbytes -= UsableByPreviousChunk; - + //We can find a aligned portion if we allocate a block that has alignment //nbytes + alignment bytes or more. size_type minimum_allocation = max_value @@ -255,7 +288,6 @@ class memory_algorithm_common second->m_size = old_size - first->m_size; BOOST_ASSERT(second->m_size >= MinBlockUnits); memory_algo->priv_mark_new_allocated_block(first); - //memory_algo->priv_tail_size(first, first->m_size); memory_algo->priv_mark_new_allocated_block(second); memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(second)); } @@ -416,11 +448,12 @@ class memory_algorithm_common } private: - static multiallocation_chain priv_allocate_many + static void priv_allocate_many ( MemoryAlgorithm *memory_algo , const size_type *elem_sizes , size_type n_elements - , size_type sizeof_element) + , size_type sizeof_element + , multiallocation_chain &chain) { //Note: sizeof_element == 0 indicates that we want to //allocate n_elements of the same size "*elem_sizes" @@ -436,111 +469,114 @@ class memory_algorithm_common } else{ for(size_type i = 0; i < n_elements; ++i){ + if(multiplication_overflows(elem_sizes[i], sizeof_element)){ + total_request_units = 0; + break; + } elem_units = memory_algo->priv_get_total_units(elem_sizes[i]*sizeof_element); elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; + if(sum_overflows(total_request_units, elem_units)){ + total_request_units = 0; + break; + } total_request_units += elem_units; } } - multiallocation_chain chain; - - size_type low_idx = 0; - while(low_idx < n_elements){ - size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; - size_type min_allocation = (!sizeof_element) - ? elem_units - : memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element); - min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; - - size_type received_size; - std::pair<void *, bool> ret = memory_algo->priv_allocate - (boost::interprocess::allocate_new, min_allocation, total_bytes, received_size, 0); - if(!ret.first){ - break; - } + if(total_request_units && !multiplication_overflows(total_request_units, Alignment)){ + size_type low_idx = 0; + while(low_idx < n_elements){ + size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; + size_type min_allocation = (!sizeof_element) + ? elem_units + : memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element); + min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; + + size_type received_size; + std::pair<void *, bool> ret = memory_algo->priv_allocate + (boost::interprocess::allocate_new, min_allocation, total_bytes, received_size, 0); + if(!ret.first){ + break; + } - block_ctrl *block = memory_algo->priv_get_block(ret.first); - size_type received_units = (size_type)block->m_size; - char *block_address = reinterpret_cast<char*>(block); + block_ctrl *block = memory_algo->priv_get_block(ret.first); + size_type received_units = (size_type)block->m_size; + char *block_address = reinterpret_cast<char*>(block); - size_type total_used_units = 0; -// block_ctrl *prev_block = 0; - while(total_used_units < received_units){ - if(sizeof_element){ - elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element); - elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; - } - if(total_used_units + elem_units > received_units) - break; - total_request_units -= elem_units; - //This is the position where the new block must be created - block_ctrl *new_block = reinterpret_cast<block_ctrl *>(block_address); - assert_alignment(new_block); - - //The last block should take all the remaining space - if((low_idx + 1) == n_elements || - (total_used_units + elem_units + - ((!sizeof_element) - ? elem_units - : std::max(memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element), ptr_size_units)) - ) > received_units){ - //By default, the new block will use the rest of the buffer - new_block->m_size = received_units - total_used_units; - memory_algo->priv_mark_new_allocated_block(new_block); - - //If the remaining units are bigger than needed and we can - //split it obtaining a new free memory block do it. - if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){ - size_type shrunk_received; - size_type shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; - bool shrink_ok = shrink - (memory_algo - ,memory_algo->priv_get_user_buffer(new_block) - ,shrunk_request - ,shrunk_request - ,shrunk_received); - (void)shrink_ok; - //Shrink must always succeed with passed parameters - BOOST_ASSERT(shrink_ok); - //Some sanity checks - BOOST_ASSERT(shrunk_request == shrunk_received); - BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits)); - //"new_block->m_size" must have been reduced to elem_units by "shrink" - BOOST_ASSERT(new_block->m_size == elem_units); - //Now update the total received units with the reduction - received_units = elem_units + total_used_units; + size_type total_used_units = 0; + while(total_used_units < received_units){ + if(sizeof_element){ + elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element); + elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; } + if(total_used_units + elem_units > received_units) + break; + total_request_units -= elem_units; + //This is the position where the new block must be created + block_ctrl *new_block = reinterpret_cast<block_ctrl *>(block_address); + assert_alignment(new_block); + + //The last block should take all the remaining space + if((low_idx + 1) == n_elements || + (total_used_units + elem_units + + ((!sizeof_element) + ? elem_units + : std::max(memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element), ptr_size_units)) + ) > received_units){ + //By default, the new block will use the rest of the buffer + new_block->m_size = received_units - total_used_units; + memory_algo->priv_mark_new_allocated_block(new_block); + + //If the remaining units are bigger than needed and we can + //split it obtaining a new free memory block do it. + if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){ + size_type shrunk_received; + size_type shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; + bool shrink_ok = shrink + (memory_algo + ,memory_algo->priv_get_user_buffer(new_block) + ,shrunk_request + ,shrunk_request + ,shrunk_received); + (void)shrink_ok; + //Shrink must always succeed with passed parameters + BOOST_ASSERT(shrink_ok); + //Some sanity checks + BOOST_ASSERT(shrunk_request == shrunk_received); + BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits)); + //"new_block->m_size" must have been reduced to elem_units by "shrink" + BOOST_ASSERT(new_block->m_size == elem_units); + //Now update the total received units with the reduction + received_units = elem_units + total_used_units; + } + } + else{ + new_block->m_size = elem_units; + memory_algo->priv_mark_new_allocated_block(new_block); + } + + block_address += new_block->m_size*Alignment; + total_used_units += (size_type)new_block->m_size; + //Check we have enough room to overwrite the intrusive pointer + BOOST_ASSERT((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer)); + void_pointer p = new(memory_algo->priv_get_user_buffer(new_block))void_pointer(0); + chain.push_back(p); + ++low_idx; } - else{ - new_block->m_size = elem_units; - memory_algo->priv_mark_new_allocated_block(new_block); - } + //Sanity check + BOOST_ASSERT(total_used_units == received_units); + } - block_address += new_block->m_size*Alignment; - total_used_units += (size_type)new_block->m_size; - //Check we have enough room to overwrite the intrusive pointer - BOOST_ASSERT((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer)); - void_pointer p = new(memory_algo->priv_get_user_buffer(new_block))void_pointer(0); - chain.push_back(p); - ++low_idx; - //prev_block = new_block; + if(low_idx != n_elements){ + priv_deallocate_many(memory_algo, chain); } - //Sanity check - BOOST_ASSERT(total_used_units == received_units); - } - - if(low_idx != n_elements){ - priv_deallocate_many(memory_algo, boost::move(chain)); } - return boost::move(chain); } - static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain) + static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain) { while(!chain.empty()){ - void *addr = to_raw_pointer(chain.front()); - chain.pop_front(); - memory_algo->priv_deallocate(addr); + memory_algo->priv_deallocate(to_raw_pointer(chain.pop_front())); } } }; |