|
|
|
@ -4,12 +4,21 @@ |
|
|
|
* Defines operations on blocks and boundary tags |
|
|
|
*/ |
|
|
|
|
|
|
|
/*---------------------*/ |
|
|
|
/* Feature test macros */ |
|
|
|
/*---------------------*/ |
|
|
|
|
|
|
|
#define _DEFAULT_SOURCE // for sbrk |
|
|
|
|
|
|
|
/*----------*/ |
|
|
|
/* Includes */ |
|
|
|
/*----------*/ |
|
|
|
|
|
|
|
#include "ya_block.h" |
|
|
|
#include <unistd.h> |
|
|
|
#include <stdio.h> |
|
|
|
|
|
|
|
#include "ya_debug.h" |
|
|
|
#include "ya_block.h" |
|
|
|
|
|
|
|
/*---------*/ |
|
|
|
/* Globals */ |
|
|
|
@ -24,12 +33,15 @@ intptr_t *heap_end = NULL; // first block outside heap |
|
|
|
|
|
|
|
#ifdef YA_DEBUG |
|
|
|
void block_print_range(intptr_t *start, intptr_t *end) { |
|
|
|
if (!start || !end) { |
|
|
|
return; |
|
|
|
} |
|
|
|
intptr_t *block; |
|
|
|
intptr_t block_size; |
|
|
|
for (block = start; block < end; block += block_size) { |
|
|
|
block_size = YA_BLK_SZ(block); |
|
|
|
intptr_t size; |
|
|
|
for (block = start; block < end; block += size) { |
|
|
|
size = block_size(block); |
|
|
|
printf("Block at %p size = %ld alloc = %d\n", |
|
|
|
block, block_size, YA_BLK_IS_ALLOC(block)); |
|
|
|
block, size, block_is_alloc(block)); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
@ -42,16 +54,24 @@ void block_init(intptr_t *block, intptr_t size) { |
|
|
|
|
|
|
|
/* Sets the allocated bit in the block's boundary tags. */ |
|
|
|
void block_alloc(intptr_t *block) { |
|
|
|
intptr_t block_size = YA_BLK_SZ(block); |
|
|
|
block[-1] |= 1; |
|
|
|
block[block_size-2] |= 1; |
|
|
|
intptr_t size = block_size(block); |
|
|
|
block[-1] |= 1; |
|
|
|
block[size-2] |= 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* Erases the allocated bit in the block's boundary tags. */ |
|
|
|
void block_free(intptr_t *block) { |
|
|
|
intptr_t block_size = YA_BLK_SZ(block); |
|
|
|
block[-1] &= -2; |
|
|
|
block[block_size-2] &= -2; |
|
|
|
intptr_t size = block_size(block); |
|
|
|
block[-1] &= -2; |
|
|
|
block[size-2] &= -2; |
|
|
|
} |
|
|
|
|
|
|
|
/* Fills block with zeros. */ |
|
|
|
void block_clear(intptr_t *block) { |
|
|
|
intptr_t *end = block + block_size(block) - 2; |
|
|
|
for (intptr_t *p = block; p < end; p++) { |
|
|
|
*p = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Returns the size in words of the smallest block that can |
|
|
|
@ -68,46 +88,47 @@ intptr_t block_fit(size_t n_bytes) { |
|
|
|
/* Tries to coalesce a block with its previous neighbor. |
|
|
|
* Returns a pointer to the coalesced block. */ |
|
|
|
intptr_t *block_join_prev(intptr_t *block) { |
|
|
|
intptr_t prev_size = YA_TAG_SZ(block[-2]); |
|
|
|
if (block < heap_start + YA_BLK_MIN_SZ) { |
|
|
|
return block; // there cannot be a previous block |
|
|
|
} |
|
|
|
intptr_t prev_size = tag_size(block[-2]); |
|
|
|
intptr_t *prev = block - prev_size; |
|
|
|
if (prev <= heap_start || YA_BLK_IS_ALLOC(prev)) { |
|
|
|
if (prev <= heap_start || block_is_alloc(prev)) { |
|
|
|
return block; |
|
|
|
} |
|
|
|
intptr_t block_size = YA_BLK_SZ(block); |
|
|
|
block_init(prev, prev_size + block_size); |
|
|
|
intptr_t size = block_size(block); |
|
|
|
block_init(prev, prev_size + size); |
|
|
|
ya_debug("block_join_prev: joining %p:%ld and %p:%ld -> %p:%ld\n", |
|
|
|
block, block_size, prev, prev_size, prev, prev_size + block_size); |
|
|
|
block, size, prev, prev_size, prev, prev_size + size); |
|
|
|
return prev; |
|
|
|
} |
|
|
|
|
|
|
|
/* Tries to colesce a block with its next neighbor. |
|
|
|
* Returns the unchanged pointer to the block. */ |
|
|
|
intptr_t *block_join_next(intptr_t *block) { |
|
|
|
intptr_t block_size = YA_BLK_SZ(block); |
|
|
|
intptr_t *next = block + block_size; |
|
|
|
if (next >= heap_end || YA_BLK_IS_ALLOC(next)) { |
|
|
|
intptr_t size = block_size(block); |
|
|
|
intptr_t *next = block + size; |
|
|
|
if (next >= heap_end || block_is_alloc(next)) { |
|
|
|
return block; |
|
|
|
} |
|
|
|
intptr_t next_size = YA_BLK_SZ(next); |
|
|
|
block_init(block, block_size + next_size); |
|
|
|
intptr_t next_size = block_size(next); |
|
|
|
block_init(block, size + next_size); |
|
|
|
ya_debug("block_join_next: joining %p:%ld and %p:%ld -> %p:%ld\n", |
|
|
|
block, block_size, next, next_size, block, block_size + next_size); |
|
|
|
block, size, next, next_size, block, size + next_size); |
|
|
|
return block; |
|
|
|
} |
|
|
|
|
|
|
|
/* Tries to coalesce a block with its previous and next neighbors. |
|
|
|
* Returns a pointer to the coalesced block. */ |
|
|
|
intptr_t *block_join(intptr_t *block) { |
|
|
|
if (block > heap_start) { |
|
|
|
block = block_join_prev(block); |
|
|
|
} |
|
|
|
block = block_join_prev(block); |
|
|
|
return block_join_next(block); |
|
|
|
} |
|
|
|
|
|
|
|
/* Split the block [block_size] into [size, block_size - size] if possible |
|
|
|
* Returns a pointer to the second block or NULL if no split occurred. */ |
|
|
|
intptr_t *block_split(intptr_t *block, intptr_t size) { |
|
|
|
intptr_t next_size = YA_BLK_SZ(block) - size; |
|
|
|
intptr_t next_size = block_size(block) - size; |
|
|
|
if (next_size < YA_BLK_MIN_SZ) { |
|
|
|
return NULL; // not enough space to warrant a split |
|
|
|
} |
|
|
|
@ -119,17 +140,17 @@ intptr_t *block_split(intptr_t *block, intptr_t size) { |
|
|
|
/* Try to find a free block at least size words big by walking the boundary |
|
|
|
* tags. If no block is found the heap is grown adequately. |
|
|
|
* Returns a pointer to the block or NULL in case of failure. */ |
|
|
|
intptr_t *block_find(intptr_t size) { |
|
|
|
intptr_t *block_find(intptr_t min_size) { |
|
|
|
intptr_t *block; |
|
|
|
intptr_t block_size; |
|
|
|
for (block = heap_start; block < heap_end; block += block_size) { |
|
|
|
block_size = YA_BLK_SZ(block); |
|
|
|
if (!YA_BLK_IS_ALLOC(block) && size <= block_size) { |
|
|
|
intptr_t size; |
|
|
|
for (block = heap_start; block < heap_end; block += size) { |
|
|
|
size = block_size(block); |
|
|
|
if (!block_is_alloc(block) && min_size <= size) { |
|
|
|
return block; |
|
|
|
} |
|
|
|
} |
|
|
|
// could not find block, extend heap |
|
|
|
return heap_extend(size); |
|
|
|
return heap_extend(min_size); |
|
|
|
} |
|
|
|
|
|
|
|
/* Initializes the heap by calling sbrk to allocate some starter memory. |
|
|
|
|