/* * Copyright 2012 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 freelist/realloc.c * @author Ioannis Koutras * @date September, 2012 * @brief realloc() implementation for freelist-organized raw blocks */ #include "dmmlib/freelist/freelist.h" #include "dmmlib/freelist/block_header.h" #include "freelist/block_header_funcs.h" /* for freelist_free() functionality */ #include "freelist/ordering_policy.h" #if defined (COALESCING_FIXED) || defined (COALESCING_VARIABLE) #include "freelist/coalesce.h" #endif /* COALESCING_FIXED || COALESCING_VARIABLE */ #include "dmmlib/dmmlib.h" #include "memcpy.h" #ifdef HAVE_LOCKS #include "dmmlib/raw_block.h" #include #endif /* HAVE_LOCKS */ #include "locks.h" #include "other.h" #include "padding.h" #include "statistics.h" /** * Re-allocates a memory block from a freelist-organized raw block * * @param raw_block The pointer of the freelist raw block. * @param ptr The pointer of the memory block to be re-allocated. * @param req_size The requested memory size. * @retval The address to serve the request. * @retval NULL No available memory space. */ void * freelist_realloc(freelist_rb_t *raw_block, void *ptr, size_t req_size) { block_header_t *block; void *ret; #if defined (WITH_ALLOCATOR_STATS) && defined (REQUEST_SIZE_INFO) size_t unmodified_req_size = req_size; #endif /* WITH_ALLOCATOR_STATS && REQUEST_SIZE_INFO */ req_size = req_padding(req_size); block = get_header(ptr); #if defined (WITH_ALLOCATOR_STATS) && defined (REQUEST_SIZE_INFO) size_t original_req_size = get_requested_size(block); #endif /* WITH_ALLOCATOR_STATS && REQUEST_SIZE_INFO */ if(get_size(block) > req_size) { /* TODO Maybe create a memory block in the unneeded space */ return ptr; } #ifdef HAVE_LOCKS raw_block_header_t *rb; rb = (raw_block_header_t *) ((uintptr_t) raw_block - sizeof(raw_block_header_t)); #endif /* HAVE_LOCKS */ /* First try to allocate space from the same raw block. * If it fails, try a more generic malloc. */ /* TODO check if the next memory block is free and try to coalesce if * possible */ LOCK_RAW_BLOCK(rb); ret = freelist_malloc(raw_block, req_size); UNLOCK_RAW_BLOCK(rb); if(ret != NULL) { #ifdef REQUEST_SIZE_INFO UPDATE_GLOBAL_STATS(REALLOC_GT, unmodified_req_size - original_req_size); #else /* REQUEST_SIZE_INFO */ UPDATE_GLOBAL_STATS(REALLOC_GT); #endif /* REQUEST_SIZE_INFO */ } else { /* FIXME stats leak from this malloc() call */ ret = malloc(req_size); } if(ret == NULL) { return NULL; } memcpy(ret, ptr, get_size(block)); LOCK_RAW_BLOCK(rb); /* start of copy from freelist_free() */ #if defined (COALESCING_FIXED) || defined (COALESCING_VARIABLE) coalesce(raw_block, block); #else mark_free(raw_block, block); ADD_BLOCK(block); #endif /* COALESCING_FIXED || COALESCING_VARIABLE */ /* end of copy from freelist_free() */ UNLOCK_RAW_BLOCK(rb); return ret; }