source: rtems/cpukit/score/src/heap.c @ 962e894f

4.104.114.84.95
Last change on this file since 962e894f was 962e894f, checked in by Joel Sherrill <joel.sherrill@…>, on 01/20/05 at 18:22:29

2005-01-20 Sergei Organov <osv@…>

PR 536/rtems
Heap manager re-implementation to consume less memory and still satisfy
alignment requirements.


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