[f2f63d1] | 1 | /** |
---|
| 2 | * @file |
---|
[ac7d5ef0] | 3 | * |
---|
[f2f63d1] | 4 | * @brief Workspace Handler Support |
---|
| 5 | * @ingroup ScoreWorkspace |
---|
| 6 | */ |
---|
| 7 | |
---|
| 8 | /* |
---|
[e63b79d] | 9 | * COPYRIGHT (c) 1989-2009. |
---|
[ac7d5ef0] | 10 | * On-Line Applications Research Corporation (OAR). |
---|
| 11 | * |
---|
[98e4ebf5] | 12 | * The license and distribution terms for this file may be |
---|
| 13 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 14 | * http://www.rtems.org/license/LICENSE. |
---|
[ac7d5ef0] | 15 | */ |
---|
| 16 | |
---|
[a8eed23] | 17 | #if HAVE_CONFIG_H |
---|
[e6f7f81] | 18 | #include "config.h" |
---|
[a8eed23] | 19 | #endif |
---|
| 20 | |
---|
[5e9b32b] | 21 | #include <rtems/score/wkspace.h> |
---|
[cfc4231d] | 22 | #include <rtems/score/assert.h> |
---|
[e6f7f81] | 23 | #include <rtems/score/heapimpl.h> |
---|
[5e9b32b] | 24 | #include <rtems/score/interr.h> |
---|
[cfc4231d] | 25 | #include <rtems/score/percpudata.h> |
---|
[022851a] | 26 | #include <rtems/score/threadimpl.h> |
---|
| 27 | #include <rtems/score/tls.h> |
---|
[e97806a] | 28 | #include <rtems/posix/pthread.h> |
---|
[e6f7f81] | 29 | #include <rtems/config.h> |
---|
[976162a6] | 30 | |
---|
[cfc4231d] | 31 | #include <string.h> |
---|
[ac7d5ef0] | 32 | |
---|
[e63b79d] | 33 | /* #define DEBUG_WORKSPACE */ |
---|
| 34 | #if defined(DEBUG_WORKSPACE) |
---|
| 35 | #include <rtems/bspIo.h> |
---|
| 36 | #endif |
---|
| 37 | |
---|
[cfc4231d] | 38 | RTEMS_LINKER_RWSET( |
---|
| 39 | _Per_CPU_Data, |
---|
| 40 | RTEMS_ALIGNED( CPU_CACHE_LINE_BYTES ) char |
---|
| 41 | ); |
---|
| 42 | |
---|
[358bd740] | 43 | Heap_Control _Workspace_Area; |
---|
| 44 | |
---|
[cfc4231d] | 45 | static uint32_t _Workspace_Get_maximum_thread_count( void ) |
---|
[022851a] | 46 | { |
---|
[cfc4231d] | 47 | uint32_t thread_count; |
---|
[022851a] | 48 | |
---|
[cfc4231d] | 49 | thread_count = 0; |
---|
[022851a] | 50 | thread_count += _Thread_Get_maximum_internal_threads(); |
---|
| 51 | |
---|
| 52 | thread_count += rtems_resource_maximum_per_allocation( |
---|
| 53 | Configuration_RTEMS_API.maximum_tasks |
---|
| 54 | ); |
---|
| 55 | |
---|
| 56 | #if defined(RTEMS_POSIX_API) |
---|
| 57 | thread_count += rtems_resource_maximum_per_allocation( |
---|
[e97806a] | 58 | _Configuration_POSIX_Maximum_threads |
---|
[022851a] | 59 | ); |
---|
| 60 | #endif |
---|
| 61 | |
---|
| 62 | return thread_count; |
---|
| 63 | } |
---|
| 64 | |
---|
[cfc4231d] | 65 | static uintptr_t _Workspace_Space_for_TLS( uintptr_t page_size ) |
---|
[8faca06] | 66 | { |
---|
[cfc4231d] | 67 | uintptr_t tls_size; |
---|
| 68 | uintptr_t space; |
---|
| 69 | |
---|
| 70 | tls_size = _TLS_Get_size(); |
---|
[47a3cd8] | 71 | |
---|
[884a6c59] | 72 | /* |
---|
| 73 | * In case we have a non-zero TLS size, then we need a TLS area for each |
---|
| 74 | * thread. These areas are allocated from the workspace. Ensure that the |
---|
| 75 | * workspace is large enough to fulfill all requests known at configuration |
---|
| 76 | * time (so excluding the unlimited option). It is not possible to estimate |
---|
| 77 | * the TLS size in the configuration at compile-time. The TLS size is |
---|
| 78 | * determined at application link-time. |
---|
| 79 | */ |
---|
[022851a] | 80 | if ( tls_size > 0 ) { |
---|
[6cf45cb] | 81 | uintptr_t tls_align = _TLS_Heap_align_up( (uintptr_t) _TLS_Alignment ); |
---|
| 82 | uintptr_t tls_alloc = _TLS_Get_allocation_size( tls_size, tls_align ); |
---|
| 83 | |
---|
| 84 | /* |
---|
| 85 | * Memory allocated with an alignment constraint is allocated from the end |
---|
| 86 | * of a free block. The last allocation may need one free block of minimum |
---|
| 87 | * size. |
---|
| 88 | */ |
---|
[cfc4231d] | 89 | space = _Heap_Min_block_size( page_size ); |
---|
[022851a] | 90 | |
---|
[cfc4231d] | 91 | space += _Workspace_Get_maximum_thread_count() |
---|
[6cf45cb] | 92 | * _Heap_Size_with_overhead( page_size, tls_alloc, tls_align ); |
---|
[cfc4231d] | 93 | } else { |
---|
| 94 | space = 0; |
---|
| 95 | } |
---|
| 96 | |
---|
| 97 | return space; |
---|
| 98 | } |
---|
| 99 | |
---|
| 100 | static uintptr_t _Workspace_Space_for_per_CPU_data( uintptr_t page_size ) |
---|
| 101 | { |
---|
| 102 | uintptr_t space; |
---|
| 103 | |
---|
| 104 | #ifdef RTEMS_SMP |
---|
| 105 | uintptr_t size; |
---|
| 106 | |
---|
| 107 | size = RTEMS_LINKER_SET_SIZE( _Per_CPU_Data ); |
---|
| 108 | _Assert( size % CPU_CACHE_LINE_BYTES == 0 ); |
---|
| 109 | |
---|
| 110 | if ( size > 0 ) { |
---|
| 111 | /* |
---|
| 112 | * Memory allocated with an alignment constraint is allocated from the end of |
---|
| 113 | * a free block. The last allocation may need one free block of minimum |
---|
| 114 | * size. |
---|
| 115 | */ |
---|
| 116 | space = _Heap_Min_block_size( page_size ); |
---|
| 117 | |
---|
| 118 | space += ( rtems_configuration_get_maximum_processors() - 1 ) |
---|
| 119 | * _Heap_Size_with_overhead( page_size, size, CPU_CACHE_LINE_BYTES ); |
---|
| 120 | } else { |
---|
| 121 | space = 0; |
---|
[022851a] | 122 | } |
---|
[cfc4231d] | 123 | #else |
---|
| 124 | space = 0; |
---|
| 125 | #endif |
---|
| 126 | |
---|
| 127 | return space; |
---|
| 128 | } |
---|
| 129 | |
---|
| 130 | static void _Workspace_Allocate_per_CPU_data( void ) |
---|
| 131 | { |
---|
| 132 | #ifdef RTEMS_SMP |
---|
[776464a] | 133 | uintptr_t size; |
---|
[cfc4231d] | 134 | |
---|
| 135 | size = RTEMS_LINKER_SET_SIZE( _Per_CPU_Data ); |
---|
| 136 | |
---|
[776464a] | 137 | if ( size > 0 ) { |
---|
| 138 | Per_CPU_Control *cpu; |
---|
| 139 | uint32_t cpu_index; |
---|
| 140 | uint32_t cpu_max; |
---|
| 141 | |
---|
| 142 | cpu = _Per_CPU_Get_by_index( 0 ); |
---|
| 143 | cpu->data = RTEMS_LINKER_SET_BEGIN( _Per_CPU_Data ); |
---|
| 144 | |
---|
| 145 | cpu_max = rtems_configuration_get_maximum_processors(); |
---|
| 146 | |
---|
| 147 | for ( cpu_index = 1 ; cpu_index < cpu_max ; ++cpu_index ) { |
---|
| 148 | cpu = _Per_CPU_Get_by_index( cpu_index ); |
---|
| 149 | cpu->data = _Workspace_Allocate_aligned( size, CPU_CACHE_LINE_BYTES ); |
---|
| 150 | _Assert( cpu->data != NULL ); |
---|
| 151 | memcpy( cpu->data, RTEMS_LINKER_SET_BEGIN( _Per_CPU_Data ), size); |
---|
| 152 | } |
---|
[cfc4231d] | 153 | } |
---|
| 154 | #endif |
---|
| 155 | } |
---|
| 156 | |
---|
| 157 | void _Workspace_Handler_initialization( |
---|
| 158 | Heap_Area *areas, |
---|
| 159 | size_t area_count, |
---|
| 160 | Heap_Initialization_or_extend_handler extend |
---|
| 161 | ) |
---|
| 162 | { |
---|
| 163 | Heap_Initialization_or_extend_handler init_or_extend; |
---|
| 164 | uintptr_t remaining; |
---|
| 165 | bool do_zero; |
---|
| 166 | bool unified; |
---|
| 167 | uintptr_t page_size; |
---|
| 168 | uintptr_t overhead; |
---|
| 169 | size_t i; |
---|
| 170 | |
---|
| 171 | page_size = CPU_HEAP_ALIGNMENT; |
---|
| 172 | |
---|
| 173 | remaining = rtems_configuration_get_work_space_size(); |
---|
| 174 | remaining += _Workspace_Space_for_TLS( page_size ); |
---|
| 175 | remaining += _Workspace_Space_for_per_CPU_data( page_size ); |
---|
| 176 | |
---|
| 177 | init_or_extend = _Heap_Initialize; |
---|
| 178 | do_zero = rtems_configuration_get_do_zero_of_workspace(); |
---|
| 179 | unified = rtems_configuration_get_unified_work_area(); |
---|
| 180 | overhead = _Heap_Area_overhead( page_size ); |
---|
| 181 | |
---|
| 182 | for ( i = 0; i < area_count; ++i ) { |
---|
| 183 | Heap_Area *area; |
---|
[022851a] | 184 | |
---|
[cfc4231d] | 185 | area = &areas[ i ]; |
---|
[47a3cd8] | 186 | |
---|
| 187 | if ( do_zero ) { |
---|
| 188 | memset( area->begin, 0, area->size ); |
---|
| 189 | } |
---|
| 190 | |
---|
| 191 | if ( area->size > overhead ) { |
---|
| 192 | uintptr_t space_available; |
---|
| 193 | uintptr_t size; |
---|
| 194 | |
---|
| 195 | if ( unified ) { |
---|
| 196 | size = area->size; |
---|
| 197 | } else { |
---|
| 198 | if ( remaining > 0 ) { |
---|
| 199 | size = remaining < area->size - overhead ? |
---|
| 200 | remaining + overhead : area->size; |
---|
| 201 | } else { |
---|
| 202 | size = 0; |
---|
| 203 | } |
---|
| 204 | } |
---|
| 205 | |
---|
[cfc4231d] | 206 | space_available = ( *init_or_extend )( |
---|
[47a3cd8] | 207 | &_Workspace_Area, |
---|
| 208 | area->begin, |
---|
| 209 | size, |
---|
| 210 | page_size |
---|
| 211 | ); |
---|
| 212 | |
---|
| 213 | area->begin = (char *) area->begin + size; |
---|
| 214 | area->size -= size; |
---|
[05279b84] | 215 | |
---|
[47a3cd8] | 216 | if ( space_available < remaining ) { |
---|
| 217 | remaining -= space_available; |
---|
| 218 | } else { |
---|
| 219 | remaining = 0; |
---|
| 220 | } |
---|
[05279b84] | 221 | |
---|
[47a3cd8] | 222 | init_or_extend = extend; |
---|
| 223 | } |
---|
| 224 | } |
---|
[05279b84] | 225 | |
---|
[47a3cd8] | 226 | if ( remaining > 0 ) { |
---|
[3a659b04] | 227 | _Internal_error( INTERNAL_ERROR_TOO_LITTLE_WORKSPACE ); |
---|
[47a3cd8] | 228 | } |
---|
[2a713e3] | 229 | |
---|
| 230 | _Heap_Protection_set_delayed_free_fraction( &_Workspace_Area, 1 ); |
---|
[cfc4231d] | 231 | _Workspace_Allocate_per_CPU_data(); |
---|
[8faca06] | 232 | } |
---|
| 233 | |
---|
[5b33dc80] | 234 | void *_Workspace_Allocate( |
---|
[7ff6115] | 235 | size_t size |
---|
[5b33dc80] | 236 | ) |
---|
| 237 | { |
---|
[a2fa532d] | 238 | void *memory; |
---|
[e63b79d] | 239 | |
---|
[a2fa532d] | 240 | memory = _Heap_Allocate( &_Workspace_Area, size ); |
---|
[e63b79d] | 241 | #if defined(DEBUG_WORKSPACE) |
---|
| 242 | printk( |
---|
| 243 | "Workspace_Allocate(%d) from %p/%p -> %p\n", |
---|
| 244 | size, |
---|
| 245 | __builtin_return_address( 0 ), |
---|
| 246 | __builtin_return_address( 1 ), |
---|
[a2fa532d] | 247 | memory |
---|
[e63b79d] | 248 | ); |
---|
| 249 | #endif |
---|
[a2fa532d] | 250 | return memory; |
---|
[5b33dc80] | 251 | } |
---|
[ac7d5ef0] | 252 | |
---|
[a850d04] | 253 | void *_Workspace_Allocate_aligned( size_t size, size_t alignment ) |
---|
| 254 | { |
---|
| 255 | return _Heap_Allocate_aligned( &_Workspace_Area, size, alignment ); |
---|
| 256 | } |
---|
| 257 | |
---|
[5b33dc80] | 258 | /* |
---|
[9d4fa67] | 259 | * _Workspace_Free |
---|
[5b33dc80] | 260 | */ |
---|
[a0323a9f] | 261 | void _Workspace_Free( |
---|
[5b33dc80] | 262 | void *block |
---|
| 263 | ) |
---|
| 264 | { |
---|
[e63b79d] | 265 | #if defined(DEBUG_WORKSPACE) |
---|
| 266 | printk( |
---|
| 267 | "Workspace_Free(%p) from %p/%p\n", |
---|
| 268 | block, |
---|
| 269 | __builtin_return_address( 0 ), |
---|
| 270 | __builtin_return_address( 1 ) |
---|
| 271 | ); |
---|
| 272 | #endif |
---|
[8249054] | 273 | _Heap_Free( &_Workspace_Area, block ); |
---|
[5b33dc80] | 274 | } |
---|
| 275 | |
---|
[ac7d5ef0] | 276 | void *_Workspace_Allocate_or_fatal_error( |
---|
[7ff6115] | 277 | size_t size |
---|
[ac7d5ef0] | 278 | ) |
---|
| 279 | { |
---|
[a2fa532d] | 280 | void *memory; |
---|
[ac7d5ef0] | 281 | |
---|
[a2fa532d] | 282 | memory = _Heap_Allocate( &_Workspace_Area, size ); |
---|
| 283 | #if defined(DEBUG_WORKSPACE) |
---|
| 284 | printk( |
---|
| 285 | "Workspace_Allocate_or_fatal_error(%d) from %p/%p -> %p\n", |
---|
| 286 | size, |
---|
| 287 | __builtin_return_address( 0 ), |
---|
| 288 | __builtin_return_address( 1 ), |
---|
| 289 | memory |
---|
| 290 | ); |
---|
| 291 | #endif |
---|
[ac7d5ef0] | 292 | |
---|
| 293 | if ( memory == NULL ) |
---|
[3a659b04] | 294 | _Internal_error( INTERNAL_ERROR_WORKSPACE_ALLOCATION ); |
---|
[ac7d5ef0] | 295 | |
---|
| 296 | return memory; |
---|
| 297 | } |
---|