/* * Copyright 2011 Institute of Communication and Computer Systems (ICCS) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ /** * \file custom_realloc.c * \author Ioannis Koutras (joko@microlab.ntua.gr) * \date January, 2012 * * \brief Implementation of a function to change the size of an allocated * block. */ #include #include #include "block_header.h" #ifndef WITH_MEMORY_SPACE_AWARENESS #include "other.h" #endif /* WITH_MEMORY_SPACE_AWARENESS */ #if defined (SPLITTING_FIXED) || defined (SPLITTING_VARIABLE) #include "split.h" #endif /* SPLITTING_FIXED || SPLITTING_VARIABLE */ /** * Allocates a new block and copies the contents of the old block to the new * block. No check is done if there is an old block! */ void * clean_realloc(allocator_t *allocator, heap_t *heap, void *ptr, size_t size); /** * Copy a memory area */ static void custom_memcpy(void* dest, const void* src, size_t n) { char *dst8, *src8; dst8 = (char *) dest + HEADER_SIZE; src8 = (char *) src + HEADER_SIZE; while(n--) { *dst8++ = *src8++; } } void * clean_realloc(allocator_t *allocator, heap_t *heap, void *ptr, size_t size) { size_t old_size; void *new_ptr; old_size = get_size(ptr); new_ptr = custom_ahmalloc(allocator, heap, size); custom_memcpy(new_ptr, ptr, old_size); custom_ahfree(allocator, heap, ptr); return new_ptr; } /** * \details The realloc() function tries to change the size of the allocation * pointed to by ptr to size, and returns ptr. realloc() creates a new * allocation, copies as much of the old data pointed to by ptr as will fit to * the new allocation, frees the old allocation and returns a pointer to the * allocated memory. If ptr is NULL, realloc() is identical to a call to * malloc() for size bytes. */ void * custom_ahrealloc(allocator_t *allocator, heap_t *heap, void *ptr, size_t size) { void *next_block; size_t old_size; #if defined (SPLITTING_FIXED) || defined (SPLITTING_VARIABLE) size_t min_split_size; #endif /* (SPLITTING_FIXED) || (SPLITTING_VARIABLE) */ #ifndef WITH_MEMORY_SPACE_AWARENESS int heap_id; /* Go to the system allocator if none was given */ if(allocator == NULL) { allocator = &systemallocator; if(allocator->initialized != true) { initialize_allocator(allocator); } } if(heap == NULL) { heap_id = map_thread_heap(); heap = &allocator->heaps[heap_id]; } #endif /* WITH_MEMORY_SPACE_AWARENESS */ if(ptr != NULL) { old_size = get_size(ptr); if(old_size > size) { /* The old size is bigger than the new, use the old block */ /* Try to split the currently allocated block */ #if defined (SPLITTING_FIXED) || defined (SPLITTING_VARIABLE) #ifdef SPLITTING_FIXED min_split_size = MIN_SPLITTING_SIZE; #endif /* SPLITTING_FIXED */ #ifdef SPLITTING_VARIABLE min_split_size = heap->dmm_knobs.min_split_size; #endif /* SPLITTING_VARIABLE */ if(old_size - size - HEADER_SIZE >= min_split_size) { split(allocator, heap, ptr, size); } #endif /* (SPLITTING_FIXED) || (SPLITTING_VARIABLE) */ return ptr; } else { /* The new size can't fit in the old box */ /* Check if the block next to the original as in the data layout * can be used. */ next_block = get_dlnext(allocator, ptr); if(next_block != NULL) { #ifndef WITH_OWNERSHIP if(is_free(next_block) == true) { #else /* WITH_OWNERSHIP */ if(is_free(next_block) == true && get_owner(next_block) == get_owner(ptr)) { #endif /* WITH_OWNERSHIP */ if(size < old_size + get_size(next_block) + HEADER_SIZE) { remove_block_from_lists(&next_block, heap); if(allocator->border_ptr == next_block) { allocator->border_ptr = ptr; } set_size_and_used(allocator, ptr, old_size + get_size(next_block) + HEADER_SIZE); #if defined (SPLITTING_FIXED) || defined (SPLITTING_VARIABLE) #ifdef SPLITTING_FIXED min_split_size = MIN_SPLITTING_SIZE; #endif /* SPLITTING_FIXED */ #ifdef SPLITTING_VARIABLE min_split_size = heap->dmm_knobs.min_split_size; #endif /* SPLITTING_VARIABLE */ if(get_size(ptr) - size >= min_split_size) { split(allocator, heap, ptr, size); } #endif /* (SPLITTING_FIXED) || (SPLITTING_VARIABLE) */ return ptr; } else { return clean_realloc(allocator, heap, ptr, size); } } else { return clean_realloc(allocator, heap, ptr, size); } } else { return clean_realloc(allocator, heap, ptr, size); } } } else { /* ptr is NULL, call malloc() */ return custom_ahmalloc(allocator, heap, size); } } #ifndef WITH_MEMORY_SPACE_AWARENESS void * custom_realloc(void *ptr, size_t size) { return custom_ahrealloc(NULL, NULL, ptr, size); } #endif /* WITH_MEMORY_SPACE_AWARENESS */