summaryrefslogtreecommitdiffstats
path: root/cpukit/libcsupport/src/malloc.c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2007-12-18 20:36:40 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2007-12-18 20:36:40 +0000
commit543fe820616f31350366ab61052050303d17dd25 (patch)
treea2e4702be2cd9988ed341586c1c8c976b8ba3bb8 /cpukit/libcsupport/src/malloc.c
parent2007-12-18 Joel Sherrill <joel.sherrill@OARcorp.com> (diff)
downloadrtems-543fe820616f31350366ab61052050303d17dd25.tar.bz2
2007-12-18 Joel Sherrill <joel.sherrill@oarcorp.com>
* 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.
Diffstat (limited to 'cpukit/libcsupport/src/malloc.c')
-rw-r--r--cpukit/libcsupport/src/malloc.c529
1 files changed, 25 insertions, 504 deletions
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 <rtems.h>
-#include <rtems/libcsupport.h>
-#include <rtems/score/protectedheap.h>
#ifdef RTEMS_NEWLIB
-#include <sys/reent.h>
-#endif
-
-#include <stdio.h>
#include <stdlib.h>
-#include <sys/types.h>
#include <errno.h>
-#include <string.h>
-
-#include <unistd.h> /* sbrk(2) */
-#include <inttypes.h>
-
-#include <rtems/chain.h>
-
-#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