Add overalignment support for segment_manager allocation_command functions.

This commit is contained in:
Ion Gaztañaga
2026-01-08 21:43:53 +01:00
parent 76e3feac9d
commit 4b6f3bd539
5 changed files with 371 additions and 507 deletions

View File

@@ -136,12 +136,12 @@ class memory_algorithm_common
} }
static bool calculate_lcm_and_needs_backwards_lcmed static bool calculate_lcm_and_needs_backwards_lcmed
(size_type backwards_multiple, size_type received_size, size_type size_to_achieve, (const size_type backwards_multiple, const size_type alignment, const size_type received_size, const size_type size_to_achieve,
size_type &lcm_out, size_type &needs_backwards_lcmed_out) size_type &lcm_out, size_type &needs_backwards_lcmed_out)
{ {
// Now calculate lcm_val // Now calculate lcm_val
size_type max = backwards_multiple; size_type max = backwards_multiple;
size_type min = Alignment; size_type min = alignment;
size_type needs_backwards; size_type needs_backwards;
size_type needs_backwards_lcmed; size_type needs_backwards_lcmed;
size_type lcm_val; size_type lcm_val;
@@ -171,23 +171,23 @@ class memory_algorithm_common
return true; return true;
} }
//Check if it's multiple of alignment //Check if it's multiple of alignment
else if((backwards_multiple & (Alignment - 1u)) == 0){ else if((backwards_multiple & (alignment - 1u)) == 0){
lcm_val = backwards_multiple; lcm_val = backwards_multiple;
current_forward = get_truncated_size(received_size, backwards_multiple); current_forward = get_truncated_size(received_size, backwards_multiple);
//No need to round needs_backwards because backwards_multiple == lcm_val //No need to round needs_backwards because backwards_multiple == lcm_val
needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
BOOST_ASSERT((needs_backwards_lcmed & (Alignment - 1u)) == 0); BOOST_ASSERT((needs_backwards_lcmed & (alignment - 1u)) == 0);
lcm_out = lcm_val; lcm_out = lcm_val;
needs_backwards_lcmed_out = needs_backwards_lcmed; needs_backwards_lcmed_out = needs_backwards_lcmed;
return true; return true;
} }
//Check if it's multiple of the half of the alignmment //Check if it's multiple of the half of the alignmment
else if((backwards_multiple & ((Alignment/2u) - 1u)) == 0){ else if((backwards_multiple & ((alignment/2u) - 1u)) == 0){
lcm_val = backwards_multiple*2u; lcm_val = backwards_multiple*2u;
current_forward = get_truncated_size(received_size, backwards_multiple); current_forward = get_truncated_size(received_size, backwards_multiple);
needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
if(0 != (needs_backwards_lcmed & (Alignment-1))) if(0 != (needs_backwards_lcmed & (alignment-1)))
//while(0 != (needs_backwards_lcmed & (Alignment-1))) //while(0 != (needs_backwards_lcmed & (alignment-1)))
needs_backwards_lcmed += backwards_multiple; needs_backwards_lcmed += backwards_multiple;
BOOST_ASSERT((needs_backwards_lcmed % lcm_val) == 0); BOOST_ASSERT((needs_backwards_lcmed % lcm_val) == 0);
lcm_out = lcm_val; lcm_out = lcm_val;
@@ -195,15 +195,15 @@ class memory_algorithm_common
return true; return true;
} }
//Check if it's multiple of the quarter of the alignmment //Check if it's multiple of the quarter of the alignmment
else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){ else if((backwards_multiple & ((alignment/4u) - 1u)) == 0){
size_type remainder; size_type remainder;
lcm_val = backwards_multiple*4u; lcm_val = backwards_multiple*4u;
current_forward = get_truncated_size(received_size, backwards_multiple); current_forward = get_truncated_size(received_size, backwards_multiple);
needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
//while(0 != (needs_backwards_lcmed & (Alignment-1))) //while(0 != (needs_backwards_lcmed & (alignment-1)))
//needs_backwards_lcmed += backwards_multiple; //needs_backwards_lcmed += backwards_multiple;
if(0 != (remainder = ((needs_backwards_lcmed & (Alignment-1))>>(Alignment/8u)))){ if(0 != (remainder = ((needs_backwards_lcmed & (alignment-1))>>(alignment/8u)))){
if(backwards_multiple & Alignment/2u){ if(backwards_multiple & alignment/2u){
needs_backwards_lcmed += (remainder)*backwards_multiple; needs_backwards_lcmed += (remainder)*backwards_multiple;
} }
else{ else{
@@ -240,25 +240,118 @@ class memory_algorithm_common
this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, chain); this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, chain);
} }
static void* allocate_aligned static void* allocate_aligned(MemoryAlgorithm * const memory_algo, const size_type nbytes, const size_type alignment)
(MemoryAlgorithm * const memory_algo, const size_type nbytes, const size_type alignment)
{ {
//Ensure power of 2 //Ensure power of 2
const bool alignment_ok = (alignment & (alignment - 1u)) == 0; const bool alignment_ok = (alignment & (alignment - 1u)) == 0;
if (!alignment_ok){ BOOST_ASSERT(alignment_ok);
//Alignment is not power of two if (BOOST_UNLIKELY(!alignment_ok)){
BOOST_ASSERT(alignment_ok);
return 0; return 0;
} }
else if(alignment <= Alignment){
if(alignment <= Alignment){
size_type real_size = nbytes; size_type real_size = nbytes;
void *ignore_reuse = 0; void *ignore_reuse = 0;
return memory_algo->priv_allocate return memory_algo->priv_allocate(boost::interprocess::allocate_new, nbytes, real_size, ignore_reuse);
(boost::interprocess::allocate_new, nbytes, real_size, ignore_reuse); }
else {
return priv_allocate_overaligned(memory_algo, nbytes, alignment);
}
}
static bool try_shrink
(MemoryAlgorithm *memory_algo, void *ptr
,const size_type max_size, size_type &received_size)
{
size_type const preferred_size = received_size;
(void)memory_algo;
//Obtain the real block
block_ctrl *block = memory_algo->priv_get_block(ptr);
size_type old_block_units = (size_type)block->m_size;
//The block must be marked as allocated
BOOST_ASSERT(memory_algo->priv_is_allocated_block(block));
//Check if alignment and block size are right
assert_alignment(ptr);
//Put this to a safe value
received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
//Now translate it to Alignment units
const size_type max_user_units = floor_units(max_size - UsableByPreviousChunk);
const size_type preferred_user_units = ceil_units(preferred_size - UsableByPreviousChunk);
//Check if rounded max and preferred are possible correct
if(max_user_units < preferred_user_units)
return false;
//Check if the block is smaller than the requested minimum
size_type old_user_units = old_block_units - AllocatedCtrlUnits;
if(old_user_units < preferred_user_units)
return false;
//If the block is smaller than the requested minimum
if(old_user_units == preferred_user_units)
return true;
size_type shrunk_user_units =
((BlockCtrlUnits - AllocatedCtrlUnits) >= preferred_user_units)
? (BlockCtrlUnits - AllocatedCtrlUnits)
: preferred_user_units;
//Some parameter checks
if(max_user_units < shrunk_user_units)
return false;
//We must be able to create at least a new empty block
if((old_user_units - shrunk_user_units) < BlockCtrlUnits ){
return false;
} }
//Update new size
received_size = shrunk_user_units*Alignment + UsableByPreviousChunk;
return true;
}
static bool shrink
(MemoryAlgorithm *memory_algo, void *ptr
,const size_type max_size, size_type &received_size)
{
size_type const preferred_size = received_size;
//Obtain the real block
block_ctrl *block = memory_algo->priv_get_block(ptr);
size_type old_block_units = (size_type)block->m_size;
if(!try_shrink(memory_algo, ptr, max_size, received_size)){
return false;
}
//Check if the old size was just the shrunk size (no splitting)
if((old_block_units - AllocatedCtrlUnits) == ceil_units(preferred_size - UsableByPreviousChunk))
return true;
//Now we can just rewrite the size of the old buffer
block->m_size = ((received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits) & block_ctrl::size_mask;
BOOST_ASSERT(block->m_size >= BlockCtrlUnits);
//We create the new block
block_ctrl *new_block = move_detail::force_ptr<block_ctrl*>
(reinterpret_cast<char*>(block) + block->m_size*Alignment);
//Write control data to simulate this new block was previously allocated
//and deallocate it
new_block->m_size = (old_block_units - block->m_size) & block_ctrl::size_mask;
BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits);
memory_algo->priv_mark_new_allocated_block(block);
memory_algo->priv_mark_new_allocated_block(new_block);
memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(new_block));
return true;
}
private:
static void* priv_allocate_overaligned
(MemoryAlgorithm * const memory_algo, const size_type nbytes, const size_type alignment)
{
//To fulfill user's request we need at least min_user_units //To fulfill user's request we need at least min_user_units
size_type needed_units = user_buffer_ceil_units(nbytes); size_type needed_units = user_buffer_ceil_units(nbytes);
//However, there is a minimum allocation unit count (BlockCtrlUnits) to be able to deallocate the buffer, //However, there is a minimum allocation unit count (BlockCtrlUnits) to be able to deallocate the buffer,
@@ -357,7 +450,7 @@ class memory_algorithm_common
//new block in the end. //new block in the end.
const size_type orig_second_units = orig_first_units - final_first_units; const size_type orig_second_units = orig_first_units - final_first_units;
const size_type second_min_units = max_value( size_type(BlockCtrlUnits) const size_type second_min_units = max_value( size_type(BlockCtrlUnits)
, user_buffer_ceil_units(nbytes) + AllocatedCtrlUnits ); , user_buffer_ceil_units(nbytes) + AllocatedCtrlUnits );
//Check if we can create a new free block (of size BlockCtrlUnits) at the end of the segment //Check if we can create a new free block (of size BlockCtrlUnits) at the end of the segment
if(orig_second_units >= (second_min_units + BlockCtrlUnits)){ if(orig_second_units >= (second_min_units + BlockCtrlUnits)){
@@ -390,97 +483,6 @@ class memory_algorithm_common
return usr_buf; return usr_buf;
} }
static bool try_shrink
(MemoryAlgorithm *memory_algo, void *ptr
,const size_type max_size, size_type &received_size)
{
size_type const preferred_size = received_size;
(void)memory_algo;
//Obtain the real block
block_ctrl *block = memory_algo->priv_get_block(ptr);
size_type old_block_units = (size_type)block->m_size;
//The block must be marked as allocated
BOOST_ASSERT(memory_algo->priv_is_allocated_block(block));
//Check if alignment and block size are right
assert_alignment(ptr);
//Put this to a safe value
received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
//Now translate it to Alignment units
const size_type max_user_units = floor_units(max_size - UsableByPreviousChunk);
const size_type preferred_user_units = ceil_units(preferred_size - UsableByPreviousChunk);
//Check if rounded max and preferred are possible correct
if(max_user_units < preferred_user_units)
return false;
//Check if the block is smaller than the requested minimum
size_type old_user_units = old_block_units - AllocatedCtrlUnits;
if(old_user_units < preferred_user_units)
return false;
//If the block is smaller than the requested minimum
if(old_user_units == preferred_user_units)
return true;
size_type shrunk_user_units =
((BlockCtrlUnits - AllocatedCtrlUnits) >= preferred_user_units)
? (BlockCtrlUnits - AllocatedCtrlUnits)
: preferred_user_units;
//Some parameter checks
if(max_user_units < shrunk_user_units)
return false;
//We must be able to create at least a new empty block
if((old_user_units - shrunk_user_units) < BlockCtrlUnits ){
return false;
}
//Update new size
received_size = shrunk_user_units*Alignment + UsableByPreviousChunk;
return true;
}
static bool shrink
(MemoryAlgorithm *memory_algo, void *ptr
,const size_type max_size, size_type &received_size)
{
size_type const preferred_size = received_size;
//Obtain the real block
block_ctrl *block = memory_algo->priv_get_block(ptr);
size_type old_block_units = (size_type)block->m_size;
if(!try_shrink(memory_algo, ptr, max_size, received_size)){
return false;
}
//Check if the old size was just the shrunk size (no splitting)
if((old_block_units - AllocatedCtrlUnits) == ceil_units(preferred_size - UsableByPreviousChunk))
return true;
//Now we can just rewrite the size of the old buffer
block->m_size = ((received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits) & block_ctrl::size_mask;
BOOST_ASSERT(block->m_size >= BlockCtrlUnits);
//We create the new block
block_ctrl *new_block = move_detail::force_ptr<block_ctrl*>
(reinterpret_cast<char*>(block) + block->m_size*Alignment);
//Write control data to simulate this new block was previously allocated
//and deallocate it
new_block->m_size = (old_block_units - block->m_size) & block_ctrl::size_mask;
BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits);
memory_algo->priv_mark_new_allocated_block(block);
memory_algo->priv_mark_new_allocated_block(new_block);
memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(new_block));
return true;
}
private:
static void priv_allocate_many static void priv_allocate_many
( MemoryAlgorithm *memory_algo ( MemoryAlgorithm *memory_algo
, const size_type *elem_sizes , const size_type *elem_sizes

View File

@@ -147,14 +147,13 @@ class simple_seq_fit_impl
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
template<class T> void * allocation_command(boost::interprocess::allocation_type command
BOOST_INTERPROCESS_NODISCARD ,size_type min_size
T *allocation_command (boost::interprocess::allocation_type command, size_type limit_size, ,size_type &prefer_in_recvd_out_size
size_type &prefer_in_recvd_out_size, T *&reuse); ,void *&reuse_ptr
,size_type sizeof_object
BOOST_INTERPROCESS_NODISCARD ,size_type alignof_object
void * raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_size, );
size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object = 1);
//!Multiple element allocation, same size //!Multiple element allocation, same size
//!Experimental. Dont' use //!Experimental. Dont' use
@@ -230,13 +229,7 @@ class simple_seq_fit_impl
//!Real allocation algorithm with min allocation option //!Real allocation algorithm with min allocation option
void * priv_allocate(boost::interprocess::allocation_type command void * priv_allocate(boost::interprocess::allocation_type command
,size_type min_size ,size_type min_size
,size_type &prefer_in_recvd_out_size, void *&reuse_ptr); ,size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type alignof_object = Alignment);
void * priv_allocation_command(boost::interprocess::allocation_type command
,size_type min_size
,size_type &prefer_in_recvd_out_size
,void *&reuse_ptr
,size_type sizeof_object);
//!Returns the number of total units that a user buffer //!Returns the number of total units that a user buffer
//!of "userbytes" bytes really occupies (including header) //!of "userbytes" bytes really occupies (including header)
@@ -259,15 +252,6 @@ class simple_seq_fit_impl
//!Real expand function implementation //!Real expand function implementation
bool priv_expand(void *ptr, size_type min_size, size_type &prefer_in_recvd_out_size); bool priv_expand(void *ptr, size_type min_size, size_type &prefer_in_recvd_out_size);
//!Real expand to both sides implementation
void* priv_expand_both_sides(boost::interprocess::allocation_type command
,size_type min_size, size_type &prefer_in_recvd_out_size
,void *reuse_ptr
,bool only_preferred_backwards);
//!Real private aligned allocation function
//void* priv_allocate_aligned (size_type nbytes, size_type alignment);
//!Checks if block has enough memory and splits/unlinks the block //!Checks if block has enough memory and splits/unlinks the block
//!returning the address to the users //!returning the address to the users
void* priv_check_and_allocate(size_type units void* priv_check_and_allocate(size_type units
@@ -592,54 +576,12 @@ inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
allocate_aligned(this, nbytes, alignment); allocate_aligned(this, nbytes, alignment);
} }
template<class MutexFamily, class VoidPointer>
template<class T>
inline T* simple_seq_fit_impl<MutexFamily, VoidPointer>::
allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
size_type &prefer_in_recvd_out_size, T *&reuse_ptr)
{
void *raw_reuse = reuse_ptr;
void * const ret = priv_allocation_command
(command, limit_size, prefer_in_recvd_out_size, raw_reuse, sizeof(T));
BOOST_ASSERT(0 == ((std::size_t)ret % ::boost::container::dtl::alignment_of<T>::value));
reuse_ptr = static_cast<T*>(raw_reuse);
return static_cast<T*>(ret);
}
template<class MutexFamily, class VoidPointer> template<class MutexFamily, class VoidPointer>
inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>:: inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects, allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object) size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object, size_type /*alignof_object*/)
{
size_type const preferred_objects = prefer_in_recvd_out_size;
if(!sizeof_object){
return reuse_ptr = 0, static_cast<void*>(0);
}
if(command & boost::interprocess::try_shrink_in_place){
if(!reuse_ptr) return static_cast<void*>(0);
prefer_in_recvd_out_size = preferred_objects*sizeof_object;
bool success = algo_impl_t::try_shrink
( this, reuse_ptr, limit_objects*sizeof_object, prefer_in_recvd_out_size);
prefer_in_recvd_out_size /= sizeof_object;
return success ? reuse_ptr : 0;
}
else{
return priv_allocation_command
(command, limit_objects, prefer_in_recvd_out_size, reuse_ptr, sizeof_object);
}
}
template<class MutexFamily, class VoidPointer>
inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object)
{ {
size_type const preferred_size = prefer_in_recvd_out_size; size_type const preferred_size = prefer_in_recvd_out_size;
command &= ~boost::interprocess::expand_bwd;
if(!command){
return reuse_ptr = 0, static_cast<void*>(0);
}
size_type max_count = m_header.m_size/sizeof_object; size_type max_count = m_header.m_size/sizeof_object;
if(limit_size > max_count || preferred_size > max_count){ if(limit_size > max_count || preferred_size > max_count){
return reuse_ptr = 0, static_cast<void*>(0); return reuse_ptr = 0, static_cast<void*>(0);
@@ -668,85 +610,6 @@ simple_seq_fit_impl<MutexFamily, VoidPointer>::size(const void *ptr) const
return block->get_user_bytes(); return block->get_user_bytes();
} }
template<class MutexFamily, class VoidPointer>
void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_expand_both_sides(boost::interprocess::allocation_type command
,size_type min_size
,size_type &prefer_in_recvd_out_size
,void *reuse_ptr
,bool only_preferred_backwards)
{
size_type const preferred_size = prefer_in_recvd_out_size;
typedef std::pair<block_ctrl *, block_ctrl *> prev_block_t;
block_ctrl *reuse = priv_get_block(reuse_ptr);
prefer_in_recvd_out_size = 0;
if(this->size(reuse_ptr) > min_size){
prefer_in_recvd_out_size = this->size(reuse_ptr);
return reuse_ptr;
}
if(command & boost::interprocess::expand_fwd){
if(priv_expand(reuse_ptr, min_size, prefer_in_recvd_out_size = preferred_size))
return reuse_ptr;
}
else{
prefer_in_recvd_out_size = this->size(reuse_ptr);
}
if(command & boost::interprocess::expand_bwd){
size_type extra_forward = !prefer_in_recvd_out_size ? 0 : prefer_in_recvd_out_size + BlockCtrlBytes;
prev_block_t prev_pair = priv_prev_block_if_free(reuse);
block_ctrl *prev = prev_pair.second;
if(!prev){
return 0;
}
size_type needs_backwards =
ipcdetail::get_rounded_size(preferred_size - extra_forward, Alignment);
if(!only_preferred_backwards){
max_value(ipcdetail::get_rounded_size(min_size - extra_forward, Alignment)
,min_value(prev->get_user_bytes(), needs_backwards));
}
//Check if previous block has enough size
if((prev->get_user_bytes()) >= needs_backwards){
//Now take all next space. This will succeed
if(!priv_expand(reuse_ptr, prefer_in_recvd_out_size, prefer_in_recvd_out_size)){
BOOST_ASSERT(0);
}
//We need a minimum size to split the previous one
if((prev->get_user_bytes() - needs_backwards) > 2*BlockCtrlBytes){
block_ctrl *new_block = move_detail::force_ptr<block_ctrl*>
(reinterpret_cast<char*>(reuse) - needs_backwards - BlockCtrlBytes);
new_block->m_next = 0;
new_block->m_size =
BlockCtrlUnits + (needs_backwards + extra_forward)/Alignment;
prev->m_size =
(prev->get_total_bytes() - needs_backwards)/Alignment - BlockCtrlUnits;
prefer_in_recvd_out_size = needs_backwards + extra_forward;
m_header.m_allocated += needs_backwards + BlockCtrlBytes;
return priv_get_user_buffer(new_block);
}
else{
//Just merge the whole previous block
block_ctrl *prev_2_block = prev_pair.first;
//Update received size and allocation
prefer_in_recvd_out_size = extra_forward + prev->get_user_bytes();
m_header.m_allocated += prev->get_total_bytes();
//Now unlink it from previous block
prev_2_block->m_next = prev->m_next;
prev->m_size = reuse->m_size + prev->m_size;
prev->m_next = 0;
priv_get_user_buffer(prev);
}
}
}
return 0;
}
template<class MutexFamily, class VoidPointer> template<class MutexFamily, class VoidPointer>
inline void simple_seq_fit_impl<MutexFamily, VoidPointer>:: inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::
deallocate_many(typename simple_seq_fit_impl<MutexFamily, VoidPointer>::multiallocation_chain &chain) deallocate_many(typename simple_seq_fit_impl<MutexFamily, VoidPointer>::multiallocation_chain &chain)
@@ -772,8 +635,17 @@ simple_seq_fit_impl<MutexFamily, VoidPointer>::
template<class MutexFamily, class VoidPointer> template<class MutexFamily, class VoidPointer>
void * simple_seq_fit_impl<MutexFamily, VoidPointer>:: void * simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_allocate(boost::interprocess::allocation_type command priv_allocate(boost::interprocess::allocation_type command
,size_type limit_size, size_type &prefer_in_recvd_out_size, void *&reuse_ptr) ,size_type limit_size, size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type alignof_object)
{ {
//Backwards expansion not supported
command &= ~boost::interprocess::expand_bwd;
if(!command){
return reuse_ptr = 0, static_cast<void*>(0);
}
if(alignof_object < Alignment)
alignof_object = Alignment;
size_type const preferred_size = prefer_in_recvd_out_size; size_type const preferred_size = prefer_in_recvd_out_size;
if(command & boost::interprocess::shrink_in_place){ if(command & boost::interprocess::shrink_in_place){
if(!reuse_ptr) return static_cast<void*>(0); if(!reuse_ptr) return static_cast<void*>(0);
@@ -798,32 +670,35 @@ void * simple_seq_fit_impl<MutexFamily, VoidPointer>::
size_type biggest_size = 0; size_type biggest_size = 0;
//Expand in place //Expand in place
if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ if( reuse_ptr && (command & boost::interprocess::expand_fwd) &&
void *ret = priv_expand_both_sides(command, limit_size, prefer_in_recvd_out_size = preferred_size, reuse_ptr, true); priv_expand(reuse_ptr, limit_size, prefer_in_recvd_out_size = preferred_size) ){
if(ret){ return reuse_ptr;
algo_impl_t::assert_alignment(ret);
return ret;
}
} }
if(command & boost::interprocess::allocate_new){ if(command & boost::interprocess::allocate_new){
prefer_in_recvd_out_size = 0;
while(block != root){ if (alignof_object > Alignment) {
//Update biggest block pointers return algo_impl_t::allocate_aligned(this, limit_size, alignof_object);
if(block->m_size > biggest_size){ }
prev_biggest_block = prev; else {
biggest_size = block->m_size; prefer_in_recvd_out_size = 0;
biggest_block = block; while(block != root){
//Update biggest block pointers
if(block->m_size > biggest_size){
prev_biggest_block = prev;
biggest_size = block->m_size;
biggest_block = block;
}
algo_impl_t::assert_alignment(block);
void *addr = this->priv_check_and_allocate(nunits, prev, block, prefer_in_recvd_out_size);
if(addr){
algo_impl_t::assert_alignment(addr);
return reuse_ptr = 0, addr;
}
//Bad luck, let's check next block
prev = block;
block = ipcdetail::to_raw_pointer(block->m_next);
} }
algo_impl_t::assert_alignment(block);
void *addr = this->priv_check_and_allocate(nunits, prev, block, prefer_in_recvd_out_size);
if(addr){
algo_impl_t::assert_alignment(addr);
return reuse_ptr = 0, addr;
}
//Bad luck, let's check next block
prev = block;
block = ipcdetail::to_raw_pointer(block->m_next);
} }
//Bad luck finding preferred_size, now if we have any biggest_block //Bad luck finding preferred_size, now if we have any biggest_block
@@ -840,12 +715,6 @@ void * simple_seq_fit_impl<MutexFamily, VoidPointer>::
return reuse_ptr = 0, ret; return reuse_ptr = 0, ret;
} }
} }
//Now try to expand both sides with min size
if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){
void *ret = priv_expand_both_sides (command, limit_size, prefer_in_recvd_out_size = preferred_size, reuse_ptr, false);
algo_impl_t::assert_alignment(ret);
return ret;
}
return reuse_ptr = 0, static_cast<void*>(0); return reuse_ptr = 0, static_cast<void*>(0);
} }
@@ -921,6 +790,11 @@ template<class MutexFamily, class VoidPointer>
inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>:: inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_expand (void *ptr, size_type min_size, size_type &received_size) priv_expand (void *ptr, size_type min_size, size_type &received_size)
{ {
if(this->size(ptr) > min_size){
received_size = this->size(ptr);
return ptr;
}
size_type preferred_size = received_size; size_type preferred_size = received_size;
//Obtain the real size of the block //Obtain the real size of the block
block_ctrl *block = move_detail::force_ptr<block_ctrl*>(priv_get_block(ptr)); block_ctrl *block = move_detail::force_ptr<block_ctrl*>(priv_get_block(ptr));

View File

@@ -226,16 +226,6 @@ class rbtree_best_fit
//!Experimental. Dont' use //!Experimental. Dont' use
void deallocate_many(multiallocation_chain &chain); void deallocate_many(multiallocation_chain &chain);
template<class T>
BOOST_INTERPROCESS_NODISCARD
T* allocation_command(boost::interprocess::allocation_type command, size_type limit_size,
size_type& prefer_in_recvd_out_size, T*& reuse);
BOOST_INTERPROCESS_NODISCARD
void* raw_allocation_command(boost::interprocess::allocation_type command, size_type limit_object,
size_type& prefer_in_recvd_out_size,
void*& reuse_ptr, size_type sizeof_object = 1);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Returns the size of the memory segment //!Returns the size of the memory segment
@@ -275,6 +265,12 @@ class rbtree_best_fit
void* allocate_aligned (size_type nbytes, size_type alignment); void* allocate_aligned (size_type nbytes, size_type alignment);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
void* allocation_command ( boost::interprocess::allocation_type command, size_type limit_size
, size_type &prefer_in_recvd_out_size, void *&reuse_ptr
, size_type sizeof_object, size_type alignof_object
);
private: private:
static size_type priv_first_block_offset_from_this(const void *this_ptr, size_type extra_hdr_bytes); static size_type priv_first_block_offset_from_this(const void *this_ptr, size_type extra_hdr_bytes);
@@ -282,14 +278,10 @@ class rbtree_best_fit
block_ctrl *priv_end_block(); block_ctrl *priv_end_block();
void* priv_allocation_command(boost::interprocess::allocation_type command, size_type limit_size,
size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object);
//!Real allocation algorithm with min allocation option //!Real allocation algorithm with min allocation option
void * priv_allocate( boost::interprocess::allocation_type command void * priv_allocate( boost::interprocess::allocation_type command
, size_type limit_size, size_type &prefer_in_recvd_out_size , size_type limit_size, size_type &prefer_in_recvd_out_size
, void *&reuse_ptr, size_type backwards_multiple = 1); , void *&reuse_ptr, size_type sizeof_object = 1, size_type alignof_object = Alignment);
//!Obtains the block control structure of the user buffer //!Obtains the block control structure of the user buffer
static block_ctrl *priv_get_block(const void *ptr); static block_ctrl *priv_get_block(const void *ptr);
@@ -310,7 +302,8 @@ class rbtree_best_fit
,size_type &prefer_in_recvd_out_size ,size_type &prefer_in_recvd_out_size
,void *reuse_ptr ,void *reuse_ptr
,bool only_preferred_backwards ,bool only_preferred_backwards
,size_type backwards_multiple); ,size_type sizeof_object
,size_type alignof_object);
//!Returns true if the previous block is allocated //!Returns true if the previous block is allocated
bool priv_is_prev_allocated(block_ctrl *ptr); bool priv_is_prev_allocated(block_ctrl *ptr);
@@ -707,47 +700,14 @@ inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
return algo_impl_t::allocate_aligned(this, nbytes, alignment); return algo_impl_t::allocate_aligned(this, nbytes, alignment);
} }
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
template<class T>
inline T* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
size_type &prefer_in_recvd_out_size, T *&reuse)
{
void* raw_reuse = reuse;
void* const ret = priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, raw_reuse, sizeof(T));
reuse = static_cast<T*>(raw_reuse);
BOOST_ASSERT(0 == ((std::size_t)ret % ::boost::container::dtl::alignment_of<T>::value));
return static_cast<T*>(ret);
}
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment> template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>:: inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects, allocation_command ( boost::interprocess::allocation_type command
size_type &prefer_in_recvd_out_objects, void *&reuse_ptr, size_type sizeof_object) , size_type limit_size
{ , size_type &prefer_in_recvd_out_size
size_type const preferred_objects = prefer_in_recvd_out_objects; , void *&reuse_ptr
if(!sizeof_object) , size_type sizeof_object
return reuse_ptr = 0, static_cast<void*>(0); , size_type alignof_object )
if(command & boost::interprocess::try_shrink_in_place){
if(!reuse_ptr) return static_cast<void*>(0);
const bool success = algo_impl_t::try_shrink
( this, reuse_ptr, limit_objects*sizeof_object
, prefer_in_recvd_out_objects = preferred_objects*sizeof_object);
prefer_in_recvd_out_objects /= sizeof_object;
return success ? reuse_ptr : 0;
}
else{
return priv_allocation_command
(command, limit_objects, prefer_in_recvd_out_objects, reuse_ptr, sizeof_object);
}
}
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
priv_allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
size_type &prefer_in_recvd_out_size,
void *&reuse_ptr, size_type sizeof_object)
{ {
void* ret; void* ret;
size_type const preferred_size = prefer_in_recvd_out_size; size_type const preferred_size = prefer_in_recvd_out_size;
@@ -758,11 +718,12 @@ inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
size_type l_size = limit_size*sizeof_object; size_type l_size = limit_size*sizeof_object;
size_type p_size = preferred_size*sizeof_object; size_type p_size = preferred_size*sizeof_object;
size_type r_size; size_type r_size;
{ {
//----------------------- //-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header); boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//----------------------- //-----------------------
ret = priv_allocate(command, l_size, r_size = p_size, reuse_ptr, sizeof_object); ret = priv_allocate(command, l_size, r_size = p_size, reuse_ptr, sizeof_object, alignof_object);
} }
prefer_in_recvd_out_size = r_size/sizeof_object; prefer_in_recvd_out_size = r_size/sizeof_object;
return ret; return ret;
@@ -811,7 +772,8 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
,size_type &prefer_in_recvd_out_size ,size_type &prefer_in_recvd_out_size
,void *reuse_ptr ,void *reuse_ptr
,bool only_preferred_backwards ,bool only_preferred_backwards
,size_type backwards_multiple) ,size_type sizeof_object
,size_type alignof_object)
{ {
size_type const preferred_size = prefer_in_recvd_out_size; size_type const preferred_size = prefer_in_recvd_out_size;
algo_impl_t::assert_alignment(reuse_ptr); algo_impl_t::assert_alignment(reuse_ptr);
@@ -825,9 +787,9 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
return reuse_ptr; return reuse_ptr;
} }
if(backwards_multiple){ if(sizeof_object){
BOOST_ASSERT(0 == (min_size % backwards_multiple)); BOOST_ASSERT(0 == (min_size % sizeof_object));
BOOST_ASSERT(0 == (preferred_size % backwards_multiple)); BOOST_ASSERT(0 == (preferred_size % sizeof_object));
} }
if(command & boost::interprocess::expand_bwd){ if(command & boost::interprocess::expand_bwd){
@@ -854,7 +816,8 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
size_type needs_backwards_aligned; size_type needs_backwards_aligned;
size_type lcm; size_type lcm;
if(!algo_impl_t::calculate_lcm_and_needs_backwards_lcmed if(!algo_impl_t::calculate_lcm_and_needs_backwards_lcmed
( backwards_multiple ( sizeof_object
, alignof_object
, prefer_in_recvd_out_size , prefer_in_recvd_out_size
, only_preferred_backwards ? preferred_size : min_size , only_preferred_backwards ? preferred_size : min_size
, lcm, needs_backwards_aligned)){ , lcm, needs_backwards_aligned)){
@@ -910,7 +873,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
//first bytes, fill them with a pattern //first bytes, fill them with a pattern
void *p = priv_get_user_buffer(new_block); void *p = priv_get_user_buffer(new_block);
void *user_ptr = reinterpret_cast<char*>(p); void *user_ptr = reinterpret_cast<char*>(p);
BOOST_ASSERT(size_type(static_cast<char*>(reuse_ptr) - static_cast<char*>(user_ptr)) % backwards_multiple == 0); BOOST_ASSERT(size_type(static_cast<char*>(reuse_ptr) - static_cast<char*>(user_ptr)) % sizeof_object == 0);
algo_impl_t::assert_alignment(user_ptr); algo_impl_t::assert_alignment(user_ptr);
return user_ptr; return user_ptr;
} }
@@ -922,7 +885,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
m_header.m_imultiset.erase(Imultiset::s_iterator_to(*prev_block)); m_header.m_imultiset.erase(Imultiset::s_iterator_to(*prev_block));
//Just merge the whole previous block //Just merge the whole previous block
//prev_block->m_size*Alignment is multiple of lcm (and backwards_multiple) //prev_block->m_size*Alignment is multiple of lcm (and sizeof_object)
prefer_in_recvd_out_size = prefer_in_recvd_out_size + (size_type)prev_block->m_size*Alignment; prefer_in_recvd_out_size = prefer_in_recvd_out_size + (size_type)prev_block->m_size*Alignment;
m_header.m_allocated += (size_type)prev_block->m_size*Alignment; m_header.m_allocated += (size_type)prev_block->m_size*Alignment;
@@ -934,7 +897,7 @@ void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
//If the backwards expansion has remaining bytes in the //If the backwards expansion has remaining bytes in the
//first bytes, fill them with a pattern //first bytes, fill them with a pattern
void *user_ptr = priv_get_user_buffer(prev_block); void *user_ptr = priv_get_user_buffer(prev_block);
BOOST_ASSERT(size_type(static_cast<char*>(reuse_ptr) - static_cast<char*>(user_ptr)) % backwards_multiple == 0); BOOST_ASSERT(size_type(static_cast<char*>(reuse_ptr) - static_cast<char*>(user_ptr)) % sizeof_object == 0);
algo_impl_t::assert_alignment(user_ptr); algo_impl_t::assert_alignment(user_ptr);
return user_ptr; return user_ptr;
} }
@@ -958,12 +921,16 @@ inline void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
template<class MutexFamily, class VoidPointer, std::size_t MemAlignment> template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
void * rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>:: void * rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
priv_allocate(boost::interprocess::allocation_type command priv_allocate( boost::interprocess::allocation_type command
,size_type limit_size , size_type limit_size
,size_type &prefer_in_recvd_out_size , size_type &prefer_in_recvd_out_size
,void *&reuse_ptr , void *&reuse_ptr
,size_type backwards_multiple) , size_type sizeof_object
, size_type alignof_object )
{ {
if(alignof_object < Alignment)
alignof_object = Alignment;
size_type const preferred_size = prefer_in_recvd_out_size; size_type const preferred_size = prefer_in_recvd_out_size;
if(command & boost::interprocess::shrink_in_place){ if(command & boost::interprocess::shrink_in_place){
if(!reuse_ptr) return static_cast<void*>(0); if(!reuse_ptr) return static_cast<void*>(0);
@@ -987,24 +954,29 @@ void * rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
prefer_in_recvd_out_size = preferred_size; prefer_in_recvd_out_size = preferred_size;
if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){
void *ret = priv_expand_both_sides void *ret = priv_expand_both_sides
(command, limit_size, prefer_in_recvd_out_size, reuse_ptr, true, backwards_multiple); (command, limit_size, prefer_in_recvd_out_size, reuse_ptr, true, sizeof_object, alignof_object);
if(ret) if(ret)
return ret; return ret;
} }
if(command & boost::interprocess::allocate_new){ if(command & boost::interprocess::allocate_new){
size_block_ctrl_compare comp; if (alignof_object > Alignment) {
imultiset_iterator it(m_header.m_imultiset.lower_bound(preferred_units, comp)); return algo_impl_t::allocate_aligned(this, limit_size, alignof_object);
if(it != m_header.m_imultiset.end()){
return reuse_ptr = 0, this->priv_check_and_allocate
(preferred_units, ipcdetail::to_raw_pointer(&*it), prefer_in_recvd_out_size);
} }
else {
size_block_ctrl_compare comp;
imultiset_iterator it(m_header.m_imultiset.lower_bound(preferred_units, comp));
if(it != m_header.m_imultiset.begin()&& if(it != m_header.m_imultiset.end()){
(--it)->m_size >= limit_units){ return reuse_ptr = 0, this->priv_check_and_allocate
return reuse_ptr = 0, this->priv_check_and_allocate (preferred_units, ipcdetail::to_raw_pointer(&*it), prefer_in_recvd_out_size);
(it->m_size, ipcdetail::to_raw_pointer(&*it), prefer_in_recvd_out_size); }
if(it != m_header.m_imultiset.begin()&&
(--it)->m_size >= limit_units){
return reuse_ptr = 0, this->priv_check_and_allocate
(it->m_size, ipcdetail::to_raw_pointer(&*it), prefer_in_recvd_out_size);
}
} }
} }
@@ -1012,7 +984,12 @@ void * rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
//Now try to expand both sides with min size //Now try to expand both sides with min size
if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){
return priv_expand_both_sides return priv_expand_both_sides
(command, limit_size, prefer_in_recvd_out_size = preferred_size, reuse_ptr, false, backwards_multiple); ( command, limit_size
, prefer_in_recvd_out_size = preferred_size
, reuse_ptr
, false
, sizeof_object
, alignof_object);
} }
return reuse_ptr = 0, static_cast<void*>(0); return reuse_ptr = 0, static_cast<void*>(0);
} }

