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

4.104.114.84.95
Last change on this file since ac7d5ef0 was ac7d5ef0, checked in by Joel Sherrill <joel.sherrill@…>, on 05/11/95 at 17:39:37

Initial revision

  • Property mode set to 100644
File size: 13.9 KB
Line 
1/*
2 *  Heap Handler
3 *
4 *  COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994.
5 *  On-Line Applications Research Corporation (OAR).
6 *  All rights assigned to U.S. Government, 1994.
7 *
8 *  This material may be reproduced by or for the U.S. Government pursuant
9 *  to the copyright license under the clause at DFARS 252.227-7013.  This
10 *  notice must appear in all copies of this file and its derivatives.
11 *
12 *  $Id$
13 */
14
15
16#include <rtems/system.h>
17#include <rtems/heap.h>
18#include <rtems/sysstate.h>
19
20/*PAGE
21 *
22 *  _Heap_Initialize
23 *
24 *  This kernel routine initializes a heap.
25 *
26 *  Input parameters:
27 *    the_heap         - pointer to heap header
28 *    starting_address - starting address of heap
29 *    size             - size of heap
30 *    page_size        - allocatable unit of memory
31 *
32 *  Output parameters:
33 *    returns - maximum memory available if RTEMS_SUCCESSFUL
34 *    0       - otherwise
35 *
36 *    This is what a heap looks like in memory immediately
37 *    after initialization:
38 *
39 *            +--------------------------------+
40 *     0      |  size = 0      | status = used |  a.k.a.  dummy back flag
41 *            +--------------------------------+
42 *     4      |  size = size-8 | status = free |  a.k.a.  front flag
43 *            +--------------------------------+
44 *     8      |  next     = PERM HEAP_TAIL     |
45 *            +--------------------------------+
46 *    12      |  previous = PERM HEAP_HEAD     |
47 *            +--------------------------------+
48 *            |                                |
49 *            |      memory available          |
50 *            |       for allocation           |
51 *            |                                |
52 *            +--------------------------------+
53 *  size - 8  |  size = size-8 | status = free |  a.k.a.  back flag
54 *            +--------------------------------+
55 *  size - 4  |  size = 0      | status = used |  a.k.a.  dummy front flag
56 *            +--------------------------------+
57 */
58
59unsigned32 _Heap_Initialize(
60  Heap_Control        *the_heap,
61  void                *starting_address,
62  unsigned32           size,
63  unsigned32           page_size
64)
65{
66  Heap_Block        *the_block;
67  unsigned32         the_size;
68
69  if ( !_Heap_Is_page_size_valid( page_size ) ||
70       (size < HEAP_MINIMUM_SIZE) )
71    return 0;
72
73  the_heap->page_size = page_size;
74  the_size = size - HEAP_OVERHEAD;
75
76  the_block             = (Heap_Block *) starting_address;
77  the_block->back_flag  = HEAP_DUMMY_FLAG;
78  the_block->front_flag = the_size;
79  the_block->next       = _Heap_Tail( the_heap );
80  the_block->previous   = _Heap_Head( the_heap );
81
82  the_heap->start          = the_block;
83  the_heap->first          = the_block;
84  the_heap->permanent_null = NULL;
85  the_heap->last           = the_block;
86
87  the_block             = _Heap_Next_block( the_block );
88  the_block->back_flag  = the_size;
89  the_block->front_flag = HEAP_DUMMY_FLAG;
90  the_heap->final       = the_block;
91
92  return ( the_size - HEAP_BLOCK_USED_OVERHEAD );
93}
94
95/*PAGE
96 *
97 *  _Heap_Extend
98 *
99 *  This routine grows the_heap memory area using the size bytes which
100 *  begin at starting_address.
101 *
102 *  Input parameters:
103 *    the_heap          - pointer to heap header.
104 *    starting_address  - pointer to the memory area.
105 *    size              - size in bytes of the memory block to allocate.
106 *
107 *  Output parameters:
108 *    *amount_extended  - amount of memory added to the_heap
109 */
110
111Heap_Extend_status _Heap_Extend(
112  Heap_Control        *the_heap,
113  void                *starting_address,
114  unsigned32           size,
115  unsigned32          *amount_extended
116)
117{
118  Heap_Block        *the_block;
119  Heap_Block        *next_block;
120  Heap_Block        *previous_block;
121
122  /*
123   *  There are five possibilities for the location of starting
124   *  address:
125   *
126   *    1. non-contiguous lower address     (NOT SUPPORTED)
127   *    2. contiguous lower address         (NOT SUPPORTED)
128   *    3. in the heap                      (ERROR)
129   *    4. contiguous higher address        (SUPPORTED)
130   *    5. non-contiguous higher address    (NOT SUPPORTED)
131   *
132   *  As noted, this code only supports (4).
133   */
134
135  if ( starting_address >= (void *) the_heap->start &&        /* case 3 */
136       starting_address <= (void *) the_heap->final
137     )
138    return HEAP_EXTEND_ERROR;
139
140  if ( starting_address < (void *) the_heap->start ) {  /* cases 1 and 2 */
141
142      return HEAP_EXTEND_NOT_IMPLEMENTED;               /* cases 1 and 2 */
143
144  } else {                                              /* cases 4 and 5 */
145
146    the_block  = (Heap_Block *) (starting_address - HEAP_OVERHEAD);
147    if ( the_block != the_heap->final )
148      return HEAP_EXTEND_NOT_IMPLEMENTED;                   /* case 5 */
149  }
150
151  /*
152   *  Currently only case 4 should make it to this point.
153   */
154
155  *amount_extended = size - HEAP_BLOCK_USED_OVERHEAD;
156
157  previous_block = the_heap->last;
158
159  the_block              = (Heap_Block *) starting_address;
160  the_block->front_flag  = size;
161  the_block->next        = previous_block->next;
162  the_block->previous    = previous_block;
163
164  previous_block->next   = the_block;
165  the_heap->last         = the_block;
166
167  next_block             = _Heap_Next_block( the_block );
168  next_block->back_flag  = size;
169  next_block->front_flag = HEAP_DUMMY_FLAG;
170  the_heap->final        = next_block;
171
172  return HEAP_EXTEND_SUCCESSFUL;
173}
174
175/*PAGE
176 *
177 *  _Heap_Allocate
178 *
179 *  This kernel routine allocates the requested size of memory
180 *  from the specified heap.
181 *
182 *  Input parameters:
183 *    the_heap  - pointer to heap header.
184 *    size      - size in bytes of the memory block to allocate.
185 *
186 *  Output parameters:
187 *    returns - starting address of memory block allocated
188 */
189
190void *_Heap_Allocate(
191  Heap_Control        *the_heap,
192  unsigned32           size
193)
194{
195  unsigned32  excess;
196  unsigned32  the_size;
197  Heap_Block *the_block;
198  Heap_Block *next_block;
199  Heap_Block *temporary_block;
200
201  excess   = size % the_heap->page_size;
202  the_size = size + HEAP_BLOCK_USED_OVERHEAD;
203
204  if ( excess )
205    the_size += the_heap->page_size - excess;
206
207  if ( the_size < sizeof( Heap_Block ) )
208    the_size = sizeof( Heap_Block );
209
210  for ( the_block = the_heap->first;
211        ;
212        the_block = the_block->next ) {
213    if ( the_block == _Heap_Tail( the_heap ) )
214      return( NULL );
215    if ( the_block->front_flag >= the_size )
216      break;
217  }
218
219  if ( (the_block->front_flag - the_size) >
220       (the_heap->page_size + HEAP_BLOCK_USED_OVERHEAD) ) {
221    the_block->front_flag -= the_size;
222    next_block             = _Heap_Next_block( the_block );
223    next_block->back_flag  = the_block->front_flag;
224
225    temporary_block            = _Heap_Block_at( next_block, the_size );
226    temporary_block->back_flag =
227    next_block->front_flag     = _Heap_Build_flag( the_size,
228                                    HEAP_BLOCK_USED );
229    return( _Heap_Start_of_user_area( next_block ) );
230  } else {
231    next_block                = _Heap_Next_block( the_block );
232    next_block->back_flag     = _Heap_Build_flag( the_block->front_flag,
233                                   HEAP_BLOCK_USED );
234    the_block->front_flag     = next_block->back_flag;
235    the_block->next->previous = the_block->previous;
236    the_block->previous->next = the_block->next;
237    return( _Heap_Start_of_user_area( the_block ) );
238  }
239}
240
241/*PAGE
242 *
243 *  _Heap_Size_of_user_area
244 *
245 *  This kernel routine returns the size of the memory area
246 *  given heap block.
247 *
248 *  Input parameters:
249 *    the_heap         - pointer to heap header
250 *    starting_address - starting address of the memory block to free.
251 *    size             - pointer to size of area
252 *
253 *  Output parameters:
254 *    size  - size of area filled in
255 *    TRUE  - if starting_address is valid heap address
256 *    FALSE - if starting_address is invalid heap address
257 */
258
259boolean _Heap_Size_of_user_area(
260  Heap_Control        *the_heap,
261  void                *starting_address,
262  unsigned32          *size
263)
264{
265  Heap_Block        *the_block;
266  Heap_Block        *next_block;
267  unsigned32         the_size;
268
269  the_block = _Heap_Block_at( starting_address, - (sizeof( void * ) * 2) );
270
271  if ( !_Heap_Is_block_in( the_heap, the_block ) ||
272        _Heap_Is_block_free( the_block ) )
273    return( FALSE );
274
275  the_size   = _Heap_Block_size( the_block );
276  next_block = _Heap_Block_at( the_block, the_size );
277
278  if ( !_Heap_Is_block_in( the_heap, next_block ) ||
279       (the_block->front_flag != next_block->back_flag) )
280    return( FALSE );
281
282  *size = the_size;
283  return( TRUE );
284}
285
286/*PAGE
287 *
288 *  _Heap_Free
289 *
290 *  This kernel routine returns the memory designated by the
291 *  given heap and given starting address to the memory pool.
292 *
293 *  Input parameters:
294 *    the_heap         - pointer to heap header
295 *    starting_address - starting address of the memory block to free.
296 *
297 *  Output parameters:
298 *    TRUE  - if starting_address is valid heap address
299 *    FALSE - if starting_address is invalid heap address
300 */
301
302boolean _Heap_Free(
303  Heap_Control        *the_heap,
304  void                *starting_address
305)
306{
307  Heap_Block        *the_block;
308  Heap_Block        *next_block;
309  Heap_Block        *new_next_block;
310  Heap_Block        *previous_block;
311  Heap_Block        *temporary_block;
312  unsigned32         the_size;
313
314  the_block = _Heap_Block_at( starting_address, - (sizeof( void * ) * 2) );
315
316  if ( !_Heap_Is_block_in( the_heap, the_block ) ||
317        _Heap_Is_block_free( the_block ) ) {
318      return( FALSE );
319  }
320
321  the_size   = _Heap_Block_size( the_block );
322  next_block = _Heap_Block_at( the_block, the_size );
323
324  if ( !_Heap_Is_block_in( the_heap, next_block ) ||
325       (the_block->front_flag != next_block->back_flag) ) {
326      return( FALSE );
327  }
328
329  if ( _Heap_Is_previous_block_free( the_block ) ) {
330    previous_block = _Heap_Previous_block( the_block );
331
332    if ( !_Heap_Is_block_in( the_heap, previous_block ) ) {
333        return( FALSE );
334    }
335
336    if ( _Heap_Is_block_free( next_block ) ) {      /* coalesce both */
337      previous_block->front_flag += next_block->front_flag + the_size;
338      temporary_block             = _Heap_Next_block( previous_block );
339      temporary_block->back_flag  = previous_block->front_flag;
340      next_block->next->previous  = next_block->previous;
341      next_block->previous->next  = next_block->next;
342    }
343    else {                     /* coalesce prev */
344      previous_block->front_flag =
345      next_block->back_flag      = previous_block->front_flag + the_size;
346    }
347  }
348  else if ( _Heap_Is_block_free( next_block ) ) { /* coalesce next */
349    the_block->front_flag     = the_size + next_block->front_flag;
350    new_next_block            = _Heap_Next_block( the_block );
351    new_next_block->back_flag = the_block->front_flag;
352    the_block->next           = next_block->next;
353    the_block->previous       = next_block->previous;
354    next_block->previous->next = the_block;
355    next_block->next->previous = the_block;
356
357    if (the_heap->first == next_block)
358        the_heap->first = the_block;
359  }
360  else {                          /* no coalesce */
361    next_block->back_flag     =
362    the_block->front_flag     = the_size;
363    the_block->previous       = _Heap_Head( the_heap );
364    the_block->next           = the_heap->first;
365    the_heap->first           = the_block;
366    the_block->next->previous = the_block;
367  }
368
369  return( TRUE );
370}
371
372/*PAGE
373 *
374 *  _Heap_Walk
375 *
376 *  This kernel routine walks the heap and verifies its correctness.
377 *
378 *  Input parameters:
379 *    the_heap  - pointer to heap header
380 *    source    - a numeric indicator of the invoker of this routine
381 *    do_dump   - when TRUE print the information
382 *
383 *  Output parameters: NONE
384 */
385
386#include <stdio.h>
387#include <unistd.h>
388
389void _Heap_Walk(
390  Heap_Control  *the_heap,
391  int            source,
392  boolean        do_dump
393)
394{
395  Heap_Block *the_block;
396  Heap_Block *next_block;
397  int         notdone = 1;
398
399  /*
400   * We don't want to allow walking the heap until we have
401   * transferred control to the user task so we watch the
402   * system state.
403   */
404
405  if ( !_System_state_Is_up( _System_state_Get() ) )
406    return;
407
408  the_block = the_heap->start;
409
410  if (do_dump == TRUE) {
411    printf("\nPASS: %d  start @ 0x%p   final 0x%p,   first 0x%p  last 0x%p\n",
412            source, the_heap->start, the_heap->final,
413                  the_heap->first, the_heap->last
414          );
415  }
416
417  /*
418   * Handle the 1st block
419   */
420
421  if (the_block->back_flag != HEAP_DUMMY_FLAG) {
422    printf("PASS: %d  Back flag of 1st block isn't HEAP_DUMMY_FLAG\n", source);
423  }
424
425  while (notdone) {
426    if (do_dump == TRUE) {
427      printf("PASS: %d  Block @ 0x%p   Back %d,   Front %d",
428              source, the_block,
429              the_block->back_flag, the_block->front_flag);
430      if ( _Heap_Is_block_free(the_block) ) {
431        printf( "      Prev 0x%p,   Next 0x%p\n",
432                          the_block->previous, the_block->next);
433      } else {
434        printf("\n");
435      }
436    }
437
438    /*
439     * Handle the last block
440     */
441
442    if ( the_block->front_flag != HEAP_DUMMY_FLAG ) {
443      next_block = _Heap_Next_block(the_block);
444      if ( the_block->front_flag != next_block->back_flag ) {
445        printf("PASS: %d  Front and back flags don't match\n", source);
446        printf("         Current Block:  Back - %d,  Front - %d",
447               the_block->back_flag, the_block->front_flag);
448        if (do_dump == TRUE) {
449          if (_Heap_Is_block_free(the_block)) {
450            printf("      Prev 0x%p,   Next 0x%p\n",
451                   the_block->previous, the_block->next);
452          } else {
453            printf("\n");
454          }
455        } else {
456          printf("\n");
457        }
458        printf("         Next Block:     Back - %d,  Front - %d",
459               next_block->back_flag, next_block->front_flag);
460        if (do_dump == TRUE) {
461          if (_Heap_Is_block_free(next_block)) {
462            printf("      Prev 0x%p,   Next 0x%p\n",
463                   the_block->previous, the_block->next);
464          } else {
465            printf("\n");
466          }
467        } else {
468          printf("\n");
469        }
470      }
471    }
472
473    if (the_block->front_flag == HEAP_DUMMY_FLAG)
474      notdone = 0;
475    else
476      the_block = next_block;
477  }
478}
Note: See TracBrowser for help on using the repository browser.