/* * partition_realloc.c */ #include #include "private.h" /*--------------------------------------------------------- */ void lub_partition_stop_here(lub_heap_status_t status, char *old_ptr, size_t new_size) { /* This is provided as a debug aid */ status = status; old_ptr = old_ptr; new_size = new_size; } /*--------------------------------------------------------- */ void lub_partition_time_to_die(lub_partition_t * this) { bool_t time_to_die = BOOL_TRUE; lub_heap_stats_t stats; lub_heap_t *local_heap = lub_partition__get_local_heap(this); if (local_heap) { lub_heap__get_stats(local_heap, &stats); if (stats.alloc_blocks) { time_to_die = BOOL_FALSE; } } if (BOOL_FALSE == time_to_die) { lub_partition_lock(this); lub_heap__get_stats(this->m_global_heap, &stats); lub_partition_unlock(this); if (stats.alloc_blocks) { time_to_die = BOOL_FALSE; } } if (BOOL_TRUE == time_to_die) { /* and so the time has come... */ lub_partition_destroy(this); } } /*--------------------------------------------------------- */ lub_heap_status_t lub_partition_global_realloc(lub_partition_t * this, char **ptr, size_t size, lub_heap_align_t alignment) { lub_heap_status_t status = LUB_HEAP_FAILED; lub_partition_lock(this); if (!this->m_global_heap) { /* * Create the global heap */ size_t required = size; void *segment = lub_partition_segment_alloc(this, &required); this->m_global_heap = lub_heap_create(segment, required); } if (this->m_global_heap) { status = lub_heap_realloc(this->m_global_heap, ptr, size, alignment); if (LUB_HEAP_FAILED == status) { /* expand memory and try again */ if (lub_partition_extend_memory(this, size)) { status = lub_heap_realloc(this->m_global_heap, ptr, size, alignment); } } } lub_partition_unlock(this); return status; } /*--------------------------------------------------------- */ lub_heap_status_t lub_partition_realloc(lub_partition_t * this, char **ptr, size_t size, lub_heap_align_t alignment) { lub_heap_status_t status = LUB_HEAP_FAILED; size_t requested_size = size; lub_heap_t *local_heap; if ((0 == size) && (0 == *ptr)) { /* simple optimisation */ return LUB_HEAP_OK; } if (this->m_dying) { local_heap = lub_partition__get_local_heap(this); if (size) { /* don't allocate any new memory when dying */ size = 0; } } else { local_heap = lub_partition_findcreate_local_heap(this); } if (local_heap) { /* try the fast local heap first */ status = lub_heap_realloc(local_heap, ptr, size, alignment); } if ((LUB_HEAP_FAILED == status) || (LUB_HEAP_INVALID_POINTER == status)) { char *old_ptr = 0; if (local_heap && (LUB_HEAP_FAILED == status) && size) { /* we need to reallocate from the global and copy from the local */ old_ptr = *ptr; *ptr = 0; } /* time to use the slower global heap */ status = lub_partition_global_realloc(this, ptr, size, alignment); if (old_ptr && (LUB_HEAP_OK == status)) { /* copy from the local to the global */ memcpy(*ptr, old_ptr, size); /* and release the local block */ status = lub_heap_realloc(local_heap, &old_ptr, 0, alignment); } } if (LUB_HEAP_OK != status) { lub_partition_stop_here(status, *ptr, size); } /* allow the partion to destroy itself if necessary */ if (this->m_dying) { lub_partition_time_to_die(this); if (requested_size) { /* we don't allocate memory whilst dying */ status = LUB_HEAP_FAILED; } } return status; } /*-------------------------------------------------------- */