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 ) ) ); } }