source: rtems/cpukit/score/src/heap.c @ dea3eccb

4.104.115
Last change on this file since dea3eccb was dea3eccb, checked in by Joel Sherrill <joel.sherrill@…>, on 09/06/09 at 15:24:08

2009-09-06 Sebastian Huber <Sebastian.Huber@…>

  • libcsupport/src/free.c, libmisc/stackchk/check.c, rtems/include/rtems/rtems/region.h, rtems/src/regioncreate.c, rtems/src/regionextend.c, rtems/src/regiongetinfo.c, rtems/src/regiongetsegment.c, rtems/src/regiongetsegmentsize.c, rtems/src/regionresizesegment.c, score/src/pheapallocate.c, score/src/pheapallocatealigned.c, score/src/pheapextend.c, score/src/pheapfree.c, score/src/pheapgetblocksize.c, score/src/pheapgetfreeinfo.c, score/src/pheapgetinfo.c, score/src/pheapgetsize.c, score/src/pheapinit.c, score/src/pheapresizeblock.c, score/src/pheapwalk.c: Update for heap API changes.
  • score/include/rtems/score/apimutex.h, score/include/rtems/score/object.h: Documentation.
  • score/include/rtems/score/heap.h, score/include/rtems/score/protectedheap.h, score/inline/rtems/score/heap.inl, score/src/heap.c, score/src/heapallocate.c, score/src/heapallocatealigned.c, score/src/heapextend.c, score/src/heapfree.c, score/src/heapgetfreeinfo.c, score/src/heapgetinfo.c, score/src/heapresizeblock.c, score/src/heapsizeofuserarea.c, score/src/heapwalk.c: Overall cleanup. Added boundary constraint to allocation function. More changes follow.
  • Property mode set to 100644
