|
@@ -20,46 +20,148 @@
|
|
|
#include "other.h"
|
|
|
#include "dmm_config.h"
|
|
|
|
|
|
-void * coalesce(allocator_t *allocator, heap_t *heap, void *ptr, size_t size) {
|
|
|
- void *prev;
|
|
|
+bool coalesce(allocator_t *allocator, heap_t *heap, void *ptr) {
|
|
|
+ size_t max_coal_size;
|
|
|
+ size_t size;
|
|
|
+ size_t current_next_size;
|
|
|
+ size_t previous_current_size;
|
|
|
+ size_t three_blocks_size;
|
|
|
+ void *previous_block, *next_block;
|
|
|
#ifdef WITH_FIXED_LISTS
|
|
|
int fixed_list_id, i;
|
|
|
maptable_node_t *current_maptable_node;
|
|
|
#endif /* WITH_FIXED_LISTS */
|
|
|
|
|
|
- prev = get_dlprevious(ptr);
|
|
|
+#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 */
|
|
|
|
|
|
-#ifdef WITH_FIXED_LISTS
|
|
|
- /* Check if it is a block of a fixed list */
|
|
|
- fixed_list_id = map_size_to_list(heap, get_size(prev));
|
|
|
- if(fixed_list_id != -1) {
|
|
|
- /* If it is, find the fixed list and remove the block */
|
|
|
- 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;
|
|
|
+ size = get_size(ptr);
|
|
|
+
|
|
|
+ previous_block = get_dlprevious(ptr);
|
|
|
+ next_block = get_dlnext(allocator, ptr);
|
|
|
+
|
|
|
+ /* Find out the sizes of all possible combinations */
|
|
|
+
|
|
|
+ /* Current + Next */
|
|
|
+ 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 */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Previous + Current */
|
|
|
+ if(is_previous_free(ptr) == true) {
|
|
|
+#ifdef WITH_OWNERSHIP
|
|
|
+ if(get_owner(ptr) == get_owner(previous_block)) {
|
|
|
+#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 */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Previous + Current + Next */
|
|
|
+ if(next_block != NULL && is_previous_free(ptr) && is_free(next_block)) {
|
|
|
+#ifdef WITH_OWNERSHIP
|
|
|
+ if(get_owner(ptr) == get_owner(previous_block) &&
|
|
|
+ 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 */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Check if Previous + Current + Next is ok */
|
|
|
+ if(three_blocks_size <= max_coal_size) {
|
|
|
+ /* If previous block is on a fixed list, remove it */
|
|
|
+#ifdef WITH_FIXED_LISTS
|
|
|
+ /* Check if it is a block of a fixed list */
|
|
|
+ fixed_list_id = map_size_to_list(heap, get_size(previous_block));
|
|
|
+ if(fixed_list_id != -1) {
|
|
|
+ /* If it is, find the fixed list and remove the block */
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
#ifdef COUNT_HOPS
|
|
|
- remove_block(heap, &ptr, ¤t_maptable_node->fixed_list_head);
|
|
|
+ remove_block(heap, &ptr, ¤t_maptable_node->fixed_list_head);
|
|
|
#else
|
|
|
- remove_block(&ptr, ¤t_maptable_node->fixed_list_head);
|
|
|
+ remove_block(&ptr, ¤t_maptable_node->fixed_list_head);
|
|
|
#endif /* COUNT_HOPS */
|
|
|
- }
|
|
|
+ }
|
|
|
#endif /* WITH_FIXED_LISTS */
|
|
|
+ /* Reset the previous block size */
|
|
|
+ set_size_and_free(allocator, previous_block, three_blocks_size);
|
|
|
+ /* Remove the next block from any freelist */
|
|
|
+ remove_block_from_lists(&next_block, heap);
|
|
|
+ /* Update border pointer if the next block was the border pointer */
|
|
|
+ if(allocator->border_ptr == next_block) {
|
|
|
+ allocator->border_ptr = ptr;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- // Set the new size
|
|
|
- // Note: the rest of the header variables will be set on free().
|
|
|
- set_size_and_free(allocator, prev, size);
|
|
|
+ if(previous_current_size <= max_coal_size) {
|
|
|
+ /* If previous block is on a fixed list, remove it */
|
|
|
+#ifdef WITH_FIXED_LISTS
|
|
|
+ /* Check if it is a block of a fixed list */
|
|
|
+ fixed_list_id = map_size_to_list(heap, get_size(previous_block));
|
|
|
+ if(fixed_list_id != -1) {
|
|
|
+ /* If it is, find the fixed list and remove the block */
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+#ifdef COUNT_HOPS
|
|
|
+ remove_block(heap, &ptr, ¤t_maptable_node->fixed_list_head);
|
|
|
+#else
|
|
|
+ remove_block(&ptr, ¤t_maptable_node->fixed_list_head);
|
|
|
+#endif /* COUNT_HOPS */
|
|
|
+ }
|
|
|
+#endif /* WITH_FIXED_LISTS */
|
|
|
+ /* Reset the previous block size */
|
|
|
+ set_size_and_free(allocator, ptr, previous_current_size);
|
|
|
+ /* Update border pointer if the current block was the border pointer */
|
|
|
+ if(allocator->border_ptr == next_block) {
|
|
|
+ allocator->border_ptr = ptr;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- /* If the current block is the allocator's border pointer, update the
|
|
|
- * latter to point to the previous block.
|
|
|
- */
|
|
|
- if(allocator->border_ptr == ptr)
|
|
|
- {
|
|
|
- allocator->border_ptr = prev;
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- return prev;
|
|
|
+ /* If everything fails, just mark the block free */
|
|
|
+ mark_free(allocator, ptr);
|
|
|
+ return false;
|
|
|
}
|
|
|
-
|