[ac7d5ef0] | 1 | /* |
---|
| 2 | * RTEMS Malloc Family Implementation |
---|
| 3 | * |
---|
| 4 | * |
---|
[08311cc3] | 5 | * COPYRIGHT (c) 1989-1999. |
---|
[ac7d5ef0] | 6 | * On-Line Applications Research Corporation (OAR). |
---|
| 7 | * |
---|
[98e4ebf5] | 8 | * The license and distribution terms for this file may be |
---|
| 9 | * found in the file LICENSE in this distribution or at |
---|
[0eae36c7] | 10 | * http://www.rtems.com/license/LICENSE. |
---|
[ac7d5ef0] | 11 | * |
---|
| 12 | * $Id$ |
---|
| 13 | */ |
---|
| 14 | |
---|
[9c49db4] | 15 | #if HAVE_CONFIG_H |
---|
| 16 | #include "config.h" |
---|
| 17 | #endif |
---|
| 18 | |
---|
[1f2d5df] | 19 | #define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ |
---|
[ac7d5ef0] | 20 | #include <rtems.h> |
---|
[3ba74c73] | 21 | #include <rtems/libcsupport.h> |
---|
[e746a88] | 22 | #include <rtems/score/protectedheap.h> |
---|
[ac7d5ef0] | 23 | #ifdef RTEMS_NEWLIB |
---|
| 24 | #include <sys/reent.h> |
---|
| 25 | #endif |
---|
| 26 | |
---|
| 27 | #include <stdio.h> |
---|
| 28 | #include <stdlib.h> |
---|
| 29 | #include <sys/types.h> |
---|
| 30 | #include <assert.h> |
---|
| 31 | #include <errno.h> |
---|
| 32 | #include <string.h> |
---|
[c7ca28cf] | 33 | |
---|
[1f94ed6b] | 34 | #include <unistd.h> /* sbrk(2) */ |
---|
[2751cbe0] | 35 | #include <inttypes.h> |
---|
[ac7d5ef0] | 36 | |
---|
[ebbe119e] | 37 | #include <rtems/chain.h> |
---|
[aab4664d] | 38 | |
---|
[2751cbe0] | 39 | #ifndef HAVE_UINTMAX_T |
---|
| 40 | /* Fall back to unsigned long if uintmax_t is not available */ |
---|
| 41 | #define unsigned long uintmax_t |
---|
| 42 | |
---|
| 43 | #ifndef PRIuMAX |
---|
[7d6701d] | 44 | #define PRIuMAX "lu" |
---|
[2751cbe0] | 45 | #endif |
---|
| 46 | #endif |
---|
| 47 | |
---|
[be31de7] | 48 | #ifdef MALLOC_ARENA_CHECK |
---|
| 49 | #define SENTINELSIZE 12 |
---|
| 50 | #define SENTINEL "\xD1\xAC\xB2\xF1" "BITE ME" |
---|
| 51 | #define CALLCHAINSIZE 5 |
---|
| 52 | struct mallocNode { |
---|
| 53 | struct mallocNode *back; |
---|
| 54 | struct mallocNode *forw; |
---|
| 55 | int callChain[CALLCHAINSIZE]; |
---|
| 56 | size_t size; |
---|
| 57 | void *memory; |
---|
| 58 | }; |
---|
| 59 | static struct mallocNode mallocNodeHead = { &mallocNodeHead, &mallocNodeHead }; |
---|
| 60 | void reportMallocError(const char *msg, struct mallocNode *mp) |
---|
| 61 | { |
---|
| 62 | unsigned char *sp = (unsigned char *)mp->memory + mp->size; |
---|
| 63 | int i, ind = 0; |
---|
| 64 | static char cbuf[500]; |
---|
| 65 | ind += sprintf(cbuf+ind, "Malloc Error: %s\n", msg); |
---|
| 66 | if ((mp->forw->back != mp) || (mp->back->forw != mp)) |
---|
| 67 | ind += sprintf(cbuf+ind, "mp:0x%x mp->forw:0x%x mp->forw->back:0x%x mp->back:0x%x mp->back->forw:0x%x\n", |
---|
| 68 | mp, mp->forw, mp->forw->back, mp->back, mp->back->forw); |
---|
| 69 | if (mp->memory != (mp + 1)) |
---|
| 70 | ind += sprintf(cbuf+ind, "mp+1:0x%x ", mp + 1); |
---|
| 71 | ind += sprintf(cbuf+ind, "mp->memory:0x%x mp->size:%d\n", mp->memory, mp->size); |
---|
| 72 | if (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0) { |
---|
| 73 | ind += sprintf(cbuf+ind, "mp->sentinel: "); |
---|
| 74 | for (i = 0 ; i < SENTINELSIZE ; i++) |
---|
| 75 | ind += sprintf(cbuf+ind, " 0x%x", sp[i]); |
---|
| 76 | ind += sprintf(cbuf+ind, "\n"); |
---|
| 77 | } |
---|
| 78 | ind += sprintf(cbuf+ind, "Call chain:"); |
---|
| 79 | for (i = 0 ; i < CALLCHAINSIZE ; i++) { |
---|
| 80 | if (mp->callChain[i] == 0) |
---|
| 81 | break; |
---|
| 82 | ind += sprintf(cbuf+ind, " 0x%x", mp->callChain[i]); |
---|
| 83 | } |
---|
| 84 | printk("\n\n%s\n\n", cbuf); |
---|
| 85 | } |
---|
| 86 | #endif |
---|
| 87 | |
---|
[e746a88] | 88 | Heap_Control RTEMS_Malloc_Heap; |
---|
[aab4664d] | 89 | Chain_Control RTEMS_Malloc_GC_list; |
---|
| 90 | |
---|
[e746a88] | 91 | /* rtems_id RTEMS_Malloc_Heap; */ |
---|
[11290355] | 92 | size_t RTEMS_Malloc_Sbrk_amount; |
---|
[ac7d5ef0] | 93 | |
---|
[11290355] | 94 | #ifdef RTEMS_DEBUG |
---|
| 95 | #define MALLOC_STATS |
---|
[1f94ed6b] | 96 | #define MALLOC_DIRTY |
---|
[55d7626] | 97 | /*#define MALLOC_ARENA_CHECK |
---|
| 98 | void checkMallocArena(void); */ |
---|
[ac7d5ef0] | 99 | #endif |
---|
| 100 | |
---|
[11290355] | 101 | #ifdef MALLOC_STATS |
---|
[dcec5a4] | 102 | #define MSBUMP(f,n) rtems_malloc_stats.f += (n) |
---|
[11290355] | 103 | |
---|
| 104 | struct { |
---|
[83c5fc1] | 105 | uint32_t space_available; /* current size of malloc area */ |
---|
| 106 | uint32_t malloc_calls; /* # calls to malloc */ |
---|
| 107 | uint32_t free_calls; |
---|
| 108 | uint32_t realloc_calls; |
---|
| 109 | uint32_t calloc_calls; |
---|
| 110 | uint32_t max_depth; /* most ever malloc'd at 1 time */ |
---|
[2751cbe0] | 111 | uintmax_t lifetime_allocated; |
---|
| 112 | uintmax_t lifetime_freed; |
---|
[dcec5a4] | 113 | } rtems_malloc_stats; |
---|
[11290355] | 114 | |
---|
[dcec5a4] | 115 | #else /* No rtems_malloc_stats */ |
---|
[11290355] | 116 | #define MSBUMP(f,n) |
---|
| 117 | #endif |
---|
[ac7d5ef0] | 118 | |
---|
| 119 | void RTEMS_Malloc_Initialize( |
---|
| 120 | void *start, |
---|
| 121 | size_t length, |
---|
| 122 | size_t sbrk_amount |
---|
| 123 | ) |
---|
| 124 | { |
---|
[e746a88] | 125 | uint32_t status; |
---|
| 126 | void *starting_address; |
---|
| 127 | uintptr_t old_address; |
---|
| 128 | uintptr_t uaddress; |
---|
[ac7d5ef0] | 129 | |
---|
[aab4664d] | 130 | /* |
---|
| 131 | * Initialize the garbage collection list to start with nothing on it. |
---|
| 132 | */ |
---|
| 133 | Chain_Initialize_empty(&RTEMS_Malloc_GC_list); |
---|
| 134 | |
---|
[ac7d5ef0] | 135 | /* |
---|
| 136 | * If the starting address is 0 then we are to attempt to |
---|
| 137 | * get length worth of memory using sbrk. Make sure we |
---|
| 138 | * align the address that we get back. |
---|
| 139 | */ |
---|
| 140 | |
---|
| 141 | starting_address = start; |
---|
[e8512eb] | 142 | RTEMS_Malloc_Sbrk_amount = sbrk_amount; |
---|
[ac7d5ef0] | 143 | |
---|
| 144 | if (!starting_address) { |
---|
[b3ee778e] | 145 | uaddress = (uintptr_t)sbrk(length); |
---|
[ac7d5ef0] | 146 | |
---|
[b3ee778e] | 147 | if (uaddress == (uintptr_t) -1) { |
---|
[ac7d5ef0] | 148 | rtems_fatal_error_occurred( RTEMS_NO_MEMORY ); |
---|
| 149 | /* DOES NOT RETURN!!! */ |
---|
| 150 | } |
---|
| 151 | |
---|
[b3ee778e] | 152 | if (uaddress & (CPU_HEAP_ALIGNMENT-1)) { |
---|
| 153 | old_address = uaddress; |
---|
| 154 | uaddress = (uaddress + CPU_HEAP_ALIGNMENT) & ~(CPU_HEAP_ALIGNMENT-1); |
---|
[4cc631db] | 155 | |
---|
[11290355] | 156 | /* |
---|
| 157 | * adjust the length by whatever we aligned by |
---|
| 158 | */ |
---|
[4cc631db] | 159 | |
---|
[b3ee778e] | 160 | length -= uaddress - old_address; |
---|
[ac7d5ef0] | 161 | } |
---|
| 162 | |
---|
[b3ee778e] | 163 | starting_address = (void *)uaddress; |
---|
[ac7d5ef0] | 164 | } |
---|
| 165 | |
---|
[3b93a2de] | 166 | /* |
---|
| 167 | * If the BSP is not clearing out the workspace, then it is most likely |
---|
[50f32b11] | 168 | * not clearing out the initial memory for the heap. There is no |
---|
[3b93a2de] | 169 | * standard supporting zeroing out the heap memory. But much code |
---|
| 170 | * with UNIX history seems to assume that memory malloc'ed during |
---|
| 171 | * initialization (before any free's) is zero'ed. This is true most |
---|
| 172 | * of the time under UNIX because zero'ing memory when it is first |
---|
| 173 | * given to a process eliminates the chance of a process seeing data |
---|
| 174 | * left over from another process. This would be a security violation. |
---|
| 175 | */ |
---|
| 176 | |
---|
[458bd34] | 177 | if ( rtems_cpu_configuration_get_do_zero_of_workspace() ) |
---|
[3b93a2de] | 178 | memset( starting_address, 0, length ); |
---|
| 179 | |
---|
[ac7d5ef0] | 180 | /* |
---|
| 181 | * Unfortunately we cannot use assert if this fails because if this |
---|
| 182 | * has failed we do not have a heap and if we do not have a heap |
---|
| 183 | * STDIO cannot work because there will be no buffers. |
---|
| 184 | */ |
---|
| 185 | |
---|
[e746a88] | 186 | status = _Protected_heap_Initialize( |
---|
| 187 | &RTEMS_Malloc_Heap, |
---|
[ac7d5ef0] | 188 | starting_address, |
---|
| 189 | length, |
---|
[e746a88] | 190 | CPU_HEAP_ALIGNMENT |
---|
[ac7d5ef0] | 191 | ); |
---|
[e746a88] | 192 | if ( !status ) |
---|
[ac7d5ef0] | 193 | rtems_fatal_error_occurred( status ); |
---|
[11290355] | 194 | |
---|
| 195 | #ifdef MALLOC_STATS |
---|
| 196 | /* zero all the stats */ |
---|
[07a3253d] | 197 | (void) memset( &rtems_malloc_stats, 0, sizeof(rtems_malloc_stats) ); |
---|
[11290355] | 198 | #endif |
---|
[50f32b11] | 199 | |
---|
[11290355] | 200 | MSBUMP(space_available, length); |
---|
[ac7d5ef0] | 201 | } |
---|
| 202 | |
---|
[1f2d5df] | 203 | #ifdef RTEMS_NEWLIB |
---|
[ac7d5ef0] | 204 | void *malloc( |
---|
| 205 | size_t size |
---|
| 206 | ) |
---|
| 207 | { |
---|
[e746a88] | 208 | void *return_this; |
---|
| 209 | void *starting_address; |
---|
[83c5fc1] | 210 | uint32_t the_size; |
---|
| 211 | uint32_t sbrk_amount; |
---|
[e746a88] | 212 | Chain_Node *to_be_freed; |
---|
[ac7d5ef0] | 213 | |
---|
[11290355] | 214 | MSBUMP(malloc_calls, 1); |
---|
| 215 | |
---|
[ac7d5ef0] | 216 | if ( !size ) |
---|
| 217 | return (void *) 0; |
---|
| 218 | |
---|
[aab4664d] | 219 | /* |
---|
| 220 | * Do not attempt to allocate memory if in a critical section or ISR. |
---|
| 221 | */ |
---|
| 222 | |
---|
[690861c] | 223 | if (_System_state_Is_up(_System_state_Get())) { |
---|
| 224 | if (_Thread_Dispatch_disable_level > 0) |
---|
| 225 | return (void *) 0; |
---|
[50f32b11] | 226 | |
---|
[690861c] | 227 | if (_ISR_Nest_level > 0) |
---|
| 228 | return (void *) 0; |
---|
| 229 | } |
---|
[50f32b11] | 230 | |
---|
[aab4664d] | 231 | /* |
---|
| 232 | * If some free's have been deferred, then do them now. |
---|
| 233 | */ |
---|
| 234 | while ((to_be_freed = Chain_Get(&RTEMS_Malloc_GC_list)) != NULL) |
---|
| 235 | free(to_be_freed); |
---|
| 236 | |
---|
[ac7d5ef0] | 237 | /* |
---|
[e746a88] | 238 | * Try to give a segment in the current heap if there is not |
---|
| 239 | * enough space then try to grow the heap. |
---|
[ac7d5ef0] | 240 | * If this fails then return a NULL pointer. |
---|
| 241 | */ |
---|
| 242 | |
---|
[be31de7] | 243 | #ifdef MALLOC_ARENA_CHECK |
---|
| 244 | size += sizeof(struct mallocNode) + SENTINELSIZE; |
---|
| 245 | #endif |
---|
[e746a88] | 246 | return_this = _Protected_heap_Allocate( &RTEMS_Malloc_Heap, size ); |
---|
[ac7d5ef0] | 247 | |
---|
[e746a88] | 248 | if ( !return_this ) { |
---|
[ac7d5ef0] | 249 | /* |
---|
| 250 | * Round to the "requested sbrk amount" so hopefully we won't have |
---|
| 251 | * to grow again for a while. This effectively does sbrk() calls |
---|
| 252 | * in "page" amounts. |
---|
| 253 | */ |
---|
| 254 | |
---|
| 255 | sbrk_amount = RTEMS_Malloc_Sbrk_amount; |
---|
| 256 | |
---|
| 257 | if ( sbrk_amount == 0 ) |
---|
| 258 | return (void *) 0; |
---|
| 259 | |
---|
| 260 | the_size = ((size + sbrk_amount) / sbrk_amount * sbrk_amount); |
---|
| 261 | |
---|
[50f32b11] | 262 | if ((starting_address = (void *)sbrk(the_size)) |
---|
[e7ceef91] | 263 | == (void*) -1) |
---|
[ac7d5ef0] | 264 | return (void *) 0; |
---|
| 265 | |
---|
[e746a88] | 266 | if ( !_Protected_heap_Extend( |
---|
| 267 | &RTEMS_Malloc_Heap, starting_address, the_size) ) { |
---|
[ac7d5ef0] | 268 | sbrk(-the_size); |
---|
| 269 | errno = ENOMEM; |
---|
| 270 | return (void *) 0; |
---|
| 271 | } |
---|
[50f32b11] | 272 | |
---|
[11290355] | 273 | MSBUMP(space_available, the_size); |
---|
| 274 | |
---|
[e746a88] | 275 | return_this = _Protected_heap_Allocate( &RTEMS_Malloc_Heap, size ); |
---|
| 276 | if ( !return_this ) { |
---|
[ac7d5ef0] | 277 | errno = ENOMEM; |
---|
| 278 | return (void *) 0; |
---|
| 279 | } |
---|
| 280 | } |
---|
| 281 | |
---|
[11290355] | 282 | #ifdef MALLOC_STATS |
---|
| 283 | if (return_this) |
---|
| 284 | { |
---|
[e746a88] | 285 | size_t actual_size = 0; |
---|
[83c5fc1] | 286 | uint32_t current_depth; |
---|
[55d7626] | 287 | void *ptr = return_this; |
---|
| 288 | _Protected_heap_Get_block_size(&RTEMS_Malloc_Heap, ptr, &actual_size); |
---|
[289ad86] | 289 | MSBUMP(lifetime_allocated, actual_size); |
---|
[07a3253d] | 290 | current_depth = rtems_malloc_stats.lifetime_allocated - |
---|
| 291 | rtems_malloc_stats.lifetime_freed; |
---|
[dcec5a4] | 292 | if (current_depth > rtems_malloc_stats.max_depth) |
---|
| 293 | rtems_malloc_stats.max_depth = current_depth; |
---|
[11290355] | 294 | } |
---|
| 295 | #endif |
---|
[1f94ed6b] | 296 | |
---|
| 297 | #ifdef MALLOC_DIRTY |
---|
| 298 | (void) memset(return_this, 0xCF, size); |
---|
| 299 | #endif |
---|
| 300 | |
---|
[be31de7] | 301 | #ifdef MALLOC_ARENA_CHECK |
---|
| 302 | { |
---|
| 303 | struct mallocNode *mp = (struct mallocNode *)return_this; |
---|
| 304 | int key, *fp, *nfp, i; |
---|
| 305 | rtems_interrupt_disable(key); |
---|
| 306 | mp->memory = mp + 1; |
---|
| 307 | return_this = mp->memory; |
---|
| 308 | mp->size = size - (sizeof(struct mallocNode) + SENTINELSIZE); |
---|
| 309 | fp = (int *)&size - 2; |
---|
| 310 | for (i = 0 ; i < CALLCHAINSIZE ; i++) { |
---|
| 311 | mp->callChain[i] = fp[1]; |
---|
| 312 | nfp = (int *)(fp[0]); |
---|
| 313 | if((nfp <= fp) || (nfp > (int *)(1 << 24))) |
---|
| 314 | break; |
---|
| 315 | fp = nfp; |
---|
| 316 | } |
---|
| 317 | while (i < CALLCHAINSIZE) |
---|
| 318 | mp->callChain[i++] = 0; |
---|
| 319 | memcpy((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE); |
---|
| 320 | mp->forw = mallocNodeHead.forw; |
---|
| 321 | mp->back = &mallocNodeHead; |
---|
| 322 | mallocNodeHead.forw->back = mp; |
---|
| 323 | mallocNodeHead.forw = mp; |
---|
| 324 | rtems_interrupt_enable(key); |
---|
| 325 | } |
---|
| 326 | #endif |
---|
[ac7d5ef0] | 327 | return return_this; |
---|
| 328 | } |
---|
| 329 | |
---|
| 330 | void *calloc( |
---|
| 331 | size_t nelem, |
---|
| 332 | size_t elsize |
---|
| 333 | ) |
---|
| 334 | { |
---|
| 335 | register char *cptr; |
---|
| 336 | int length; |
---|
| 337 | |
---|
[11290355] | 338 | MSBUMP(calloc_calls, 1); |
---|
| 339 | |
---|
[ac7d5ef0] | 340 | length = nelem * elsize; |
---|
| 341 | cptr = malloc( length ); |
---|
| 342 | if ( cptr ) |
---|
| 343 | memset( cptr, '\0', length ); |
---|
| 344 | |
---|
[1f94ed6b] | 345 | MSBUMP(malloc_calls, -1); /* subtract off the malloc */ |
---|
| 346 | |
---|
[ac7d5ef0] | 347 | return cptr; |
---|
| 348 | } |
---|
| 349 | |
---|
| 350 | void *realloc( |
---|
| 351 | void *ptr, |
---|
| 352 | size_t size |
---|
| 353 | ) |
---|
| 354 | { |
---|
[e7ceef91] | 355 | size_t old_size; |
---|
[ac7d5ef0] | 356 | char *new_area; |
---|
| 357 | |
---|
[11290355] | 358 | MSBUMP(realloc_calls, 1); |
---|
| 359 | |
---|
[aab4664d] | 360 | /* |
---|
| 361 | * Do not attempt to allocate memory if in a critical section or ISR. |
---|
| 362 | */ |
---|
| 363 | |
---|
[690861c] | 364 | if (_System_state_Is_up(_System_state_Get())) { |
---|
| 365 | if (_Thread_Dispatch_disable_level > 0) |
---|
| 366 | return (void *) 0; |
---|
[50f32b11] | 367 | |
---|
[690861c] | 368 | if (_ISR_Nest_level > 0) |
---|
| 369 | return (void *) 0; |
---|
| 370 | } |
---|
[50f32b11] | 371 | |
---|
[aab4664d] | 372 | /* |
---|
[80f2885b] | 373 | * Continue with realloc(). |
---|
[aab4664d] | 374 | */ |
---|
[ac7d5ef0] | 375 | if ( !ptr ) |
---|
| 376 | return malloc( size ); |
---|
| 377 | |
---|
| 378 | if ( !size ) { |
---|
| 379 | free( ptr ); |
---|
| 380 | return (void *) 0; |
---|
| 381 | } |
---|
| 382 | |
---|
[be31de7] | 383 | #ifdef MALLOC_ARENA_CHECK |
---|
| 384 | { |
---|
[e746a88] | 385 | void *np; |
---|
| 386 | np = malloc(size); |
---|
| 387 | if (!np) return np; |
---|
| 388 | memcpy(np,ptr,size); |
---|
| 389 | free(ptr); |
---|
| 390 | return np; |
---|
[be31de7] | 391 | } |
---|
| 392 | #endif |
---|
[e746a88] | 393 | if ( _Protected_heap_Resize_block( &RTEMS_Malloc_Heap, ptr, size ) ) { |
---|
[80f2885b] | 394 | return ptr; |
---|
| 395 | } |
---|
| 396 | |
---|
[ac7d5ef0] | 397 | new_area = malloc( size ); |
---|
[50f32b11] | 398 | |
---|
[8b2ecf85] | 399 | MSBUMP(malloc_calls, -1); /* subtract off the malloc */ |
---|
| 400 | |
---|
[d9c3805] | 401 | /* |
---|
[50f32b11] | 402 | * There used to be a free on this error case but it is wrong to |
---|
[d9c3805] | 403 | * free the memory per OpenGroup Single UNIX Specification V2 |
---|
| 404 | * and the C Standard. |
---|
| 405 | */ |
---|
| 406 | |
---|
[ac7d5ef0] | 407 | if ( !new_area ) { |
---|
| 408 | return (void *) 0; |
---|
| 409 | } |
---|
| 410 | |
---|
[e746a88] | 411 | if ( !_Protected_heap_Get_block_size(&RTEMS_Malloc_Heap, ptr, &old_size) ) { |
---|
[11290355] | 412 | errno = EINVAL; |
---|
| 413 | return (void *) 0; |
---|
| 414 | } |
---|
| 415 | |
---|
[ac7d5ef0] | 416 | memcpy( new_area, ptr, (size < old_size) ? size : old_size ); |
---|
| 417 | free( ptr ); |
---|
| 418 | |
---|
| 419 | return new_area; |
---|
| 420 | |
---|
| 421 | } |
---|
| 422 | |
---|
| 423 | void free( |
---|
| 424 | void *ptr |
---|
| 425 | ) |
---|
| 426 | { |
---|
[11290355] | 427 | MSBUMP(free_calls, 1); |
---|
| 428 | |
---|
[ac7d5ef0] | 429 | if ( !ptr ) |
---|
| 430 | return; |
---|
| 431 | |
---|
[aab4664d] | 432 | /* |
---|
| 433 | * Do not attempt to free memory if in a critical section or ISR. |
---|
| 434 | */ |
---|
| 435 | |
---|
[690861c] | 436 | if (_System_state_Is_up(_System_state_Get())) { |
---|
| 437 | if ((_Thread_Dispatch_disable_level > 0) || (_ISR_Nest_level > 0)) { |
---|
| 438 | Chain_Append(&RTEMS_Malloc_GC_list, (Chain_Node *)ptr); |
---|
| 439 | return; |
---|
| 440 | } |
---|
[aab4664d] | 441 | } |
---|
[50f32b11] | 442 | |
---|
[be31de7] | 443 | #ifdef MALLOC_ARENA_CHECK |
---|
| 444 | { |
---|
| 445 | struct mallocNode *mp = (struct mallocNode *)ptr - 1; |
---|
| 446 | struct mallocNode *mp1; |
---|
| 447 | int key; |
---|
| 448 | rtems_interrupt_disable(key); |
---|
| 449 | if ((mp->memory != (mp + 1)) |
---|
| 450 | || (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0)) |
---|
| 451 | reportMallocError("Freeing with inconsistent pointer/sentinel", mp); |
---|
| 452 | mp1 = mallocNodeHead.forw; |
---|
| 453 | while (mp1 != &mallocNodeHead) { |
---|
| 454 | if (mp1 == mp) |
---|
| 455 | break; |
---|
| 456 | mp1 = mp1->forw; |
---|
| 457 | } |
---|
| 458 | if (mp1 != mp) |
---|
| 459 | reportMallocError("Freeing, but not on allocated list", mp); |
---|
| 460 | mp->forw->back = mp->back; |
---|
| 461 | mp->back->forw = mp->forw; |
---|
| 462 | mp->back = mp->forw = NULL; |
---|
| 463 | ptr = mp; |
---|
| 464 | rtems_interrupt_enable(key); |
---|
| 465 | } |
---|
| 466 | #endif |
---|
[11290355] | 467 | #ifdef MALLOC_STATS |
---|
| 468 | { |
---|
[e746a88] | 469 | size_t size; |
---|
[55d7626] | 470 | if (_Protected_heap_Get_block_size(&RTEMS_Malloc_Heap, ptr, &size) ) { |
---|
[e746a88] | 471 | MSBUMP(lifetime_freed, size); |
---|
| 472 | } |
---|
[11290355] | 473 | } |
---|
| 474 | #endif |
---|
[50f32b11] | 475 | |
---|
[e746a88] | 476 | if ( !_Protected_heap_Free( &RTEMS_Malloc_Heap, ptr ) ) { |
---|
[ac7d5ef0] | 477 | errno = EINVAL; |
---|
| 478 | assert( 0 ); |
---|
| 479 | } |
---|
| 480 | } |
---|
[be31de7] | 481 | |
---|
| 482 | #ifdef MALLOC_ARENA_CHECK |
---|
| 483 | void checkMallocArena(void) |
---|
| 484 | { |
---|
| 485 | struct mallocNode *mp = mallocNodeHead.forw; |
---|
| 486 | int key; |
---|
| 487 | rtems_interrupt_disable(key); |
---|
| 488 | while (mp != &mallocNodeHead) { |
---|
| 489 | if ((mp->forw->back != mp) |
---|
| 490 | || (mp->back->forw != mp)) |
---|
| 491 | reportMallocError("Pointers mangled", mp); |
---|
| 492 | if((mp->memory != (mp + 1)) |
---|
| 493 | || (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0)) |
---|
| 494 | reportMallocError("Inconsistent pointer/sentinel", mp); |
---|
| 495 | mp = mp->forw; |
---|
| 496 | } |
---|
| 497 | rtems_interrupt_enable(key); |
---|
| 498 | } |
---|
| 499 | #endif |
---|
| 500 | |
---|
[1f2d5df] | 501 | /* end if RTEMS_NEWLIB */ |
---|
| 502 | #endif |
---|
[ac7d5ef0] | 503 | |
---|
[11290355] | 504 | #ifdef MALLOC_STATS |
---|
| 505 | /* |
---|
| 506 | * Dump the malloc statistics |
---|
| 507 | * May be called via atexit() (installable by our bsp) or |
---|
| 508 | * at any time by user |
---|
| 509 | */ |
---|
| 510 | |
---|
| 511 | void malloc_dump(void) |
---|
| 512 | { |
---|
[83c5fc1] | 513 | uint32_t allocated = rtems_malloc_stats.lifetime_allocated - |
---|
[07a3253d] | 514 | rtems_malloc_stats.lifetime_freed; |
---|
[11290355] | 515 | |
---|
| 516 | printf("Malloc stats\n"); |
---|
[2751cbe0] | 517 | printf(" avail:%"PRIu32"k allocated:%"PRIu32"k (%"PRId32"%%) " |
---|
| 518 | "max:%"PRIu32"k (%"PRIu32"%%)" |
---|
| 519 | " lifetime:%"PRIuMAX"k freed:%"PRIuMAX"k\n", |
---|
| 520 | rtems_malloc_stats.space_available / 1024, |
---|
| 521 | allocated / 1024, |
---|
[11290355] | 522 | /* avoid float! */ |
---|
[dcec5a4] | 523 | (allocated * 100) / rtems_malloc_stats.space_available, |
---|
[2751cbe0] | 524 | rtems_malloc_stats.max_depth / 1024, |
---|
[dcec5a4] | 525 | (rtems_malloc_stats.max_depth * 100) / rtems_malloc_stats.space_available, |
---|
[2751cbe0] | 526 | rtems_malloc_stats.lifetime_allocated / 1024, |
---|
| 527 | rtems_malloc_stats.lifetime_freed / 1024 |
---|
| 528 | ); |
---|
| 529 | printf(" Call counts: malloc:%"PRIu32" free:%"PRIu32" realloc:%"PRIu32" calloc:%"PRIu32"\n", |
---|
[dcec5a4] | 530 | rtems_malloc_stats.malloc_calls, |
---|
| 531 | rtems_malloc_stats.free_calls, |
---|
| 532 | rtems_malloc_stats.realloc_calls, |
---|
| 533 | rtems_malloc_stats.calloc_calls); |
---|
[1f2d5df] | 534 | } |
---|
| 535 | |
---|
| 536 | |
---|
| 537 | void malloc_walk(size_t source, size_t printf_enabled) |
---|
| 538 | { |
---|
[e746a88] | 539 | _Protected_heap_Walk( &RTEMS_Malloc_Heap, source, printf_enabled ); |
---|
[1f2d5df] | 540 | } |
---|
| 541 | |
---|
| 542 | #else |
---|
| 543 | |
---|
| 544 | void malloc_dump(void) |
---|
| 545 | { |
---|
| 546 | return; |
---|
| 547 | } |
---|
[50f32b11] | 548 | |
---|
[1f2d5df] | 549 | void malloc_walk(size_t source, size_t printf_enabled) |
---|
| 550 | { |
---|
| 551 | return; |
---|
| 552 | } |
---|
| 553 | |
---|
[11290355] | 554 | #endif |
---|
| 555 | |
---|
[ac7d5ef0] | 556 | /* |
---|
| 557 | * "Reentrant" versions of the above routines implemented above. |
---|
| 558 | */ |
---|
| 559 | |
---|
| 560 | #ifdef RTEMS_NEWLIB |
---|
[388be68f] | 561 | void *_malloc_r( |
---|
[ac7d5ef0] | 562 | struct _reent *ignored, |
---|
| 563 | size_t size |
---|
| 564 | ) |
---|
| 565 | { |
---|
| 566 | return malloc( size ); |
---|
| 567 | } |
---|
| 568 | |
---|
[388be68f] | 569 | void *_calloc_r( |
---|
| 570 | struct _reent *ignored, |
---|
[ac7d5ef0] | 571 | size_t nelem, |
---|
| 572 | size_t elsize |
---|
| 573 | ) |
---|
| 574 | { |
---|
| 575 | return calloc( nelem, elsize ); |
---|
| 576 | } |
---|
| 577 | |
---|
[388be68f] | 578 | void *_realloc_r( |
---|
| 579 | struct _reent *ignored, |
---|
[ac7d5ef0] | 580 | void *ptr, |
---|
| 581 | size_t size |
---|
| 582 | ) |
---|
| 583 | { |
---|
[388be68f] | 584 | return realloc( ptr, size ); |
---|
[ac7d5ef0] | 585 | } |
---|
| 586 | |
---|
[388be68f] | 587 | void _free_r( |
---|
| 588 | struct _reent *ignored, |
---|
[ac7d5ef0] | 589 | void *ptr |
---|
| 590 | ) |
---|
| 591 | { |
---|
| 592 | free( ptr ); |
---|
| 593 | } |
---|
[8ef3818] | 594 | |
---|
[ac7d5ef0] | 595 | #endif |
---|