/* * 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. * */ #include #include #include "other.h" #ifdef HAVE_LOCKS #include "posix_lock.h" #endif /* HAVE_LOCKS */ #if defined (COALESCING_FIXED) || defined (COALESCING_VARIABLE) #include "coalesce.h" #endif /* COALESCING_FIXED || COALESCING_VARIABLE */ #ifdef WITH_ADAPTIVITY #include "dmm_adaptor.h" #endif /* WITH_ADAPTIVITY */ #include "block_header.h" void custom_ahfree(allocator_t *allocator, heap_t* heap, void *ptr) { size_t size; #ifdef WITH_FIXED_LISTS int fixed_list_id, i; maptable_node_t *current_maptable_node; #endif /* WITH_FIXED_LISTS */ #if defined (COALESCING_FIXED) || defined (COALESCING_VARIABLE) bool coalesced; size_t max_coal_size; void *next_block; size_t current_next_size; size_t previous_current_size; size_t three_blocks_size; #endif /* COALESCING_FIXED || COALESCING_VARIABLE */ #ifndef WITH_MEMORY_SPACE_AWARENESS int heap_id; /* Currently all the memory space aware allocators are pre-initialized */ if(allocator == NULL) { allocator = &systemallocator; } if(heap == NULL) { heap_id = map_thread_heap(); heap = &allocator->heaps[heap_id]; } #endif /* WITH_MEMORY_SPACE_AWARENESS */ size = get_size(ptr); #ifdef HAVE_LOCKS posix_lock(heap); #endif /* HAVE_LOCKS */ #ifdef FUTURE_FEATURES remove_block(&ptr, &heap->used_blocks_head); #endif /* FUTURE_FEATURES */ #ifdef WITH_STATS heap->dmm_stats.mem_allocated -= size; #ifdef FUTURE_FEATURES heap->dmm_stats.mem_requested -= get_requested_size(ptr); #endif /* FUTURE_FEATURES */ #endif /* WITH_STATS */ #if defined (COALESCING_FIXED) || defined (COALESCING_VARIABLE) coalesced = false; #ifdef COALESCING_FIXED max_coal_size = MAX_COALESCE_SIZE; #endif /* COALESCING_FIXED */ #ifdef COALESCING_VARIABLE max_coal_size = heap->dmm_knobs.max_coalesce_size; #endif /* COALESCING_VARIABLE */ next_block = get_dlnext(allocator, ptr); if(next_block != NULL) { if(is_free(next_block) == true) { #ifdef WITH_OWNERSHIP if(get_owner(next_block) == get_owner(ptr)) { #endif /* WITH_OWNERSHIP */ current_next_size = size + get_size(next_block) + HEADER_SIZE; #ifdef WITH_OWNERSHIP } #endif /* WITH_OWNERSHIP */ } else { current_next_size = (size_t) -1; /* SIZE_MAX */ } } else { current_next_size = (size_t) -1; /* SIZE_MAX */ } if(is_previous_free(ptr) == true) { #ifdef WITH_OWNERSHIP if(get_owner(ptr) == get_owner(get_dlprevious(ptr))) { #endif /* WITH_OWNERSHIP */ previous_current_size = size + get_previous_size(ptr) + HEADER_SIZE; #ifdef WITH_OWNERSHIP } #endif /* WITH_OWNERSHIP */ } else { previous_current_size = (size_t) -1; /* SIZE_MAX */ } if(next_block != NULL && is_previous_free(ptr)) { #ifdef WITH_OWNERSHIP if(get_owner(ptr) == get_owner(get_dlprevious(ptr) && get_owner(ptr) == get_owner(next_block))) { #endif /* WITH_OWNERSHIP */ three_blocks_size = get_previous_size(ptr) + size + get_size(next_block) + 2 * HEADER_SIZE; #ifdef WITH_OWNERSHIP } #endif /* WITH_OWNERSHIP */ } else { three_blocks_size = (size_t) -1; /* SIZE_MAX */ } if(three_blocks_size <= max_coal_size) { ptr = coalesce(allocator, heap, ptr, three_blocks_size); remove_block_from_lists(&next_block, heap); if(allocator->border_ptr == next_block) { allocator->border_ptr = ptr; } coalesced = true; size = three_blocks_size; } else { if(previous_current_size <= max_coal_size) { ptr = coalesce(allocator, heap, ptr, previous_current_size); coalesced = true; size = previous_current_size; } else { if(current_next_size <= max_coal_size) { set_size_and_free(allocator, ptr, current_next_size); remove_block_from_lists(&next_block, heap); if(allocator->border_ptr == next_block) { allocator->border_ptr = ptr; } } else { mark_free(allocator, ptr); } } } #else mark_free(allocator, ptr); #endif /* COALESCING_FIXED || COALESCING_VARIABLE */ #ifdef WITH_FIXED_LISTS /* Check if the block could be put in a fixed list */ fixed_list_id = map_size_to_list(heap, size); if(fixed_list_id != -1) { current_maptable_node = heap->maptable_head; if(fixed_list_id != 0) { for(i = 1; i < fixed_list_id; i++) { current_maptable_node = current_maptable_node->next; } } push_block(&ptr, ¤t_maptable_node->fixed_list_head); } else { /* put it in the free list */ #endif /* WITH_FIXED_LISTS */ #if defined (COALESCING_FIXED) || defined (COALESCING_VARIABLE) /* The block should be added to the free list only if it is not * coalesced */ if(!coalesced) { push_block(&ptr, &heap->free_list_head); } #else push_block(&ptr, &heap->free_list_head); #endif /* COALESCING_FIXED || COALESCING_VARIABLE */ #ifdef WITH_FIXED_LISTS } #endif /* WITH_FIXED_LISTS */ #ifdef WITH_STATS /* Update Stats */ heap->dmm_stats.live_objects -= 1; heap->dmm_stats.num_free += 1; /* End of Stats */ #endif /* WITH_STATS */ #ifdef WITH_ADAPTIVITY /* Refresh the state of the heap allocator if a certain number of * free's has been served already */ /* TODO Define 100 as a constant */ if(heap->dmm_stats.num_free % 100) { free_state_refresh(heap); } #endif /* WITH_ADAPTIVITY */ #ifdef HAVE_LOCKS posix_unlock(heap); #endif /* HAVE_LOCKS */ } /* Currently all the memory space aware allocators are pre-initialized, so * we do not expect any custom_ahmalloc call without knowing which allocator * and heap are to be used. */ #ifndef WITH_MEMORY_SPACE_AWARENESS void custom_free(void *ptr) { custom_ahfree(NULL, NULL, ptr); } #endif /* WITH_MEMORY_SPACE_AWARENESS */