From aab87032408d113a1ed65a1c90864f59c7d1e2dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 10 Jan 2026 18:58:01 +0100 Subject: [PATCH] Modify experimental "allocate_many" function to take an alignment parameter. --- doc/interprocess.qbk | 8 +- example/doc_managed_multiple_allocation.cpp | 6 +- .../detail/managed_memory_impl.hpp | 16 +-- .../mem_algo/detail/mem_algo_common.hpp | 10 +- .../mem_algo/detail/simple_seq_fit_impl.hpp | 12 +- .../interprocess/mem_algo/rbtree_best_fit.hpp | 8 +- .../boost/interprocess/segment_manager.hpp | 16 +-- test/memory_algorithm_test_template.hpp | 135 +++++++++--------- 8 files changed, 112 insertions(+), 99 deletions(-) diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index f196e75..d440258 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -3986,7 +3986,7 @@ Here is a small example showing how aligned allocation is used: [section:managed_memory_segment_multiple_allocations Multiple allocation functions] -[caution This feature is experimental, interface and ABI are unstable] +[caution This feature is experimental, API and ABI are unstable] If an application needs to allocate a lot of memory buffers but it needs to deallocate them independently, the application is normally forced to loop @@ -6875,6 +6875,12 @@ thank them: * Added `BOOST_HEADER_DEPRECATED` to ` headers. They were deprecated several releases ago, but this message will annoy existing users to switch to Boost.Container headers. +* Changed the interface of [link managed_memory_segment_advanced_features.managed_memory_segment_multiple_allocations Multiple allocation functions] + (still experimental and API/ABI unstable) to support alignment. + +Added `BOOST_HEADER_DEPRECATED` to ` headers. They were deprecated several releases ago, but this + message will annoy existing users to switch to Boost.Container headers. + * Fixed bugs: * [@https://github.com/boostorg/interprocess/issues/242 GitHub #242 (['"Cygwin compatibility issues"])]. * [@https://github.com/boostorg/interprocess/issues/247 GitHub #247 (['"destruction of move-constructed map using private_adaptive_pool triggers Assertion"])]. diff --git a/example/doc_managed_multiple_allocation.cpp b/example/doc_managed_multiple_allocation.cpp index bd32c3d..fd416e0 100644 --- a/example/doc_managed_multiple_allocation.cpp +++ b/example/doc_managed_multiple_allocation.cpp @@ -38,9 +38,9 @@ int main() managed_shared_memory managed_shm(create_only,test::get_process_id_name(), 65536); - //Allocate 16 elements of 100 bytes in a single call. Non-throwing version. + //Allocate 16 elements of 100 bytes with a minimal alignment of 4, in a single call. Non-throwing version. multiallocation_chain chain; - managed_shm.allocate_many(std::nothrow, 100, 16, chain); + managed_shm.allocate_many(std::nothrow, 100, 16, 4u, chain); //Check if the memory allocation was successful if(chain.empty()) return 1; @@ -68,7 +68,7 @@ int main() for(std::size_t i = 0; i < 10; ++i) sizes[i] = i*3; - managed_shm.allocate_many(sizes, 10, 1, chain); + managed_shm.allocate_many(sizes, 10, 1, 4, chain); managed_shm.deallocate_many(chain); return 0; } diff --git a/include/boost/interprocess/detail/managed_memory_impl.hpp b/include/boost/interprocess/detail/managed_memory_impl.hpp index 2857b64..8d64110 100644 --- a/include/boost/interprocess/detail/managed_memory_impl.hpp +++ b/include/boost/interprocess/detail/managed_memory_impl.hpp @@ -307,24 +307,24 @@ class basic_managed_memory_impl //!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) - { mp_header->allocate_many(elem_bytes, n_elements, chain); } + void allocate_many(size_type elem_bytes, size_type n_elements, size_type alignment, multiallocation_chain &chain) + { mp_header->allocate_many(elem_bytes, n_elements, alignment, chain); } //!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) - { mp_header->allocate_many(element_lengths, n_elements, sizeof_element, chain); } + void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain) + { mp_header->allocate_many(element_lengths, n_elements, sizeof_element, alignment, chain); } //!Allocates n_elements of elem_bytes bytes. //!Non-throwing version. chain.size() is not increased on failure. - void allocate_many(const std::nothrow_t &tag, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) - { mp_header->allocate_many(tag, elem_bytes, n_elements, chain); } + void allocate_many(const std::nothrow_t &tag, size_type elem_bytes, size_type n_elements, size_type alignment, multiallocation_chain &chain) + { mp_header->allocate_many(tag, elem_bytes, n_elements, alignment, 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 &tag, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) - { mp_header->allocate_many(tag, elem_sizes, n_elements, sizeof_element, chain); } + void allocate_many(const std::nothrow_t &tag, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain) + { mp_header->allocate_many(tag, elem_sizes, n_elements, sizeof_element, alignment, chain); } //!Deallocates all elements contained in chain. //!Never throws. 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 9522abc..5daf795 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -125,9 +125,9 @@ class memory_algorithm_common { return get_rounded_size(size, Alignment); } static void allocate_many - (MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + (MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, size_type alignment, multiallocation_chain &chain) { - return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0, chain); + return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, alignment, 0, chain); } static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain) @@ -235,9 +235,10 @@ class memory_algorithm_common , const size_type *elem_sizes , size_type n_elements , size_type sizeof_element + , size_type alignment , multiallocation_chain &chain) { - 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, alignment, chain); } static void* allocate_aligned(MemoryAlgorithm * const memory_algo, const size_type nbytes, const size_type alignment) @@ -487,6 +488,7 @@ class memory_algorithm_common ( MemoryAlgorithm *memory_algo , const size_type *elem_sizes , size_type n_elements + , size_type alignment , size_type sizeof_element , multiallocation_chain &chain) { @@ -530,7 +532,7 @@ class memory_algorithm_common size_type received_size = total_bytes; void *ignore_reuse = 0; void *ret = memory_algo->priv_allocate - (boost::interprocess::allocate_new, min_allocation, received_size, ignore_reuse); + (boost::interprocess::allocate_new, min_allocation, received_size, ignore_reuse, 1, alignment); if(!ret){ break; } 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 775a16b..bf53b92 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 @@ -157,22 +157,22 @@ class simple_seq_fit_impl //!Multiple element allocation, same size //!Experimental. Dont' use - void allocate_many(size_type elem_bytes, size_type num_elements, multiallocation_chain &chain) + void allocate_many(size_type elem_bytes, size_type num_elements, size_type alignment, multiallocation_chain &chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - algo_impl_t::allocate_many(this, elem_bytes, num_elements, chain); + algo_impl_t::allocate_many(this, elem_bytes, num_elements, alignment, chain); } //!Multiple element allocation, different size //!Experimental. Dont' use - void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, chain); + algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, alignment, chain); } //!Multiple element deallocation @@ -229,7 +229,7 @@ class simple_seq_fit_impl //!Real allocation algorithm with min allocation option void * priv_allocate(boost::interprocess::allocation_type command ,size_type min_size - ,size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type alignof_object = Alignment); + ,size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object = 1, size_type alignof_object = Alignment); //!Returns the number of total units that a user buffer //!of "userbytes" bytes really occupies (including header) @@ -635,7 +635,7 @@ simple_seq_fit_impl:: template void * simple_seq_fit_impl:: priv_allocate(boost::interprocess::allocation_type command - ,size_type limit_size, size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type alignof_object) + ,size_type limit_size, size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type /*sizeof_object*/, size_type alignof_object) { //Backwards expansion not supported command &= ~boost::interprocess::expand_bwd; diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index e0595ae..f217aa6 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -204,22 +204,22 @@ class rbtree_best_fit //!Multiple element allocation, same size //!Experimental. Dont' use - void allocate_many(size_type elem_bytes, size_type num_elements, multiallocation_chain &chain) + void allocate_many(size_type elem_bytes, size_type num_elements, size_type alignment, multiallocation_chain &chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - algo_impl_t::allocate_many(this, elem_bytes, num_elements, chain); + algo_impl_t::allocate_many(this, elem_bytes, num_elements, alignment, chain); } //!Multiple element allocation, different size //!Experimental. Dont' use - void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, chain); + algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, alignment, chain); } //!Multiple element allocation, different size diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index 296676a..cee3135 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -210,10 +210,10 @@ class segment_manager_base //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) + void allocate_many(size_type elem_bytes, size_type n_elements, size_type alignment, multiallocation_chain &chain) { size_type prev_size = chain.size(); - MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); + MemoryAlgorithm::allocate_many(elem_bytes, n_elements, alignment, chain); if(!elem_bytes || chain.size() == prev_size){ throw bad_alloc(); } @@ -222,10 +222,10 @@ class segment_manager_base //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) + void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain) { size_type prev_size = chain.size(); - MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain); + MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, alignment, chain); if(!sizeof_element || chain.size() == prev_size){ throw bad_alloc(); } @@ -234,15 +234,15 @@ class segment_manager_base //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); } + void allocate_many(const std::nothrow_t &, size_type elem_bytes, size_type n_elements, size_type alignment, multiallocation_chain &chain) + { MemoryAlgorithm::allocate_many(elem_bytes, n_elements, alignment, 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); } + void allocate_many(const std::nothrow_t &, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain) + { MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, alignment, chain); } //Experimental. Don't use. //!Deallocates all elements contained in chain. diff --git a/test/memory_algorithm_test_template.hpp b/test/memory_algorithm_test_template.hpp index 3b7950b..0c8c818 100644 --- a/test/memory_algorithm_test_template.hpp +++ b/test/memory_algorithm_test_template.hpp @@ -40,7 +40,7 @@ bool test_allocation(SegMngr &sm) void *ptr = sm.allocate(i, std::nothrow); if(!ptr) break; - std::size_t size = sm.size(ptr); + std::size_t size = sm.size(ptr); std::memset(ptr, 0, size); buffers.push_back(ptr); } @@ -700,72 +700,74 @@ bool test_many_equal_allocation(SegMngr &sm) return false; typedef typename SegMngr::multiallocation_chain multiallocation_chain; - std::vector buffers; - for(std::size_t i = 0; true; ++i){ - multiallocation_chain chain; - sm.allocate_many(std::nothrow, i+1, (i+1)*2, chain); - if(chain.empty()) - break; + for(std::size_t al = 1; al <= SegMngr::MemAlignment*32u; al *= 2u) { + std::vector buffers; + for(std::size_t i = 0; true; ++i){ + multiallocation_chain chain; + sm.allocate_many(std::nothrow, i+1, (i+1)*2, al, chain); + if(chain.empty()) + break; - typename multiallocation_chain::size_type n = chain.size(); - while(!chain.empty()){ - buffers.push_back(ipcdetail::to_raw_pointer(chain.pop_front())); + typename multiallocation_chain::size_type n = chain.size(); + while(!chain.empty()){ + buffers.push_back(ipcdetail::to_raw_pointer(chain.pop_front())); + } + if(n != std::size_t((i+1)*2)) + return false; } - if(n != std::size_t((i+1)*2)) + + if(!sm.check_sanity()) return false; - } - if(!sm.check_sanity()) - return false; - - switch(t){ - case DirectDeallocation: - { - for(std::size_t j = 0, max = buffers.size() - ;j < max - ;++j){ - sm.deallocate(buffers[j]); + switch(t){ + case DirectDeallocation: + { + for(std::size_t j = 0, max = buffers.size() + ;j < max + ;++j){ + sm.deallocate(buffers[j]); + } } - } - break; - case InverseDeallocation: - { - for(std::size_t j = buffers.size() - ;j-- - ;){ - sm.deallocate(buffers[j]); + break; + case InverseDeallocation: + { + for(std::size_t j = buffers.size() + ;j-- + ;){ + sm.deallocate(buffers[j]); + } } - } - break; - case MixedDeallocation: - { - 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)); + break; + case MixedDeallocation: + { + 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)); + } } + break; + default: + break; } - break; - default: - break; + + //Deallocate the rest of the blocks + + //Deallocate it in non sequential order + for(std::size_t j = 0, max = buffers2.size() + ;j < max + ;++j){ + std::size_t pos = (j%4)*(buffers2.size())/4; + sm.deallocate(buffers2[pos]); + buffers2.erase(buffers2.begin()+std::ptrdiff_t(pos)); + } + + bool ok = free_memory == sm.get_free_memory() && + sm.all_memory_deallocated() && sm.check_sanity(); + if(!ok) return ok; } - - //Deallocate the rest of the blocks - - //Deallocate it in non sequential order - for(std::size_t j = 0, max = buffers2.size() - ;j < max - ;++j){ - std::size_t pos = (j%4)*(buffers2.size())/4; - sm.deallocate(buffers2[pos]); - buffers2.erase(buffers2.begin()+std::ptrdiff_t(pos)); - } - - bool ok = free_memory == sm.get_free_memory() && - sm.all_memory_deallocated() && sm.check_sanity(); - if(!ok) return ok; } return true; } @@ -776,12 +778,13 @@ template bool test_many_different_allocation(SegMngr &sm) { typedef typename SegMngr::multiallocation_chain multiallocation_chain; - const std::size_t ArraySize = 11; + const std::size_t ArraySize = 22; typename SegMngr::size_type requested_sizes[ArraySize]; for(std::size_t i = 0; i < ArraySize; ++i){ requested_sizes[i] = 4*i; } + for(std::size_t al = 1; al <= SegMngr::MemAlignment*32u; al *= 2u) for( deallocation_type t = DirectDeallocation ; t != EndDeallocationType ; t = (deallocation_type)((int)t + 1)){ @@ -791,7 +794,9 @@ bool test_many_different_allocation(SegMngr &sm) //Allocate buffers with extra memory for(std::size_t i = 0; true; ++i){ - void *ptr = sm.allocate(i, std::nothrow); + void *ptr = al > SegMngr::MemAlignment + ? sm.allocate_aligned(i, al, std::nothrow) + : sm.allocate(i, std::nothrow); if(!ptr) break; std::size_t size = sm.size(ptr); @@ -813,7 +818,7 @@ bool test_many_different_allocation(SegMngr &sm) std::vector buffers; while(true){ multiallocation_chain chain; - sm.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain); + sm.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, al, chain); if(chain.empty()) break; typename multiallocation_chain::size_type n = chain.size(); @@ -881,8 +886,6 @@ bool test_many_different_allocation(SegMngr &sm) template bool test_many_deallocation(SegMngr &sm) { - typedef typename SegMngr::multiallocation_chain multiallocation_chain; - typedef typename SegMngr::multiallocation_chain multiallocation_chain; const std::size_t ArraySize = 11; boost::container::vector buffers; @@ -892,10 +895,11 @@ bool test_many_deallocation(SegMngr &sm) } typename SegMngr::size_type free_memory = sm.get_free_memory(); + for(std::size_t al = 1; al <= SegMngr::MemAlignment*32u; al *= 2u) { while(true){ multiallocation_chain chain; - sm.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain); + sm.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, al, chain); if(chain.empty()) break; buffers.push_back(boost::move(chain)); @@ -909,10 +913,11 @@ bool test_many_deallocation(SegMngr &sm) if(!ok) return ok; } + for(std::size_t al = 1; al <= SegMngr::MemAlignment*32u; al *= 2u) { for(std::size_t i = 0; true; ++i){ multiallocation_chain chain; - sm.allocate_many(std::nothrow, i*4, ArraySize, chain); + sm.allocate_many(std::nothrow, i*4, ArraySize, al, chain); if(chain.empty()) break; buffers.push_back(boost::move(chain));