Exemple #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 );
}
Exemple #2
0
static void test_heap_do_block_allocate( int variant, void *p2 )
{
  Heap_Block *const block =
    _Heap_Block_of_alloc_area( (uintptr_t) p2, test_page_size());
  uintptr_t const alloc_box_begin = _Heap_Alloc_area_of_block( block );
  uintptr_t const alloc_box_size = _Heap_Block_size( block );
  uintptr_t const alloc_box_end = alloc_box_begin + alloc_box_size;
  uintptr_t alloc_begin = 0;
  uintptr_t alloc_size = 0;

  puts( "\tallocate block at the beginning");
  alloc_begin = alloc_box_begin;
  alloc_size = 0;
  test_block_alloc( variant, 0, alloc_begin, alloc_size );

  puts( "\tallocate block full space");
  alloc_begin = alloc_box_begin;
  alloc_size = alloc_box_size + HEAP_ALLOC_BONUS
    - HEAP_BLOCK_HEADER_SIZE;
  test_block_alloc( variant, 1, alloc_begin, alloc_size );

  puts( "\tallocate block in the middle");
  alloc_begin = alloc_box_begin + TEST_DEFAULT_PAGE_SIZE;
  alloc_size = 0;
  test_block_alloc( variant, 2, alloc_begin, alloc_size );

  puts( "\tallocate block at the end");
  alloc_begin = alloc_box_end - TEST_DEFAULT_PAGE_SIZE;
  alloc_size = TEST_DEFAULT_PAGE_SIZE + HEAP_ALLOC_BONUS
    - HEAP_BLOCK_HEADER_SIZE;
  test_block_alloc( variant, 3, alloc_begin, alloc_size );
}
Exemple #3
0
Heap_Resize_status _Heap_Resize_block(
  Heap_Control *heap,
  void *alloc_begin_ptr,
  uintptr_t new_alloc_size,
  uintptr_t *old_size,
  uintptr_t *new_size
)
{
  uintptr_t const page_size = heap->page_size;

  uintptr_t const alloc_begin = (uintptr_t) alloc_begin_ptr;

  Heap_Block *const block = _Heap_Block_of_alloc_area( alloc_begin, page_size );

  *old_size = 0;
  *new_size = 0;

  if ( _Heap_Is_block_in_heap( heap, block ) ) {
    _Heap_Protection_block_check( heap, block );
    return _Heap_Resize_block_checked(
      heap,
      block,
      alloc_begin,
      new_alloc_size,
      old_size,
      new_size
    );
  }
  return HEAP_RESIZE_FATAL_ERROR;
}
Exemple #4
0
static uintptr_t _Heap_Check_block(
  const Heap_Control *heap,
  const Heap_Block *block,
  uintptr_t alloc_size,
  uintptr_t alignment,
  uintptr_t boundary
)
{
  uintptr_t const page_size = heap->page_size;
  uintptr_t const min_block_size = heap->min_block_size;

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

  uintptr_t const alloc_begin_floor = _Heap_Alloc_area_of_block( block );
  uintptr_t const alloc_begin_ceiling = block_end - min_block_size
    + HEAP_BLOCK_HEADER_SIZE + page_size - 1;

  uintptr_t alloc_end = block_end + HEAP_ALLOC_BONUS;
  uintptr_t alloc_begin = alloc_end - alloc_size;

  alloc_begin = _Heap_Align_down( alloc_begin, alignment );

  /* Ensure that the we have a valid new block at the end */
  if ( alloc_begin > alloc_begin_ceiling ) {
    alloc_begin = _Heap_Align_down( alloc_begin_ceiling, alignment );
  }

  alloc_end = alloc_begin + alloc_size;

  /* Ensure boundary constaint */
  if ( boundary != 0 ) {
    uintptr_t const boundary_floor = alloc_begin_floor + alloc_size;
    uintptr_t boundary_line = _Heap_Align_down( alloc_end, boundary );

    while ( alloc_begin < boundary_line && boundary_line < alloc_end ) {
      if ( boundary_line < boundary_floor ) {
        return 0;
      }
      alloc_begin = boundary_line - alloc_size;
      alloc_begin = _Heap_Align_down( alloc_begin, alignment );
      alloc_end = alloc_begin + alloc_size;
      boundary_line = _Heap_Align_down( alloc_end, boundary );
    }
  }

  /* Ensure that the we have a valid new block at the beginning */
  if ( alloc_begin >= alloc_begin_floor ) {
    uintptr_t const alloc_block_begin =
      (uintptr_t) _Heap_Block_of_alloc_area( alloc_begin, page_size );
    uintptr_t const free_size = alloc_block_begin - block_begin;

    if ( free_size >= min_block_size || free_size == 0 ) {
      return alloc_begin;
    }
  }

  return 0;
}
Exemple #5
0
bool _Heap_Size_of_alloc_area(
  Heap_Control *heap,
  void *alloc_begin_ptr,
  uintptr_t *alloc_size
)
{
  uintptr_t const page_size = heap->page_size;
  uintptr_t const alloc_begin = (uintptr_t) alloc_begin_ptr;
  Heap_Block *block = _Heap_Block_of_alloc_area( alloc_begin, page_size );
  Heap_Block *next_block = NULL;
  uintptr_t block_size = 0;

  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 )
      || !_Heap_Is_prev_used( next_block )
  ) {
    return false;
  }

  *alloc_size = (uintptr_t) next_block + HEAP_BLOCK_SIZE_OFFSET - alloc_begin;

  return true;
}
static Heap_Block *_Heap_Block_allocate_from_end(
  Heap_Control *heap,
  Heap_Block *block,
  Heap_Block *free_list_anchor,
  uintptr_t alloc_begin,
  uintptr_t alloc_size
)
{
  Heap_Statistics *const stats = &heap->stats;

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

  Heap_Block *const new_block =
    _Heap_Block_of_alloc_area( alloc_begin, heap->page_size );
  uintptr_t const new_block_begin = (uintptr_t) new_block;
  uintptr_t const new_block_size = block_end - new_block_begin;

  block_end = new_block_begin;
  block_size = block_end - block_begin;

  _HAssert( block_size >= heap->min_block_size );
  _HAssert( new_block_size >= heap->min_block_size );

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

  if ( _Heap_Is_prev_used( block ) ) {
    _Heap_Free_list_insert_after( free_list_anchor, block );

    free_list_anchor = block;

    /* Statistics */
    ++stats->free_blocks;
  } else {
    Heap_Block *const prev_block = _Heap_Prev_block( block );
    uintptr_t const prev_block_size = _Heap_Block_size( prev_block );

    block = prev_block;
    block_begin = (uintptr_t) block;
    block_size += prev_block_size;
  }

  block->size_and_flag = block_size | HEAP_PREV_BLOCK_USED;

  new_block->prev_size = block_size;
  new_block->size_and_flag = new_block_size;

  _Heap_Block_split( heap, new_block, free_list_anchor, alloc_size );

  return new_block;
}
Exemple #7
0
static void test_check_free_list(void)
{
  void *p1 = NULL;
  Heap_Block *first_free_block = NULL;
  Heap_Block *secound_free_block = NULL;
  Heap_Block *third_free_block = NULL;
  Heap_Block *used_block = NULL;

  puts( "testing the _Heap_Walk_check_free_list() function" );

  puts( "\tno free blocks" );
  test_heap_init_custom();
  test_fill_heap();
  test_call_heap_walk( true );

  puts( "\tcreate a loop in the free list" );
  test_heap_init_default();
  test_create_heap_with_gaps();
  /* find free blocks */
  first_free_block = _Heap_Free_list_first( &TestHeap );
  secound_free_block = first_free_block->next;
  third_free_block = secound_free_block->next;
  /* create a loop */
  third_free_block->next = secound_free_block;
  secound_free_block->prev = third_free_block;
  test_call_heap_walk( false );

  puts( "\tput a block outside the heap to the free list" );
  test_heap_init_default();
  first_free_block = _Heap_Free_list_first( &TestHeap );
  first_free_block->next = TestHeap.first_block - 1;
  test_call_heap_walk( false );

  puts( "\tput a block on the free list, which is not page-aligned" );
  test_heap_init_custom();
  test_create_heap_with_gaps();
  first_free_block = _Heap_Free_list_first( &TestHeap );
  first_free_block->next = (Heap_Block *) ((uintptr_t) first_free_block->next + CPU_ALIGNMENT);
  first_free_block->next->prev = first_free_block;
  test_call_heap_walk( false );

  puts( "\tput a used block on the free list" );
  test_heap_init_custom();
  test_create_heap_with_gaps();
  p1 = test_allocate_block();
  first_free_block = _Heap_Free_list_first( &TestHeap );
  used_block = _Heap_Block_of_alloc_area( (uintptr_t) p1, TestHeap.page_size );
  _Heap_Free_list_insert_after( first_free_block, used_block );
  test_call_heap_walk( false );
}
Exemple #8
0
Heap_Block *_Heap_Greedy_allocate(
  Heap_Control *heap,
  const uintptr_t *block_sizes,
  size_t block_count
)
{
  Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap );
  Heap_Block *allocated_blocks = NULL;
  Heap_Block *blocks = NULL;
  Heap_Block *current;
  size_t i;

  _Heap_Protection_free_all_delayed_blocks( heap );

  for (i = 0; i < block_count; ++i) {
    void *next = _Heap_Allocate( heap, block_sizes [i] );

    if ( next != NULL ) {
      Heap_Block *next_block = _Heap_Block_of_alloc_area(
        (uintptr_t) next,
        heap->page_size
      );

      next_block->next = allocated_blocks;
      allocated_blocks = next_block;
    }
  }

  while ( (current = _Heap_Free_list_first( heap )) != free_list_tail ) {
    _Heap_Block_allocate(
      heap,
      current,
      _Heap_Alloc_area_of_block( current ),
      _Heap_Block_size( current ) - HEAP_BLOCK_HEADER_SIZE
    );

    current->next = blocks;
    blocks = current;
  }

  while ( allocated_blocks != NULL ) {
    current = allocated_blocks;
    allocated_blocks = allocated_blocks->next;
    _Heap_Free( heap, (void *) _Heap_Alloc_area_of_block( current ) );
  }

  return blocks;
}
Exemple #9
0
static void test_heap_free(void)
{
  Heap_Control *heap = &TestHeap;
  void *p;
  Heap_Block *block;
  bool ok;

  _Heap_Initialize( heap, &TestHeapMemory[0], sizeof(TestHeapMemory), 0 );

  p = _Heap_Allocate( heap, 1 );
  rtems_test_assert( p != NULL );

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

  /*
   * This will kick the next block outside of the heap area and the next
   * _Heap_Free() will detect this.
   */
  block->size_and_flag += sizeof(TestHeapMemory);

  ok = _Heap_Free( heap, p );
  rtems_test_assert( !ok );
}
Exemple #10
0
static void test_heap_resize_block(void)
{
  void *p1, *p2, *p3;
  uintptr_t new_alloc_size = 0;
  Heap_Block *block = NULL;

  puts( "run tests for _Heap_Resize_Block()" );

  puts( "\tgive a block outside the heap to the function" );
  test_heap_init( TEST_DEFAULT_PAGE_SIZE );
  p1 = TestHeap.first_block - TEST_DEFAULT_PAGE_SIZE;
  new_alloc_size = 1;
  test_simple_resize_block( p1, new_alloc_size, HEAP_RESIZE_FATAL_ERROR );

  puts( "\tincrease size");

  puts( "\t\tlet the next block be used alredy and try to get a size bigger than the actual block" );
  test_heap_init( TEST_DEFAULT_PAGE_SIZE );
  p1 = test_alloc_one_page();
  rtems_test_assert( p1 );

  p2 = test_alloc_one_page();
  rtems_test_assert( p2 );

  new_alloc_size = 3 * TEST_DEFAULT_PAGE_SIZE / 2;
  test_simple_resize_block( p1, new_alloc_size, HEAP_RESIZE_UNSATISFIED );

  puts( "\t\tnext block not used and try to set the new allocation size between the page-alignments" );
  test_heap_init( TEST_DEFAULT_PAGE_SIZE );
  p1 = test_alloc_one_page();
  new_alloc_size = 3 * TEST_DEFAULT_PAGE_SIZE / 2;
  test_simple_resize_block( p1, new_alloc_size, HEAP_RESIZE_SUCCESSFUL );

  puts( "\t\tlet the block after the next be used and try to allocate more then one pagesize more" );
  test_heap_init( TEST_DEFAULT_PAGE_SIZE );
  p1 = test_alloc_one_page();
  rtems_test_assert( p1 );

  p2 = test_alloc_one_page();
  rtems_test_assert( p2 );

  p3 = test_alloc_one_page();
  rtems_test_assert( p3 );

  test_free( p2 );
  new_alloc_size = 5 * TEST_DEFAULT_PAGE_SIZE / 2;
  test_simple_resize_block( p1, new_alloc_size, HEAP_RESIZE_UNSATISFIED );

  puts( "\ttry to resize to the same size" );
  test_heap_init( TEST_DEFAULT_PAGE_SIZE );
  p1 = test_alloc_one_page();
  block = _Heap_Block_of_alloc_area( (uintptr_t) p1, TestHeap.page_size );
  new_alloc_size = _Heap_Block_size( block );
  test_simple_resize_block( p1, new_alloc_size, HEAP_RESIZE_SUCCESSFUL );

  puts( "\tdecrease size");

  puts( "\t\tdecrease a block with two pages to one page" );
  test_heap_init( TEST_DEFAULT_PAGE_SIZE );
  p1 = test_alloc_two_pages();
  new_alloc_size = 1;
  test_simple_resize_block( p1, new_alloc_size, HEAP_RESIZE_SUCCESSFUL );

  puts( "\t\tresize the block to the size 0" );
  test_heap_init( TEST_DEFAULT_PAGE_SIZE );
  p1 = test_alloc_one_page();
  new_alloc_size = 0;
  test_simple_resize_block( p1, new_alloc_size, HEAP_RESIZE_SUCCESSFUL );
}
Exemple #11
0
static void test_block_alloc(
  int free_variant,
  int alloc_variant,
  uintptr_t alloc_begin,
  uintptr_t alloc_size
)
{
  void *p1 = NULL;
  void *p2 = NULL;
  void *p3 = NULL;

  uintptr_t size_fresh_heap = 0;
  uintptr_t pages_per_default_block = 0;
  uint32_t exp_free_pages = 0;
  uint32_t exp_free_blocks = 0;
  uint32_t exp_used_blocks = 0;

  test_heap_init( TEST_DEFAULT_PAGE_SIZE );

  size_fresh_heap = _Heap_Get_size( &TestHeap );
  exp_free_pages = size_fresh_heap / TestHeap.page_size;

  p1 = test_create_used_block();
  p2 = test_create_used_block();
  p3 = test_create_used_block();

  pages_per_default_block = _Heap_Block_size(
    _Heap_Block_of_alloc_area( (uintptr_t) p1, TestHeap.page_size )
  ) / TestHeap.page_size;

  if (free_variant == 1) {
    test_free( p1 );
  } else if (free_variant == 2) {
    test_free( p3 );
  } else if (free_variant == 3) {
    test_free( p2 );
    test_free( p3 );
  }

  _Heap_Block_allocate(
    &TestHeap,
    _Heap_Block_of_alloc_area( (uintptr_t) p2, test_page_size()),
    alloc_begin,
    alloc_size
  );

  test_check_alloc_simple( (void *) alloc_begin, alloc_size, 0, 0 );

  /* check statistics */
  switch( free_variant ) {
    case 1:
      exp_free_pages = exp_free_pages - 2 * pages_per_default_block;
      exp_used_blocks = 2;

      switch( alloc_variant ) {
	case 1:
	  /* allocate block full space */
	  exp_free_blocks = 2;
	  break;
	case 2:
	  /* allocate block in the middle */
	  exp_free_pages = exp_free_pages + pages_per_default_block - 1;
	  exp_free_blocks = 3;
	  break;
	case 3:
	  /* allocate block at the end */
	  exp_free_pages = exp_free_pages + pages_per_default_block - 2;
	  exp_free_blocks = 2;
	  break;
	default:
	  /* allocate block at the beginning */
	  exp_free_pages = exp_free_pages + pages_per_default_block - 1;
	  exp_free_blocks = 3;
	  break;
      }
      break;
    case 2:
      exp_free_pages = exp_free_pages - 2 * pages_per_default_block;
      exp_used_blocks = 2;

      switch( alloc_variant ) {
	case 1:
	  /* allocate block full space */
	  exp_free_blocks = 1;
	  break;
	case 2:
	  /* allocate block in the middle */
	  exp_free_pages = exp_free_pages + pages_per_default_block - 1;
	  exp_free_blocks = 2;
	  break;
	case 3:
	  /* allocate block at the end */
	  exp_free_pages = exp_free_pages + pages_per_default_block - 1;
	  exp_free_blocks = 2;
	  break;
	default:
	  /* allocate block at the beginning */
	  exp_free_pages = exp_free_pages + pages_per_default_block - 1;
	  exp_free_blocks = 1;
	  break;
      }
      break;
    case 3:
      exp_free_pages = exp_free_pages - pages_per_default_block;
      exp_used_blocks = 2;

      switch( alloc_variant ) {
	case 1:
	  /* allocate block full space */
	  exp_free_pages = exp_free_pages - pages_per_default_block;
	  exp_free_blocks = 1;
	  break;
	case 2:
	  /* allocate block in the middle */
	  exp_free_pages = exp_free_pages - 1;
	  exp_free_blocks = 2;
	  break;
	case 3:
	  /* allocate block at the end */
	  exp_free_pages = exp_free_pages - 2;
	  exp_free_blocks = 2;
	  break;
	default:
	  /* allocate block at the beginning */
	  exp_free_pages = exp_free_pages - 1;
	  exp_free_blocks = 1;
	  break;
      }
      break;
    default:
      exp_free_pages = exp_free_pages - 3 * pages_per_default_block;
      exp_used_blocks = 3;

      switch( alloc_variant ) {
	case 1:
	  /* allocate block full space */
	  exp_free_blocks = 1;
	  break;
	case 2:
	  /* allocate block in the middle */
	  exp_free_blocks = 3;
	  exp_free_pages = exp_free_pages + pages_per_default_block - 1;
	  break;
	case 3:
	  /* allocate block at the end */
	  exp_free_blocks = 2;
	  exp_free_pages = exp_free_pages + pages_per_default_block - 1;
	  break;
	default:
	  /* allocate block at the beginning */
	  exp_free_blocks = 2;
	  exp_free_pages = exp_free_pages + pages_per_default_block - 1;
      }
  }

  rtems_test_assert( TestHeap.stats.free_size == exp_free_pages * TestHeap.page_size );
  rtems_test_assert( TestHeap.stats.free_blocks == exp_free_blocks );
  rtems_test_assert( TestHeap.stats.used_blocks == exp_used_blocks );
}
Exemple #12
0
static void test_check_alloc(
  void *alloc_begin_ptr,
  void *expected_alloc_begin_ptr,
  uintptr_t alloc_size,
  uintptr_t alignment,
  uintptr_t boundary
)
{
  uintptr_t const min_block_size = TestHeap.min_block_size;
  uintptr_t const page_size = TestHeap.page_size;

  rtems_test_assert( alloc_begin_ptr == expected_alloc_begin_ptr );

  if( expected_alloc_begin_ptr != NULL ) {
    uintptr_t const alloc_begin = (uintptr_t ) alloc_begin_ptr;
    uintptr_t const alloc_end = alloc_begin + alloc_size;

    uintptr_t const alloc_area_begin = _Heap_Align_down( alloc_begin, page_size );
    uintptr_t const alloc_area_offset = alloc_begin - alloc_area_begin;
#if UNUSED
    uintptr_t const alloc_area_size = alloc_area_offset + alloc_size;
#endif
    Heap_Block *block = _Heap_Block_of_alloc_area( alloc_area_begin, page_size );
    uintptr_t const block_begin = (uintptr_t ) block;
    uintptr_t const block_size = _Heap_Block_size( block );
    uintptr_t const block_end = block_begin + block_size;

    rtems_test_assert( block_size >= min_block_size );
    rtems_test_assert( block_begin < block_end );
    rtems_test_assert(
      _Heap_Is_aligned( block_begin + HEAP_BLOCK_HEADER_SIZE, page_size )
    );
    rtems_test_assert(
      _Heap_Is_aligned( block_size, page_size )
    );

    rtems_test_assert( alloc_end <= block_end + HEAP_ALLOC_BONUS );
    rtems_test_assert( alloc_area_begin > block_begin );
    rtems_test_assert( alloc_area_offset < page_size );

    rtems_test_assert( _Heap_Is_aligned( alloc_area_begin, page_size ) );
    if ( alignment == 0 ) {
      rtems_test_assert( alloc_begin == alloc_area_begin );
    } else {
      rtems_test_assert( _Heap_Is_aligned( alloc_begin, alignment ) );
    }

    if ( boundary != 0 ) {
      uintptr_t boundary_line = _Heap_Align_down( alloc_end, boundary );

      rtems_test_assert( alloc_size <= boundary );
      rtems_test_assert(
        boundary_line <= alloc_begin
          || alloc_end <= boundary_line
      );
    }
  }

  rtems_test_assert(
    page_size < CPU_ALIGNMENT
      || _Heap_Walk( &TestHeap, 0, false )
  );
}
Exemple #13
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 );
}
Exemple #14
0
uintptr_t _Heap_Extend(
  Heap_Control *heap,
  void *extend_area_begin_ptr,
  uintptr_t extend_area_size,
  uintptr_t unused __attribute__((unused))
)
{
  Heap_Statistics *const stats = &heap->stats;
  Heap_Block *const first_block = heap->first_block;
  Heap_Block *start_block = first_block;
  Heap_Block *merge_below_block = NULL;
  Heap_Block *merge_above_block = NULL;
  Heap_Block *link_below_block = NULL;
  Heap_Block *link_above_block = NULL;
  Heap_Block *extend_first_block = NULL;
  Heap_Block *extend_last_block = NULL;
  uintptr_t const page_size = heap->page_size;
  uintptr_t const min_block_size = heap->min_block_size;
  uintptr_t const extend_area_begin = (uintptr_t) extend_area_begin_ptr;
  uintptr_t const extend_area_end = extend_area_begin + extend_area_size;
  uintptr_t const free_size = stats->free_size;
  uintptr_t extend_first_block_size = 0;
  uintptr_t extended_size = 0;
  bool extend_area_ok = false;

  if ( extend_area_end < extend_area_begin ) {
    return 0;
  }

  extend_area_ok = _Heap_Get_first_and_last_block(
    extend_area_begin,
    extend_area_size,
    page_size,
    min_block_size,
    &extend_first_block,
    &extend_last_block
  );
  if (!extend_area_ok ) {
    /* For simplicity we reject extend areas that are too small */
    return 0;
  }

  do {
    uintptr_t const sub_area_begin = (start_block != first_block) ?
      (uintptr_t) start_block : heap->area_begin;
    uintptr_t const sub_area_end = start_block->prev_size;
    Heap_Block *const end_block =
      _Heap_Block_of_alloc_area( sub_area_end, page_size );

    if (
      sub_area_end > extend_area_begin && extend_area_end > sub_area_begin
    ) {
      return 0;
    }

    if ( extend_area_end == sub_area_begin ) {
      merge_below_block = start_block;
    } else if ( extend_area_end < sub_area_end ) {
      link_below_block = start_block;
    }

    if ( sub_area_end == extend_area_begin ) {
      start_block->prev_size = extend_area_end;

      merge_above_block = end_block;
    } else if ( sub_area_end < extend_area_begin ) {
      link_above_block = end_block;
    }

    start_block = _Heap_Block_at( end_block, _Heap_Block_size( end_block ) );
  } while ( start_block != first_block );

  if ( extend_area_begin < heap->area_begin ) {
    heap->area_begin = extend_area_begin;
  } else if ( heap->area_end < extend_area_end ) {
    heap->area_end = extend_area_end;
  }

  extend_first_block_size =
    (uintptr_t) extend_last_block - (uintptr_t) extend_first_block;

  extend_first_block->prev_size = extend_area_end;
  extend_first_block->size_and_flag =
    extend_first_block_size | HEAP_PREV_BLOCK_USED;
  _Heap_Protection_block_initialize( heap, extend_first_block );

  extend_last_block->prev_size = extend_first_block_size;
  extend_last_block->size_and_flag = 0;
  _Heap_Protection_block_initialize( heap, extend_last_block );

  if ( (uintptr_t) extend_first_block < (uintptr_t) heap->first_block ) {
    heap->first_block = extend_first_block;
  } else if ( (uintptr_t) extend_last_block > (uintptr_t) heap->last_block ) {
    heap->last_block = extend_last_block;
  }

  if ( merge_below_block != NULL ) {
    _Heap_Merge_below( heap, extend_area_begin, merge_below_block );
  } else if ( link_below_block != NULL ) {
    _Heap_Link_below(
      link_below_block,
      extend_last_block
    );
  }

  if ( merge_above_block != NULL ) {
    _Heap_Merge_above( heap, merge_above_block, extend_area_end );
  } else if ( link_above_block != NULL ) {
    _Heap_Link_above(
      link_above_block,
      extend_first_block,
      extend_last_block
    );
  }

  if ( merge_below_block == NULL && merge_above_block == NULL ) {
    _Heap_Free_block( heap, extend_first_block );
  }

  _Heap_Set_last_block_size( heap );

  extended_size = stats->free_size - free_size;

  /* Statistics */
  stats->size += extended_size;

  return extended_size;
}
Exemple #15
0
static void test_main_loop(void)
{
  void *p1 = NULL;
  void *p2 = NULL;
  Heap_Block *block = NULL;
  Heap_Block *next_block = NULL;

  puts( "Test the main loop" );

  puts( "\tset the blocksize so, that the next block is outside the heap" );
  test_heap_init_custom();
  /* use all blocks */
  p1 = test_fill_heap();
  block = _Heap_Block_of_alloc_area( (uintptr_t) p1, TestHeap.page_size );
  block->size_and_flag = ( 2 * _Heap_Block_size( block ) ) | HEAP_PREV_BLOCK_USED;
  test_call_heap_walk( false );

  puts( "\twalk a heap with blocks with different states of the previous-used flag" );
  test_heap_init_custom();
  test_create_heap_with_gaps();
  test_allocate_block(); /* fill one gap */
  test_call_heap_walk( true );

  puts( "\tcreate a block with a not page aligned size" );
  test_heap_init_custom();
  p1 = test_allocate_block();
  p2 = test_allocate_block();
  _Heap_Free( &TestHeap, p1 );
  block = _Heap_Block_of_alloc_area( (uintptr_t) p2, TestHeap.page_size );
  block->size_and_flag = (3 * TestHeap.page_size / 2) & ~HEAP_PREV_BLOCK_USED;
  test_call_heap_walk( false );

  puts( "\tcreate a block with a size smaller than the min_block_size" );
  test_heap_init_default();
  p1 = test_allocate_block();
  p2 = test_allocate_block();
  _Heap_Free( &TestHeap, p1 );
  block = _Heap_Block_of_alloc_area( (uintptr_t) p2, TestHeap.page_size );
  block->size_and_flag = 0;
  test_call_heap_walk( false );

  puts( "\tmake a block with a size, so that the block reaches into the next block" );
  test_heap_init_default();
  p1 = test_allocate_block();
  p2 = test_allocate_block();
  block = _Heap_Block_of_alloc_area( (uintptr_t) p1, TestHeap.page_size  );
  block->size_and_flag = ( 3 * _Heap_Block_size( block ) / 2 ) | HEAP_PREV_BLOCK_USED;
  test_call_heap_walk( false );

  puts( "\tcreate a block with invalid successor" );
  test_heap_init_default();
  test_allocate_block();
  p1 = test_allocate_block();
  block = _Heap_Block_of_alloc_area( (uintptr_t) p1, TestHeap.page_size  );
  block->size_and_flag = (0 - TestHeap.page_size) | HEAP_PREV_BLOCK_USED;
  test_call_heap_walk( false );

  puts( "\tmake a block with a size, so that it includes the next block" );
  test_heap_init_default();
  p1 = test_allocate_block();
  p2 = test_allocate_block();
  block = _Heap_Block_of_alloc_area( (uintptr_t) p1, TestHeap.page_size  );
  next_block = _Heap_Block_at( block, _Heap_Block_size( block ) );
  block->size_and_flag = ( _Heap_Block_size( block ) + _Heap_Block_size( next_block ) ) | HEAP_PREV_BLOCK_USED;
  test_call_heap_walk( true );
}
Exemple #16
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 );
}