From 3e2a8a9fc6d81bcd0e6cb057f48e05c685cb23a4 Mon Sep 17 00:00:00 2001 From: Przemyslaw Czerpak Date: Wed, 12 Nov 2008 22:15:28 +0000 Subject: [PATCH] 2008-11-12 23:16 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/source/vm/fm.c + added support for enabling/disabling memory statistic when application starts. To enable memory statistic it's enough to set HB_FM_STAT environment variable to non empty value. To disable memory statistic it's enough to set HB_NO_FM_STAT envvar. The default setting may depend on build time option. Now is enabled when memory statistic is compiled when harbour is created. It may not work if C compiler does not allow to check environment variables from startup code. F.e. functions to access environment can be also part of dynamic library registered after harbour.dll or harbour core code startup functions. Viktor I would like to ask you only about one thing. Please do not remove current support for HB_FM_STATISTICS_OFF from GNU make builds so Harbour user can still create binaries without any memory statistic code using -[no]fmstat switch in hb* scripts. The above feature is only for users who need support for enabling/disabling memory statistic to test application if foreign environment, f.e. at client computers. Of course if it will work with given C compiler and/or type of application (linked dynamically or statically). Please check. --- harbour/ChangeLog | 23 +++ harbour/source/rtl/hbgtcore.c | 25 +++ harbour/source/vm/fm.c | 276 ++++++++++++++++++++-------------- 3 files changed, 210 insertions(+), 114 deletions(-) diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 9906612568..b59be47002 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,29 @@ 2008-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org) */ +2008-11-12 23:16 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/source/vm/fm.c + + added support for enabling/disabling memory statistic when + application starts. To enable memory statistic it's enough + to set HB_FM_STAT environment variable to non empty value. + To disable memory statistic it's enough to set HB_NO_FM_STAT + envvar. The default setting may depend on build time option. + Now is enabled when memory statistic is compiled when harbour + is created. It may not work if C compiler does not allow to + check environment variables from startup code. F.e. functions + to access environment can be also part of dynamic library + registered after harbour.dll or harbour core code startup + functions. + Viktor I would like to ask you only about one thing. + Please do not remove current support for HB_FM_STATISTICS_OFF + from GNU make builds so Harbour user can still create binaries + without any memory statistic code using -[no]fmstat switch in + hb* scripts. The above feature is only for users who need support + for enabling/disabling memory statistic to test application + if foreign environment, f.e. at client computers. Of course if + it will work with given C compiler and/or type of application + (linked dynamically or statically). Please check. + 2008-11-12 20:03 UTC+0100 Viktor Szakats (harbour.01 syenar hu) * doc/linux1st.txt * Updated for Ubuntu 8.10. diff --git a/harbour/source/rtl/hbgtcore.c b/harbour/source/rtl/hbgtcore.c index c0250df814..7151901bab 100644 --- a/harbour/source/rtl/hbgtcore.c +++ b/harbour/source/rtl/hbgtcore.c @@ -3410,3 +3410,28 @@ HB_FUNC( HB_GTSELECT ) hb_retptrGC( gtHolder ); } } + + +HB_FUNC( HB_GTINFOEX ) +{ + if( ISPOINTER( 1 ) && ISNUM( 2 ) ) + { + PHB_GT pGT = hb_gt_ItemBase( hb_param( 1, HB_IT_ANY ) ); + + if( pGT ) + { + HB_GT_INFO gtInfo; + gtInfo.pNewVal = hb_param( 3, HB_IT_ANY ); + gtInfo.pNewVal2 = hb_param( 4, HB_IT_ANY ); + gtInfo.pResult = NULL; + + HB_GTSELF_INFO( pGT, hb_parni( 2 ), >Info ); + hb_gt_BaseFree( pGT ); + + if( gtInfo.pResult ) + hb_itemReturnRelease( gtInfo.pResult ); + } + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} diff --git a/harbour/source/vm/fm.c b/harbour/source/vm/fm.c index 20c65e662b..99cb70c06b 100644 --- a/harbour/source/vm/fm.c +++ b/harbour/source/vm/fm.c @@ -108,6 +108,11 @@ #endif #endif +#if defined( HB_FM_STATISTICS_OFF ) +# undef HB_FM_STATISTICS +#endif + + /* #define HB_FM_WIN32_ALLOC */ /* #define HB_FM_STATISTICS */ /* #define HB_PARANOID_MEM_CHECK */ @@ -193,25 +198,32 @@ typedef struct _HB_MEMINFO } HB_MEMINFO, * PHB_MEMINFO; #ifdef HB_ALLOC_ALIGNMENT -# define HB_MEMINFO_SIZE ( ( ( sizeof( HB_MEMINFO ) + HB_ALLOC_ALIGNMENT - 1 ) - \ +# define _HB_MEMINFO_SIZE ( ( ( sizeof( HB_MEMINFO ) + HB_ALLOC_ALIGNMENT - 1 ) - \ ( sizeof( HB_MEMINFO ) + HB_ALLOC_ALIGNMENT - 1 ) % HB_ALLOC_ALIGNMENT ) + \ HB_COUNTER_OFFSET ) #else -# define HB_MEMINFO_SIZE ( sizeof( HB_MEMINFO ) + HB_COUNTER_OFFSET ) +# define _HB_MEMINFO_SIZE ( sizeof( HB_MEMINFO ) + HB_COUNTER_OFFSET ) #endif -#define HB_ALLOC_SIZE( n ) ( ( n ) + HB_MEMINFO_SIZE + sizeof( UINT32 ) ) +#define HB_MEMINFO_SIZE ( s_fStatistic ? sizeof( HB_MEMINFO ) + HB_COUNTER_OFFSET : HB_COUNTER_OFFSET ) + +#define HB_FM_GETSIG( p, n ) HB_GET_UINT32( ( BYTE * ) ( p ) + ( n ) ) +#define HB_FM_SETSIG( p, n ) HB_PUT_UINT32( ( BYTE * ) ( p ) + ( n ), HB_MEMINFO_SIGNATURE ) +#define HB_FM_CLRSIG( p, n ) HB_PUT_UINT32( ( BYTE * ) ( p ) + ( n ), 0 ) + +#define HB_ALLOC_SIZE( n ) ( ( n ) + ( s_fStatistic ? _HB_MEMINFO_SIZE + sizeof( UINT32 ) : HB_COUNTER_OFFSET ) ) #define HB_FM_PTR( p ) ( ( PHB_MEMINFO ) ( ( BYTE * ) ( p ) - HB_MEMINFO_SIZE ) ) -#define HB_FM_GETSIG( p, n ) HB_GET_UINT32( ( BYTE * )( p ) + ( n ) ) -#define HB_FM_SETSIG( p, n ) HB_PUT_UINT32( ( BYTE * )( p ) + ( n ), HB_MEMINFO_SIGNATURE ) -#define HB_FM_CLRSIG( p, n ) HB_PUT_UINT32( ( BYTE * )( p ) + ( n ), 0 ) +#define HB_FM_BLOCKSIZE( p ) ( s_fStatistic ? HB_FM_PTR( pMem )->ulSize : 0 ) /* NOTE: we cannot use here HB_TRACE because it will overwrite the * function name/line number of code which called hb_xalloc/hb_xgrab */ #define HB_TRACE_FM HB_TRACE_STEALTH +static BOOL s_fInited = FALSE; +static BOOL s_fStatistic = FALSE; + static LONG s_lMemoryBlocks = 0; /* memory blocks used */ static LONG s_lMemoryMaxBlocks = 0; /* maximum number of used memory blocks */ static LONG s_lMemoryMaxConsumed = 0; /* memory size consumed */ @@ -296,7 +308,6 @@ void hb_xsetinfo( char * szValue ) #endif } - void * hb_xalloc( ULONG ulSize ) /* allocates fixed memory, returns NULL on failure */ { PHB_MEMINFO pMem; @@ -306,6 +317,11 @@ void * hb_xalloc( ULONG ulSize ) /* allocates fixed memory, returns NULL if( ulSize == 0 ) hb_errInternal( HB_EI_XALLOCNULLSIZE, NULL, NULL, NULL ); +#ifdef HB_FM_STATISTICS + if( !s_fInited ) + hb_xinit(); +#endif + pMem = ( PHB_MEMINFO ) malloc( HB_ALLOC_SIZE( ulSize ) ); if( ! pMem ) @@ -313,54 +329,58 @@ void * hb_xalloc( ULONG ulSize ) /* allocates fixed memory, returns NULL #ifdef HB_FM_STATISTICS - HB_FM_LOCK - - if( ! s_pFirstBlock ) + if( s_fStatistic ) { - pMem->pPrevBlock = NULL; - s_pFirstBlock = pMem; - } - else - { - pMem->pPrevBlock = s_pLastBlock; - s_pLastBlock->pNextBlock = pMem; - } - s_pLastBlock = pMem; + HB_FM_LOCK - pMem->pNextBlock = NULL; - pMem->u32Signature = HB_MEMINFO_SIGNATURE; - HB_FM_SETSIG( HB_MEM_PTR( pMem ), ulSize ); - pMem->ulSize = ulSize; /* size of the memory block */ + if( ! s_pFirstBlock ) + { + pMem->pPrevBlock = NULL; + s_pFirstBlock = pMem; + } + else + { + pMem->pPrevBlock = s_pLastBlock; + s_pLastBlock->pNextBlock = pMem; + } + s_pLastBlock = pMem; - if( hb_tr_level() >= HB_TR_DEBUG ) - { - /* NOTE: PRG line number/procname is not very useful during hunting - * for memory leaks - this is why we are using the previously stored - * function/line info - this is a location of code that called - * hb_xalloc/hb_xgrab - */ - pMem->uiProcLine = hb_tr_line_; /* C line number */ - hb_strncpy( pMem->szProcName, hb_tr_file_, sizeof( pMem->szProcName ) - 1 ); - } - else - { - hb_stackBaseProcInfo( pMem->szProcName, &pMem->uiProcLine ); - } + pMem->pNextBlock = NULL; + pMem->u32Signature = HB_MEMINFO_SIGNATURE; + HB_FM_SETSIG( HB_MEM_PTR( pMem ), ulSize ); + pMem->ulSize = ulSize; /* size of the memory block */ - s_lMemoryConsumed += ulSize + sizeof( HB_COUNTER ); - if( s_lMemoryMaxConsumed < s_lMemoryConsumed ) - s_lMemoryMaxConsumed = s_lMemoryConsumed; - s_lMemoryBlocks++; - if( s_lMemoryMaxBlocks < s_lMemoryBlocks ) - s_lMemoryMaxBlocks = s_lMemoryBlocks; + if( hb_tr_level() >= HB_TR_DEBUG ) + { + /* NOTE: PRG line number/procname is not very useful during hunting + * for memory leaks - this is why we are using the previously stored + * function/line info - this is a location of code that called + * hb_xalloc/hb_xgrab + */ + pMem->uiProcLine = hb_tr_line_; /* C line number */ + hb_strncpy( pMem->szProcName, hb_tr_file_, sizeof( pMem->szProcName ) - 1 ); + } + else + { + hb_stackBaseProcInfo( pMem->szProcName, &pMem->uiProcLine ); + } - HB_FM_UNLOCK + s_lMemoryConsumed += ulSize + sizeof( HB_COUNTER ); + if( s_lMemoryMaxConsumed < s_lMemoryConsumed ) + s_lMemoryMaxConsumed = s_lMemoryConsumed; + s_lMemoryBlocks++; + if( s_lMemoryMaxBlocks < s_lMemoryBlocks ) + s_lMemoryMaxBlocks = s_lMemoryBlocks; + + HB_FM_UNLOCK #ifdef HB_PARANOID_MEM_CHECK - memset( HB_MEM_PTR( pMem ), HB_MEMFILER, ulSize ); + memset( HB_MEM_PTR( pMem ), HB_MEMFILER, ulSize ); #endif -#endif + } + +#endif /* HB_FM_STATISTICS */ HB_ATOM_SET( HB_COUNTER_PTR( HB_MEM_PTR( pMem ) ), 1 ); @@ -376,6 +396,11 @@ void * hb_xgrab( ULONG ulSize ) /* allocates fixed memory, exits on fail if( ulSize == 0 ) hb_errInternal( HB_EI_XGRABNULLSIZE, NULL, NULL, NULL ); +#ifdef HB_FM_STATISTICS + if( !s_fInited ) + hb_xinit(); +#endif + pMem = ( PHB_MEMINFO ) malloc( HB_ALLOC_SIZE( ulSize ) ); if( ! pMem ) @@ -383,54 +408,58 @@ void * hb_xgrab( ULONG ulSize ) /* allocates fixed memory, exits on fail #ifdef HB_FM_STATISTICS - HB_FM_LOCK - - if( ! s_pFirstBlock ) + if( s_fStatistic ) { - pMem->pPrevBlock = NULL; - s_pFirstBlock = pMem; - } - else - { - pMem->pPrevBlock = s_pLastBlock; - s_pLastBlock->pNextBlock = pMem; - } - s_pLastBlock = pMem; + HB_FM_LOCK - pMem->pNextBlock = NULL; - pMem->u32Signature = HB_MEMINFO_SIGNATURE; - HB_FM_SETSIG( HB_MEM_PTR( pMem ), ulSize ); - pMem->ulSize = ulSize; /* size of the memory block */ + if( ! s_pFirstBlock ) + { + pMem->pPrevBlock = NULL; + s_pFirstBlock = pMem; + } + else + { + pMem->pPrevBlock = s_pLastBlock; + s_pLastBlock->pNextBlock = pMem; + } + s_pLastBlock = pMem; - if( hb_tr_level() >= HB_TR_DEBUG ) - { - /* NOTE: PRG line number/procname is not very useful during hunting - * for memory leaks - this is why we are using the previously stored - * function/line info - this is a location of code that called - * hb_xalloc/hb_xgrab - */ - pMem->uiProcLine = hb_tr_line_; /* C line number */ - hb_strncpy( pMem->szProcName, hb_tr_file_, sizeof( pMem->szProcName ) - 1 ); - } - else - { - hb_stackBaseProcInfo( pMem->szProcName, &pMem->uiProcLine ); - } + pMem->pNextBlock = NULL; + pMem->u32Signature = HB_MEMINFO_SIGNATURE; + HB_FM_SETSIG( HB_MEM_PTR( pMem ), ulSize ); + pMem->ulSize = ulSize; /* size of the memory block */ - s_lMemoryConsumed += ulSize + sizeof( HB_COUNTER ); - if( s_lMemoryMaxConsumed < s_lMemoryConsumed ) - s_lMemoryMaxConsumed = s_lMemoryConsumed; - s_lMemoryBlocks++; - if( s_lMemoryMaxBlocks < s_lMemoryBlocks ) - s_lMemoryMaxBlocks = s_lMemoryBlocks; + if( hb_tr_level() >= HB_TR_DEBUG ) + { + /* NOTE: PRG line number/procname is not very useful during hunting + * for memory leaks - this is why we are using the previously stored + * function/line info - this is a location of code that called + * hb_xalloc/hb_xgrab + */ + pMem->uiProcLine = hb_tr_line_; /* C line number */ + hb_strncpy( pMem->szProcName, hb_tr_file_, sizeof( pMem->szProcName ) - 1 ); + } + else + { + hb_stackBaseProcInfo( pMem->szProcName, &pMem->uiProcLine ); + } - HB_FM_UNLOCK + s_lMemoryConsumed += ulSize + sizeof( HB_COUNTER ); + if( s_lMemoryMaxConsumed < s_lMemoryConsumed ) + s_lMemoryMaxConsumed = s_lMemoryConsumed; + s_lMemoryBlocks++; + if( s_lMemoryMaxBlocks < s_lMemoryBlocks ) + s_lMemoryMaxBlocks = s_lMemoryBlocks; + + HB_FM_UNLOCK #ifdef HB_PARANOID_MEM_CHECK - memset( HB_MEM_PTR( pMem ), HB_MEMFILER, ulSize ); + memset( HB_MEM_PTR( pMem ), HB_MEMFILER, ulSize ); #endif -#endif + } + +#endif /* HB_FM_STATISTICS */ HB_ATOM_SET( HB_COUNTER_PTR( HB_MEM_PTR( pMem ) ), 1 ); @@ -462,7 +491,7 @@ void * hb_xrealloc( void * pMem, ULONG ulSize ) /* reallocates memory */ hb_xfree( pMem ); return NULL; } - else + else if( s_fStatistic ) { PHB_MEMINFO pMemBlock; ULONG ulMemSize; @@ -519,10 +548,13 @@ void * hb_xrealloc( void * pMem, ULONG ulSize ) /* reallocates memory */ } HB_FM_UNLOCK - - if( ! pMem ) - hb_errInternal( HB_EI_XREALLOC, NULL, NULL, NULL ); } + else + pMem = realloc( HB_FM_PTR( pMem ), HB_ALLOC_SIZE( ulSize ) ); + + if( ! pMem ) + hb_errInternal( HB_EI_XREALLOC, NULL, NULL, NULL ); + #else if( pMem == NULL ) @@ -559,35 +591,37 @@ void hb_xfree( void * pMem ) /* frees fixed memory */ PHB_MEMINFO pMemBlock = HB_FM_PTR( pMem ); - if( pMemBlock->u32Signature != HB_MEMINFO_SIGNATURE ) - hb_errInternal( HB_EI_XFREEINV, NULL, NULL, NULL ); + if( s_fStatistic ) + { + if( pMemBlock->u32Signature != HB_MEMINFO_SIGNATURE ) + hb_errInternal( HB_EI_XFREEINV, NULL, NULL, NULL ); - if( HB_FM_GETSIG( pMem, pMemBlock->ulSize ) != HB_MEMINFO_SIGNATURE ) - hb_errInternal( HB_EI_XMEMOVERFLOW, NULL, NULL, NULL ); + if( HB_FM_GETSIG( pMem, pMemBlock->ulSize ) != HB_MEMINFO_SIGNATURE ) + hb_errInternal( HB_EI_XMEMOVERFLOW, NULL, NULL, NULL ); - HB_FM_LOCK + HB_FM_LOCK - s_lMemoryConsumed -= pMemBlock->ulSize + sizeof( HB_COUNTER ); - s_lMemoryBlocks--; + s_lMemoryConsumed -= pMemBlock->ulSize + sizeof( HB_COUNTER ); + s_lMemoryBlocks--; - if( pMemBlock->pPrevBlock ) - pMemBlock->pPrevBlock->pNextBlock = pMemBlock->pNextBlock; - else - s_pFirstBlock = pMemBlock->pNextBlock; + if( pMemBlock->pPrevBlock ) + pMemBlock->pPrevBlock->pNextBlock = pMemBlock->pNextBlock; + else + s_pFirstBlock = pMemBlock->pNextBlock; - if( pMemBlock->pNextBlock ) - pMemBlock->pNextBlock->pPrevBlock = pMemBlock->pPrevBlock; - else - s_pLastBlock = pMemBlock->pPrevBlock; + if( pMemBlock->pNextBlock ) + pMemBlock->pNextBlock->pPrevBlock = pMemBlock->pPrevBlock; + else + s_pLastBlock = pMemBlock->pPrevBlock; - HB_FM_UNLOCK - - pMemBlock->u32Signature = 0; - HB_FM_CLRSIG( pMem, pMemBlock->ulSize ); + HB_FM_UNLOCK + pMemBlock->u32Signature = 0; + HB_FM_CLRSIG( pMem, pMemBlock->ulSize ); #ifdef HB_PARANOID_MEM_CHECK - memset( pMemBlock, HB_MEMFILER, HB_ALLOC_SIZE( pMemBlock->ulSize ) ); + memset( pMemBlock, HB_MEMFILER, HB_ALLOC_SIZE( pMemBlock->ulSize ) ); #endif + } free( ( void * ) pMemBlock ); @@ -621,7 +655,7 @@ void hb_xRefFree( void * pMem ) { #ifdef HB_FM_STATISTICS - if( HB_FM_PTR( pMem )->u32Signature != HB_MEMINFO_SIGNATURE ) + if( s_fStatistic && HB_FM_PTR( pMem )->u32Signature != HB_MEMINFO_SIGNATURE ) hb_errInternal( HB_EI_XFREEINV, NULL, NULL, NULL ); if( HB_ATOM_DEC( HB_COUNTER_PTR( pMem ) ) == 0 ) @@ -695,7 +729,7 @@ ULONG hb_xsize( void * pMem ) /* returns the size of an allocated memory block HB_TRACE(HB_TR_DEBUG, ("hb_xsize(%p)", pMem)); #ifdef HB_FM_STATISTICS - return HB_FM_PTR( pMem )->ulSize; + return HB_FM_BLOCKSIZE( pMem ); #else HB_SYMBOL_UNUSED( pMem ); @@ -706,6 +740,20 @@ ULONG hb_xsize( void * pMem ) /* returns the size of an allocated memory block void hb_xinit( void ) /* Initialize fixed memory subsystem */ { HB_TRACE(HB_TR_DEBUG, ("hb_xinit()")); + +#ifdef HB_FM_STATISTICS + if( !s_fInited ) + { + if( hb_getenv_buffer( "HB_FM_STAT", NULL, 0 ) ) + s_fStatistic = TRUE; + else if( hb_getenv_buffer( "HB_NO_FM_STAT", NULL, 0 ) ) + s_fStatistic = FALSE; + else + s_fStatistic = TRUE; /* enabled by default */ + + s_fInited = TRUE; + } +#endif } /* Returns pointer to string containing printable version @@ -804,15 +852,15 @@ void hb_xexit( void ) /* Deinitialize fixed memory subsystem */ { HB_TRACE( HB_TR_ERROR, ( "Block %i (size %lu) %s(%i), \"%s\"", ui, pMemBlock->ulSize, pMemBlock->szProcName, pMemBlock->uiProcLine, - hb_mem2str( membuffer, ( char * ) pMemBlock + HB_MEMINFO_SIZE, + hb_mem2str( membuffer, ( char * ) HB_MEM_PTR( pMemBlock ), HB_MIN( pMemBlock->ulSize, HB_MAX_MEM2STR_BLOCK ) ) ) ); if( hLog ) { fprintf( hLog, HB_I_("Block %i %p (size %lu) %s(%i), \"%s\"\n"), ui, - ( char * ) pMemBlock + HB_MEMINFO_SIZE, + ( char * ) HB_MEM_PTR( pMemBlock ), pMemBlock->ulSize, pMemBlock->szProcName, pMemBlock->uiProcLine, - hb_mem2str( membuffer, ( char * ) pMemBlock + HB_MEMINFO_SIZE, + hb_mem2str( membuffer, ( char * ) HB_MEM_PTR( pMemBlock ), HB_MIN( pMemBlock->ulSize, HB_MAX_MEM2STR_BLOCK ) ) ); } }