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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
/*
* 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$
*/
#include <rtems/system.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/heap.h>
/*PAGE
*
* _Heap_Free
*
* This kernel routine returns the memory designated by the
* given heap and given starting address to the memory pool.
*
* Input parameters:
* the_heap - pointer to heap header
* starting_address - starting address of the memory block to free.
*
* Output parameters:
* TRUE - if starting_address is valid heap address
* FALSE - if starting_address is invalid heap address
*/
boolean _Heap_Free(
Heap_Control *the_heap,
void *starting_address
)
{
Heap_Block *the_block;
Heap_Block *next_block;
uint32_t the_size;
uint32_t next_size;
Heap_Statistics *const stats = &the_heap->stats;
boolean next_is_free;
_Heap_Start_of_block( the_heap, starting_address, &the_block );
if ( !_Heap_Is_block_in( the_heap, the_block ) ) {
_HAssert(starting_address == NULL);
return( FALSE );
}
the_size = _Heap_Block_size( the_block );
next_block = _Heap_Block_at( the_block, the_size );
if ( !_Heap_Is_prev_used( next_block ) ) {
_HAssert(FALSE);
return( FALSE );
}
if ( !_Heap_Is_block_in( the_heap, next_block ) ) {
_HAssert(FALSE);
return( FALSE );
}
next_size = _Heap_Block_size( next_block );
next_is_free = next_block < the_heap->final &&
!_Heap_Is_prev_used(_Heap_Block_at(next_block, next_size));
if ( !_Heap_Is_prev_used( the_block ) ) {
uint32_t const prev_size = the_block->prev_size;
Heap_Block *const prev_block = _Heap_Block_at( the_block, -prev_size );
if ( !_Heap_Is_block_in( the_heap, prev_block ) ) {
_HAssert(FALSE);
return( FALSE );
}
/* As we always coalesce free blocks, the block that preceedes prev_block
must have been used. */
if ( !_Heap_Is_prev_used ( prev_block) ) {
_HAssert(FALSE);
return( FALSE );
}
if ( next_is_free ) { /* coalesce both */
uint32_t const size = the_size + prev_size + next_size;
_Heap_Block_remove( next_block );
stats->free_blocks -= 1;
prev_block->size = size | HEAP_PREV_USED;
next_block = _Heap_Block_at( prev_block, size );
_HAssert(!_Heap_Is_prev_used( next_block));
next_block->prev_size = size;
}
else { /* coalesce prev */
uint32_t const size = the_size + prev_size;
prev_block->size = size | HEAP_PREV_USED;
next_block->size &= ~HEAP_PREV_USED;
next_block->prev_size = size;
}
}
else if ( next_is_free ) { /* coalesce next */
uint32_t const size = the_size + next_size;
_Heap_Block_replace( next_block, the_block );
the_block->size = size | HEAP_PREV_USED;
next_block = _Heap_Block_at( the_block, size );
next_block->prev_size = size;
}
else { /* no coalesce */
/* Add 'the_block' to the head of the free blocks list as it tends to
produce less fragmentation than adding to the tail. */
_Heap_Block_insert_after( _Heap_Head( the_heap), the_block );
the_block->size = the_size | HEAP_PREV_USED;
next_block->size &= ~HEAP_PREV_USED;
next_block->prev_size = the_size;
stats->free_blocks += 1;
if ( stats->max_free_blocks < stats->free_blocks )
stats->max_free_blocks = stats->free_blocks;
}
stats->used_blocks -= 1;
stats->free_size += the_size;
stats->frees += 1;
return( TRUE );
}
|