2011-11-02 12:38:39 +01:00
|
|
|
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */
|
2003-11-01 06:35:29 +01:00
|
|
|
/*
|
2009-01-18 17:37:44 +01:00
|
|
|
* Copyright 2001-2009 by Eric House (xwords@eehouse.org). All rights
|
|
|
|
* reserved.
|
2003-11-01 06:35:29 +01:00
|
|
|
*
|
|
|
|
* This program 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
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef MEM_DEBUG
|
|
|
|
|
|
|
|
#include "mempool.h"
|
|
|
|
#include "comtypes.h"
|
|
|
|
#include "xwstream.h"
|
|
|
|
|
2008-07-28 07:05:39 +02:00
|
|
|
/* #define MPOOL_DEBUG */
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
#ifdef CPLUS
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2016-04-09 20:54:08 +02:00
|
|
|
#ifndef MEMPOOL_SYNC_DECL
|
|
|
|
# include <pthread.h>
|
|
|
|
# define MEMPOOL_SYNC_DECL pthread_mutex_t mutex
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef MEMPOOL_SYNC_INIT
|
|
|
|
# define MEMPOOL_SYNC_INIT(mp) \
|
|
|
|
pthread_mutex_init( &((mp)->mutex), NULL )
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef MEMPOOL_SYNC_DESTROY
|
|
|
|
# define MEMPOOL_SYNC_DESTROY(mp) \
|
|
|
|
pthread_mutex_destroy( &((mp)->mutex ) )
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef MEMPOOL_SYNC_START
|
|
|
|
# define MEMPOOL_SYNC_START(mp) \
|
|
|
|
pthread_mutex_lock( &((mp)->mutex) )
|
|
|
|
#endif
|
|
|
|
#ifndef MEMPOOL_SYNC_END
|
|
|
|
# define MEMPOOL_SYNC_END(mp) \
|
|
|
|
pthread_mutex_unlock( &((mp)->mutex) )
|
|
|
|
#endif
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
typedef struct MemPoolEntry {
|
|
|
|
struct MemPoolEntry* next;
|
2006-09-15 09:32:04 +02:00
|
|
|
const char* fileName;
|
2009-01-18 17:37:44 +01:00
|
|
|
const char* func;
|
2003-11-01 06:35:29 +01:00
|
|
|
XP_U32 lineNo;
|
|
|
|
XP_U32 size;
|
|
|
|
void* ptr;
|
2012-09-06 04:08:22 +02:00
|
|
|
XP_U16 index;
|
2003-11-01 06:35:29 +01:00
|
|
|
} MemPoolEntry;
|
|
|
|
|
|
|
|
struct MemPoolCtx {
|
2016-04-09 20:54:08 +02:00
|
|
|
MEMPOOL_SYNC_DECL;
|
2003-11-01 06:35:29 +01:00
|
|
|
MemPoolEntry* freeList;
|
|
|
|
MemPoolEntry* usedList;
|
|
|
|
|
|
|
|
XP_U16 nFree;
|
|
|
|
XP_U16 nUsed;
|
|
|
|
XP_U16 nAllocs;
|
2021-03-05 18:46:21 +01:00
|
|
|
XP_U32 maxBytes;
|
|
|
|
XP_U32 curBytes;
|
2015-02-10 04:15:43 +01:00
|
|
|
|
|
|
|
XP_UCHAR tag[64];
|
2003-11-01 06:35:29 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
MemPoolCtx*
|
2015-02-10 04:15:43 +01:00
|
|
|
mpool_make( const XP_UCHAR* tag )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
MemPoolCtx* result = (MemPoolCtx*)XP_PLATMALLOC( sizeof(*result) );
|
|
|
|
XP_MEMSET( result, 0, sizeof(*result) );
|
2016-04-09 20:54:08 +02:00
|
|
|
MEMPOOL_SYNC_INIT(result);
|
2015-02-10 04:15:43 +01:00
|
|
|
mpool_setTag( result, tag );
|
2003-11-01 06:35:29 +01:00
|
|
|
return result;
|
|
|
|
} /* mpool_make */
|
|
|
|
|
2015-02-10 04:15:43 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
mpool_setTag( MemPoolCtx* mpool, const XP_UCHAR* tag )
|
|
|
|
{
|
|
|
|
if ( !!tag ) {
|
|
|
|
if( !!mpool->tag[0] ) {
|
|
|
|
XP_LOGF( "%s: tag changing from %s to %s", __func__,
|
|
|
|
mpool->tag, tag );
|
|
|
|
}
|
|
|
|
XP_ASSERT( XP_STRLEN(tag) < sizeof(mpool->tag) + 1 );
|
|
|
|
XP_MEMCPY( &mpool->tag, tag, XP_STRLEN(tag) + 1 );
|
|
|
|
} else {
|
|
|
|
mpool->tag[0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const XP_UCHAR*
|
|
|
|
mpool_getTag( const MemPoolCtx* mpool )
|
|
|
|
{
|
|
|
|
return mpool->tag;
|
|
|
|
}
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static void
|
|
|
|
freeList( MemPoolEntry* entry )
|
|
|
|
{
|
|
|
|
while ( !!entry ) {
|
|
|
|
MemPoolEntry* next = entry->next;
|
|
|
|
|
|
|
|
XP_ASSERT( !entry->ptr );
|
|
|
|
XP_PLATFREE( entry );
|
|
|
|
|
|
|
|
entry = next;
|
|
|
|
}
|
|
|
|
} /* freeList */
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
static char*
|
|
|
|
checkIsText( MemPoolEntry* entry )
|
|
|
|
{
|
|
|
|
unsigned char* txt = (unsigned char*)entry->ptr;
|
|
|
|
XP_U32 len = entry->size;
|
2013-01-06 01:08:47 +01:00
|
|
|
char* result = NULL;
|
|
|
|
|
|
|
|
if ( 0 < len ) {
|
|
|
|
while ( len-- ) {
|
|
|
|
unsigned char c = *txt++;
|
|
|
|
if ( c < 32 || c > 127 ) {
|
|
|
|
if ( len == 0 && c == '\0' ) {
|
|
|
|
result = (char*)entry->ptr;
|
|
|
|
}
|
|
|
|
break;
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-06 01:08:47 +01:00
|
|
|
return result;
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* checkIsText */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
|
|
|
mpool_destroy( MemPoolCtx* mpool )
|
|
|
|
{
|
2008-07-28 07:05:39 +02:00
|
|
|
if ( mpool->nUsed > 0 ) {
|
2012-09-06 04:08:22 +02:00
|
|
|
XP_WARNF( "leaking %d blocks (of %d allocs)", mpool->nUsed,
|
|
|
|
mpool->nAllocs );
|
2008-07-28 07:05:39 +02:00
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
if ( !!mpool->usedList ) {
|
|
|
|
MemPoolEntry* entry;
|
|
|
|
for ( entry = mpool->usedList; !!entry; entry = entry->next ) {
|
2008-05-31 05:26:16 +02:00
|
|
|
#ifndef FOR_GREMLINS /* I don't want to hear about this right now */
|
2014-01-07 15:58:20 +01:00
|
|
|
XP_LOGF( "%s: " XP_P " index=%d, in %s, ln %d of %s\n", __func__,
|
2012-09-06 04:08:22 +02:00
|
|
|
entry->ptr, entry->index,
|
|
|
|
entry->func, entry->lineNo, entry->fileName );
|
2008-05-31 05:26:16 +02:00
|
|
|
#ifdef DEBUG
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
char* tryTxt;
|
|
|
|
tryTxt = checkIsText( entry );
|
|
|
|
if ( !!tryTxt ) {
|
|
|
|
XP_WARNF( "--- looks like text: %s\n", tryTxt );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef FOR_GREMLINS
|
2016-04-09 20:54:08 +02:00
|
|
|
XP_ASSERT( !mpool->usedList );
|
|
|
|
XP_ASSERT( mpool->nUsed == 0 );
|
2003-11-01 06:35:29 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
freeList( mpool->freeList );
|
2016-04-09 20:54:08 +02:00
|
|
|
MEMPOOL_SYNC_DESTROY(mpool);
|
2003-11-01 06:35:29 +01:00
|
|
|
XP_PLATFREE( mpool );
|
|
|
|
} /* mpool_destroy */
|
|
|
|
|
|
|
|
void*
|
2009-01-18 17:37:44 +01:00
|
|
|
mpool_alloc( MemPoolCtx* mpool, XP_U32 size, const char* file,
|
|
|
|
const char* func, XP_U32 lineNo )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
MemPoolEntry* entry;
|
2016-04-09 20:54:08 +02:00
|
|
|
void* result = NULL;
|
|
|
|
MEMPOOL_SYNC_START(mpool);
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
if ( mpool->nFree > 0 ) {
|
|
|
|
entry = mpool->freeList;
|
|
|
|
mpool->freeList = entry->next;
|
|
|
|
--mpool->nFree;
|
|
|
|
} else {
|
|
|
|
entry = (MemPoolEntry*)XP_PLATMALLOC( sizeof(*entry) );
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->next = mpool->usedList;
|
|
|
|
mpool->usedList = entry;
|
|
|
|
|
|
|
|
entry->fileName = file;
|
2009-01-18 17:37:44 +01:00
|
|
|
entry->func = func;
|
2003-11-01 06:35:29 +01:00
|
|
|
entry->lineNo = lineNo;
|
|
|
|
entry->size = size;
|
|
|
|
entry->ptr = XP_PLATMALLOC( size );
|
|
|
|
XP_ASSERT( !!entry->ptr );
|
2012-09-06 04:08:22 +02:00
|
|
|
entry->index = ++mpool->nAllocs;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
++mpool->nUsed;
|
2021-03-05 18:46:21 +01:00
|
|
|
mpool->curBytes += size;
|
|
|
|
if ( mpool->curBytes > mpool->maxBytes ) {
|
|
|
|
mpool->maxBytes = mpool->curBytes;
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-07-28 07:05:39 +02:00
|
|
|
#ifdef MPOOL_DEBUG
|
2012-09-06 04:08:22 +02:00
|
|
|
XP_LOGF( "%s(size=%ld,index=%d,file=%s,lineNo=%ld)=>%p",
|
|
|
|
__func__, size, entry->index, file, lineNo, entry->ptr );
|
2008-07-28 07:05:39 +02:00
|
|
|
#endif
|
|
|
|
|
2016-04-09 20:54:08 +02:00
|
|
|
result = entry->ptr;
|
|
|
|
MEMPOOL_SYNC_END(mpool);
|
|
|
|
|
|
|
|
return result;
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* mpool_alloc */
|
|
|
|
|
2010-01-02 02:42:07 +01:00
|
|
|
void*
|
|
|
|
mpool_calloc( MemPoolCtx* mpool, XP_U32 size, const char* file,
|
|
|
|
const char* func, XP_U32 lineNo )
|
|
|
|
{
|
|
|
|
void* ptr = mpool_alloc( mpool, size, file, func, lineNo );
|
|
|
|
XP_MEMSET( ptr, 0, size );
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
static MemPoolEntry*
|
|
|
|
findEntryFor( MemPoolCtx* mpool, void* ptr, MemPoolEntry** prevP )
|
|
|
|
{
|
|
|
|
MemPoolEntry* entry;
|
|
|
|
MemPoolEntry* prev;
|
|
|
|
|
|
|
|
for ( prev = (MemPoolEntry*)NULL, entry = mpool->usedList; !!entry;
|
|
|
|
prev = entry, entry = prev->next ) {
|
|
|
|
|
|
|
|
if ( entry->ptr == ptr ) {
|
|
|
|
|
|
|
|
if ( !!prevP ) {
|
|
|
|
*prevP = prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (MemPoolEntry*)NULL;
|
|
|
|
} /* findEntryFor */
|
|
|
|
|
|
|
|
void*
|
2009-01-18 17:37:44 +01:00
|
|
|
mpool_realloc( MemPoolCtx* mpool, void* ptr, XP_U32 newsize, const char* file,
|
|
|
|
const char* func, XP_U32 lineNo )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2018-07-06 06:40:56 +02:00
|
|
|
// XP_LOGF( "%s(func=%s, line=%d): newsize: %d", __func__, func, lineNo, newsize );
|
|
|
|
void* result;
|
|
|
|
if ( ptr == NULL ) {
|
|
|
|
result = mpool_alloc( mpool, newsize, file, func, lineNo );
|
2007-11-22 06:04:40 +01:00
|
|
|
} else {
|
2018-07-06 06:40:56 +02:00
|
|
|
MemPoolEntry* entry = findEntryFor( mpool, ptr, (MemPoolEntry**)NULL );
|
|
|
|
|
|
|
|
if ( !entry ) {
|
|
|
|
XP_LOGF( "findEntryFor failed; called from %s, line %d",
|
|
|
|
file, lineNo );
|
|
|
|
} else {
|
|
|
|
entry->ptr = XP_PLATREALLOC( entry->ptr, newsize );
|
|
|
|
XP_ASSERT( !!entry->ptr );
|
|
|
|
entry->fileName = file;
|
|
|
|
entry->func = func;
|
|
|
|
entry->lineNo = lineNo;
|
2021-03-09 16:45:33 +01:00
|
|
|
mpool->curBytes += newsize - entry->size;
|
|
|
|
if ( mpool->curBytes > mpool->maxBytes ) {
|
|
|
|
mpool->maxBytes = mpool->curBytes;
|
|
|
|
}
|
2018-07-06 06:40:56 +02:00
|
|
|
entry->size = newsize;
|
|
|
|
}
|
|
|
|
result = entry->ptr;
|
2007-11-22 06:04:40 +01:00
|
|
|
}
|
2018-07-06 06:40:56 +02:00
|
|
|
return result;
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* mpool_realloc */
|
|
|
|
|
|
|
|
void
|
2009-01-18 17:37:44 +01:00
|
|
|
mpool_free( MemPoolCtx* mpool, void* ptr, const char* file,
|
|
|
|
const char* func, XP_U32 lineNo )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
MemPoolEntry* entry;
|
|
|
|
MemPoolEntry* prev;
|
|
|
|
|
2016-04-09 20:54:08 +02:00
|
|
|
MEMPOOL_SYNC_START(mpool);
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
entry = findEntryFor( mpool, ptr, &prev );
|
|
|
|
|
2007-11-22 06:04:40 +01:00
|
|
|
if ( !entry ) {
|
2014-01-07 15:58:20 +01:00
|
|
|
XP_LOGF( "findEntryFor failed; called from %s, line %d in %s",
|
2009-01-18 17:37:44 +01:00
|
|
|
func, lineNo, file );
|
2013-07-09 16:19:20 +02:00
|
|
|
XP_ASSERT( 0 );
|
2007-11-22 06:04:40 +01:00
|
|
|
} else {
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2008-07-28 07:05:39 +02:00
|
|
|
#ifdef MPOOL_DEBUG
|
2012-09-06 04:08:22 +02:00
|
|
|
XP_LOGF( "%s(ptr=%p):size=%ld,index=%d,func=%s,file=%s,lineNo=%ld)", __func__,
|
|
|
|
entry->ptr, entry->size, entry->index, entry->func, entry->fileName,
|
2009-01-18 17:37:44 +01:00
|
|
|
entry->lineNo );
|
2008-07-28 07:05:39 +02:00
|
|
|
#endif
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
if ( !!prev ) {
|
|
|
|
prev->next = entry->next;
|
|
|
|
} else {
|
|
|
|
mpool->usedList = entry->next;
|
|
|
|
}
|
2021-03-05 18:46:21 +01:00
|
|
|
mpool->curBytes -= entry->size;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
XP_MEMSET( entry->ptr, 0x00, entry->size );
|
|
|
|
XP_PLATFREE( entry->ptr );
|
|
|
|
entry->ptr = NULL;
|
|
|
|
|
|
|
|
entry->next = mpool->freeList;
|
|
|
|
mpool->freeList = entry;
|
|
|
|
|
|
|
|
++mpool->nFree;
|
|
|
|
--mpool->nUsed;
|
|
|
|
}
|
2016-04-09 20:54:08 +02:00
|
|
|
MEMPOOL_SYNC_END(mpool);
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* mpool_free */
|
|
|
|
|
2011-04-08 03:07:45 +02:00
|
|
|
void
|
|
|
|
mpool_freep( MemPoolCtx* mpool, void** ptr, const char* file,
|
|
|
|
const char* func, XP_U32 lineNo )
|
|
|
|
{
|
|
|
|
if ( !!*ptr ) {
|
|
|
|
mpool_free( mpool, *ptr, file, func, lineNo );
|
|
|
|
*ptr = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-18 17:37:44 +01:00
|
|
|
#define STREAM_OR_LOG(stream,buf) \
|
|
|
|
if ( !!stream ) { \
|
2009-03-29 20:26:59 +02:00
|
|
|
stream_catString( stream, buf ); \
|
2009-01-18 17:37:44 +01:00
|
|
|
} else { \
|
|
|
|
XP_LOGF( "%s", buf ); \
|
|
|
|
} \
|
|
|
|
|
2021-03-05 18:46:21 +01:00
|
|
|
XP_Bool
|
|
|
|
mpool_getStats( const MemPoolCtx* mpool, MPStatsBuf* io )
|
|
|
|
{
|
|
|
|
XP_Bool changed = XP_FALSE;
|
|
|
|
|
|
|
|
if ( io->curBytes != mpool->curBytes ) {
|
|
|
|
changed = XP_TRUE;
|
|
|
|
io->curBytes = mpool->curBytes;
|
|
|
|
}
|
|
|
|
if ( io->maxBytes != mpool->maxBytes ) {
|
|
|
|
changed = XP_TRUE;
|
|
|
|
io->maxBytes = mpool->maxBytes;
|
|
|
|
}
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
void
|
|
|
|
mpool_stats( MemPoolCtx* mpool, XWStreamCtxt* stream )
|
|
|
|
{
|
|
|
|
XP_UCHAR buf[128];
|
|
|
|
MemPoolEntry* entry;
|
2009-01-18 17:37:44 +01:00
|
|
|
XP_U32 total = 0;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
XP_SNPRINTF( buf, sizeof(buf), (XP_UCHAR*)"Number of blocks in use: %d\n"
|
|
|
|
"Number of free blocks: %d\n"
|
|
|
|
"Total number of blocks allocated: %d\n",
|
|
|
|
mpool->nUsed, mpool->nFree, mpool->nAllocs );
|
2009-01-18 17:37:44 +01:00
|
|
|
STREAM_OR_LOG( stream, buf );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
for ( entry = mpool->usedList; !!entry; entry = entry->next ) {
|
|
|
|
XP_SNPRINTF( buf, sizeof(buf),
|
2014-01-07 15:58:20 +01:00
|
|
|
(XP_UCHAR*)"%d byte block allocated at %p, at line %d "
|
2009-01-18 17:37:44 +01:00
|
|
|
"in %s, %s\n", entry->size, entry->ptr, entry->lineNo,
|
|
|
|
entry->func, entry->fileName );
|
|
|
|
STREAM_OR_LOG( stream, buf );
|
|
|
|
total += entry->size;
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
2009-01-18 17:37:44 +01:00
|
|
|
|
2014-01-07 15:58:20 +01:00
|
|
|
XP_SNPRINTF( buf, sizeof(buf), "total bytes allocated: %d\n", total );
|
2009-01-18 17:37:44 +01:00
|
|
|
STREAM_OR_LOG( stream, buf );
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* mpool_stats */
|
|
|
|
|
|
|
|
XP_U16
|
|
|
|
mpool_getNUsed( MemPoolCtx* mpool )
|
|
|
|
{
|
|
|
|
return mpool->nUsed;
|
|
|
|
} /* mpool_getNUsed */
|
|
|
|
|
|
|
|
#ifdef CPLUS
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* MEM_DEBUG */
|