1111
1212#define DEFAULT_CHUNK_SIZE 1024 *256 // 256KB chunks
1313
14+ // Structure for segments allocated inside of an MMAPed "chunk"
1415struct segment_s {
1516 segment_s* next;
1617 size_t size;
1718 bool is_allocated;
1819 bool is_footer;
1920};
2021
22+ // mmap()'ed parent "chunks", on which variable size "segments" are allocated
2123struct chunk_s {
2224 chunk_s* next;
2325 size_t allocated_size;
@@ -37,10 +39,10 @@ chunk_s* root;
3739chunk_s* cur;
3840size_t pagesize = sysconf(_SC_PAGE_SIZE);
3941
42+ // Add a header and footer identifying metadata for new chunk,
43+ // then add the chunk to the chunk map list.
44+ // Add footer to end of allocation
4045void tag_chunk (char *chunk, size_t aligned_size) {
41- // Add a header and footer identifying metadata for new chunk,
42- // then add the chunk to the chunk map list.
43- // Add footer to end of allocation
4446 struct chunk_s * footer = reinterpret_cast <chunk_s*>(static_cast <char *>(chunk) + (aligned_size - sizeof (chunk_s)));
4547 debug (std::cout, " writing CHUNK footer at" , footer);
4648
@@ -77,31 +79,32 @@ void tag_chunk(char *chunk, size_t aligned_size) {
7779 }
7880}
7981
82+ // Align to OS page size
8083size_t align_to_pagesize (size_t size) {
8184 return (size_t ) (size + (pagesize - (size % pagesize)));
8285}
8386
87+ // Align size to next nearest 4 byte boundary
8488size_t align_4 (size_t size) {
85- // Align size to next nearest 4 byte boundary
8689 return (size_t ) (size + (4 - (size % 4 )));
8790}
8891
92+ // Get a pointer to the first byte of the payload section
93+ // from a segment_s header
8994void * get_payload (uintptr_t addr) {
90- // Get a pointer to the first byte of the payload section
91- // from a segment_s header
9295 return reinterpret_cast <void *>(align_4 (addr + sizeof (segment_s)));
9396}
9497
98+ // Get a pointer to the header struct of payload
9599void * get_header (void * ptr) {
96- // Get a pointer to the header struct of payload
97- return reinterpret_cast <void *>((uintptr_t ) ptr - (sizeof (segment_s)));
100+ return reinterpret_cast <void *>(reinterpret_cast <uintptr_t >(ptr) - (sizeof (segment_s)));
98101}
99102
103+ // Add a chunk capable of containing at least the size passed. By default, create
104+ // a large chunk (specified by DEFAULT_CHUNK_SIZE), unless new() requires more memory
105+ // than the chunk size, in which case, create a chunk aligned up to the nearest page
106+ // beyond the requested size.
100107size_t add_chunk (size_t size) {
101- // Add a chunk capable of containing at least the size passed. By default, create
102- // a large chunk (specified by DEFAULT_CHUNK_SIZE), unless new() requires more memory
103- // than the chunk size, in which case, create a chunk aligned up to the nearest page
104- // beyond the requested size.
105108 size_t aligned_size;
106109
107110 // Pad to ensure there's enough room for desired allocation + headers/footers structs
@@ -117,8 +120,8 @@ size_t add_chunk(size_t size) {
117120 return aligned_size;
118121}
119122
123+ // Find free space in parent chunk, and reserve it
120124void * create_segment_in_chunk (chunk_s* chunk, size_t size) {
121- // Find free space in parent chunk, and reserve it
122125 debug (std::cout, " SIZE REMAINING:" , chunk->remaining_size );
123126 segment_s* segment_iter = chunk->next_segment ;
124127
@@ -132,13 +135,13 @@ void* create_segment_in_chunk(chunk_s* chunk, size_t size) {
132135 uintptr_t free_space_ptr;
133136 if (segment_iter == nullptr ) {
134137 // No segments currently exist in this chunk, initialize with offset from chunk_s header
135- free_space_ptr = ( uintptr_t ) chunk + sizeof (chunk_s) + 1 ;
138+ free_space_ptr = reinterpret_cast < uintptr_t >( chunk) + sizeof (chunk_s) + 1 ;
136139 } else {
137140 // Iterate to end of currently allocated space
138141 while (segment_iter->next ) {
139142 segment_iter = segment_iter->next ;
140143 }
141- free_space_ptr = ( uintptr_t ) segment_iter + sizeof (segment_s) + 1 ;
144+ free_space_ptr = reinterpret_cast < uintptr_t >( segment_iter) + sizeof (segment_s) + 1 ;
142145 }
143146
144147 // Now write a header and footer for the new segment
@@ -177,8 +180,9 @@ void* create_segment_in_chunk(chunk_s* chunk, size_t size) {
177180 return get_payload (free_space_ptr);
178181}
179182
183+ // Find free space in parent chunk (if it exists), reserve it,
184+ // and return a void* pointer to it.
180185void * reserve_segment (chunk_s* parent_chunk, segment_s* segment, size_t size) {
181- // Find free space in parent chunk, and reserve it
182186 debug (std::cout, " Reusing segment:" , segment, " in parent chunk:" , parent_chunk,
183187 " with size:" , segment->size , " for new segment of size:" , size);
184188
@@ -195,8 +199,14 @@ void* reserve_segment(chunk_s* parent_chunk, segment_s* segment, size_t size) {
195199 return reinterpret_cast <void *>((uintptr_t ) segment + sizeof (segment_s));
196200}
197201
202+ // Find and return a void* pointer to a new memory segment to new()
203+ // The second call to find_segment() is guaranteed to return a segment if
204+ // add_chunk succeeds (as this is happening in a mutex that prevents anyone)
205+ // else from claiming it. There's a little unnecessary overhead since we
206+ // walk the linked list from root to get there, so it makes sense to refactor
207+ // this later to have add_chunk also create the first segment and return the
208+ // pointer to it directly.
198209void *get_segment (size_t size) {
199- // Find and return a void* pointer to a new memory segment to new()
200210 void *seg = find_segment (size);
201211
202212 if (seg == nullptr ) {
@@ -209,6 +219,7 @@ void *get_segment(size_t size) {
209219 return find_segment (size);
210220}
211221
222+ // Locate (or create) and return a viable segment, and return a void* to it.
212223void *find_segment (size_t minimum_size) {
213224#ifdef DEBUG
214225 print_memory_stack ();
@@ -219,7 +230,7 @@ void *find_segment(size_t minimum_size) {
219230 chunk_s* r = root;
220231 chunk_s* parent_chunk;
221232
222- while (r != NULL ) {
233+ while (r) {
223234 debug (std::cout, " Checking CHUNK" , r, " with size" , r->allocated_size , " and remaining space" , r->remaining_size );
224235 parent_chunk = r;
225236 segment_s* segment_iter = r->next_segment ;
@@ -248,7 +259,7 @@ void *find_segment(size_t minimum_size) {
248259
249260 debug (std::cout, " No suitable segments available, need to allocate one." );
250261
251- return NULL ;
262+ return nullptr ;
252263}
253264
254265void unlink_node (chunk_s* root_node, chunk_s* node_to_remove) {
@@ -294,7 +305,7 @@ void free_segment(void* ptr) {
294305 chunk_s* r = root;
295306 chunk_s* current_parent_node;
296307
297- while (r && r-> next != NULL ) {
308+ while (r) {
298309 // Check that pointer address that we're freeing is in the range of allocated
299310 // space for this chunk. If it's not, don't bother descending into this chunks
300311 // segments, move to next chunk.
@@ -336,7 +347,7 @@ void print_memory_stack() {
336347
337348 if (r) std::cout << r << std::endl;
338349
339- while (r != NULL ) {
350+ while (r) {
340351 std::cout << std::boolalpha
341352 << " SEGMENT: " << r
342353 << " ALLOCATED SIZE: " << r->allocated_size
0 commit comments