Beispiel #1
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;
}
Beispiel #2
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;
}
void *_Heap_Allocate(
  Heap_Control        *the_heap,
  size_t               size
)
{
  uint32_t  the_size;
  uint32_t  search_count;
  Heap_Block *the_block;
  void       *ptr = NULL;
  Heap_Statistics *const stats = &the_heap->stats;
  Heap_Block *const tail = _Heap_Tail(the_heap);

  the_size =
    _Heap_Calc_block_size(size, the_heap->page_size, the_heap->min_block_size);
  if(the_size == 0)
    return NULL;

  /* Find large enough free block. */
  for(the_block = _Heap_First(the_heap), search_count = 0;
      the_block != tail;
      the_block = the_block->next, ++search_count)
  {
    /* As we always coalesce free blocks, prev block must have been used. */
    _HAssert(_Heap_Is_prev_used(the_block));

    /* Don't bother to mask out the HEAP_PREV_USED bit as it won't change the
       result of the comparison. */
    if(the_block->size >= the_size) {
      (void)_Heap_Block_allocate(the_heap, the_block, the_size );

      ptr = _Heap_User_area(the_block);

      stats->allocs += 1;
      stats->searches += search_count + 1;

      _HAssert(_Heap_Is_aligned_ptr(ptr, the_heap->page_size));
      break;
    }
  }

  if(stats->max_search < search_count)
    stats->max_search = search_count;

  return ptr;
}
Beispiel #4
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 );
}
Beispiel #5
0
void *_Heap_Allocate_aligned_with_boundary(
  Heap_Control *heap,
  uintptr_t alloc_size,
  uintptr_t alignment,
  uintptr_t boundary
)
{
  Heap_Statistics *const stats = &heap->stats;
  uintptr_t const block_size_floor = alloc_size + HEAP_BLOCK_HEADER_SIZE
    - HEAP_ALLOC_BONUS;
  uintptr_t const page_size = heap->page_size;
  Heap_Block *block = NULL;
  uintptr_t alloc_begin = 0;
  uint32_t search_count = 0;
  bool search_again = false;

  if ( block_size_floor < alloc_size ) {
    /* Integer overflow occured */
    return NULL;
  }

  if ( boundary != 0 ) {
    if ( boundary < alloc_size ) {
      return NULL;
    }

    if ( alignment == 0 ) {
      alignment = page_size;
    }
  }

  do {
    Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap );

    block = _Heap_Free_list_first( heap );
    while ( block != free_list_tail ) {
      _HAssert( _Heap_Is_prev_used( block ) );

      _Heap_Protection_block_check( heap, block );

      /*
       * The HEAP_PREV_BLOCK_USED flag is always set in the block size_and_flag
       * field.  Thus the value is about one unit larger than the real block
       * size.  The greater than operator takes this into account.
       */
      if ( block->size_and_flag > block_size_floor ) {
        if ( alignment == 0 ) {
          alloc_begin = _Heap_Alloc_area_of_block( block );
        } else {
          alloc_begin = _Heap_Check_block(
            heap,
            block,
            alloc_size,
            alignment,
            boundary
          );
        }
      }

      /* Statistics */
      ++search_count;

      if ( alloc_begin != 0 ) {
        break;
      }

      block = block->next;
    }

    search_again = _Heap_Protection_free_delayed_blocks( heap, alloc_begin );
  } while ( search_again );

  if ( alloc_begin != 0 ) {
    /* Statistics */
    ++stats->allocs;
    stats->searches += search_count;

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

    _Heap_Check_allocation(
      heap,
      block,
      alloc_begin,
      alloc_size,
      alignment,
      boundary
    );
  }

  /* Statistics */
  if ( stats->max_search < search_count ) {
    stats->max_search = search_count;
  }

  return (void *) alloc_begin;
}