blob: 0e0329f4e633c0246c04a8d1e4cee95979013552 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/*
* Heap Handler
*
* COPYRIGHT (c) 1989-1999.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
* $Id$
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Extend
*
* This routine grows the_heap memory area using the size bytes which
* begin at starting_address.
*
* Input parameters:
* the_heap - pointer to heap header.
* starting_address - pointer to the memory area.
* size - size in bytes of the memory block to allocate.
*
* Output parameters:
* *amount_extended - amount of memory added to the_heap
*/
Heap_Extend_status _Heap_Extend(
Heap_Control *the_heap,
void *starting_address,
ssize_t size,
uint32_t *amount_extended
)
{
uint32_t the_size;
Heap_Statistics *const stats = &the_heap->stats;
/*
* The overhead was taken from the original heap memory.
*/
Heap_Block *old_final;
Heap_Block *new_final;
/*
* There are five possibilities for the location of starting
* address:
*
* 1. non-contiguous lower address (NOT SUPPORTED)
* 2. contiguous lower address (NOT SUPPORTED)
* 3. in the heap (ERROR)
* 4. contiguous higher address (SUPPORTED)
* 5. non-contiguous higher address (NOT SUPPORTED)
*
* As noted, this code only supports (4).
*/
if ( starting_address >= the_heap->begin && /* case 3 */
starting_address < the_heap->end
)
return HEAP_EXTEND_ERROR;
if ( starting_address != the_heap->end )
return HEAP_EXTEND_NOT_IMPLEMENTED; /* cases 1, 2, and 5 */
/*
* Currently only case 4 should make it to this point.
* The basic trick is to make the extend area look like a used
* block and free it.
*/
old_final = the_heap->final;
the_heap->end = _Addresses_Add_offset( the_heap->end, size );
the_size = _Addresses_Subtract( the_heap->end, old_final ) - HEAP_OVERHEAD;
_Heap_Align_down( &the_size, the_heap->page_size );
*amount_extended = size;
if( the_size < the_heap->min_block_size )
return HEAP_EXTEND_SUCCESSFUL;
old_final->size = the_size | (old_final->size & HEAP_PREV_USED);
new_final = _Heap_Block_at( old_final, the_size );
new_final->size = HEAP_PREV_USED;
the_heap->final = new_final;
stats->size += size;
stats->used_blocks += 1;
stats->frees -= 1; /* Don't count subsequent call as actual free() */
_Heap_Free( the_heap, _Heap_User_area( old_final ) );
return HEAP_EXTEND_SUCCESSFUL;
}
|