File size: 11.6 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreHeap
5 *
6 * @brief Heap Handler implementation.
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-2009.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  Copyright (c) 2009 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/heap.h>
28
29#if CPU_ALIGNMENT == 0 || CPU_ALIGNMENT % 4 != 0
30  #error "invalid CPU_ALIGNMENT value"
31#endif
32
33static uint32_t instance = 0;
34
35/*PAGE
36 *
37 *  _Heap_Initialize
38 *
39 *  This kernel routine initializes a heap.
40 *
41 *  Input parameters:
42 *    heap         - pointer to heap header
43 *    area_begin - starting address of heap
44 *    size             - size of heap
45 *    page_size        - allocatable unit of memory
46 *
47 *  Output parameters:
48 *    returns - maximum memory available if RTEMS_SUCCESSFUL
49 *    0       - otherwise
50 *
51 *  This is what a heap looks like in memory immediately after initialization:
52 *
53 *
54 *            +--------------------------------+ <- begin = area_begin
55 *            |  unused space due to alignment |
56 *            |       size < page_size         |
57 *         0  +--------------------------------+ <- first block
58 *            |  prev_size = page_size         |
59 *         4  +--------------------------------+
60 *            |  size = size0              | 1 |
61 *         8  +---------------------+----------+ <- aligned on page_size
62 *            |  next = HEAP_TAIL   |          |
63 *        12  +---------------------+          |
64 *            |  prev = HEAP_HEAD   |  memory  |
65 *            +---------------------+          |
66 *            |                     available  |
67 *            |                                |
68 *            |                for allocation  |
69 *            |                                |
70 *     size0  +--------------------------------+ <- last dummy block
71 *            |  prev_size = size0             |
72 *        +4  +--------------------------------+
73 *            |  size = page_size          | 0 | <- prev block is free
74 *        +8  +--------------------------------+ <- aligned on page_size
75 *            |  unused space due to alignment |
76 *            |       size < page_size         |
77 *            +--------------------------------+ <- end = begin + size
78 *
79 *  Below is what a heap looks like after first allocation of SIZE bytes using
80 *  _Heap_allocate(). BSIZE stands for SIZE + 4 aligned up on 'page_size'
81 *  boundary.
82 *  [NOTE: If allocation were performed by _Heap_Allocate_aligned(), the
83 *  block size BSIZE is defined differently, and previously free block will
84 *  be split so that upper part of it will become used block (see
85 *  'heapallocatealigned.c' for details).]
86 *
87 *            +--------------------------------+ <- begin = area_begin
88 *            |  unused space due to alignment |
89 *            |       size < page_size         |
90 *         0  +--------------------------------+ <- used block
91 *            |  prev_size = page_size         |
92 *         4  +--------------------------------+
93 *            |  size = BSIZE              | 1 | <- prev block is used
94 *         8  +--------------------------------+ <- aligned on page_size
95 *            |              .                 | Pointer returned to the user
96 *            |              .                 | is 8 for _Heap_Allocate()
97 *            |              .                 | and is in range
98 * 8 +        |         user-accessible        | [8,8+page_size) for
99 *  page_size +- - -                      - - -+ _Heap_Allocate_aligned()
100 *            |             area               |
101 *            |              .                 |
102 *     BSIZE  +- - - - -     .        - - - - -+ <- free block
103 *            |              .                 |
104 * BSIZE  +4  +--------------------------------+
105 *            |  size = S = size0 - BSIZE  | 1 | <- prev block is used
106 * BSIZE  +8  +-------------------+------------+ <- aligned on page_size
107 *            |  next = HEAP_TAIL |            |
108 * BSIZE +12  +-------------------+            |
109 *            |  prev = HEAP_HEAD |     memory |
110 *            +-------------------+            |
111 *            |                   .  available |
112 *            |                   .            |
113 *            |                   .        for |
114 *            |                   .            |
115 * BSIZE +S+0 +-------------------+ allocation + <- last dummy block
116 *            |  prev_size = S    |            |
117 *       +S+4 +-------------------+------------+
118 *            |  size = page_size          | 0 | <- prev block is free
119 *       +S+8 +--------------------------------+ <- aligned on page_size
120 *            |  unused space due to alignment |
121 *            |       size < page_size         |
122 *            +--------------------------------+ <- end = begin + size
123 *
124 */
125
126uintptr_t _Heap_Initialize(
127  Heap_Control *heap,
128  void *heap_area_begin_ptr,
129  uintptr_t heap_area_size,
130  uintptr_t page_size
131)
132{
133  Heap_Statistics *const stats = &heap->stats;
134  uintptr_t const heap_area_begin = (uintptr_t) heap_area_begin_ptr;
135  uintptr_t const heap_area_end = heap_area_begin + heap_area_size;
136  uintptr_t alloc_area_begin = heap_area_begin + HEAP_BLOCK_HEADER_SIZE;
137  uintptr_t alloc_area_size = 0;
138  uintptr_t first_block_begin = 0;
139  uintptr_t first_block_size = 0;
140  uintptr_t min_block_size = 0;
141  uintptr_t overhead = 0;
142  Heap_Block *first_block = NULL;
143  Heap_Block *second_block = NULL;
144
145  if ( page_size == 0 ) {
146    page_size = CPU_ALIGNMENT;
147  } else {
148    page_size = _Heap_Align_up( page_size, CPU_ALIGNMENT );
149  }
150  min_block_size = _Heap_Align_up( sizeof( Heap_Block ), page_size );
151
152  alloc_area_begin = _Heap_Align_up( alloc_area_begin, page_size );
153  first_block_begin = alloc_area_begin - HEAP_BLOCK_HEADER_SIZE;
154  overhead = HEAP_BLOCK_HEADER_SIZE + (first_block_begin - heap_area_begin);
155  first_block_size = heap_area_size - overhead;
156  first_block_size = _Heap_Align_down ( first_block_size, page_size );
157  alloc_area_size = first_block_size - HEAP_BLOCK_HEADER_SIZE;
158
159  if (
160    heap_area_end < heap_area_begin
161      || heap_area_size <= overhead
162      || first_block_size < min_block_size
163  ) {
164    /* Invalid area or area too small */
165    return 0;
166  }
167
168  /* First block */
169  first_block = (Heap_Block *) first_block_begin;
170  first_block->prev_size = page_size;
171  first_block->size_and_flag = first_block_size | HEAP_PREV_BLOCK_USED;
172  first_block->next = _Heap_Free_list_tail( heap );
173  first_block->prev = _Heap_Free_list_head( heap );
174
175  /* Second and last block */
176  second_block = _Heap_Block_at( first_block, first_block_size );
177  second_block->prev_size = first_block_size;
178  second_block->size_and_flag = page_size;
179
180  /* Heap control */
181  heap->page_size = page_size;
182  heap->min_block_size = min_block_size;
183  heap->area_begin = heap_area_begin;
184  heap->area_end = heap_area_end;
185  heap->first_block = first_block;
186  heap->last_block = second_block;
187  _Heap_Free_list_head( heap )->next = first_block;
188  _Heap_Free_list_tail( heap )->prev = first_block;
189
190  /* Statistics */
191  stats->size = heap_area_size;
192  stats->free_size = first_block_size;
193  stats->min_free_size = first_block_size;
194  stats->free_blocks = 1;
195  stats->max_free_blocks = 1;
196  stats->used_blocks = 0;
197  stats->max_search = 0;
198  stats->allocs = 0;
199  stats->searches = 0;
200  stats->frees = 0;
201  stats->resizes = 0;
202  stats->instance = instance++;
203
204  _HAssert( _Heap_Is_aligned( CPU_ALIGNMENT, 4 ) );
205  _HAssert( _Heap_Is_aligned( heap->page_size, CPU_ALIGNMENT ) );
206  _HAssert( _Heap_Is_aligned( heap->min_block_size, page_size ) );
207  _HAssert(
208    _Heap_Is_aligned( _Heap_Alloc_area_of_block( first_block ), page_size )
209  );
210  _HAssert(
211    _Heap_Is_aligned( _Heap_Alloc_area_of_block( second_block ), page_size )
212  );
213
214  if ( !_Heap_Walk( heap, 0, false ) ) {
215    _Heap_Walk( heap, 0, true );
216  }
217
218  return alloc_area_size;
219}
220
221static Heap_Block *_Heap_Block_split(
222  Heap_Control *heap,
223  Heap_Block *block,
224  uintptr_t alloc_size
225)
226{
227  uintptr_t const page_size = heap->page_size;
228  uintptr_t const min_block_size = heap->min_block_size;
229  uintptr_t const min_alloc_size = min_block_size - HEAP_BLOCK_HEADER_SIZE;
230
231  uintptr_t const block_size = _Heap_Block_size( block );
232
233  uintptr_t const used_size =
234    _Heap_Max( alloc_size, min_alloc_size ) + HEAP_BLOCK_HEADER_SIZE;
235  uintptr_t const used_block_size = _Heap_Align_up( used_size, page_size );
236
237  uintptr_t const free_size = block_size + HEAP_BLOCK_SIZE_OFFSET - used_size;
238  uintptr_t const free_size_limit = min_block_size + HEAP_BLOCK_SIZE_OFFSET;
239
240  Heap_Block *const next_block = _Heap_Block_at( block, block_size );
241
242  _HAssert( used_size <= block_size + HEAP_BLOCK_SIZE_OFFSET );
243  _HAssert( used_size + free_size == block_size + HEAP_BLOCK_SIZE_OFFSET );
244
245  if ( free_size >= free_size_limit ) {
246    uintptr_t const free_block_size = block_size - used_block_size;
247    Heap_Block *const free_block = _Heap_Block_at( block, used_block_size );
248
249    _HAssert( used_block_size + free_block_size == block_size );
250
251    block->size_and_flag = used_block_size
252      | (block->size_and_flag & HEAP_PREV_BLOCK_USED);
253    free_block->size_and_flag = free_block_size | HEAP_PREV_BLOCK_USED;
254    next_block->prev_size = free_block_size;
255
256    return free_block;
257  } else {
258    next_block->size_and_flag |= HEAP_PREV_BLOCK_USED;
259
260    return NULL;
261  }
262}
263
264static Heap_Block *_Heap_Block_allocate_from_begin(
265  Heap_Control *heap,
266  Heap_Block *block,
267  uintptr_t alloc_size
268)
269{
270  Heap_Block *const free_block = _Heap_Block_split( heap, block, alloc_size );
271
272  if ( free_block != NULL ) {
273    _Heap_Free_list_replace( block, free_block );
274  } else {
275    Heap_Statistics *const stats = &heap->stats;
276
277    _Heap_Free_list_remove( block );
278
279    /* Statistics */
280    --stats->free_blocks;
281  }
282
283  return block;
284}
285
286static Heap_Block *_Heap_Block_allocate_from_end(
287  Heap_Control *heap,
288  Heap_Block *block,
289  uintptr_t alloc_begin,
290  uintptr_t alloc_size
291)
292{
293  uintptr_t const block_begin = (uintptr_t) block;
294  uintptr_t block_size = _Heap_Block_size( block );
295  uintptr_t block_end = block_begin + block_size;
296
297  Heap_Block *const new_block =
298    _Heap_Block_of_alloc_area( alloc_begin, heap->page_size );
299  uintptr_t const new_block_begin = (uintptr_t) new_block;
300  uintptr_t const new_block_size = block_end - new_block_begin;
301
302  Heap_Block *free_block = NULL;
303
304  block_end = new_block_begin;
305  block_size = block_end - block_begin;
306
307  _HAssert( block_size >= heap->min_block_size );
308  _HAssert( new_block_size >= heap->min_block_size );
309
310  block->size_and_flag = block_size | HEAP_PREV_BLOCK_USED;
311  new_block->prev_size = block_size;
312  new_block->size_and_flag = new_block_size;
313
314  free_block = _Heap_Block_split( heap, new_block, alloc_size );
315  if ( free_block != NULL ) {
316    _Heap_Free_list_insert_after( block, free_block );
317  }
318
319  return new_block;
320}
321
322Heap_Block *_Heap_Block_allocate(
323  Heap_Control *heap,
324  Heap_Block *block,
325  uintptr_t alloc_begin,
326  uintptr_t alloc_size
327)
328{
329  Heap_Statistics *const stats = &heap->stats;
330  uintptr_t const alloc_area_begin = _Heap_Alloc_area_of_block( block );
331  uintptr_t const alloc_area_offset = alloc_begin - alloc_area_begin;
332
333  _HAssert( _Heap_Is_prev_used( block ) );
334  _HAssert( alloc_area_begin <= alloc_begin );
335
336  if ( alloc_area_offset < heap->page_size ) {
337    alloc_size += alloc_area_offset;
338
339    block = _Heap_Block_allocate_from_begin( heap, block, alloc_size );
340  } else {
341    block = _Heap_Block_allocate_from_end( heap, block, alloc_begin, alloc_size );
342  }
343
344  /* Statistics */
345  ++stats->used_blocks;
346  stats->free_size -= _Heap_Block_size( block );
347  if ( stats->min_free_size > stats->free_size ) {
348    stats->min_free_size = stats->free_size;
349  }
350
351  return block;
352}
Note: See TracBrowser for help on using the repository browser.