Skip to content

Commit 9fcfda9

Browse files
committed
Reimplement managed_heap_memory to use overaligned capable operator new instead of a vector of chars, since the alignment required by a segment manager alignment might be bigger than the default one provided by mallo.c
1 parent 70364b4 commit 9fcfda9

3 files changed

Lines changed: 260 additions & 17 deletions

File tree

include/boost/interprocess/detail/managed_memory_impl.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,31 +226,31 @@ class basic_managed_memory_impl
226226

227227
//!Returns the base address of the memory in this process. Never throws.
228228
void * get_address () const
229-
{ return reinterpret_cast<char*>(mp_header) - Offset; }
229+
{ return mp_header ? reinterpret_cast<char*>(mp_header) - Offset : 0; }
230230

231231
//!Returns the size of memory segment. Never throws.
232232
size_type get_size () const
233-
{ return mp_header->get_size() + Offset; }
233+
{ return mp_header ? mp_header->get_size() + Offset : 0u; }
234234

235235
//!Returns the number of free bytes of the memory
236236
//!segment
237237
size_type get_free_memory() const
238-
{ return mp_header->get_free_memory(); }
238+
{ return mp_header ? mp_header->get_free_memory() : 0; }
239239

240240
//!Returns the result of "all_memory_deallocated()" function
241241
//!of the used memory algorithm
242242
bool all_memory_deallocated()
243-
{ return mp_header->all_memory_deallocated(); }
243+
{ return mp_header ? mp_header->all_memory_deallocated() : true; }
244244

245245
//!Returns the result of "check_sanity()" function
246246
//!of the used memory algorithm
247247
bool check_sanity()
248-
{ return mp_header->check_sanity(); }
248+
{ return mp_header ? mp_header->check_sanity() : true; }
249249

250250
//!Writes to zero free memory (memory not yet allocated) of
251251
//!the memory algorithm
252252
void zero_free_memory()
253-
{ mp_header->zero_free_memory(); }
253+
{ if (mp_header) mp_header->zero_free_memory(); }
254254

255255
//!Transforms an absolute address into an offset from base address.
256256
//!The address must belong to the memory segment. Never throws.

include/boost/interprocess/managed_heap_memory.hpp

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@
2323
#include <boost/interprocess/detail/workaround.hpp>
2424
#include <boost/interprocess/creation_tags.hpp>
2525
#include <boost/move/utility_core.hpp>
26-
#include <vector>
2726
#include <boost/interprocess/detail/managed_memory_impl.hpp>
2827
//These includes needed to fulfill default template parameters of
2928
//predeclarations in interprocess_fwd.hpp
3029
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
3130
#include <boost/interprocess/sync/mutex_family.hpp>
3231
#include <boost/interprocess/indexes/iset_index.hpp>
32+
#include <boost/container/detail/operator_new_helpers.hpp>
33+
#include <cstring>
3334

3435
//!\file
3536
//!Describes a named heap memory allocation user class.
@@ -73,10 +74,13 @@ class basic_managed_heap_memory
7374
//!Creates heap memory and initializes the segment manager.
7475
//!This can throw.
7576
basic_managed_heap_memory(size_type size)
76-
: m_heapmem(size, char(0))
7777
{
78-
if(!base_t::create_impl(&m_heapmem[0], size)){
78+
void *const paddr =
79+
boost::container::dtl::operator_new_raw_allocate(size, base_t::segment_manager::MemAlignment);
80+
81+
if(!base_t::create_impl(paddr, size)){
7982
this->priv_close();
83+
boost::container::dtl::operator_delete_raw_deallocate(paddr, size, base_t::segment_manager::MemAlignment);
8084
throw interprocess_exception("Could not initialize heap in basic_managed_heap_memory constructor");
8185
}
8286
}
@@ -107,17 +111,27 @@ class basic_managed_heap_memory
107111
//If memory is reallocated, data will
108112
//be automatically copied
109113
BOOST_INTERPROCESS_TRY{
110-
m_heapmem.resize(m_heapmem.size()+extra_bytes);
114+
const std::size_t old_sz = this->base_t::get_size();
115+
void * const old_ptr = this->base_t::get_address();
116+
const std::size_t new_sz = old_sz + extra_bytes;
117+
//This can throw
118+
void * const new_ptr =
119+
boost::container::dtl::operator_new_raw_allocate
120+
(new_sz, base_t::segment_manager::MemAlignment);
121+
122+
//No-throw steps
123+
std::memcpy(new_ptr, old_ptr, old_sz);
124+
base_t::close_impl();
125+
base_t::open_impl(new_ptr, old_sz);
126+
base_t::grow(extra_bytes);
127+
boost::container::dtl::operator_delete_raw_deallocate
128+
(old_ptr, old_sz, base_t::segment_manager::MemAlignment);
111129
}
112130
BOOST_INTERPROCESS_CATCH(...){
113131
return false;
114132
}
115133
BOOST_INTERPROCESS_CATCH_END
116134

117-
//Grow always works
118-
base_t::close_impl();
119-
base_t::open_impl(&m_heapmem[0], m_heapmem.size());
120-
base_t::grow(extra_bytes);
121135
return true;
122136
}
123137

