Example #1
0
static void test_check_free_block(void)
{
  Heap_Block *block = NULL;
  Heap_Block *next_block = NULL;
  Heap_Block *first_free_block = NULL;
  Heap_Block *secound_free_block = NULL;
  void *p1 = NULL;

  puts( "test the _Heap_Walk_check_free_block() function" );

  puts( "\tset a previous size for the next block which is not equal to the size of the actual block" );
  test_heap_init_default();
  block = _Heap_Free_list_first( &TestHeap );
  next_block = _Heap_Block_at( block, _Heap_Block_size( block ) );
  next_block->prev_size = _Heap_Block_size( block ) - 1;
  test_call_heap_walk( false );

  puts( "\tclear the previous_used flag of the first free block after an used block" );
  test_heap_init_default();
  p1 = test_allocate_block();
  block = _Heap_Block_of_alloc_area( (uintptr_t) p1, TestHeap.page_size );
  first_free_block = _Heap_Free_list_first( &TestHeap );
  first_free_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED;
  first_free_block->prev_size = _Heap_Block_size( block );
  _Heap_Free_list_insert_after( first_free_block, block );
  test_call_heap_walk( false );

  puts( "\ttake a free block out of the free list" );
  test_heap_init_custom();
  test_create_heap_with_gaps();
  first_free_block = _Heap_Free_list_first( &TestHeap );
  secound_free_block = first_free_block->next;
  _Heap_Free_list_remove( secound_free_block );
  test_call_heap_walk( false );
}
Example #2
0
static Heap_Resize_status _Heap_Resize_block_checked(
  Heap_Control *heap,
  Heap_Block *block,
  uintptr_t alloc_begin,
  uintptr_t new_alloc_size,
  uintptr_t *old_size,
  uintptr_t *new_size
)
{
  Heap_Statistics *const stats = &heap->stats;

  uintptr_t const block_begin = (uintptr_t) block;
  uintptr_t block_size = _Heap_Block_size( block );
  uintptr_t block_end = block_begin + block_size;

  uintptr_t alloc_size = block_end - alloc_begin + HEAP_ALLOC_BONUS;

  Heap_Block *next_block = _Heap_Block_at( block, block_size );
  uintptr_t next_block_size = _Heap_Block_size( next_block );
  bool next_block_is_free = _Heap_Is_free( next_block );

  _HAssert( _Heap_Is_block_in_heap( heap, next_block ) );
  _HAssert( _Heap_Is_prev_used( next_block ) );

  *old_size = alloc_size;

  if ( next_block_is_free ) {
    block_size += next_block_size;
    alloc_size += next_block_size;
  }

  if ( new_alloc_size > alloc_size ) {
    return HEAP_RESIZE_UNSATISFIED;
  }

  if ( next_block_is_free ) {
    _Heap_Block_set_size( block, block_size );

    _Heap_Free_list_remove( next_block );

    next_block = _Heap_Block_at( block, block_size );
    next_block->size_and_flag |= HEAP_PREV_BLOCK_USED;

    /* Statistics */
    --stats->free_blocks;
    stats->free_size -= next_block_size;
  }

  block = _Heap_Block_allocate( heap, block, alloc_begin, new_alloc_size );

  block_size = _Heap_Block_size( block );
  next_block = _Heap_Block_at( block, block_size );
  *new_size = (uintptr_t) next_block - alloc_begin + HEAP_ALLOC_BONUS;

  /* Statistics */
  ++stats->resizes;

  return HEAP_RESIZE_SUCCESSFUL;
}
Heap_Block *_Heap_Block_allocate(
  Heap_Control *heap,
  Heap_Block *block,
  uintptr_t alloc_begin,
  uintptr_t alloc_size
)
{
  Heap_Statistics *const stats = &heap->stats;

  uintptr_t const alloc_area_begin = _Heap_Alloc_area_of_block( block );
  uintptr_t const alloc_area_offset = alloc_begin - alloc_area_begin;

  Heap_Block *free_list_anchor = NULL;

  _HAssert( alloc_area_begin <= alloc_begin );

  if ( _Heap_Is_free( block ) ) {
    free_list_anchor = block->prev;

    _Heap_Free_list_remove( block );

    /* Statistics */
    --stats->free_blocks;
    ++stats->used_blocks;
    stats->free_size -= _Heap_Block_size( block );
  } else {
    free_list_anchor = _Heap_Free_list_head( heap );
  }

  if ( alloc_area_offset < heap->page_size ) {
    alloc_size += alloc_area_offset;

    block = _Heap_Block_allocate_from_begin(
      heap,
      block,
      free_list_anchor,
      alloc_size
    );
  } else {
    block = _Heap_Block_allocate_from_end(
      heap,
      block,
      free_list_anchor,
      alloc_begin,
      alloc_size
    );
  }

  /* Statistics */
  if ( stats->min_free_size > stats->free_size ) {
    stats->min_free_size = stats->free_size;
  }

  return block;
}
Example #4
0
static void _Heap_Free_block( Heap_Control *heap, Heap_Block *block )
{
  Heap_Statistics *const stats = &heap->stats;
  Heap_Block *first_free;

  /* Statistics */
  ++stats->used_blocks;
  --stats->frees;

  /*
   * The _Heap_Free() will place the block to the head of free list.  We want
   * the new block at the end of the free list.  So that initial and earlier
   * areas are consumed first.
   */
  _Heap_Free( heap, (void *) _Heap_Alloc_area_of_block( block ) );
  _Heap_Protection_free_all_delayed_blocks( heap );
  first_free = _Heap_Free_list_first( heap );
  _Heap_Free_list_remove( first_free );
  _Heap_Free_list_insert_before( _Heap_Free_list_tail( heap ), first_free );
}
Example #5
0
bool _Heap_Free( Heap_Control *heap, void *alloc_begin_ptr )
{
    Heap_Statistics *const stats = &heap->stats;
    uintptr_t alloc_begin = (uintptr_t) alloc_begin_ptr;
    Heap_Block *block =
        _Heap_Block_of_alloc_area( alloc_begin, heap->page_size );
    Heap_Block *next_block = NULL;
    uintptr_t block_size = 0;
    uintptr_t next_block_size = 0;
    bool next_is_free = false;

    if ( !_Heap_Is_block_in_heap( heap, block ) ) {
        return false;
    }

    block_size = _Heap_Block_size( block );
    next_block = _Heap_Block_at( block, block_size );

    if ( !_Heap_Is_block_in_heap( heap, next_block ) ) {
        _HAssert( false );
        return false;
    }

    if ( !_Heap_Is_prev_used( next_block ) ) {
        _HAssert( false );
        return false;
    }

    next_block_size = _Heap_Block_size( next_block );
    next_is_free = next_block != heap->last_block
                   && !_Heap_Is_prev_used( _Heap_Block_at( next_block, next_block_size ));

    if ( !_Heap_Is_prev_used( block ) ) {
        uintptr_t const prev_size = block->prev_size;
        Heap_Block * const prev_block = _Heap_Block_at( block, -prev_size );

        if ( !_Heap_Is_block_in_heap( heap, prev_block ) ) {
            _HAssert( false );
            return( false );
        }

        /* As we always coalesce free blocks, the block that preceedes prev_block
           must have been used. */
        if ( !_Heap_Is_prev_used ( prev_block) ) {
            _HAssert( false );
            return( false );
        }

        if ( next_is_free ) {       /* coalesce both */
            uintptr_t const size = block_size + prev_size + next_block_size;
            _Heap_Free_list_remove( next_block );
            stats->free_blocks -= 1;
            prev_block->size_and_flag = size | HEAP_PREV_BLOCK_USED;
            next_block = _Heap_Block_at( prev_block, size );
            _HAssert(!_Heap_Is_prev_used( next_block));
            next_block->prev_size = size;
        } else {                      /* coalesce prev */
            uintptr_t const size = block_size + prev_size;
            prev_block->size_and_flag = size | HEAP_PREV_BLOCK_USED;
            next_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED;
            next_block->prev_size = size;
        }
    } else if ( next_is_free ) {    /* coalesce next */
        uintptr_t const size = block_size + next_block_size;
        _Heap_Free_list_replace( next_block, block );
        block->size_and_flag = size | HEAP_PREV_BLOCK_USED;
        next_block  = _Heap_Block_at( block, size );
        next_block->prev_size = size;
    } else {                        /* no coalesce */
        /* Add 'block' to the head of the free blocks list as it tends to
           produce less fragmentation than adding to the tail. */
        _Heap_Free_list_insert_after( _Heap_Free_list_head( heap), block );
        block->size_and_flag = block_size | HEAP_PREV_BLOCK_USED;
        next_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED;
        next_block->prev_size = block_size;

        /* Statistics */
        ++stats->free_blocks;
        if ( stats->max_free_blocks < stats->free_blocks ) {
            stats->max_free_blocks = stats->free_blocks;
        }
    }

    /* Statistics */
    --stats->used_blocks;
    ++stats->frees;
    stats->free_size += block_size;

    return( true );
}
Example #6
0
bool _Heap_Free( Heap_Control *heap, void *alloc_begin_ptr )
{
  Heap_Statistics *const stats = &heap->stats;
  uintptr_t alloc_begin;
  Heap_Block *block;
  Heap_Block *next_block = NULL;
  uintptr_t block_size = 0;
  uintptr_t next_block_size = 0;
  bool next_is_free = false;

  /*
   * If NULL return true so a free on NULL is considered a valid release. This
   * is a special case that could be handled by the in heap check how-ever that
   * would result in false being returned which is wrong.
   */
  if ( alloc_begin_ptr == NULL ) {
    return true;
  }

  alloc_begin = (uintptr_t) alloc_begin_ptr;
  block = _Heap_Block_of_alloc_area( alloc_begin, heap->page_size );

  if ( !_Heap_Is_block_in_heap( heap, block ) ) {
    return false;
  }

  _Heap_Protection_block_check( heap, block );

  block_size = _Heap_Block_size( block );
  next_block = _Heap_Block_at( block, block_size );

  if ( !_Heap_Is_block_in_heap( heap, next_block ) ) {
    return false;
  }

  _Heap_Protection_block_check( heap, next_block );

  if ( !_Heap_Is_prev_used( next_block ) ) {
    _Heap_Protection_block_error( heap, block );
    return false;
  }

  if ( !_Heap_Protection_determine_block_free( heap, block ) ) {
    return true;
  }

  next_block_size = _Heap_Block_size( next_block );
  next_is_free = next_block != heap->last_block
    && !_Heap_Is_prev_used( _Heap_Block_at( next_block, next_block_size ));

  if ( !_Heap_Is_prev_used( block ) ) {
    uintptr_t const prev_size = block->prev_size;
    Heap_Block * const prev_block = _Heap_Block_at( block, -prev_size );

    if ( !_Heap_Is_block_in_heap( heap, prev_block ) ) {
      _HAssert( false );
      return( false );
    }

    /* As we always coalesce free blocks, the block that preceedes prev_block
       must have been used. */
    if ( !_Heap_Is_prev_used ( prev_block) ) {
      _HAssert( false );
      return( false );
    }

    if ( next_is_free ) {       /* coalesce both */
      uintptr_t const size = block_size + prev_size + next_block_size;
      _Heap_Free_list_remove( next_block );
      stats->free_blocks -= 1;
      prev_block->size_and_flag = size | HEAP_PREV_BLOCK_USED;
      next_block = _Heap_Block_at( prev_block, size );
      _HAssert(!_Heap_Is_prev_used( next_block));
      next_block->prev_size = size;
    } else {                      /* coalesce prev */
      uintptr_t const size = block_size + prev_size;
      prev_block->size_and_flag = size | HEAP_PREV_BLOCK_USED;
      next_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED;
      next_block->prev_size = size;
    }
  } else if ( next_is_free ) {    /* coalesce next */
    uintptr_t const size = block_size + next_block_size;
    _Heap_Free_list_replace( next_block, block );
    block->size_and_flag = size | HEAP_PREV_BLOCK_USED;
    next_block  = _Heap_Block_at( block, size );
    next_block->prev_size = size;
  } else {                        /* no coalesce */
    /* Add 'block' to the head of the free blocks list as it tends to
       produce less fragmentation than adding to the tail. */
    _Heap_Free_list_insert_after( _Heap_Free_list_head( heap), block );
    block->size_and_flag = block_size | HEAP_PREV_BLOCK_USED;
    next_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED;
    next_block->prev_size = block_size;

    /* Statistics */
    ++stats->free_blocks;
    if ( stats->max_free_blocks < stats->free_blocks ) {
      stats->max_free_blocks = stats->free_blocks;
    }
  }

  /* Statistics */
  --stats->used_blocks;
  ++stats->frees;
  stats->free_size += block_size;

  return( true );
}