@@ -77,7 +77,6 @@ class basic_multiallocation_chain
77
77
}
78
78
};
79
79
80
-
81
80
// !This class implements several allocation functions shared by different algorithms
82
81
// !(aligned allocation, multiple allocation...).
83
82
template <class MemoryAlgorithm >
@@ -91,7 +90,6 @@ class memory_algorithm_common
91
90
typedef typename MemoryAlgorithm::size_type size_type;
92
91
93
92
static const size_type Alignment = MemoryAlgorithm::Alignment;
94
- static const size_type MinBlockUnits = MemoryAlgorithm::MinBlockUnits;
95
93
static const size_type AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes;
96
94
static const size_type AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits;
97
95
static const size_type BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes;
@@ -116,6 +114,13 @@ class memory_algorithm_common
116
114
static size_type floor_units (size_type size)
117
115
{ return size/Alignment; }
118
116
117
+ static size_type user_buffer_ceil_units (size_type size)
118
+ {
119
+ if (size <= UsableByPreviousChunk)
120
+ return 0 ;
121
+ return ceil_units (size - UsableByPreviousChunk);
122
+ }
123
+
119
124
static size_type multiple_of_units (size_type size)
120
125
{ return get_rounded_size (size, Alignment); }
121
126
@@ -236,133 +241,153 @@ class memory_algorithm_common
236
241
}
237
242
238
243
static void * allocate_aligned
239
- (MemoryAlgorithm *memory_algo, size_type nbytes, size_type alignment)
244
+ (MemoryAlgorithm * const memory_algo, const size_type nbytes, const size_type alignment)
240
245
{
241
246
242
247
// Ensure power of 2
243
- if ((alignment & (alignment - size_type (1u ))) != 0 ){
248
+ const bool alignment_ok = (alignment & (alignment - 1u )) == 0 ;
249
+ if (!alignment_ok){
244
250
// Alignment is not power of two
245
- BOOST_ASSERT ((alignment & (alignment - size_type ( 1u ))) == 0 );
251
+ BOOST_ASSERT (alignment_ok );
246
252
return 0 ;
247
253
}
248
254
249
- size_type real_size = nbytes;
250
255
if (alignment <= Alignment){
256
+ size_type real_size = nbytes;
251
257
void *ignore_reuse = 0 ;
252
258
return memory_algo->priv_allocate
253
259
(boost::interprocess::allocate_new, nbytes, real_size, ignore_reuse);
254
260
}
255
261
256
- if (nbytes > UsableByPreviousChunk)
257
- nbytes -= UsableByPreviousChunk;
258
-
259
- // We can find a aligned portion if we allocate a block that has alignment
260
- // nbytes + alignment bytes or more.
261
- size_type minimum_allocation = max_value
262
- (nbytes + alignment, size_type (MinBlockUnits*Alignment));
263
- // Since we will split that block, we must request a bit more memory
264
- // if the alignment is near the beginning of the buffer, because otherwise,
265
- // there is no space for a new block before the alignment.
266
- //
267
- // ____ Aligned here
268
- // |
269
- // -----------------------------------------------------
270
- // | MBU |
271
- // -----------------------------------------------------
272
- size_type request =
273
- minimum_allocation + (2 *MinBlockUnits*Alignment - AllocatedCtrlBytes
274
- // prevsize - UsableByPreviousChunk
275
- );
262
+ // To fulfill user's request we need at least min_user_units
263
+ size_type needed_units = user_buffer_ceil_units (nbytes);
264
+ // However, there is a minimum allocation unit count (BlockCtrlUnits) to be able to deallocate the buffer,
265
+ // The allocation will give us a part of it (AllocatedCtrlUnits) so (BlockCtrlUnits - AllocatedCtrlUnits)
266
+ // is the minimum ammount of blocks we need to allocate.
267
+ needed_units += max_value (needed_units, BlockCtrlUnits - AllocatedCtrlUnits);
268
+ // If we need to align, we need to at least move enough to create a new block at the beginning
269
+ // that can be marked as free, so we need BlockCtrlUnits units for that
270
+ needed_units += BlockCtrlUnits;
271
+ // Finally, we need to add extra space to be sure we will find an aligned address
272
+ needed_units += (alignment - Alignment)/Alignment;
273
+
274
+ // Transform units to bytes
275
+ const size_type request = needed_units*Alignment + UsableByPreviousChunk;
276
276
277
277
// Now allocate the buffer
278
- real_size = request;
278
+ size_type real_size = request;
279
279
void *ignore_reuse = 0 ;
280
- void *buffer = memory_algo->priv_allocate (boost::interprocess::allocate_new, request, real_size, ignore_reuse);
280
+ void *const buffer = memory_algo->priv_allocate (boost::interprocess::allocate_new, request, real_size, ignore_reuse);
281
281
if (!buffer){
282
282
return 0 ;
283
283
}
284
- else if ((((std::size_t )(buffer)) % alignment) == 0 ){
284
+ else if ((((std::size_t )(buffer)) & ( alignment- 1 ) ) == 0 ){
285
285
// If we are lucky and the buffer is aligned, just split it and
286
286
// return the high part
287
- block_ctrl *first = memory_algo->priv_get_block (buffer);
288
- size_type old_size = first->m_size ;
287
+ block_ctrl *const first = memory_algo->priv_get_block (buffer);
288
+ const size_type orig_first_units = first->m_size ;
289
289
const size_type first_min_units =
290
- max_value (ceil_units (nbytes) + AllocatedCtrlUnits, size_type (MinBlockUnits ));
290
+ max_value (user_buffer_ceil_units (nbytes) + AllocatedCtrlUnits, size_type (BlockCtrlUnits ));
291
291
// We can create a new block in the end of the segment
292
- if (old_size >= (first_min_units + MinBlockUnits )){
292
+ if (orig_first_units >= (first_min_units + BlockCtrlUnits )){
293
293
block_ctrl *second = move_detail::force_ptr<block_ctrl*>
294
294
(reinterpret_cast <char *>(first) + Alignment*first_min_units);
295
+ // Update first size
295
296
first->m_size = first_min_units & block_ctrl::size_mask;
296
- second->m_size = (old_size - first->m_size ) & block_ctrl::size_mask;
297
- BOOST_ASSERT (second->m_size >= MinBlockUnits);
298
297
memory_algo->priv_mark_new_allocated_block (first);
298
+
299
+ // Deallocate the remaining memory
300
+ second->m_size = (orig_first_units - first_min_units) & block_ctrl::size_mask;
299
301
memory_algo->priv_mark_new_allocated_block (second);
300
302
memory_algo->priv_deallocate (memory_algo->priv_get_user_buffer (second));
301
303
}
302
304
return buffer;
303
305
}
304
306
305
- // Buffer not aligned, find the aligned part.
307
+ // Now obtain the address of the allocated block
308
+ block_ctrl* const first = memory_algo->priv_get_block (buffer);
309
+ // The block must be marked as allocated
310
+ BOOST_ASSERT (memory_algo->priv_is_allocated_block (first));
311
+ // Assert allocated block has at least the desired size
312
+ BOOST_ASSERT (first->m_size >= (needed_units + AllocatedCtrlUnits));
313
+ // Assert allocated block can be splitted in the two blocks
314
+ BOOST_ASSERT (first->m_size >= 2 * BlockCtrlUnits);
315
+
316
+ // Buffer is not overaligned, so find the aligned part
317
+
318
+ // BCB: BlockControlBytes
319
+ // ACB: AllocatedControlBytes (<= BlockControlBytes)
306
320
//
307
- // ____ Aligned here
308
- // |
321
+ // __________> Block control ("first")
322
+ // | _________> Block control ("second")
323
+ // | | ___> usr_buf, overaligned
324
+ // | | |
309
325
// -----------------------------------------------------
310
- // | MBU +more | ACB |
326
+ // | BCB +more | ACB |
311
327
// -----------------------------------------------------
312
- char *pos = reinterpret_cast <char *>
313
- (reinterpret_cast <std::size_t >(static_cast <char *>(buffer) +
314
- // This is the minimum size of (2)
315
- (MinBlockUnits*Alignment - AllocatedCtrlBytes) +
316
- // This is the next MBU for the aligned memory
317
- AllocatedCtrlBytes +
318
- // This is the alignment trick
319
- alignment - 1 ) & -alignment);
320
-
321
- // Now obtain the address of the blocks
322
- block_ctrl *first = memory_algo->priv_get_block (buffer);
323
- block_ctrl *second = memory_algo->priv_get_block (pos);
324
- BOOST_ASSERT (pos <= (reinterpret_cast <char *>(first) + first->m_size *Alignment));
325
- BOOST_ASSERT (first->m_size >= 2 *MinBlockUnits);
326
- BOOST_ASSERT ((pos + MinBlockUnits*Alignment - AllocatedCtrlBytes + nbytes*Alignment/Alignment) <=
327
- (reinterpret_cast <char *>(first) + first->m_size *Alignment));
328
- // Set the new size of the first block
329
- size_type old_size = first->m_size ;
330
- first->m_size = size_type (size_type (reinterpret_cast <char *>(second) - reinterpret_cast <char *>(first))/Alignment
331
- & block_ctrl::size_mask);
332
- memory_algo->priv_mark_new_allocated_block (first);
328
+ char *const usr_buf = reinterpret_cast <char *>
329
+ (reinterpret_cast <std::size_t >(static_cast <char *>(buffer)
330
+ + BlockCtrlBytes // Minimum to create a free block at the beginning
331
+ + alignment - 1 ) & -alignment); // This is the alignment trick
332
+
333
+ // Assert the user buffer is inside the allocated range
334
+ BOOST_ASSERT (usr_buf <= (reinterpret_cast <char *>(first) + first->m_size *Alignment));
335
+ // Assert all user data is inside the allocated range
336
+ BOOST_ASSERT ((usr_buf + nbytes) <= (reinterpret_cast <char *>(first) + first->m_size *Alignment + UsableByPreviousChunk));
337
+
338
+ // Set the new size of the secone block
339
+ const size_type orig_first_units = first->m_size ;
340
+
341
+ block_ctrl* const second = memory_algo->priv_get_block (usr_buf);
342
+
343
+ // Update first block size until second block starts and deallocate it
344
+ const size_type final_first_units =
345
+ size_type (reinterpret_cast <char *>(second) - reinterpret_cast <char *>(first))/Alignment & block_ctrl::size_mask;
333
346
334
347
// Now check if we can create a new buffer in the end
335
348
//
336
- // __"second" block
337
- // | __Aligned here
338
- // | | __"third" block
339
- // -----------|-----|-----|------------------------------
340
- // | MBU +more | ACB | (3) | BCU |
349
+ // _______________________> "first" (free block)
350
+ // | ____________> "second" block
351
+ // | | ______> user data aligned here (usr_buf)
352
+ // | | | ____> optional "third" (free block)
353
+ // ----------|-----|-----------|------------------------------
354
+ // | BCB+more | ACB | user_data | BCB |
341
355
// -----------------------------------------------------
342
356
// This size will be the minimum size to be able to create a
343
357
// new block in the end.
344
- const size_type second_min_units = max_value (size_type (MinBlockUnits),
345
- ceil_units (nbytes) + AllocatedCtrlUnits );
358
+ const size_type orig_second_units = orig_first_units - final_first_units;
359
+ const size_type second_min_units = max_value ( size_type (BlockCtrlUnits)
360
+ , user_buffer_ceil_units (nbytes) + AllocatedCtrlUnits );
346
361
347
- // Check if we can create a new block (of size MinBlockUnits) in the end of the segment
348
- if ((old_size - first-> m_size ) > = (second_min_units + MinBlockUnits )){
362
+ // Check if we can create a new free block (of size BlockCtrlUnits) at the end of the segment
363
+ if (orig_second_units > = (second_min_units + BlockCtrlUnits )){
349
364
// Now obtain the address of the end block
350
- block_ctrl *third = new (reinterpret_cast <char *>(second) + Alignment*second_min_units) block_ctrl;
365
+ block_ctrl *const third = :: new (reinterpret_cast <char *>(second) + Alignment*second_min_units, boost_container_new_t ()) block_ctrl;
351
366
second->m_size = second_min_units & block_ctrl::size_mask;
352
- third->m_size = (old_size - first-> m_size - second->m_size ) & block_ctrl::size_mask;
353
- BOOST_ASSERT (third->m_size >= MinBlockUnits );
367
+ third->m_size = (orig_second_units - second->m_size ) & block_ctrl::size_mask;
368
+ BOOST_ASSERT (third->m_size >= BlockCtrlUnits );
354
369
memory_algo->priv_mark_new_allocated_block (second);
355
370
memory_algo->priv_mark_new_allocated_block (third);
371
+ // We can deallocate third block because the previous "second" is properly set
356
372
memory_algo->priv_deallocate (memory_algo->priv_get_user_buffer (third));
357
373
}
358
374
else {
359
- second->m_size = (old_size - first-> m_size ) & block_ctrl::size_mask;
360
- BOOST_ASSERT (second->m_size >= MinBlockUnits );
375
+ second->m_size = orig_second_units & block_ctrl::size_mask;
376
+ BOOST_ASSERT (second->m_size >= BlockCtrlUnits );
361
377
memory_algo->priv_mark_new_allocated_block (second);
362
378
}
363
379
380
+ // We can deallocate first block because the next "second" is properly set
381
+ first->m_size = final_first_units & block_ctrl::size_mask;
382
+ // Now mark second's previous allocated flag as allocated
383
+ memory_algo->priv_mark_new_allocated_block (first);
364
384
memory_algo->priv_deallocate (memory_algo->priv_get_user_buffer (first));
365
- return memory_algo->priv_get_user_buffer (second);
385
+
386
+ // Make sure all user data fits
387
+ BOOST_ASSERT ((reinterpret_cast <char *>(usr_buf) + nbytes) <= (reinterpret_cast <char *>(second) + second->m_size *Alignment + UsableByPreviousChunk));
388
+ // Make sure user data is properly aligned
389
+ BOOST_ASSERT (0 == ((std::size_t )usr_buf & (alignment-1u )));
390
+ return usr_buf;
366
391
}
367
392
368
393
static bool try_shrink
0 commit comments