123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- #include <string.h>
- #include <assert.h>
- #include "private.h"
- /*--------------------------------------------------------- */
- lub_heap_status_t
- lub_heap_raw_realloc(lub_heap_t * this,
- char **ptr,
- size_t requested_size, lub_heap_align_t alignment)
- {
- lub_heap_status_t result = LUB_HEAP_FAILED;
- lub_heap_block_t *block = NULL;
- words_t words;
- char *new_ptr = NULL;
- const size_t MIN_SIZE = sizeof(lub_heap_free_block_t);
- /* make the minimum alignment leave enough space for
- * (sizeof(lub_heap_free_block_t) + sizeof(lub_heap_alloc_block_t) + sizeof(lub_heap_node_t))
- * approx 72 bytes on 64-bit architecture
- */
- const lub_heap_align_t MIN_ALIGN_NON_NATIVE = LUB_HEAP_ALIGN_2_POWER_7;
- size_t size = requested_size;
- do {
- if (NULL == ptr)
- break; /* The client MUST give us a pointer to play with */
- if (LUB_HEAP_ZERO_ALLOC == *ptr) {
- *ptr = NULL;
- }
- if (*ptr
- && (BOOL_FALSE == lub_heap_validate_pointer(this, *ptr))) {
- /* This is not a valid pointer */
- result = LUB_HEAP_INVALID_POINTER;
- break;
- }
- /* check the heap integrity */
- if (BOOL_FALSE == lub_heap_check_memory(this)) {
- result = LUB_HEAP_CORRUPTED;
- break;
- }
- if (size) {
- /* make sure we get enough space for the header/tail */
- size += sizeof(lub_heap_alloc_block_t);
- /* make sure we are at least natively aligned */
- size += (LUB_HEAP_ALIGN_NATIVE - 1);
- size &= ~(LUB_HEAP_ALIGN_NATIVE - 1);
- if (size < MIN_SIZE) {
- /*
- * we must ensure that any allocated block is at least
- * large enough to hold a free block node when it is released
- */
- size = MIN_SIZE;
- }
- if (LUB_HEAP_ALIGN_NATIVE != alignment) {
- if (alignment < MIN_ALIGN_NON_NATIVE) {
- /*
- * ensure that we always leave enough space
- * to be able to collapse the block to the
- * right size
- */
- alignment = MIN_ALIGN_NON_NATIVE;
- }
- /* add twice the alignment */
- size += (alignment << 1);
- }
- }
- words = (size >> 2);
- if (requested_size > size) {
- /* the size has wrapped when accounting for overheads */
- break;
- }
- if (NULL != *ptr) {
- /* get reference to the current block */
- block = lub_heap_block_from_ptr(*ptr);
- /* first of all check this is an allocated block */
- if (1 == block->alloc.tag.free) {
- result = LUB_HEAP_DOUBLE_FREE;
- break;
- }
- /* first of all check this is an allocated block */
- if (BOOL_FALSE == lub_heap_block_check(block)) {
- result = LUB_HEAP_CORRUPTED;
- break;
- }
- /* is the current block large enough for the request */
- if (words && (block->alloc.tag.words >= words)) {
- lub_heap_block_t *next_block =
- lub_heap_block_getnext(block);
- words_t delta =
- (block->alloc.tag.words - words);
- lub_heap_tag_t *tail;
- result = LUB_HEAP_OK;
- new_ptr = *ptr;
- if (delta && (NULL != next_block)) {
- /* can we graft this spare memory to a following free block? */
- if (1 == next_block->free.tag.free) {
- block->alloc.tag.words = words;
- tail =
- lub_heap_block__get_tail
- (block);
- tail->words = words;
- tail->free = 0;
- tail->segment = 0;
- lub_heap_graft_to_bottom(this,
- next_block,
- &tail
- [1],
- delta,
- BOOL_FALSE,
- BOOL_FALSE);
- this->stats.alloc_bytes -=
- (delta << 2);
- break;
- }
- }
- /* Is there enough space to turn the spare memory into a free block? */
- if (delta >=
- (sizeof(lub_heap_free_block_t) >> 2)) {
- tail = lub_heap_block__get_tail(block);
- lub_heap_init_free_block(this,
- &tail[1 -
- delta],
- (delta << 2),
- BOOL_FALSE,
- tail->segment);
- block->alloc.tag.words = words;
- tail = lub_heap_block__get_tail(block);
- tail->words = words;
- tail->free = 0;
- tail->segment = 0;
- this->stats.alloc_bytes -= (delta << 2);
- }
- break;
- } else if (words) {
- /* can we simple extend the current allocated block? */
- if ((BOOL_TRUE ==
- lub_heap_extend_upwards(this, &block,
- words))
- || (BOOL_TRUE ==
- lub_heap_extend_downwards(this, &block,
- words))
- || (BOOL_TRUE ==
- lub_heap_extend_both_ways(this, &block,
- words))) {
- result = LUB_HEAP_OK;
- new_ptr = (char *)block->alloc.memory;
- break;
- }
- }
- }
- if (words && (LUB_HEAP_FAILED == result)) {
- /* need to reallocate and copy the data */
- new_ptr = lub_heap_new_alloc_block(this, words);
- if (NULL != new_ptr) {
- result = LUB_HEAP_OK;
- if (NULL != block) {
- /* now copy the old contents across */
- memcpy(new_ptr,
- (const char *)block->alloc.
- memory,
- (block->alloc.tag.words << 2) -
- sizeof(lub_heap_alloc_block_t));
- }
- } else {
- /* couldn't find the space for the request */
- break;
- }
- }
- /* now it's time to release the memory of the old block */
- if (NULL != block) {
- words_t old_words = block->alloc.tag.words;
- bool_t done = BOOL_FALSE;
- /* combine with the next block */
- if (LUB_HEAP_OK ==
- lub_heap_merge_with_next(this, block)) {
- done = BOOL_TRUE;
- }
- /* combine with the previous block */
- if (LUB_HEAP_OK ==
- lub_heap_merge_with_previous(this, block)) {
- done = BOOL_TRUE;
- }
- if (BOOL_FALSE == done) {
- /* create a new free block */
- lub_heap_new_free_block(this, block);
- }
- result = LUB_HEAP_OK;
- --this->stats.alloc_blocks;
- this->stats.alloc_bytes -= (old_words << 2);
- this->stats.alloc_bytes +=
- sizeof(lub_heap_alloc_block_t);
- this->stats.alloc_overhead -=
- sizeof(lub_heap_alloc_block_t);
- }
- } while (0);
- if (LUB_HEAP_OK == result) {
- unsigned delta;
- /* align the block as required */
- if (LUB_HEAP_ALIGN_NATIVE != alignment) {
- lub_heap_align_block(this, alignment, &new_ptr, &size);
- }
- /* revert to client space available */
- size -= sizeof(lub_heap_alloc_block_t);
- *ptr = new_ptr;
- delta = (size - requested_size);
- if (*ptr && requested_size && (0 < delta)) {
- /* make sure that any excess memory is tainted */
- lub_heap_taint_memory(*ptr + requested_size,
- LUB_HEAP_TAINT_ALLOC, delta);
- }
- } else if ((LUB_HEAP_FAILED == result)
- && (0 == requested_size)
- && (NULL == *ptr)) {
- /* freeing zero is always OK */
- result = LUB_HEAP_OK;
- }
- return result;
- }
- /*--------------------------------------------------------- */
|