This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
new memory debug feature
- From: Øyvind Harboe <oyvind dot harboe at zylin dot com>
- To: ecos-patches at sources dot redhat dot com, andrew at lunn dot ch
- Date: Thu, 24 Jun 2004 13:25:00 +0200
- Subject: new memory debug feature
- Organization: Zylin AS
--
Øyvind Harboe
http://www.zylin.com
Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/ChangeLog,v
retrieving revision 1.30
diff -u -5 -p -w -r1.30 ChangeLog
--- ChangeLog 15 Mar 2004 15:42:04 -0000 1.30
+++ ChangeLog 24 Jun 2004 11:23:28 -0000
@@ -1,5 +1,13 @@
+2004-06-24 Oyvind Harboe <oyvind.harboe@zylin.com>
+
+ *
+ * Added cyg_memalloc_alloc_fail() fn which is invoked before
+ return NULL from failed allocations. Useful breakpoint site.
+ Andrew Lunn wrote some of the code and pointed out various
+ wrinkles to be ironed out.
+
2004-02-15 Jonathan Larmour <jifl@eCosCentric.com>
* include/kapi.h: Add throw specifications throughout.
* src/kapi.cxx: Ditto.
Index: cdl/memalloc.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/cdl/memalloc.cdl,v
retrieving revision 1.12
diff -u -5 -p -w -r1.12 memalloc.cdl
--- cdl/memalloc.cdl 6 Oct 2003 16:41:07 -0000 1.12
+++ cdl/memalloc.cdl 24 Jun 2004 11:23:28 -0000
@@ -54,11 +54,11 @@ cdl_package CYGPKG_MEMALLOC {
This package provides memory allocator infrastructure required for
dynamic memory allocators, including the ISO standard malloc
interface. It also contains some sample implementations."
include_dir cyg/memalloc
compile dlmalloc.cxx memfixed.cxx memvar.cxx \
- sepmeta.cxx
+ sepmeta.cxx debug.c
# ====================================================================
cdl_component CYGPKG_MEMALLOC_ALLOCATORS {
display "Memory allocator implementations"
@@ -237,10 +237,19 @@ cdl_package CYGPKG_MEMALLOC {
either argument 0 ). It is permitted by the standard to return
either a NULL pointer or a unique pointer. Enabling this option
forces a NULL pointer to be returned."
}
+ cdl_option CYGSEM_MEMALLOC_INVOKE_OUT_OF_MEMORY {
+ display "Breakpoint site when running out of memory"
+ default_value 0
+ description "
+ Whenever the system runs out of memory, it invokes this function
+ before either going to sleep(waiting for memory to become
+ available) or returning failure."
+ }
+
cdl_component CYGPKG_MEMALLOC_MALLOC_ALLOCATORS {
display "malloc() and supporting allocators"
flavor bool
active_if CYGPKG_ISOINFRA
implements CYGINT_ISO_MALLOC
Index: include/common.hxx
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/include/common.hxx,v
retrieving revision 1.3
diff -u -5 -p -w -r1.3 common.hxx
--- include/common.hxx 23 May 2002 23:08:43 -0000 1.3
+++ include/common.hxx 24 Jun 2004 11:23:36 -0000
@@ -55,10 +55,12 @@
//
//========================================================================*/
/* CONFIGURATION */
+#include <cyg/kernel/kapi.h>
+#include <cyg/memalloc/kapi.h>
#include <pkgconf/memalloc.h>
/* TYPE DEFINITIONS */
// struct Cyg_Mempool_Status is returned by the get_status() method of
@@ -129,7 +131,20 @@ public:
// And an opaque type for any arguments with these flags
typedef cyg_uint16 cyg_mempool_status_flag_t;
+// breakpoint site for out of memory conditions
+
+#ifdef CYGSEM_MEMALLOC_INVOKE_OUT_OF_MEMORY
+#define CYG_MEMALLOC_FAIL_TEST( test, size) \
+ CYG_MACRO_START \
+ if ( test) { \
+ cyg_memalloc_alloc_fail(__FILE__, __LINE__, size ); \
+ } \
+ CYG_MACRO_END
+#else
+#define CYG_MEMALLOC_FAIL_TEST( test, size) CYG_EMPTY_STATEMENT
+#endif
+
#endif /* ifndef CYGONCE_MEMALLOC_COMMON_HXX */
/* EOF common.hxx */
Index: include/kapi.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/include/kapi.h,v
retrieving revision 1.4
diff -u -5 -p -w -r1.4 kapi.h
--- include/kapi.h 15 Mar 2004 15:42:04 -0000 1.4
+++ include/kapi.h 24 Jun 2004 11:23:36 -0000
@@ -174,9 +174,10 @@ cyg_bool_t cyg_mempool_fix_waiting(cyg_h
/* Puts information about a variable memory pool into the structure
provided. */
void cyg_mempool_fix_get_info(cyg_handle_t fixpool, cyg_mempool_info *info) __THROW;
-
+/* user overrideable function invoked before running out of memory. */
+__externC void cyg_memalloc_alloc_fail(char * file, int line, cyg_int32 size) __THROW;
#endif /* ifndef CYGONCE_MEMALLOC_KAPI_H */
/* EOF kapi.h */
Index: include/memjoin.inl
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/include/memjoin.inl,v
retrieving revision 1.6
diff -u -5 -p -w -r1.6 memjoin.inl
--- include/memjoin.inl 5 Feb 2003 01:10:12 -0000 1.6
+++ include/memjoin.inl 24 Jun 2004 11:23:37 -0000
@@ -176,10 +176,13 @@ Cyg_Mempool_Joined<T>::try_alloc( cyg_in
if ( NULL != ptr )
break;
}
CYG_REPORT_RETVAL( ptr );
+
+ CYG_MEMALLOC_FAIL_TEST(ptr==NULL, size);
+
return ptr;
} // Cyg_Mempool_Joined<T>::try_alloc()
// -------------------------------------------------------------------------
@@ -212,10 +215,11 @@ Cyg_Mempool_Joined<T>::resize_alloc( cyg
CYG_ASSERT( NULL != pool, "Couldn't find pool for pointer!" );
ret = pool->resize_alloc( alloc_ptr, newsize, oldsize );
CYG_REPORT_RETVAL( ret );
+
return ret;
} // Cyg_Mempool_Joined<T>::resize_alloc()
// -------------------------------------------------------------------------
Index: include/mempolt2.inl
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/include/mempolt2.inl,v
retrieving revision 1.3
diff -u -5 -p -w -r1.3 mempolt2.inl
--- include/mempolt2.inl 23 May 2002 23:08:43 -0000 1.3
+++ include/mempolt2.inl 24 Jun 2004 11:23:37 -0000
@@ -114,10 +114,12 @@ Cyg_Mempolt2<T>::alloc( cyg_int32 size )
Cyg_Thread *self = Cyg_Thread::self();
Mempolt2WaitInfo waitinfo( size );
+ CYG_MEMALLOC_FAIL_TEST(true, size);
+
self->set_wait_info( (CYG_ADDRWORD)&waitinfo );
self->set_sleep_reason( Cyg_Thread::WAIT );
self->sleep();
queue.enqueue( self );
@@ -185,10 +187,13 @@ Cyg_Mempolt2<T>::alloc( cyg_int32 size,
// If the timeout is in the past, the wake reason will have been set to
// something other than NONE already. If so, skip the wait and go
// straight to unlock.
if( Cyg_Thread::NONE == self->get_wake_reason() ) {
+
+ CYG_MEMALLOC_FAIL_TEST(true, size);
+
self->set_wait_info( (CYG_ADDRWORD)&waitinfo );
self->sleep();
queue.enqueue( self );
}
@@ -249,10 +254,13 @@ Cyg_Mempolt2<T>::try_alloc( cyg_int32 si
CYG_ASSERTCLASS( this, "Bad this pointer");
// Unlock the scheduler and maybe switch threads
Cyg_Scheduler::unlock();
+
+ CYG_MEMALLOC_FAIL_TEST(ret==NULL, size);
+
return ret;
}
// -------------------------------------------------------------------------
@@ -281,10 +289,13 @@ Cyg_Mempolt2<T>::resize_alloc( cyg_uint8
CYG_ASSERTCLASS( this, "Bad this pointer");
// Unlock the scheduler and maybe switch threads
Cyg_Scheduler::unlock();
+
+ CYG_MEMALLOC_FAIL_TEST(ret==NULL, newsize);
+
return ret;
}
// -------------------------------------------------------------------------
Index: include/mempoolt.inl
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/include/mempoolt.inl,v
retrieving revision 1.3
diff -u -5 -p -w -r1.3 mempoolt.inl
--- include/mempoolt.inl 23 May 2002 23:08:43 -0000 1.3
+++ include/mempoolt.inl 24 Jun 2004 11:23:38 -0000
@@ -109,10 +109,13 @@ Cyg_Mempoolt<T>::alloc( cyg_int32 size )
// grabbing the freed storage between the wakeup in free() and this
// thread actually starting.
cyg_uint8 *ret;
cyg_bool result = true;
while( result && (NULL == (ret = pool.alloc( size ))) ) {
+
+ CYG_MEMALLOC_FAIL_TEST(true, size);
+
self->set_sleep_reason( Cyg_Thread::WAIT );
self->sleep();
queue.enqueue( self );
CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(),
@@ -180,10 +183,12 @@ Cyg_Mempoolt<T>::alloc( cyg_int32 size,
if( self->get_wake_reason() != Cyg_Thread::NONE )
result = false;
while( result && (NULL == (ret = pool.alloc( size ))) ) {
+ CYG_MEMALLOC_FAIL_TEST(true, size);
+
self->set_sleep_reason( Cyg_Thread::TIMEOUT );
self->sleep();
queue.enqueue( self );
CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(),
@@ -246,10 +251,13 @@ Cyg_Mempoolt<T>::try_alloc( cyg_int32 si
CYG_ASSERTCLASS( this, "Bad this pointer");
// Unlock the scheduler and maybe switch threads
Cyg_Scheduler::unlock();
CYG_REPORT_RETVAL( ret );
+
+ CYG_MEMALLOC_FAIL_TEST(ret==NULL, size);
+
return ret;
}
// -------------------------------------------------------------------------
Index: include/mfiximpl.inl
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/include/mfiximpl.inl,v
retrieving revision 1.3
diff -u -5 -p -w -r1.3 mfiximpl.inl
--- include/mfiximpl.inl 23 May 2002 23:08:44 -0000 1.3
+++ include/mfiximpl.inl 24 Jun 2004 11:23:38 -0000
@@ -57,10 +57,11 @@
#include <pkgconf/memalloc.h>
#include <cyg/hal/hal_arch.h> // HAL_LSBIT_INDEX magic asm code
#include <cyg/memalloc/mfiximpl.hxx>
+
// -------------------------------------------------------------------------
inline
Cyg_Mempool_Fixed_Implementation::Cyg_Mempool_Fixed_Implementation(
cyg_uint8 *base,
@@ -120,12 +121,14 @@ Cyg_Mempool_Fixed_Implementation::~Cyg_M
inline cyg_uint8 *
Cyg_Mempool_Fixed_Implementation::try_alloc( cyg_int32 size )
{
// size parameter is not used
CYG_UNUSED_PARAM( cyg_int32, size );
- if ( 0 >= freeblocks )
+ if ( 0 >= freeblocks ) {
+ CYG_MEMALLOC_FAIL_TEST(true, size);
return NULL;
+ }
cyg_int32 i = firstfree;
cyg_uint8 *p = NULL;
do {
if ( 0xffffffff != bitmap[ i ] ) {
// then there is a free block in this bucket
@@ -170,12 +173,14 @@ Cyg_Mempool_Fixed_Implementation::resize
if ( NULL != oldsize )
*oldsize = blocksize;
if (newsize == blocksize)
return alloc_ptr;
- else
+ else {
+ CYG_MEMALLOC_FAIL_TEST(true, newsize);
return NULL;
+ }
} // resize_alloc()
// -------------------------------------------------------------------------
Index: include/mvarimpl.inl
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/include/mvarimpl.inl,v
retrieving revision 1.5
diff -u -5 -p -w -r1.5 mvarimpl.inl
--- include/mvarimpl.inl 23 May 2002 23:08:44 -0000 1.5
+++ include/mvarimpl.inl 24 Jun 2004 11:23:38 -0000
@@ -273,10 +273,12 @@ Cyg_Mempool_Variable_Implementation::try
freemem -=size;
cyg_uint8 *ptr = memdq2alloc( dq );
CYG_ASSERT( ((CYG_ADDRESS)ptr & (alignment-1)) == 0,
"returned memory not aligned" );
+ CYG_MEMALLOC_FAIL_TEST(ptr==NULL, size);
+
return ptr;
}
// -------------------------------------------------------------------------
// resize existing allocation, if oldsize is non-NULL, previous
@@ -356,10 +358,12 @@ Cyg_Mempool_Variable_Implementation::res
} // if
else if ( newsize == dq->size ) {
ret = alloc_ptr;
}
+ CYG_MEMALLOC_FAIL_TEST(ret==NULL, newsize);
+
return ret;
} // resize_alloc()
Index: include/sepmetaimpl.inl
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/include/sepmetaimpl.inl,v
retrieving revision 1.4
diff -u -5 -p -w -r1.4 sepmetaimpl.inl
--- include/sepmetaimpl.inl 23 May 2002 23:08:44 -0000 1.4
+++ include/sepmetaimpl.inl 24 Jun 2004 11:23:39 -0000
@@ -372,12 +372,16 @@ Cyg_Mempool_Sepmeta_Implementation::try_
return NULL;
size = (size + alignment - 1) & -alignment;
struct memdq *dq = find_free_dq( size );
- if (NULL == dq)
+
+
+ if (NULL == dq) {
+ CYG_MEMALLOC_FAIL_TEST(true, size);
return NULL;
+ }
cyg_int32 dqsize = dq->memnext->mem - dq->mem;
if( size == dqsize ) {
// exact fit -- unlink from free list
@@ -397,12 +401,15 @@ Cyg_Mempool_Sepmeta_Implementation::try_
// Split into two memdq's, returning the second one
// first get a memdq
- if ( NULL == freemetahead ) // out of metadata.
+ if ( NULL == freemetahead ) {
+ // out of metadata.
+ CYG_MEMALLOC_FAIL_TEST(true, size);
return NULL;
+ }
// FIXME: since we don't search all the way for an exact fit
// first we may be able to find an exact fit later and therefore
// not need more metadata. We don't do this yet though.
@@ -494,11 +501,14 @@ Cyg_Mempool_Sepmeta_Implementation::resi
}
if ( dq->prev != dq->memprev) { // ditto
prevmemsize = dq->mem - dq->memprev->mem;
}
if (nextmemsize + prevmemsize + currsize < newsize)
+ {
+ CYG_MEMALLOC_FAIL_TEST(true, newsize);
return NULL; // can't fit it
+ }
// expand forwards
if ( nextmemsize != 0 ) {
if (nextmemsize <= (newsize - currsize)) { // taking all of it
struct memdq *fblk = dq->memnext;
@@ -558,12 +568,14 @@ Cyg_Mempool_Sepmeta_Implementation::resi
CYG_ASSERT( dq->memnext->mem > dq->mem,
"moving next block back corruption" );
} else {
// if its already allocated we need to create a new free list
// entry
- if (NULL == freemetahead)
+ if (NULL == freemetahead) {
+ CYG_MEMALLOC_FAIL_TEST(true, newsize);
return NULL; // can't do it
+ }
struct memdq *fdq = freemetahead;
freemetahead = fdq->next;
fdq->memprev = dq;
Index: src/dlmalloc.cxx
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/src/dlmalloc.cxx,v
retrieving revision 1.8
diff -u -5 -p -w -r1.8 dlmalloc.cxx
--- src/dlmalloc.cxx 6 Oct 2003 18:25:57 -0000 1.8
+++ src/dlmalloc.cxx 24 Jun 2004 11:23:40 -0000
@@ -207,18 +207,24 @@
//----------------------------------------------------------------------------
/* Preliminaries */
+#include <cyg/kernel/kapi.h>
#include <pkgconf/memalloc.h> // configuration header
#include <pkgconf/infra.h> // CYGDBG_USE_ASSERTS
#include <cyg/infra/cyg_type.h> // types
#include <cyg/infra/cyg_ass.h> // assertions
#include <stddef.h> // for size_t
#include <cyg/memalloc/dlmalloc.hxx>
+
+#include <cyg/memalloc/kapi.h>
+
//#include <cyg/infra/diag.h>
+
+
/*
Debugging:
Because freed chunks may be overwritten with link fields, this
malloc will often die when freed memory is overwritten by user
@@ -1271,10 +1277,11 @@ Cyg_Mempool_dlmalloc_Implementation::try
if (chunksize(top) < nb || remainder_size < (long)MINSIZE)
{
//diag_printf("chunksize(top)=%ld, nb=%d, remainder=%ld\n", chunksize(top),
// nb, remainder_size);
MALLOC_UNLOCK;
+ CYG_MEMALLOC_FAIL_TEST(true, bytes);
return NULL; /* propagate failure */
}
victim = top;
set_head(victim, nb | PREV_INUSE);
@@ -1556,10 +1563,11 @@ Cyg_Mempool_dlmalloc_Implementation::res
}
}
// couldn't resize the allocation any direction, so return failure
MALLOC_UNLOCK;
+ CYG_MEMALLOC_FAIL_TEST(true, bytes);
return NULL;
}
split: /* split off extra room in old or expanded chunk */
Index: src/malloc.cxx
===================================================================
RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/src/malloc.cxx,v
retrieving revision 1.5
diff -u -5 -p -w -r1.5 malloc.cxx
--- src/malloc.cxx 23 May 2002 23:08:45 -0000 1.5
+++ src/malloc.cxx 24 Jun 2004 11:23:41 -0000
@@ -280,8 +280,11 @@ mallinfo( void )
CYG_REPORT_RETURN();
return ret;
} // mallinfo()
+
#endif // ifdef CYGPKG_MEMALLOC_MALLOC_ALLOCATORS
+
+
// EOF malloc.cxx
--- /dev/null 2004-06-24 13:23:53.455000000 +0200
+++ src/debug.c 2004-06-24 13:00:03.179331200 +0200
@@ -0,0 +1,71 @@
+//========================================================================
+//
+// debug.c
+//
+// default implementation of out of memory debug breakpoint site
+//
+//========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): oyvind
+// Contributors:
+// Date: 2000-06-17
+// Purpose:
+// Description: Memory usage debugging
+// Usage:
+//
+//####DESCRIPTIONEND####
+//
+//========================================================================
+
+// CONFIGURATION
+
+#include <pkgconf/memalloc.h> // Configuration header
+
+#include <cyg/infra/cyg_type.h> // Common type definitions and support
+#include <cyg/infra/cyg_trac.h> // Common tracing support
+#include <cyg/infra/cyg_ass.h> // Common assertion support
+#include <string.h> // For memset() and memmove()
+#include <stdlib.h> // header for this file
+
+#if CYGSEM_MEMALLOC_INVOKE_OUT_OF_MEMORY
+void cyg_memalloc_alloc_fail(char * file, int line, cyg_int32 size) __THROW
+{
+ // handy breakpoint site.
+}
+#endif
+
+// EOF debug.c