@@ -126,19 +140,21 @@ class basic_managed_heap_memory
126140
void swap(basic_managed_heap_memory &other) BOOST_NOEXCEPT
127141
{
128142
base_t::swap(other);
129-
m_heapmem.swap(other.m_heapmem);
130143
}
131144

132145
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
133146
private:
134147
//!Frees resources. Never throws.
135148
void priv_close()
136149
{
150+
void * const paddr = this->base_t::get_address();
151+
const std::size_t sz = this->base_t::get_size();
137152
base_t::destroy_impl();
138-
std::vector<char>().swap(m_heapmem);
153+
if(paddr)
154+
boost::container::dtl::operator_delete_raw_deallocate
155+
(paddr, sz, base_t::segment_manager::MemAlignment);
139156
}
140157

141-
std::vector<char> m_heapmem;
142158
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
143159
};
144160

test/managed_heap_memory_test.cpp

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
//////////////////////////////////////////////////////////////////////////////
2+
//
3+
// (C) Copyright Ion Gaztanaga 2025-2025. Distributed under the Boost
4+
// Software License, Version 1.0. (See accompanying file
5+
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
// See http://www.boost.org/libs/interprocess for documentation.
8+
//
9+
//////////////////////////////////////////////////////////////////////////////
10+
11+
#include <boost/interprocess/allocators/allocator.hpp>
12+
#include <boost/container/vector.hpp>
13+
#include <boost/interprocess/managed_heap_memory.hpp>
14+
#include <cstdio>
15+
#include <string>
16+
#include "get_process_id_name.hpp"
17+
18+
using namespace boost::interprocess;
19+
20+
template <class CharT>
21+
struct filename_traits;
22+
23+
template <>
24+
struct filename_traits<char>
25+
{
26+
27+
static const char* get()
28+
{ return filename.c_str(); }
29+
30+
static std::string filename;
31+
};
32+
33+
std::string filename_traits<char>::filename = get_filename();
34+
35+
36+
#ifdef BOOST_INTERPROCESS_WCHAR_NAMED_RESOURCES
37+
38+
template <>
39+
struct filename_traits<wchar_t>
40+
{
41+
42+
static const wchar_t* get()
43+
{ return filename.c_str(); }
44+
45+
static std::wstring filename;
46+
};
47+
48+
std::wstring filename_traits<wchar_t>::filename = get_wfilename();
49+
50+
#endif //#ifdef BOOST_INTERPROCESS_WCHAR_NAMED_RESOURCES
51+
52+
template<class CharT>
53+
int test_managed_heap_memory()
54+
{
55+
const int MemSize = 65536*10;
56+
57+
//STL compatible allocator object for heap
58+
typedef allocator<int, managed_heap_memory::segment_manager>
59+
allocator_int_t;
60+
//A vector that uses that allocator
61+
typedef boost::container::vector<int, allocator_int_t> MyVect;
62+
63+
{
64+
const int max = 100;
65+
void *array[std::size_t(max)];
66+
//Named allocate capable shared memory allocator
67+
managed_heap_memory mheap(MemSize);
68+
69+
std::size_t i;
70+
//Let's allocate some memory
71+
for(i = 0; i < max; ++i){
72+
array[std::ptrdiff_t(i)] = mheap.allocate(i+1u);
73+
}
74+
75+
//Deallocate allocated memory
76+
for(i = 0; i < max; ++i){
77+
mheap.deallocate(array[std::ptrdiff_t(i)]);
78+
}
79+
80+
//Construct the STL-like allocator with the segment manager
81+
const allocator_int_t myallocator (mheap.get_segment_manager());
82+
83+
//Construct vector
84+
MyVect *mheap_vect = mheap.construct<MyVect> ("MyVector") (myallocator);
85+
86+
//Test that vector can be found via name
87+
if(mheap_vect != mheap.find<MyVect>("MyVector").first)
88+
return -1;
89+
90+
//Destroy and check it is not present
91+
mheap.destroy<MyVect> ("MyVector");
92+
mheap_vect = 0;
93+
if(0 != mheap.find<MyVect>("MyVector").first)
94+
return -1;
95+
96+
//Construct a vector in the heap
97+
mheap_vect = mheap.construct<MyVect> ("MyVector") (myallocator);
98+
99+
managed_heap_memory::size_type old_free_memory = mheap.get_free_memory();
100+
101+
//Now grow the file
102+
mheap.grow(MemSize);
103+
104+
//Check vector is still there
105+
mheap_vect = mheap.find<MyVect>("MyVector").first;
106+
if(!mheap_vect)
107+
return -1;
108+
109+
if(mheap.get_size() != (MemSize*2))
110+
return -1;
111+
if(mheap.get_free_memory() <= old_free_memory)
112+
return -1;
113+
114+
//Destroy and check it is not present
115+
mheap.destroy_ptr(mheap_vect);
116+
mheap_vect = 0;
117+
if(0 != mheap.find<MyVect>("MyVector").first)
118+
return -1;
119+
120+
{
121+
//Now test move semantics
122+
managed_heap_memory original(1024u);
123+
managed_heap_memory move_ctor(boost::move(original));
124+
managed_heap_memory move_assign;
125+
move_assign = boost::move(move_ctor);
126+
move_assign.swap(original);
127+
}
128+
}
129+
130+
return 0;
131+
}
132+
133+
int main ()
134+
{
135+
int r;
136+
r = test_managed_heap_memory<char>();
137+
if(r) return r;
138+
#ifdef BOOST_INTERPROCESS_WCHAR_NAMED_RESOURCES
139+
r = test_managed_heap_memory<wchar_t>();
140+
if(r) return r;
141+
#endif
142+
return 0;
143+
}
144+
145+
/*
146+
//////////////////////////////////////////////////////////////////////////////
147+
//
148+
// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost
149+
// Software License, Version 1.0. (See accompanying file
150+
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
151+
//
152+
// See http://www.boost.org/libs/interprocess for documentation.
153+
//
154+
//////////////////////////////////////////////////////////////////////////////
155+
156+
#include <boost/interprocess/detail/workaround.hpp>
157+
//[doc_managed_heap_memory
158+
#include <boost/container/list.hpp>
159+
#include <boost/interprocess/managed_heap_memory.hpp>
160+
#include <boost/interprocess/allocators/allocator.hpp>
161+
#include <cstddef>
162+
163+
using namespace boost::interprocess;
164+
typedef boost::container::list<int, allocator<int, managed_heap_memory::segment_manager> >
165+
MyList;
166+
167+
int main ()
168+
{
169+
//We will create a buffer of 1000 bytes to store a list
170+
managed_heap_memory heap_memory(1000);
171+
172+
MyList * mylist = heap_memory.construct<MyList>("MyList")
173+
(heap_memory.get_segment_manager());
174+
175+
//Obtain handle, that identifies the list in the buffer
176+
managed_heap_memory::handle_t list_handle = heap_memory.get_handle_from_address(mylist);
177+
178+
//Fill list until there is no more memory in the buffer
179+
BOOST_INTERPROCESS_TRY{
180+
while(1) {
181+
mylist->insert(mylist->begin(), 0);
182+
}
183+
}
184+
BOOST_INTERPROCESS_CATCH(const bad_alloc &){
185+
//memory is full
186+
} BOOST_INTERPROCESS_CATCH_END
187+
//Let's obtain the size of the list
188+
MyList::size_type old_size = mylist->size();
189+
//<-
190+
(void)old_size;
191+
//->
192+
193+
//To make the list bigger, let's increase the heap buffer
194+
//in 1000 bytes more.
195+
heap_memory.grow(1000);
196+
197+
//If memory has been reallocated, the old pointer is invalid, so
198+
//use previously obtained handle to find the new pointer.
199+
mylist = static_cast<MyList *>
200+
(heap_memory.get_address_from_handle(list_handle));
201+
202+
//Fill list until there is no more memory in the buffer
203+
BOOST_INTERPROCESS_TRY{
204+
while(1) {
205+
mylist->insert(mylist->begin(), 0);
206+
}
207+
}
208+
BOOST_INTERPROCESS_CATCH(const bad_alloc &){
209+
//memory is full
210+
} BOOST_INTERPROCESS_CATCH_END
211+
212+
//Let's obtain the new size of the list
213+
MyList::size_type new_size = mylist->size();
214+
//<-
215+
(void)new_size;
216+
//->
217+
218+
assert(new_size > old_size);
219+
220+
//Destroy list
221+
heap_memory.destroy_ptr(mylist);
222+
223+
return 0;
224+
}
225+
//]
226+
*/
227+

0 commit comments

Comments
 (0)