/* * 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 "freelist/split.h" #include "dmmlib/config.h" #ifdef WITH_KNOBS #include "dmmlib/dmmlib.h" #endif /* WITH_KNOBS */ #include "other.h" #include "freelist/block_header_funcs.h" #include "freelist/ordering_policy.h" void split(freelist_rb_t *raw_block, block_header_t *ptr, size_t req_size) { size_t new_size; size_t min_split_size; block_header_t *new_block; #ifdef COALESCE_AFTER_SPLIT size_t max_coal_size; block_header_t *next_block; size_t current_next_size; next_block = get_dlnext(raw_block, ptr); #endif /* COALESCE_AFTER_SPLIT */ /* Align the requested size */ req_size = req_padding(req_size); /* Check what would be the size of the new block if we split the current * one. * Note: new_size is a size_t, so compare first in order to prevent an * underflow. */ if(get_size(ptr) > req_size + HEADER_SIZE) { new_size = get_size(ptr) - req_size - HEADER_SIZE; } else { new_size = 0; } #ifdef SPLITTING_FIXED min_split_size = MIN_SPLIT_SIZE; #endif /* SPLITTING_FIXED */ #ifdef SPLITTING_VARIABLE min_split_size = (size_t) systemallocator.dmm_knobs.min_split_size; #endif /* SPLITTING_VARIABLE */ if(new_size < min_split_size) { return; } new_block = (block_header_t *)((char *)ptr + req_size + HEADER_SIZE); if(raw_block->border_ptr == ptr) { raw_block->border_ptr = new_block; } /* Resize the previous, to be used block */ set_size_and_used(raw_block, ptr, req_size); #ifdef COALESCE_AFTER_SPLIT /* Try to coalesce with the next block if it is free */ #ifdef COALESCING_FIXED max_coal_size = MAX_COAL_SIZE; #endif /* COALESCING_FIXED */ #ifdef COALESCING_VARIABLE max_coal_size = systemallocator.dmm_knobs.max_coal_size; #endif /* COALESCING_VARIABLE */ if(next_block != NULL && is_free(next_block) == true) { current_next_size = new_size + get_size(next_block) + HEADER_SIZE; if(current_next_size <= max_coal_size) { REMOVE_FSLLIST(raw_block, next_block); if(raw_block->border_ptr == next_block) { raw_block->border_ptr = new_block; } new_size = current_next_size; } } #endif /* COALESCE_AFTER_SPLIT */ set_size_and_free(raw_block, new_block, new_size); ADD_BLOCK(new_block); }