View File

@@ -105,7 +105,7 @@ class segment_manager_base
segment_manager_base(size_type sz, size_type reserved_bytes) segment_manager_base(size_type sz, size_type reserved_bytes)
: MemoryAlgorithm(sz, reserved_bytes) : MemoryAlgorithm(sz, reserved_bytes)
{ {
BOOST_ASSERT((sizeof(segment_manager_base<MemoryAlgorithm>) == sizeof(MemoryAlgorithm))); BOOST_INTERPROCESS_STATIC_ASSERT((sizeof(segment_manager_base<MemoryAlgorithm>) == sizeof(MemoryAlgorithm)));
} }
//!Returns the size of the memory //!Returns the size of the memory
@@ -128,63 +128,6 @@ class segment_manager_base
void * allocate (size_type nbytes, const std::nothrow_t &) void * allocate (size_type nbytes, const std::nothrow_t &)
{ return MemoryAlgorithm::allocate(nbytes); } { return MemoryAlgorithm::allocate(nbytes); }
//!Returns a reference to the internal memory algorithm.
//!This function is useful for custom memory algorithms that
//!need additional configuration options after construction. Never throws.
//!This function should be only used by advanced users.
MemoryAlgorithm &get_memory_algorithm()
{ return static_cast<MemoryAlgorithm&>(*this); }
//!Returns a const reference to the internal memory algorithm.
//!This function is useful for custom memory algorithms that
//!need additional configuration options after construction. Never throws.
//!This function should be only used by advanced users.
const MemoryAlgorithm &get_memory_algorithm() const
{ return static_cast<const MemoryAlgorithm&>(*this); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Experimental. Dont' use.
//!Allocates n_elements of elem_bytes bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{
size_type prev_size = chain.size();
MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain);
if(!elem_bytes || chain.size() == prev_size){
throw bad_alloc();
}
}
//!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{
size_type prev_size = chain.size();
MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain);
if(!sizeof_element || chain.size() == prev_size){
throw bad_alloc();
}
}
//!Allocates n_elements of elem_bytes bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{ MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); }
//!Allocates n_elements, each one of
//!element_lengths[i]*sizeof_element bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{ MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); }
//!Deallocates all elements contained in chain.
//!Never throws.
void deallocate_many(multiallocation_chain &chain)
{ MemoryAlgorithm::deallocate_many(chain); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
//!on failure //!on failure
void * allocate(size_type nbytes) void * allocate(size_type nbytes)
@@ -210,33 +153,7 @@ class segment_manager_base
return ret; return ret;
} }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) //!Deallocates the bytes allocated with allocate/allocate_aligned()
template<class T>
T *allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
size_type &prefer_in_recvd_out_size, T *&reuse)
{
T *ret = MemoryAlgorithm::allocation_command
(command | boost::interprocess::nothrow_allocation, limit_size, prefer_in_recvd_out_size, reuse);
if(!(command & boost::interprocess::nothrow_allocation) && !ret)
throw bad_alloc();
return ret;
}
void *raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects,
size_type &prefer_in_recvd_out_size, void *&reuse, size_type sizeof_object = 1)
{
void *ret = MemoryAlgorithm::raw_allocation_command
( command | boost::interprocess::nothrow_allocation, limit_objects,
prefer_in_recvd_out_size, reuse, sizeof_object);
if(!(command & boost::interprocess::nothrow_allocation) && !ret)
throw bad_alloc();
return ret;
}
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Deallocates the bytes allocated with allocate/allocate_many()
//!pointed by addr //!pointed by addr
void deallocate (void *addr) void deallocate (void *addr)
{ MemoryAlgorithm::deallocate(addr); } { MemoryAlgorithm::deallocate(addr); }
@@ -273,6 +190,91 @@ class segment_manager_base
//!Returns the size of the buffer previously allocated pointed by ptr //!Returns the size of the buffer previously allocated pointed by ptr
size_type size(const void *ptr) const size_type size(const void *ptr) const
{ return MemoryAlgorithm::size(ptr); } { return MemoryAlgorithm::size(ptr); }
//!Returns a reference to the internal memory algorithm.
//!This function is useful for custom memory algorithms that
//!need additional configuration options after construction. Never throws.
//!This function should be only used by advanced users.
MemoryAlgorithm &get_memory_algorithm()
{ return static_cast<MemoryAlgorithm&>(*this); }
//!Returns a const reference to the internal memory algorithm.
//!This function is useful for custom memory algorithms that
//!need additional configuration options after construction. Never throws.
//!This function should be only used by advanced users.
const MemoryAlgorithm &get_memory_algorithm() const
{ return static_cast<const MemoryAlgorithm&>(*this); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Experimental. Don't use.
//!Allocates n_elements of elem_bytes bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{
size_type prev_size = chain.size();
MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain);
if(!elem_bytes || chain.size() == prev_size){
throw bad_alloc();
}
}
//Experimental. Don't use.
//!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{
size_type prev_size = chain.size();
MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain);
if(!sizeof_element || chain.size() == prev_size){
throw bad_alloc();
}
}
//Experimental. Don't use.
//!Allocates n_elements of elem_bytes bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{ MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); }
//Experimental. Don't use.
//!Allocates n_elements, each one of
//!element_lengths[i]*sizeof_element bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{ MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); }
//Experimental. Don't use.
//!Deallocates all elements contained in chain.
//!Never throws.
void deallocate_many(multiallocation_chain &chain)
{ MemoryAlgorithm::deallocate_many(chain); }
//Experimental. Don't use.
template<class T>
T *allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
size_type &prefer_in_recvd_out_size, T *&reuse)
{
void* raw_reuse = reuse;
const size_type al = ::boost::container::dtl::alignment_of<T>::value;
void* const ret = this->allocation_command(command, limit_size, prefer_in_recvd_out_size, raw_reuse, sizeof(T), al);
reuse = static_cast<T*>(raw_reuse);
BOOST_ASSERT(0 == ((std::size_t)ret % al));
return static_cast<T*>(ret);
}
//Experimental. Don't use.
void *allocation_command ( boost::interprocess::allocation_type command, size_type limit_size
, size_type &prefer_in_recvd_out_size, void *&reuse, size_type sizeof_object, size_type alignof_object )
{
void *ret = MemoryAlgorithm::allocation_command
(command | boost::interprocess::nothrow_allocation, limit_size, prefer_in_recvd_out_size, reuse, sizeof_object, alignof_object);
if(!(command & boost::interprocess::nothrow_allocation) && !ret)
throw bad_alloc();
return ret;
}
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
}; };
//!This object is placed in the beginning of memory segment and //!This object is placed in the beginning of memory segment and

