| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | #if HAVE_CONFIG_H1 |
| 23 | #include "config.h" |
| 24 | #endif |
| 25 | |
| 26 | #include <rtems/system.h> |
| 27 | #include <rtems/score/sysstate.h> |
| 28 | #include <rtems/score/heap.h> |
| 29 | |
| 30 | #ifndef HEAP_PROTECTION |
| 31 | #define _Heap_Protection_free_delayed_blocks( heap, alloc_begin )0 false0 |
| 32 | #else |
| 33 | static bool_Bool _Heap_Protection_free_delayed_blocks(0 |
| 34 | Heap_Control *heap,0 |
| 35 | uintptr_t alloc_begin0 |
| 36 | )0 |
| 37 | { |
| 38 | bool_Bool search_again = false0; |
| 39 | uintptr_t const blocks_to_free_count = |
| 40 | (heap->Protection.delayed_free_block_count + 1) / 2; |
| 41 | |
| 42 | if ( alloc_begin == 0 && blocks_to_free_count > 0 ) { |
| 43 | Heap_Block *block_to_free = heap->Protection.first_delayed_free_block; |
| 44 | uintptr_t count = 0; |
| 45 | |
| 46 | for ( count = 0; count < blocks_to_free_count; ++count ) { |
| 47 | Heap_Block *next_block_to_free = |
| 48 | block_to_free->Protection_begin.next_delayed_free_block; |
| 49 | |
| 50 | block_to_free->Protection_begin.next_delayed_free_block = |
| 51 | HEAP_PROTECTION_OBOLUS; |
| 52 | |
| 53 | _Heap_Free( |
| 54 | heap, |
| 55 | (void *) _Heap_Alloc_area_of_block( block_to_free ) |
| 56 | ); |
| 57 | |
| 58 | block_to_free = next_block_to_free; |
| 59 | } |
| 60 | |
| 61 | heap->Protection.delayed_free_block_count -= blocks_to_free_count; |
| 62 | heap->Protection.first_delayed_free_block = block_to_free; |
| 63 | |
| 64 | search_again = true1; |
| 65 | } |
| 66 | |
| 67 | return search_again; |
| 68 | } |
| 69 | #endif |
| 70 | |
| 71 | #ifdef RTEMS_HEAP_DEBUG |
| 72 | static void _Heap_Check_allocation(((void) 0) |
| 73 | const Heap_Control *heap,((void) 0) |
| 74 | const Heap_Block *block,((void) 0) |
| 75 | uintptr_t alloc_begin,((void) 0) |
| 76 | uintptr_t alloc_size,((void) 0) |
| 77 | uintptr_t alignment,((void) 0) |
| 78 | uintptr_t boundary((void) 0) |
| 79 | )((void) 0) |
| 80 | { |
| 81 | uintptr_t const min_block_size = heap->min_block_size; |
| 82 | uintptr_t const page_size = heap->page_size; |
| 83 | |
| 84 | uintptr_t const block_begin = (uintptr_t) block; |
| 85 | uintptr_t const block_size = _Heap_Block_size( block ); |
| 86 | uintptr_t const block_end = block_begin + block_size; |
| 87 | |
| 88 | uintptr_t const alloc_end = alloc_begin + alloc_size; |
| 89 | |
| 90 | uintptr_t const alloc_area_begin = _Heap_Alloc_area_of_block( block ); |
| 91 | uintptr_t const alloc_area_offset = alloc_begin - alloc_area_begin; |
| 92 | |
| 93 | _HAssert( block_size >= min_block_size )((void) 0); |
| 94 | _HAssert( block_begin < block_end )((void) 0); |
| 95 | _HAssert(((void) 0) |
| 96 | _Heap_Is_aligned( block_begin + HEAP_BLOCK_HEADER_SIZE, page_size )((void) 0) |
| 97 | )((void) 0); |
| 98 | _HAssert(((void) 0) |
| 99 | _Heap_Is_aligned( block_size, page_size )((void) 0) |
| 100 | )((void) 0); |
| 101 | |
| 102 | _HAssert( alloc_end <= block_end + HEAP_ALLOC_BONUS )((void) 0); |
| 103 | _HAssert( alloc_area_begin == block_begin + HEAP_BLOCK_HEADER_SIZE)((void) 0); |
| 104 | _HAssert( alloc_area_offset < page_size )((void) 0); |
| 105 | |
| 106 | _HAssert( _Heap_Is_aligned( alloc_area_begin, page_size ) )((void) 0); |
| 107 | if ( alignment == 0 ) { |
| 108 | _HAssert( alloc_begin == alloc_area_begin )((void) 0); |
| 109 | } else { |
| 110 | _HAssert( _Heap_Is_aligned( alloc_begin, alignment ) )((void) 0); |
| 111 | } |
| 112 | |
| 113 | if ( boundary != 0 ) { |
| 114 | uintptr_t boundary_line = _Heap_Align_down( alloc_end, boundary ); |
| 115 | |
| 116 | _HAssert( alloc_size <= boundary )((void) 0); |
| 117 | _HAssert( boundary_line <= alloc_begin || alloc_end <= boundary_line )((void) 0); |
| 118 | } |
| 119 | } |
| 120 | #else |
| 121 | #define _Heap_Check_allocation( h, b, ab, as, ag, bd )((void) 0) ((void) 0) |
| 122 | #endif |
| 123 | |
| 124 | static uintptr_t _Heap_Check_block( |
| 125 | const Heap_Control *heap, |
| 126 | const Heap_Block *block, |
| 127 | uintptr_t alloc_size, |
| 128 | uintptr_t alignment, |
| 129 | uintptr_t boundary |
| 130 | ) |
| 131 | { |
| 132 | uintptr_t const page_size = heap->page_size; |
| 133 | uintptr_t const min_block_size = heap->min_block_size; |
| 134 | |
| 135 | uintptr_t const block_begin = (uintptr_t) block; |
| 136 | uintptr_t const block_size = _Heap_Block_size( block ); |
| 137 | uintptr_t const block_end = block_begin + block_size; |
| 138 | |
| 139 | uintptr_t const alloc_begin_floor = _Heap_Alloc_area_of_block( block ); |
| 140 | uintptr_t const alloc_begin_ceiling = block_end - min_block_size |
| 141 | + HEAP_BLOCK_HEADER_SIZE(2 * sizeof(uintptr_t) + 0) + page_size - 1; |
| 142 | |
| 143 | uintptr_t alloc_end = block_end + HEAP_ALLOC_BONUSsizeof(uintptr_t); |
| 144 | uintptr_t alloc_begin = alloc_end - alloc_size; |
| 145 | |
| 146 | alloc_begin = _Heap_Align_down( alloc_begin, alignment ); |
| 147 | |
| 148 | |
| 149 | if ( alloc_begin > alloc_begin_ceiling ) { |
| 150 | alloc_begin = _Heap_Align_down( alloc_begin_ceiling, alignment ); |
| 151 | } |
| 152 | |
| 153 | alloc_end = alloc_begin + alloc_size; |
| 154 | |
| 155 | |
| 156 | if ( boundary != 0 ) { |
| 157 | uintptr_t const boundary_floor = alloc_begin_floor + alloc_size; |
| 158 | uintptr_t boundary_line = _Heap_Align_down( alloc_end, boundary ); |
| 159 | |
| 160 | while ( alloc_begin < boundary_line && boundary_line < alloc_end ) { |
| 161 | if ( boundary_line < boundary_floor ) { |
| 162 | return 0; |
| 163 | } |
| 164 | alloc_begin = boundary_line - alloc_size; |
| 165 | alloc_begin = _Heap_Align_down( alloc_begin, alignment ); |
| 166 | alloc_end = alloc_begin + alloc_size; |
| 167 | boundary_line = _Heap_Align_down( alloc_end, boundary ); |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | |
| 172 | if ( alloc_begin >= alloc_begin_floor ) { |
| 173 | uintptr_t const alloc_block_begin = |
| 174 | (uintptr_t) _Heap_Block_of_alloc_area( alloc_begin, page_size ); |
| 175 | uintptr_t const free_size = alloc_block_begin - block_begin; |
| 176 | |
| 177 | if ( free_size >= min_block_size || free_size == 0 ) { |
| 178 | return alloc_begin; |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | return 0; |
| 183 | } |
| 184 | |
| 185 | void *_Heap_Allocate_aligned_with_boundary( |
| 186 | Heap_Control *heap, |
| 187 | uintptr_t alloc_size, |
| 188 | uintptr_t alignment, |
| 189 | uintptr_t boundary |
| 190 | ) |
| 191 | { |
| 192 | Heap_Statistics *const stats = &heap->stats; |
| 193 | uintptr_t const block_size_floor = alloc_size + HEAP_BLOCK_HEADER_SIZE(2 * sizeof(uintptr_t) + 0) |
| 194 | - HEAP_ALLOC_BONUSsizeof(uintptr_t); |
| 195 | uintptr_t const page_size = heap->page_size; |
| 196 | Heap_Block *block = NULL((void*)0); |
| 197 | uintptr_t alloc_begin = 0; |
| 198 | uint32_t search_count = 0; |
| 199 | bool_Bool search_again = false0; |
| 200 | |
| 201 | if ( block_size_floor < alloc_size ) { |
| 202 | |
| 203 | return NULL((void*)0); |
| 204 | } |
| 205 | |
| 206 | if ( boundary != 0 ) { |
| 207 | if ( boundary < alloc_size ) { |
| 208 | return NULL((void*)0); |
| 209 | } |
| 210 | |
| 211 | if ( alignment == 0 ) { |
| 212 | alignment = page_size; |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | do { |
| 217 | Heap_Block *const free_list_tail = _Heap_Free_list_tail( heap ); |
| 218 | |
| 219 | block = _Heap_Free_list_first( heap ); |
| 220 | while ( block != free_list_tail ) { |
| 221 | _HAssert( _Heap_Is_prev_used( block ) )((void) 0); |
| 222 | |
| 223 | _Heap_Protection_block_check( heap, block )((void) 0); |
| 224 | |
| 225 | |
| 226 | |
| 227 | |
| 228 | |
| 229 | |
| 230 | if ( block->size_and_flag > block_size_floor ) { |
| 231 | if ( alignment == 0 ) { |
| 232 | alloc_begin = _Heap_Alloc_area_of_block( block ); |
| 233 | } else { |
| 234 | alloc_begin = _Heap_Check_block( |
| 235 | heap, |
| 236 | block, |
| 237 | alloc_size, |
| 238 | alignment, |
| 239 | boundary |
| 240 | ); |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | |
| 245 | ++search_count; |
| 246 | |
| 247 | if ( alloc_begin != 0 ) { |
| 248 | break; |
| 249 | } |
| 250 | |
| 251 | block = block->next; |
| 252 | } |
| 253 | |
| 254 | search_again = _Heap_Protection_free_delayed_blocks( heap, alloc_begin )0; |
| 255 | } while ( search_again ); |
| 256 | |
| 257 | if ( alloc_begin != 0 ) { |
| 258 | |
| 259 | ++stats->allocs; |
| 260 | stats->searches += search_count; |
| 261 | |
| 262 | block = _Heap_Block_allocate( heap, block, alloc_begin, alloc_size ); |
| Value stored to 'block' is never read |
| 263 | |
| 264 | _Heap_Check_allocation(((void) 0) |
| 265 | heap,((void) 0) |
| 266 | block,((void) 0) |
| 267 | alloc_begin,((void) 0) |
| 268 | alloc_size,((void) 0) |
| 269 | alignment,((void) 0) |
| 270 | boundary((void) 0) |
| 271 | )((void) 0); |
| 272 | } |
| 273 | |
| 274 | |
| 275 | if ( stats->max_search < search_count ) { |
| 276 | stats->max_search = search_count; |
| 277 | } |
| 278 | |
| 279 | return (void *) alloc_begin; |
| 280 | } |