source: rtems/cpukit/score/src/heap.c @ 22ce0881

4.104.114.95
Last change on this file since 22ce0881 was 493e405, checked in by Joel Sherrill <joel.sherrill@…>, on 09/12/07 at 20:11:33

2007-09-12 Sergei Organov <osv@…>

PR 1258/rtems

  • cpukit/score/src/heapallocatealigned.c (block_allocate): New routine.
  • cpukit/score/src/heapallocatealigned.c (_Heap_Allocate_aligned): Use block_allocate() instead of _Heap_Block_allocate(). Replace _Heap_Head(the_heap)->next with equivalent _Heap_First(the_heap).
  • cpukit/score/src/heap.c (_Heap_Allocate): fix comments according to changed block split strategy in _Heap_Allocate_aligned().
  • Property mode set to 100644
File size: 10.2 KB
Line 
1/*
2 *  Heap Handler
3 *
4 *  COPYRIGHT (c) 1989-2006.
5 *  On-Line Applications Research Corporation (OAR).
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.com/license/LICENSE.
10 *
11 *  $Id$
12 */
13
14#if HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18#include <rtems/system.h>
19#include <rtems/score/sysstate.h>
20#include <rtems/score/heap.h>
21
22static uint32_t instance = 0;
23
24/*PAGE
25 *
26 *  _Heap_Initialize
27 *
28 *  This kernel routine initializes a heap.
29 *
30 *  Input parameters:
31 *    the_heap         - pointer to heap header
32 *    starting_address - starting address of heap
33 *    size             - size of heap
34 *    page_size        - allocatable unit of memory
35 *
36 *  Output parameters:
37 *    returns - maximum memory available if RTEMS_SUCCESSFUL
38 *    0       - otherwise
39 *
40 *  This is what a heap looks like in memory immediately after initialization:
41 *
42 *
43 *            +--------------------------------+ <- begin = starting_address
44 *            |  unused space due to alignment |
45 *            |       size < page_size         |
46 *         0  +--------------------------------+ <- first block
47 *            |  prev_size = page_size         |
48 *         4  +--------------------------------+
49 *            |  size = size0              | 1 |
50 *         8  +---------------------+----------+ <- aligned on page_size
51 *            |  next = HEAP_TAIL   |          |
52 *        12  +---------------------+          |
53 *            |  prev = HEAP_HEAD   |  memory  |
54 *            +---------------------+          |
55 *            |                     available  |
56 *            |                                |
57 *            |                for allocation  |
58 *            |                                |
59 *     size0  +--------------------------------+ <- last dummy block
60 *            |  prev_size = size0             |
61 *        +4  +--------------------------------+
62 *            |  size = page_size          | 0 | <- prev block is free
63 *        +8  +--------------------------------+ <- aligned on page_size
64 *            |  unused space due to alignment |
65 *            |       size < page_size         |
66 *            +--------------------------------+ <- end = begin + size
67 *
68 *  Below is what a heap looks like after first allocation of SIZE bytes using
69 *  _Heap_allocate(). BSIZE stands for SIZE + 4 aligned up on 'page_size'
70 *  boundary.
71 *  [NOTE: If allocation were performed by _Heap_Allocate_aligned(), the
72 *  block size BSIZE is defined differently, and previously free block will
73 *  be split so that upper part of it will become used block (see
74 *  'heapallocatealigned.c' for details).]
75 *
76 *            +--------------------------------+ <- begin = starting_address
77 *            |  unused space due to alignment |
78 *            |       size < page_size         |
79 *         0  +--------------------------------+ <- used block
80 *            |  prev_size = page_size         |
81 *         4  +--------------------------------+
82 *            |  size = BSIZE              | 1 | <- prev block is used
83 *         8  +--------------------------------+ <- aligned on page_size
84 *            |              .                 | Pointer returned to the user
85 *            |              .                 | is 8 for _Heap_Allocate()
86 *            |              .                 | and is in range
87 * 8 +        |         user-accessible        | [8,8+page_size) for
88 *  page_size +- - -                      - - -+ _Heap_Allocate_aligned()
89 *            |             area               |
90 *            |              .                 |
91 *     BSIZE  +- - - - -     .        - - - - -+ <- free block
92 *            |              .                 |
93 * BSIZE  +4  +--------------------------------+
94 *            |  size = S = size0 - BSIZE  | 1 | <- prev block is used
95 * BSIZE  +8  +-------------------+------------+ <- aligned on page_size
96 *            |  next = HEAP_TAIL |            |
97 * BSIZE +12  +-------------------+            |
98 *            |  prev = HEAP_HEAD |     memory |
99 *            +-------------------+            |
100 *            |                   .  available |
101 *            |                   .            |
102 *            |                   .        for |
103 *            |                   .            |
104 * BSIZE +S+0 +-------------------+ allocation + <- last dummy block
105 *            |  prev_size = S    |            |
106 *       +S+4 +-------------------+------------+
107 *            |  size = page_size          | 0 | <- prev block is free
108 *       +S+8 +--------------------------------+ <- aligned on page_size
109 *            |  unused space due to alignment |
110 *            |       size < page_size         |
111 *            +--------------------------------+ <- end = begin + size
112 *
113 */
114
115uint32_t   _Heap_Initialize(
116  Heap_Control        *the_heap,
117  void                *starting_address,
118  size_t               size,
119  uint32_t             page_size
120)
121{
122  Heap_Block            *the_block;
123  uint32_t               the_size;
124  _H_uptr_t              start;
125  _H_uptr_t              aligned_start;
126  uint32_t               overhead;
127  Heap_Statistics *const stats = &the_heap->stats;
128
129  if (page_size == 0)
130    page_size = CPU_ALIGNMENT;
131  else
132    _Heap_Align_up( &page_size, CPU_ALIGNMENT );
133
134  /* Calculate aligned_start so that aligned_start + HEAP_BLOCK_USER_OFFSET
135     (value of user pointer) is aligned on 'page_size' boundary. Make sure
136     resulting 'aligned_start' is not below 'starting_address'. */
137  start = _H_p2u(starting_address);
138  aligned_start = start + HEAP_BLOCK_USER_OFFSET;
139  _Heap_Align_up_uptr ( &aligned_start, page_size );
140  aligned_start -= HEAP_BLOCK_USER_OFFSET;
141
142  /* Calculate 'min_block_size'. It's HEAP_MIN_BLOCK_SIZE aligned up to the
143     nearest multiple of 'page_size'. */
144  the_heap->min_block_size = HEAP_MIN_BLOCK_SIZE;
145  _Heap_Align_up ( &the_heap->min_block_size, page_size );
146
147  /* Calculate 'the_size' -- size of the first block so that there is enough
148     space at the end for the permanent last block. It is equal to 'size'
149     minus total overhead aligned down to the nearest multiple of
150     'page_size'. */
151  overhead = HEAP_OVERHEAD + (aligned_start - start);
152  if ( size < overhead )
153    return 0;   /* Too small area for the heap */
154  the_size = size - overhead;
155  _Heap_Align_down ( &the_size, page_size );
156  if ( the_size == 0 )
157    return 0;   /* Too small area for the heap */
158
159  the_heap->page_size = page_size;
160  the_heap->begin = starting_address;
161  the_heap->end = starting_address + size;
162
163  the_block = (Heap_Block *) aligned_start;
164
165  the_block->prev_size = page_size;
166  the_block->size = the_size | HEAP_PREV_USED;
167  the_block->next = _Heap_Tail( the_heap );
168  the_block->prev = _Heap_Head( the_heap );
169  _Heap_Head(the_heap)->next = the_block;
170  _Heap_Tail(the_heap)->prev = the_block;
171  the_heap->start = the_block;
172
173  _HAssert(_Heap_Is_aligned(the_heap->page_size, CPU_ALIGNMENT));
174  _HAssert(_Heap_Is_aligned(the_heap->min_block_size, page_size));
175  _HAssert(_Heap_Is_aligned_ptr(_Heap_User_area(the_block), page_size));
176
177  the_block = _Heap_Block_at( the_block, the_size );
178  the_heap->final = the_block;       /* Permanent final block of the heap */
179  the_block->prev_size = the_size;   /* Previous block is free */
180  the_block->size = page_size;
181
182  stats->size = size;
183  stats->free_size = the_size;
184  stats->min_free_size = the_size;
185  stats->free_blocks = 1;
186  stats->max_free_blocks = 1;
187  stats->used_blocks = 0;
188  stats->max_search = 0;
189  stats->allocs = 0;
190  stats->searches = 0;
191  stats->frees = 0;
192  stats->resizes = 0;
193  stats->instance = instance++;
194
195  return ( the_size - HEAP_BLOCK_USED_OVERHEAD );
196}
197
198/*PAGE
199 *
200 * Internal routines shared by _Heap_Allocate() and _Heap_Allocate_aligned().
201 *
202 * Note: there is no reason to put them into a separate file(s) as they are
203 * always required for heap to be useful.
204 */
205
206/*
207 * Convert user requested 'size' of memory block to the block size.
208 * Return block size on success, 0 if overflow occured
209 */
210size_t _Heap_Calc_block_size(
211  size_t   size,
212  uint32_t page_size,
213  uint32_t min_size)
214{
215  uint32_t block_size = size + HEAP_BLOCK_USED_OVERHEAD;
216  _Heap_Align_up(&block_size, page_size);
217  if (block_size < min_size) block_size = min_size;
218  /* 'block_size' becomes <= 'size' if and only if overflow occured. */
219  return (block_size > size) ? block_size : 0;
220}
221
222/*
223 * Allocate block of size 'alloc_size' from 'the_block' belonging to
224 * 'the_heap'. Split 'the_block' if possible, otherwise allocate it entirely.
225 * When split, make the lower part used, and leave the upper part free.
226 * Return the size of allocated block.
227 */
228uint32_t _Heap_Block_allocate(
229  Heap_Control* the_heap,
230  Heap_Block*   the_block,
231  uint32_t      alloc_size
232)
233{
234  Heap_Statistics *const stats = &the_heap->stats;
235  uint32_t const block_size = _Heap_Block_size(the_block);
236  uint32_t const the_rest = block_size - alloc_size;
237
238  _HAssert(_Heap_Is_aligned(block_size, the_heap->page_size));
239  _HAssert(_Heap_Is_aligned(alloc_size, the_heap->page_size));
240  _HAssert(alloc_size <= block_size);
241  _HAssert(_Heap_Is_prev_used(the_block));
242
243  if(the_rest >= the_heap->min_block_size) {
244    /* Split the block so that upper part is still free, and lower part
245       becomes used. This is slightly less optimal than leaving lower part
246       free as it requires replacing block in the free blocks list, but it
247       makes it possible to reuse this code in the _Heap_Resize_block(). */
248    Heap_Block *next_block = _Heap_Block_at(the_block, alloc_size);
249    _Heap_Block_replace(the_block, next_block);
250    the_block->size = alloc_size | HEAP_PREV_USED;
251    next_block->size = the_rest | HEAP_PREV_USED;
252    _Heap_Block_at(next_block, the_rest)->prev_size = the_rest;
253  }
254  else {
255    /* Don't split the block as remainder is either zero or too small to be
256       used as a separate free block. Change 'alloc_size' to the size of the
257       block and remove the block from the list of free blocks. */
258    _Heap_Block_remove(the_block);
259    alloc_size = block_size;
260    _Heap_Block_at(the_block, alloc_size)->size |= HEAP_PREV_USED;
261    stats->free_blocks -= 1;
262  }
263  /* Update statistics */
264  stats->free_size -= alloc_size;
265  if(stats->min_free_size > stats->free_size)
266    stats->min_free_size = stats->free_size;
267  stats->used_blocks += 1;
268  return alloc_size;
269}
Note: See TracBrowser for help on using the repository browser.