123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- #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;
- }
- /*--------------------------------------------------------- */
|