summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/heap.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/score/src/heap.c')
-rw-r--r--cpukit/score/src/heap.c86
1 files changed, 46 insertions, 40 deletions
diff --git a/cpukit/score/src/heap.c b/cpukit/score/src/heap.c
index 00dda0afb0..e6c9cd920c 100644
--- a/cpukit/score/src/heap.c
+++ b/cpukit/score/src/heap.c
@@ -44,7 +44,7 @@ static uint32_t instance = 0;
* | unused space due to alignment |
* | size < page_size |
* 0 +--------------------------------+ <- first block
- * | prev_size = 1 (arbitrary) |
+ * | prev_size = page_size |
* 4 +--------------------------------+
* | size = size0 | 1 |
* 8 +---------------------+----------+ <- aligned on page_size
@@ -59,7 +59,7 @@ static uint32_t instance = 0;
* size0 +--------------------------------+ <- last dummy block
* | prev_size = size0 |
* +4 +--------------------------------+
- * | size = 0 (arbitrary) | 0 | <- prev block is free
+ * | size = page_size | 0 | <- prev block is free
* +8 +--------------------------------+ <- aligned on page_size
* | unused space due to alignment |
* | size < page_size |
@@ -74,36 +74,36 @@ static uint32_t instance = 0;
* +--------------------------------+ <- begin = starting_address
* | unused space due to alignment |
* | size < page_size |
- * 0 +--------------------------------+ <- first block
- * | prev_size = 1 (arbitrary) |
+ * 0 +--------------------------------+ <- used block
+ * | prev_size = page_size |
* 4 +--------------------------------+
- * | size = S = size0 - BSIZE | 1 |
- * 8 +---------------------+----------+ <- aligned on page_size
- * | next = HEAP_TAIL | |
- * 12 +---------------------+ |
- * | prev = HEAP_HEAD | memory |
- * +---------------------+ |
- * | available |
- * | |
- * | for allocation |
- * | |
- * S +--------------------------------+ <- used block
- * | prev_size = size0 - BSIZE |
- * +4 +--------------------------------+
- * | size = BSIZE | 0 | <- prev block is free
- * +8 +--------------------------------+ <- aligned on page_size
+ * | size = BSIZE | 1 | <- prev block is used
+ * 8 +--------------------------------+ <- aligned on page_size
* | . | Pointer returned to the user
- * | . | is (S+8) for _Heap_Allocate()
+ * | . | is 8 for _Heap_Allocate()
* | . | and is in range
- * S + 8 + | user-accessible | [S+8,S+8+page_size) for
- * page_size+- - - - - -+ _Heap_Allocate_aligned()
+ * 8 + | user-accessible | [8,8+page_size) for
+ * page_size +- - - - - -+ _Heap_Allocate_aligned()
* | area |
* | . |
- * S + BSIZE +- - - - - . - - - - -+ <- last dummy block
+ * BSIZE +- - - - - . - - - - -+ <- free block
* | . |
- * +4 +--------------------------------+
- * | size = 0 (arbitrary) | 1 | <- prev block is used
- * +8 +--------------------------------+ <- aligned on page_size
+ * BSIZE +4 +--------------------------------+
+ * | size = S = size0 - BSIZE | 1 | <- prev block is used
+ * BSIZE +8 +-------------------+------------+ <- aligned on page_size
+ * | next = HEAP_TAIL | |
+ * BSIZE +12 +-------------------+ |
+ * | prev = HEAP_HEAD | memory |
+ * +-------------------+ |
+ * | . available |
+ * | . |
+ * | . for |
+ * | . |
+ * BSIZE +S+0 +-------------------+ allocation + <- last dummy block
+ * | prev_size = S | |
+ * +S+4 +-------------------+------------+
+ * | size = page_size | 0 | <- prev block is free
+ * +S+8 +--------------------------------+ <- aligned on page_size
* | unused space due to alignment |
* | size < page_size |
* +--------------------------------+ <- end = begin + size
@@ -160,7 +160,7 @@ uint32_t _Heap_Initialize(
the_block = (Heap_Block *) aligned_start;
- the_block->prev_size = HEAP_PREV_USED;
+ the_block->prev_size = page_size;
the_block->size = the_size | HEAP_PREV_USED;
the_block->next = _Heap_Tail( the_heap );
the_block->prev = _Heap_Head( the_heap );
@@ -175,7 +175,7 @@ uint32_t _Heap_Initialize(
the_block = _Heap_Block_at( the_block, the_size );
the_heap->final = the_block; /* Permanent final block of the heap */
the_block->prev_size = the_size; /* Previous block is free */
- the_block->size = 0; /* This is the only block with size=0 */
+ the_block->size = page_size;
stats->size = size;
stats->free_size = the_size;
@@ -187,6 +187,7 @@ uint32_t _Heap_Initialize(
stats->allocs = 0;
stats->searches = 0;
stats->frees = 0;
+ stats->resizes = 0;
stats->instance = instance++;
return ( the_size - HEAP_BLOCK_USED_OVERHEAD );
@@ -213,15 +214,17 @@ uint32_t _Heap_Calc_block_size(
uint32_t block_size = size + HEAP_BLOCK_USED_OVERHEAD;
_Heap_Align_up(&block_size, page_size);
if(block_size < min_size) block_size = min_size;
+ /* 'block_size' becomes <= 'size' if and only if overflow occured. */
return (block_size > size) ? block_size : 0;
}
/*
* Allocate block of size 'alloc_size' from 'the_block' belonging to
- * 'the_heap'. Either split 'the_block' or allocate it entirely.
- * Return the block allocated.
+ * 'the_heap'. Split 'the_block' if possible, otherwise allocate it entirely.
+ * When split, make the lower part used, and leave the upper part free.
+ * Return the size of allocated block.
*/
-Heap_Block* _Heap_Block_allocate(
+unsigned32 _Heap_Block_allocate(
Heap_Control* the_heap,
Heap_Block* the_block,
uint32_t alloc_size)
@@ -233,14 +236,18 @@ Heap_Block* _Heap_Block_allocate(
_HAssert(_Heap_Is_aligned(block_size, the_heap->page_size));
_HAssert(_Heap_Is_aligned(alloc_size, the_heap->page_size));
_HAssert(alloc_size <= block_size);
+ _HAssert(_Heap_Is_prev_used(the_block));
if(the_rest >= the_heap->min_block_size) {
- /* Split the block so that lower part is still free, and upper part
- becomes used. */
- the_block->size = the_rest | HEAP_PREV_USED;
- the_block = _Heap_Block_at(the_block, the_rest);
- the_block->prev_size = the_rest;
- the_block->size = alloc_size;
+ /* Split the block so that upper part is still free, and lower part
+ becomes used. This is slightly less optimal than leaving lower part
+ free as it requires replacing block in the free blocks list, but it
+ makes it possible to reuse this code in the _Heap_Resize_block(). */
+ Heap_Block *next_block = _Heap_Block_at(the_block, alloc_size);
+ _Heap_Block_replace(the_block, next_block);
+ the_block->size = alloc_size | HEAP_PREV_USED;
+ next_block->size = the_rest | HEAP_PREV_USED;
+ _Heap_Block_at(next_block, the_rest)->prev_size = the_rest;
}
else {
/* Don't split the block as remainder is either zero or too small to be
@@ -248,14 +255,13 @@ Heap_Block* _Heap_Block_allocate(
block and remove the block from the list of free blocks. */
_Heap_Block_remove(the_block);
alloc_size = block_size;
+ _Heap_Block_at(the_block, alloc_size)->size |= HEAP_PREV_USED;
stats->free_blocks -= 1;
}
- /* Mark the block as used (in the next block). */
- _Heap_Block_at(the_block, alloc_size)->size |= HEAP_PREV_USED;
/* Update statistics */
stats->free_size -= alloc_size;
if(stats->min_free_size > stats->free_size)
stats->min_free_size = stats->free_size;
stats->used_blocks += 1;
- return the_block;
+ return alloc_size;
}