From 543fe820616f31350366ab61052050303d17dd25 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Tue, 18 Dec 2007 20:36:40 +0000 Subject: 2007-12-18 Joel Sherrill * libcsupport/Makefile.am, libcsupport/preinstall.am, libcsupport/src/malloc.c, libcsupport/src/mallocinfo.c, libmisc/Makefile.am, libmisc/shell/main_mallocinfo.c, libmisc/shell/shellconfig.h: Split malloc.c into multiple files with one function per file. Also split out statistics into a separate file which can be plugged in dynamically. Right now, it is always in. I suspect that splitting the file removed more code than leaving statistics in. I tinkered with malloc information command in the shell. I resurrected the malloc arena code as malloc boundary. This code is now compiled all the time even though it does not appear to work. * libcsupport/include/rtems/malloc.h, libcsupport/src/_calloc_r.c, libcsupport/src/_free_r.c, libcsupport/src/_malloc_r.c, libcsupport/src/_realloc_r.c, libcsupport/src/calloc.c, libcsupport/src/free.c, libcsupport/src/malloc_boundary.c, libcsupport/src/malloc_get_statistics.c, libcsupport/src/malloc_initialize.c, libcsupport/src/malloc_p.h, libcsupport/src/malloc_report_statistics.c, libcsupport/src/malloc_report_statistics_plugin.c, libcsupport/src/malloc_statistics_helpers.c, libcsupport/src/malloc_walk.c, libcsupport/src/realloc.c, libmisc/shell/main_perioduse.c: New files. --- cpukit/libcsupport/src/malloc.c | 529 ++-------------------------------------- 1 file changed, 25 insertions(+), 504 deletions(-) (limited to 'cpukit/libcsupport/src/malloc.c') diff --git a/cpukit/libcsupport/src/malloc.c b/cpukit/libcsupport/src/malloc.c index 6a8f584a98..d1b3bb3504 100644 --- a/cpukit/libcsupport/src/malloc.c +++ b/cpukit/libcsupport/src/malloc.c @@ -2,7 +2,7 @@ * RTEMS Malloc Family Implementation * * - * COPYRIGHT (c) 1989-1999. + * COPYRIGHT (c) 1989-2007. * On-Line Applications Research Corporation (OAR). * * The license and distribution terms for this file may be @@ -16,201 +16,12 @@ #include "config.h" #endif -#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ -#include -#include -#include #ifdef RTEMS_NEWLIB -#include -#endif - -#include #include -#include #include -#include - -#include /* sbrk(2) */ -#include - -#include - -#ifndef HAVE_UINTMAX_T -/* Fall back to unsigned long if uintmax_t is not available */ -#define unsigned long uintmax_t - -#ifndef PRIuMAX -#define PRIuMAX "lu" -#endif -#endif - -#ifdef MALLOC_ARENA_CHECK -#define SENTINELSIZE 12 -#define SENTINEL "\xD1\xAC\xB2\xF1" "BITE ME" -#define CALLCHAINSIZE 5 -struct mallocNode { - struct mallocNode *back; - struct mallocNode *forw; - int callChain[CALLCHAINSIZE]; - size_t size; - void *memory; -}; -static struct mallocNode mallocNodeHead = { &mallocNodeHead, &mallocNodeHead }; -void reportMallocError(const char *msg, struct mallocNode *mp) -{ - unsigned char *sp = (unsigned char *)mp->memory + mp->size; - int i, ind = 0; - static char cbuf[500]; - ind += sprintf(cbuf+ind, "Malloc Error: %s\n", msg); - if ((mp->forw->back != mp) || (mp->back->forw != mp)) - 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", - mp, mp->forw, mp->forw->back, mp->back, mp->back->forw); - if (mp->memory != (mp + 1)) - ind += sprintf(cbuf+ind, "mp+1:0x%x ", mp + 1); - ind += sprintf(cbuf+ind, "mp->memory:0x%x mp->size:%d\n", mp->memory, mp->size); - if (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0) { - ind += sprintf(cbuf+ind, "mp->sentinel: "); - for (i = 0 ; i < SENTINELSIZE ; i++) - ind += sprintf(cbuf+ind, " 0x%x", sp[i]); - ind += sprintf(cbuf+ind, "\n"); - } - ind += sprintf(cbuf+ind, "Call chain:"); - for (i = 0 ; i < CALLCHAINSIZE ; i++) { - if (mp->callChain[i] == 0) - break; - ind += sprintf(cbuf+ind, " 0x%x", mp->callChain[i]); - } - printk("\n\n%s\n\n", cbuf); -} -#endif - -Heap_Control RTEMS_Malloc_Heap; -Chain_Control RTEMS_Malloc_GC_list; - -/* rtems_id RTEMS_Malloc_Heap; */ -size_t RTEMS_Malloc_Sbrk_amount; - -#ifdef RTEMS_DEBUG -#define MALLOC_STATS -#define MALLOC_DIRTY -/*#define MALLOC_ARENA_CHECK -void checkMallocArena(void); */ -#endif - -#ifdef MALLOC_STATS -#define MSBUMP(f,n) rtems_malloc_stats.f += (n) - -struct { - uint32_t space_available; /* current size of malloc area */ - uint32_t malloc_calls; /* # calls to malloc */ - uint32_t free_calls; - uint32_t realloc_calls; - uint32_t calloc_calls; - uint32_t max_depth; /* most ever malloc'd at 1 time */ - uintmax_t lifetime_allocated; - uintmax_t lifetime_freed; -} rtems_malloc_stats; - -#else /* No rtems_malloc_stats */ -#define MSBUMP(f,n) -#endif - -void RTEMS_Malloc_Initialize( - void *start, - size_t length, - size_t sbrk_amount -) -{ - uint32_t status; - void *starting_address; - uintptr_t old_address; - uintptr_t uaddress; - - /* - * Initialize the garbage collection list to start with nothing on it. - */ - Chain_Initialize_empty(&RTEMS_Malloc_GC_list); - - /* - * If the starting address is 0 then we are to attempt to - * get length worth of memory using sbrk. Make sure we - * align the address that we get back. - */ - - starting_address = start; - RTEMS_Malloc_Sbrk_amount = sbrk_amount; - - if (!starting_address) { - uaddress = (uintptr_t)sbrk(length); - - if (uaddress == (uintptr_t) -1) { - rtems_fatal_error_occurred( RTEMS_NO_MEMORY ); - /* DOES NOT RETURN!!! */ - } - - if (uaddress & (CPU_HEAP_ALIGNMENT-1)) { - old_address = uaddress; - uaddress = (uaddress + CPU_HEAP_ALIGNMENT) & ~(CPU_HEAP_ALIGNMENT-1); - - /* - * adjust the length by whatever we aligned by - */ - - length -= uaddress - old_address; - } - - starting_address = (void *)uaddress; - } - - /* - * If the BSP is not clearing out the workspace, then it is most likely - * not clearing out the initial memory for the heap. There is no - * standard supporting zeroing out the heap memory. But much code - * with UNIX history seems to assume that memory malloc'ed during - * initialization (before any free's) is zero'ed. This is true most - * of the time under UNIX because zero'ing memory when it is first - * given to a process eliminates the chance of a process seeing data - * left over from another process. This would be a security violation. - */ - - if ( rtems_configuration_get_do_zero_of_workspace() ) - memset( starting_address, 0, length ); - - /* - * Unfortunately we cannot use assert if this fails because if this - * has failed we do not have a heap and if we do not have a heap - * STDIO cannot work because there will be no buffers. - */ - - status = _Protected_heap_Initialize( - &RTEMS_Malloc_Heap, - starting_address, - length, - CPU_HEAP_ALIGNMENT - ); - if ( !status ) - rtems_fatal_error_occurred( status ); - - #if defined(RTEMS_HEAP_DEBUG) - if ( _Protected_heap_Walk( &RTEMS_Malloc_Heap, 0, FALSE ) ) { - printk( "Malloc heap not initialized correctly\n" ); - rtems_print_buffer( start, 32 ); - printk( "\n" ); - rtems_print_buffer( (start + length) - 48, 48 ); - rtems_fatal_error_occurred( RTEMS_NO_MEMORY ); - } - #endif -#ifdef MALLOC_STATS - /* zero all the stats */ - (void) memset( &rtems_malloc_stats, 0, sizeof(rtems_malloc_stats) ); -#endif - MSBUMP(space_available, length); -} +#include "malloc_p.h" -#ifdef RTEMS_NEWLIB void *malloc( size_t size ) @@ -248,15 +59,21 @@ void *malloc( while ((to_be_freed = Chain_Get(&RTEMS_Malloc_GC_list)) != NULL) free(to_be_freed); + #if defined(RTEMS_MALLOC_BOUNDARY_HELPERS) + /* + * If the support for a boundary area at the end of the heap + * block allocated is turned on, then adjust the size. + */ + if (rtems_malloc_boundary_helpers) + size += (*rtems_malloc_boundary_helpers->overhead)(); + #endif + /* * Try to give a segment in the current heap if there is not * enough space then try to grow the heap. * If this fails then return a NULL pointer. */ -#ifdef MALLOC_ARENA_CHECK - size += sizeof(struct mallocNode) + SENTINELSIZE; -#endif return_this = _Protected_heap_Allocate( &RTEMS_Malloc_Heap, size ); if ( !return_this ) { @@ -293,324 +110,28 @@ void *malloc( } } -#ifdef MALLOC_STATS - if (return_this) - { - size_t actual_size = 0; - uint32_t current_depth; - void *ptr = return_this; - _Protected_heap_Get_block_size(&RTEMS_Malloc_Heap, ptr, &actual_size); - MSBUMP(lifetime_allocated, actual_size); - current_depth = rtems_malloc_stats.lifetime_allocated - - rtems_malloc_stats.lifetime_freed; - if (current_depth > rtems_malloc_stats.max_depth) - rtems_malloc_stats.max_depth = current_depth; - } -#endif - -#ifdef MALLOC_DIRTY - (void) memset(return_this, 0xCF, size); -#endif - -#ifdef MALLOC_ARENA_CHECK - { - struct mallocNode *mp = (struct mallocNode *)return_this; - int key, *fp, *nfp, i; - rtems_interrupt_disable(key); - mp->memory = mp + 1; - return_this = mp->memory; - mp->size = size - (sizeof(struct mallocNode) + SENTINELSIZE); - fp = (int *)&size - 2; - for (i = 0 ; i < CALLCHAINSIZE ; i++) { - mp->callChain[i] = fp[1]; - nfp = (int *)(fp[0]); - if((nfp <= fp) || (nfp > (int *)(1 << 24))) - break; - fp = nfp; - } - while (i < CALLCHAINSIZE) - mp->callChain[i++] = 0; - memcpy((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE); - mp->forw = mallocNodeHead.forw; - mp->back = &mallocNodeHead; - mallocNodeHead.forw->back = mp; - mallocNodeHead.forw = mp; - rtems_interrupt_enable(key); - } -#endif - return return_this; -} - -void *calloc( - size_t nelem, - size_t elsize -) -{ - register char *cptr; - int length; - - MSBUMP(calloc_calls, 1); - - length = nelem * elsize; - cptr = malloc( length ); - if ( cptr ) - memset( cptr, '\0', length ); - - MSBUMP(malloc_calls, -1); /* subtract off the malloc */ - - return cptr; -} - -void *realloc( - void *ptr, - size_t size -) -{ - size_t old_size; - char *new_area; - - MSBUMP(realloc_calls, 1); - - /* - * Do not attempt to allocate memory if in a critical section or ISR. - */ - - if (_System_state_Is_up(_System_state_Get())) { - if (_Thread_Dispatch_disable_level > 0) - return (void *) 0; - - if (_ISR_Nest_level > 0) - return (void *) 0; - } - - /* - * Continue with realloc(). - */ - if ( !ptr ) - return malloc( size ); - - if ( !size ) { - free( ptr ); - return (void *) 0; - } - -#ifdef MALLOC_ARENA_CHECK - { - void *np; - np = malloc(size); - if (!np) return np; - memcpy(np,ptr,size); - free(ptr); - return np; - } -#endif - if ( _Protected_heap_Resize_block( &RTEMS_Malloc_Heap, ptr, size ) ) { - return ptr; - } - - new_area = malloc( size ); - - MSBUMP(malloc_calls, -1); /* subtract off the malloc */ - /* - * There used to be a free on this error case but it is wrong to - * free the memory per OpenGroup Single UNIX Specification V2 - * and the C Standard. + * If the user wants us to dirty the allocated memory, then do it. */ - - if ( !new_area ) { - return (void *) 0; - } - - if ( !_Protected_heap_Get_block_size(&RTEMS_Malloc_Heap, ptr, &old_size) ) { - errno = EINVAL; - return (void *) 0; - } - - memcpy( new_area, ptr, (size < old_size) ? size : old_size ); - free( ptr ); - - return new_area; - -} - -void free( - void *ptr -) -{ - MSBUMP(free_calls, 1); - - if ( !ptr ) - return; - - #if defined(RTEMS_HEAP_DEBUG) - _Protected_heap_Walk( &RTEMS_Malloc_Heap, 0, FALSE ); + #ifdef MALLOC_DIRTY + (void) memset(return_this, 0xCF, size); #endif /* - * Do not attempt to free memory if in a critical section or ISR. + * If configured, update the statistics */ + if ( rtems_malloc_statistics_helpers ) + (*rtems_malloc_statistics_helpers->at_malloc)(return_this); - if (_System_state_Is_up(_System_state_Get())) { - if ((_Thread_Dispatch_disable_level > 0) || (_ISR_Nest_level > 0)) { - Chain_Append(&RTEMS_Malloc_GC_list, (Chain_Node *)ptr); - return; - } - } - -#ifdef MALLOC_ARENA_CHECK - { - struct mallocNode *mp = (struct mallocNode *)ptr - 1; - struct mallocNode *mp1; - int key; - rtems_interrupt_disable(key); - if ((mp->memory != (mp + 1)) - || (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0)) - reportMallocError("Freeing with inconsistent pointer/sentinel", mp); - mp1 = mallocNodeHead.forw; - while (mp1 != &mallocNodeHead) { - if (mp1 == mp) - break; - mp1 = mp1->forw; - } - if (mp1 != mp) - reportMallocError("Freeing, but not on allocated list", mp); - mp->forw->back = mp->back; - mp->back->forw = mp->forw; - mp->back = mp->forw = NULL; - ptr = mp; - rtems_interrupt_enable(key); - } -#endif -#ifdef MALLOC_STATS - { - size_t size; - if (_Protected_heap_Get_block_size(&RTEMS_Malloc_Heap, ptr, &size) ) { - MSBUMP(lifetime_freed, size); - } - } -#endif - - if ( !_Protected_heap_Free( &RTEMS_Malloc_Heap, ptr ) ) { - printk( "Program heap: free of bad pointer %p -- range %p - %p \n", - ptr, - RTEMS_Malloc_Heap.start, - RTEMS_Malloc_Heap.end - ); - } -} - -#ifdef MALLOC_ARENA_CHECK -void checkMallocArena(void) -{ - struct mallocNode *mp = mallocNodeHead.forw; - int key; - rtems_interrupt_disable(key); - while (mp != &mallocNodeHead) { - if ((mp->forw->back != mp) - || (mp->back->forw != mp)) - reportMallocError("Pointers mangled", mp); - if((mp->memory != (mp + 1)) - || (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0)) - reportMallocError("Inconsistent pointer/sentinel", mp); - mp = mp->forw; - } - rtems_interrupt_enable(key); -} -#endif - -/* end if RTEMS_NEWLIB */ -#endif - -#ifdef MALLOC_STATS -/* - * Dump the malloc statistics - * May be called via atexit() (installable by our bsp) or - * at any time by user - */ - -void malloc_dump(void) -{ - uint32_t allocated = rtems_malloc_stats.lifetime_allocated - - rtems_malloc_stats.lifetime_freed; - - printf("Malloc stats\n"); - printf(" avail:%"PRIu32"k allocated:%"PRIu32"k (%"PRId32"%%) " - "max:%"PRIu32"k (%"PRIu32"%%)" - " lifetime:%"PRIuMAX"k freed:%"PRIuMAX"k\n", - rtems_malloc_stats.space_available / 1024, - allocated / 1024, - /* avoid float! */ - (allocated * 100) / rtems_malloc_stats.space_available, - rtems_malloc_stats.max_depth / 1024, - (rtems_malloc_stats.max_depth * 100) / rtems_malloc_stats.space_available, - rtems_malloc_stats.lifetime_allocated / 1024, - rtems_malloc_stats.lifetime_freed / 1024 - ); - printf(" Call counts: malloc:%"PRIu32" free:%"PRIu32" realloc:%"PRIu32" calloc:%"PRIu32"\n", - rtems_malloc_stats.malloc_calls, - rtems_malloc_stats.free_calls, - rtems_malloc_stats.realloc_calls, - rtems_malloc_stats.calloc_calls); -} - - -void malloc_walk(size_t source, size_t printf_enabled) -{ - _Protected_heap_Walk( &RTEMS_Malloc_Heap, source, printf_enabled ); -} - -#else - -void malloc_dump(void) -{ - return; -} - -void malloc_walk(size_t source, size_t printf_enabled) -{ - return; -} - -#endif - -/* - * "Reentrant" versions of the above routines implemented above. - */ - -#ifdef RTEMS_NEWLIB -void *_malloc_r( - struct _reent *ignored, - size_t size -) -{ - return malloc( size ); -} - -void *_calloc_r( - struct _reent *ignored, - size_t nelem, - size_t elsize -) -{ - return calloc( nelem, elsize ); -} - -void *_realloc_r( - struct _reent *ignored, - void *ptr, - size_t size -) -{ - return realloc( ptr, size ); -} + #if defined(RTEMS_MALLOC_BOUNDARY_HELPERS) + /* + * If configured, set the boundary area + */ + if (rtems_malloc_boundary_helpers) + (*rtems_malloc_boundary_helpers->at_malloc)(return_this, size); + #endif -void _free_r( - struct _reent *ignored, - void *ptr -) -{ - free( ptr ); + return return_this; } #endif -- cgit v1.2.3