source: rtems/cpukit/score/src/heapextend.c @ b2a0214

4.115
Last change on this file since b2a0214 was b2a0214, checked in by Sebastian Huber <sebastian.huber@…>, on 06/07/10 at 09:35:01

2010-06-07 Sebastian Huber <sebastian.huber@…>

  • score/include/rtems/score/heap.h: Declare _Heap_Get_first_and_last_block(). Removed Heap_Extend_status. Changed return type of _Heap_Extend() to bool.
  • score/inline/rtems/score/heap.inl: Define _Heap_Set_last_block_size().
  • score/src/heap.c: Define and use _Heap_Get_first_and_last_block().
  • score/src/heapgetinfo.c: Removed assert statements. Do not count the last block. This ensures that all size values are an integral multiple of the page size which is consistent with the other statistics.
  • score/src/heapextend.c: Implemented support for scattered heap areas.
  • score/src/heapwalk.c: Dump also last block. Changes for new first and last block values.
  • ./score/src/pheapextend.c, rtems/src/regionextend.c: Update for _Heap_Extend() changes.
  • Property mode set to 100644
File size: 6.5 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreHeap
5 *
6 * @brief Heap Handler implementation.
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-1999.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  Copyright (c) 2010 embedded brains GmbH.
14 *
15 *  The license and distribution terms for this file may be
16 *  found in the file LICENSE in this distribution or at
17 *  http://www.rtems.com/license/LICENSE.
18 *
19 *  $Id$
20 */
21
22#if HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include <rtems/system.h>
27#include <rtems/score/sysstate.h>
28#include <rtems/score/heap.h>
29
30static void _Heap_Free_block( Heap_Control *heap, Heap_Block *block )
31{
32  Heap_Statistics *const stats = &heap->stats;
33
34  /* Statistics */
35  ++stats->used_blocks;
36  --stats->frees;
37
38  _Heap_Free( heap, (void *) _Heap_Alloc_area_of_block( block ));
39}
40
41static void _Heap_Merge_below(
42  Heap_Control *heap,
43  uintptr_t extend_area_begin,
44  Heap_Block *first_block
45)
46{
47  uintptr_t const page_size = heap->page_size;
48  uintptr_t const new_first_block_alloc_begin =
49    _Heap_Align_up( extend_area_begin + HEAP_BLOCK_HEADER_SIZE, page_size );
50  uintptr_t const new_first_block_begin =
51    new_first_block_alloc_begin - HEAP_BLOCK_HEADER_SIZE;
52  uintptr_t const first_block_begin = (uintptr_t) first_block;
53  uintptr_t const new_first_block_size =
54    first_block_begin - new_first_block_begin;
55  Heap_Block *const new_first_block = (Heap_Block *) new_first_block_begin;
56
57  new_first_block->prev_size = first_block->prev_size;
58  new_first_block->size_and_flag = new_first_block_size | HEAP_PREV_BLOCK_USED;
59
60  _Heap_Free_block( heap, new_first_block );
61}
62
63static void _Heap_Merge_above(
64  Heap_Control *heap,
65  Heap_Block *last_block,
66  uintptr_t extend_area_end
67)
68{
69  uintptr_t const page_size = heap->page_size;
70  uintptr_t const last_block_begin = (uintptr_t) last_block;
71  uintptr_t const last_block_new_size = _Heap_Align_down(
72    extend_area_end - last_block_begin - HEAP_BLOCK_HEADER_SIZE,
73    page_size
74  );
75  Heap_Block *const new_last_block =
76    _Heap_Block_at( last_block, last_block_new_size );
77
78  new_last_block->size_and_flag =
79    (last_block->size_and_flag - last_block_new_size)
80      | HEAP_PREV_BLOCK_USED;
81
82  _Heap_Block_set_size( last_block, last_block_new_size );
83
84  _Heap_Free_block( heap, last_block );
85}
86
87static void _Heap_Link_below(
88  Heap_Block *link,
89  Heap_Block *last_block
90)
91{
92  uintptr_t const last_block_begin = (uintptr_t) last_block;
93  uintptr_t const link_begin = (uintptr_t) link;
94
95  last_block->size_and_flag =
96    (link_begin - last_block_begin) | HEAP_PREV_BLOCK_USED;
97}
98
99static void _Heap_Link_above(
100  Heap_Block *link,
101  Heap_Block *first_block,
102  Heap_Block *last_block
103)
104{
105  uintptr_t const link_begin = (uintptr_t) link;
106  uintptr_t const first_block_begin = (uintptr_t) first_block;
107
108  _Heap_Block_set_size( link, first_block_begin - link_begin );
109
110  last_block->size_and_flag |= HEAP_PREV_BLOCK_USED;
111}
112
113bool _Heap_Extend(
114  Heap_Control *heap,
115  void *extend_area_begin_ptr,
116  uintptr_t extend_area_size,
117  uintptr_t *extended_size_ptr
118)
119{
120  Heap_Statistics *const stats = &heap->stats;
121  Heap_Block *const first_block = heap->first_block;
122  Heap_Block *start_block = first_block;
123  Heap_Block *merge_below_block = NULL;
124  Heap_Block *merge_above_block = NULL;
125  Heap_Block *link_below_block = NULL;
126  Heap_Block *link_above_block = NULL;
127  Heap_Block *extend_first_block = NULL;
128  Heap_Block *extend_last_block = NULL;
129  uintptr_t const page_size = heap->page_size;
130  uintptr_t const min_block_size = heap->min_block_size;
131  uintptr_t const extend_area_begin = (uintptr_t) extend_area_begin_ptr;
132  uintptr_t const extend_area_end = extend_area_begin + extend_area_size;
133  uintptr_t const free_size = stats->free_size;
134  uintptr_t extend_first_block_size = 0;
135  uintptr_t extended_size = 0;
136  bool extend_area_ok = false;
137
138  if ( extend_area_end < extend_area_begin ) {
139    return false;
140  }
141
142  extend_area_ok = _Heap_Get_first_and_last_block(
143    extend_area_begin,
144    extend_area_size,
145    page_size,
146    min_block_size,
147    &extend_first_block,
148    &extend_last_block
149  );
150  if (!extend_area_ok ) {
151    /* For simplicity we reject extend areas that are too small */
152    return false;
153  }
154
155  do {
156    uintptr_t const sub_area_begin = (start_block != first_block) ?
157      (uintptr_t) start_block : heap->area_begin;
158    uintptr_t const sub_area_end = start_block->prev_size;
159    Heap_Block *const end_block =
160      _Heap_Block_of_alloc_area( sub_area_end, page_size );
161
162    if (
163      sub_area_end > extend_area_begin && extend_area_end > sub_area_begin
164    ) {
165      return false;
166    }
167
168    if ( extend_area_end == sub_area_begin ) {
169      merge_below_block = start_block;
170    } else if ( extend_area_end < sub_area_end ) {
171      link_below_block = start_block;
172    }
173
174    if ( sub_area_end == extend_area_begin ) {
175      start_block->prev_size = extend_area_end;
176
177      merge_above_block = end_block;
178    } else if ( sub_area_end < extend_area_begin ) {
179      link_above_block = end_block;
180    }
181
182    start_block = _Heap_Block_at( end_block, _Heap_Block_size( end_block ) );
183  } while ( start_block != first_block );
184
185  if ( extend_area_begin < heap->area_begin ) {
186    heap->area_begin = extend_area_begin;
187  } else if ( heap->area_end < extend_area_end ) {
188    heap->area_end = extend_area_end;
189  }
190
191  extend_first_block_size =
192    (uintptr_t) extend_last_block - (uintptr_t) extend_first_block;
193
194  extend_first_block->prev_size = extend_area_end;
195  extend_first_block->size_and_flag =
196    extend_first_block_size | HEAP_PREV_BLOCK_USED;
197
198  extend_last_block->prev_size = extend_first_block_size;
199  extend_last_block->size_and_flag = 0;
200
201  if ( (uintptr_t) extend_first_block < (uintptr_t) heap->first_block ) {
202    heap->first_block = extend_first_block;
203  } else if ( (uintptr_t) extend_last_block > (uintptr_t) heap->last_block ) {
204    heap->last_block = extend_last_block;
205  }
206
207  if ( merge_below_block != NULL ) {
208    _Heap_Merge_below( heap, extend_area_begin, merge_below_block );
209  } else if ( link_below_block != NULL ) {
210    _Heap_Link_below(
211      link_below_block,
212      extend_last_block
213    );
214  }
215
216  if ( merge_above_block != NULL ) {
217    _Heap_Merge_above( heap, merge_above_block, extend_area_end );
218  } else if ( link_above_block != NULL ) {
219    _Heap_Link_above(
220      link_above_block,
221      extend_first_block,
222      extend_last_block
223    );
224  }
225
226  if ( merge_below_block == NULL && merge_above_block == NULL ) {
227    _Heap_Free_block( heap, extend_first_block );
228  }
229
230  _Heap_Set_last_block_size( heap );
231
232  extended_size = stats->free_size - free_size;
233
234  /* Statistics */
235  stats->size += extended_size;
236
237  if ( extended_size_ptr != NULL )
238    *extended_size_ptr = extended_size;
239
240  return true;
241}
Note: See TracBrowser for help on using the repository browser.