View File

@@ -149,46 +149,51 @@ bool test_allocation_expand(SegMngr &sm)
{ {
std::vector<void*> buffers; std::vector<void*> buffers;
//Allocate buffers with extra memory //We will repeat this test for different sized elements and alignments
for(std::size_t i = 0; true; ++i){ for(std::size_t al = 1; al <= SegMngr::MemAlignment*32u; al *= 2u) {
void *ptr = sm.allocate(i, std::nothrow); //Allocate buffers with extra memory
if(!ptr) for(std::size_t i = 0; true; ++i){
break; void *ptr = al > SegMngr::MemAlignment
std::size_t size = sm.size(ptr); ? sm.allocate_aligned(i, al, std::nothrow)
std::memset(ptr, 0, size); : sm.allocate(i, std::nothrow);
buffers.push_back(ptr); if(!ptr)
} break;
std::size_t size = sm.size(ptr);
//Now try to expand to the double of the size std::memset(ptr, 0, size);
for(std::size_t i = 0, max = buffers.size() buffers.push_back(ptr);
;i < max
;++i){
typename SegMngr::size_type received_size;
std::size_t min_size = i+1;
std::size_t preferred_size = i*2;
preferred_size = min_size > preferred_size ? min_size : preferred_size;
char *reuse = static_cast<char*>(buffers[i]);
while(sm.template allocation_command<char>
( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size
, received_size = preferred_size, reuse)){
//Check received size is bigger than minimum
if(received_size < min_size){
return false;
}
//Now, try to expand further
min_size = received_size+1;
preferred_size = min_size*2;
} }
}
//Deallocate it in non sequential order //Now try to expand to the double of the size
for(std::size_t j = 0, max = buffers.size() for(std::size_t i = 0, max = buffers.size()
;j < max ;i < max
;++j){ ;++i){
std::size_t pos = (j%4)*(buffers.size())/4; typename SegMngr::size_type received_size;
sm.deallocate(buffers[pos]); std::size_t min_size = i+1;
buffers.erase(buffers.begin()+std::ptrdiff_t(pos)); std::size_t preferred_size = i*2;
preferred_size = min_size > preferred_size ? min_size : preferred_size;
char *reuse = static_cast<char*>(buffers[i]);
while(sm.template allocation_command<char>
( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size
, received_size = preferred_size, reuse)){
//Check received size is bigger than minimum
if(received_size < min_size){
return false;
}
//Now, try to expand further
min_size = received_size+1;
preferred_size = min_size*2;
}
}
//Deallocate it in non sequential order
for(std::size_t j = 0, max = buffers.size()
;j < max
;++j){
std::size_t pos = (j%4)*(buffers.size())/4;
sm.deallocate(buffers[pos]);
buffers.erase(buffers.begin()+std::ptrdiff_t(pos));
}
} }
return sm.all_memory_deallocated() && sm.check_sanity(); return sm.all_memory_deallocated() && sm.check_sanity();
@@ -351,13 +356,16 @@ bool test_allocation_deallocation_expand(SegMngr &sm)
template<class SegMngr> template<class SegMngr>
bool test_allocation_with_reuse(SegMngr &sm) bool test_allocation_with_reuse(SegMngr &sm)
{ {
//We will repeat this test for different sized elements //We will repeat this test for different sized elements and alignments
for(std::size_t al = 1; al <= SegMngr::MemAlignment*32u; al *= 2u)
for(std::size_t sizeof_object = 1; sizeof_object < 20u; ++sizeof_object){ for(std::size_t sizeof_object = 1; sizeof_object < 20u; ++sizeof_object){
std::vector<void*> buffers; std::vector<void*> buffers;
//Allocate buffers with extra memory //Allocate buffers with extra memory
for(std::size_t i = 0; true; ++i){ for(std::size_t i = 0; true; ++i){
void *ptr = sm.allocate(i*sizeof_object, std::nothrow); void *ptr = al > SegMngr::MemAlignment
? sm.allocate_aligned(i*sizeof_object, al, std::nothrow)
: sm.allocate(i*sizeof_object, std::nothrow);
if(!ptr) if(!ptr)
break; break;
std::size_t size = sm.size(ptr); std::size_t size = sm.size(ptr);
@@ -379,16 +387,17 @@ bool test_allocation_with_reuse(SegMngr &sm)
//Now allocate with reuse //Now allocate with reuse
typename SegMngr::size_type received_size = 0; typename SegMngr::size_type received_size = 0;
// for(std::size_t al = 0; al <= 512u; ++h){
for(std::size_t i = 0; true; ++i){ for(std::size_t i = 0; true; ++i){
std::size_t min_size = (received_size + 1); std::size_t min_size = (received_size + 1);
std::size_t prf_size = (received_size + (i+1)*2); std::size_t prf_size = (received_size + (i+1)*2);
void *reuse = ptr; void *reuse = ptr;
void *ret = sm.raw_allocation_command void *ret = sm.allocation_command
( boost::interprocess::expand_bwd | boost::interprocess::nothrow_allocation, min_size ( boost::interprocess::expand_bwd | boost::interprocess::nothrow_allocation, min_size
, received_size = prf_size, reuse, sizeof_object/*, alignof_object*/); , received_size = prf_size, reuse, sizeof_object, al);
if(!ret) if(!ret)
break; break;
if(((std::size_t)ret & (al - 1)) != 0)
return 1;
//If we have memory, this must be a buffer reuse //If we have memory, this must be a buffer reuse
if(!reuse) if(!reuse)
return 1; return 1;
@@ -992,15 +1001,6 @@ bool test_all_allocation(SegMngr &sm)
return false; return false;
} }
std::cout << "Starting test_allocation_with_reuse. Class: "
<< typeid(sm).name() << std::endl;
if(!test_allocation_with_reuse(sm)){
std::cout << "test_allocation_with_reuse failed. Class: "
<< typeid(sm).name() << std::endl;
return false;
}
std::cout << "Starting test_aligned_allocation. Class: " std::cout << "Starting test_aligned_allocation. Class: "
<< typeid(sm).name() << std::endl; << typeid(sm).name() << std::endl;
@@ -1019,6 +1019,15 @@ bool test_all_allocation(SegMngr &sm)
return false; return false;
} }
std::cout << "Starting test_allocation_with_reuse. Class: "
<< typeid(sm).name() << std::endl;
if(!test_allocation_with_reuse(sm)){
std::cout << "test_allocation_with_reuse failed. Class: "
<< typeid(sm).name() << std::endl;
return false;
}
std::cout << "Starting test_clear_free_memory. Class: " std::cout << "Starting test_clear_free_memory. Class: "
<< typeid(sm).name() << std::endl; << typeid(sm).name() << std::endl;