From e59993bdb14fab12dcc3e1698c088e18f951d437 Mon Sep 17 00:00:00 2001 From: Przemyslaw Czerpak Date: Wed, 2 Jun 2010 08:30:20 +0000 Subject: [PATCH] 2010-06-02 10:30 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/src/vm/garbage.c + added new PRG function HB_GCSETAUTO( [] ) -> which allows to set the frequency of automatic GC activation. is number of GC items (in thousands). If total number of new GC items allocated from last GC pass exceed this value then GC is automatically activated. Setting 0 disable automatic GC activation. Automatic GC activation is necessary for programs which allocates big number of complex items with cyclic references without entering any idle state which can activate GC. In such case users have to add to their code call to hb_gcAll() function. In xHarbour they used sometimes background task for this job but it's inefficient workaround for the problem due to reduced performance. This code is still experimental code enabled by HB_GC_AUTO Harbour compile time macro. * harbour/src/debug/dbgentry.c ! fixed potential memory leak in unused code for GLOBAL [EXTERN] variables ! cleaned a little bit code for line numbers with good break points --- harbour/ChangeLog | 22 ++++++ harbour/src/debug/dbgentry.c | 29 ++++++-- harbour/src/vm/garbage.c | 138 ++++++++++++++++++----------------- 3 files changed, 116 insertions(+), 73 deletions(-) diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 2c129c0d46..571bbb82bc 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,28 @@ past entries belonging to author(s): Viktor Szakats. */ +2010-06-02 10:30 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/src/vm/garbage.c + + added new PRG function HB_GCSETAUTO( [] ) -> + which allows to set the frequency of automatic GC activation. + is number of GC items (in thousands). If total number + of new GC items allocated from last GC pass exceed this value + then GC is automatically activated. Setting 0 disable automatic + GC activation. Automatic GC activation is necessary for programs + which allocates big number of complex items with cyclic references + without entering any idle state which can activate GC. In such + case users have to add to their code call to hb_gcAll() function. + In xHarbour they used sometimes background task for this job + but it's inefficient workaround for the problem due to reduced + performance. + This code is still experimental code enabled by HB_GC_AUTO Harbour + compile time macro. + + * harbour/src/debug/dbgentry.c + ! fixed potential memory leak in unused code for GLOBAL [EXTERN] + variables + ! cleaned a little bit code for line numbers with good break points + 2010-06-02 00:41 UTC-0800 Pritpal Bedi (bedipritpal@hotmail.com) * contrib/gtwvg/tests/demowvg.prg * contrib/gtwvg/tests/wvgcuigdialog.prg diff --git a/harbour/src/debug/dbgentry.c b/harbour/src/debug/dbgentry.c index f33b996af1..b73664b36e 100644 --- a/harbour/src/debug/dbgentry.c +++ b/harbour/src/debug/dbgentry.c @@ -702,21 +702,26 @@ static void hb_dbgAddStopLines( HB_DEBUGINFO * info, PHB_ITEM pItem ) int nOrigLen = hb_arrayGetCLen( pLines, 3 ); int nNewLen = hb_arrayGetCLen( pEntry, 3 ); int nMin = HB_MIN( nNewMin, nOrigMin ); - int nMax = HB_MAX( nNewMin + nNewLen * 8, nOrigMin + nOrigLen * 8 ); + int nMax = HB_MAX( nNewMin + ( nNewLen << 3 ) - 1, + nOrigMin + ( nOrigLen << 3 ) - 1 ); const char * pOrigBuffer = hb_arrayGetCPtr( pLines, 3 ); const char * pNewBuffer = hb_arrayGetCPtr( pEntry, 3 ); - int nLen = ( nMax + 1 - nMin + 7 ) / 8 + 1; + int nLen = ( ( nMax - nMin ) >> 3 ) + 1; int k; - char * pBuffer = ( char * ) hb_xgrab( nLen ); + char * pBuffer = ( char * ) hb_xgrab( nLen + 1 ); hb_xmemset( pBuffer, 0, nLen ); - memmove( &( pBuffer[ ( nNewMin - nMin ) / 8 ] ), pNewBuffer, nNewLen ); + /* the bitfields with line numbers should use + * 8bit alignment so it's safe to use byte copy + */ + memmove( &pBuffer[ ( nNewMin - nMin ) >> 3 ], pNewBuffer, nNewLen ); + nOrigMin = ( nOrigMin - nMin ) >> 3; for( k = 0; k < nOrigLen; k++ ) - pBuffer[ nOrigMin / 8 + k - nMin / 8 ] |= pOrigBuffer[ k ]; + pBuffer[ nOrigMin + k ] |= pOrigBuffer[ k ]; hb_arraySetNL( pLines, 2, nMin ); - if( !hb_arraySetCLPtr( pLines, 3, pBuffer, nLen - 1 ) ) + if( !hb_arraySetCLPtr( pLines, 3, pBuffer, nLen ) ) hb_xfree( pBuffer ); bFound = HB_TRUE; break; @@ -1351,10 +1356,10 @@ HB_BOOL hb_dbgIsValidStopLine( void * handle, const char * szModule, int nLine ) int nMin = hb_arrayGetNL( pEntry, 2 ); int nOfs = nLine - nMin; - if( nLine < nMin || ( HB_SIZE )( nOfs / 8 ) > hb_arrayGetCLen( pEntry, 3 ) ) + if( nOfs < 0 || ( HB_SIZE ) ( nOfs >> 3 ) >= hb_arrayGetCLen( pEntry, 3 ) ) return HB_FALSE; - return ( hb_arrayGetCPtr( pEntry, 3 )[ nOfs / 8 ] & ( 1 << ( nOfs % 8 ) ) ) != 0; + return ( hb_arrayGetCPtr( pEntry, 3 )[ nOfs >> 3 ] & ( 1 << ( nOfs & 0x07 ) ) ) != 0; } } return HB_FALSE; @@ -1387,6 +1392,14 @@ static void hb_dbgQuit( HB_DEBUGINFO * info ) { hb_xfree( module->aStatics ); } + if( module->nGlobals ) + { + hb_xfree( module->aGlobals ); + } + if( module->nExternGlobals ) + { + hb_xfree( module->aExternGlobals ); + } if( module->szModule ) { hb_xfree( module->szModule ); diff --git a/harbour/src/vm/garbage.c b/harbour/src/vm/garbage.c index d0eca56559..aa9307e1ab 100644 --- a/harbour/src/vm/garbage.c +++ b/harbour/src/vm/garbage.c @@ -131,14 +131,15 @@ typedef struct HB_GARBAGE_ #define HB_GC_DELETELST 4 /* item will be deleted during finalization */ #ifdef HB_GC_AUTO -#define HB_GC_AUTO_CHECK 100000 -#define HB_GC_AUTO_MAX ( ( HB_PTRUINT ) ( -1 ) ); +#define HB_GC_AUTO_MAX ( ( HB_PTRUINT ) ( -1 ) ) /* number of allocated memory blocks */ static HB_PTRUINT s_ulBlocks = 0; /* number of allocated memory blocks after last GC activation */ static HB_PTRUINT s_ulBlocksMarked = 0; +/* number of memory blocks between automatic GC activation */ +static HB_PTRUINT s_ulBlocksAuto = 0; /* number of allocated memory blocks which should force next GC activation */ -static HB_PTRUINT s_ulBlocksCheck = HB_GC_AUTO_CHECK; +static HB_PTRUINT s_ulBlocksCheck = 0; # define HB_GC_AUTO_INC ++s_ulBlocks; # define HB_GC_AUTO_DEC --s_ulBlocks; @@ -200,28 +201,14 @@ void * hb_gcAllocate( HB_SIZE ulSize, const HB_GC_FUNCS * pFuncs ) HB_GARBAGE_PTR pAlloc; pAlloc = HB_GARBAGE_NEW( ulSize ); - if( pAlloc ) - { - pAlloc->pFuncs = pFuncs; - pAlloc->locked = 1; - pAlloc->used = s_uUsedFlag; - HB_GC_LOCK -#ifdef HB_GC_AUTO - if( s_ulBlocks > s_ulBlocksCheck ) - { - HB_GC_UNLOCK - hb_gcCollectAll( HB_TRUE ); - HB_GC_LOCK - pAlloc->used = s_uUsedFlag; - } -#endif - hb_gcLink( &s_pLockedBlock, pAlloc ); - HB_GC_UNLOCK + pAlloc->pFuncs = pFuncs; + pAlloc->locked = 1; + pAlloc->used = s_uUsedFlag; + HB_GC_LOCK + hb_gcLink( &s_pLockedBlock, pAlloc ); + HB_GC_UNLOCK - return HB_BLOCK_PTR( pAlloc ); /* hide the internal data */ - } - else - return NULL; + return HB_BLOCK_PTR( pAlloc ); /* hide the internal data */ } /* allocates a memory block */ @@ -230,30 +217,25 @@ void * hb_gcAllocRaw( HB_SIZE ulSize, const HB_GC_FUNCS * pFuncs ) HB_GARBAGE_PTR pAlloc; pAlloc = HB_GARBAGE_NEW( ulSize ); - if( pAlloc ) - { - pAlloc->pFuncs = pFuncs; - pAlloc->locked = 0; - pAlloc->used = s_uUsedFlag; + pAlloc->pFuncs = pFuncs; + pAlloc->locked = 0; + pAlloc->used = s_uUsedFlag; - HB_GC_LOCK + HB_GC_LOCK #ifdef HB_GC_AUTO - if( s_ulBlocks > s_ulBlocksCheck ) - { - HB_GC_UNLOCK - hb_gcCollectAll( HB_TRUE ); - HB_GC_LOCK - pAlloc->used = s_uUsedFlag; - } - HB_GC_AUTO_INC -#endif - hb_gcLink( &s_pCurrBlock, pAlloc ); + if( s_ulBlocks > s_ulBlocksCheck ) + { HB_GC_UNLOCK - - return HB_BLOCK_PTR( pAlloc ); /* hide the internal data */ + hb_gcCollectAll( HB_TRUE ); + HB_GC_LOCK + pAlloc->used = s_uUsedFlag; } - else - return NULL; + HB_GC_AUTO_INC +#endif + hb_gcLink( &s_pCurrBlock, pAlloc ); + HB_GC_UNLOCK + + return HB_BLOCK_PTR( pAlloc ); /* hide the internal data */ } /* release a memory block allocated with hb_gcAlloc*() */ @@ -399,30 +381,23 @@ static const HB_GC_FUNCS s_gcGripFuncs = HB_ITEM_PTR hb_gcGripGet( HB_ITEM_PTR pOrigin ) { - HB_GARBAGE_PTR pAlloc; + HB_GARBAGE_PTR pAlloc = HB_GARBAGE_NEW( sizeof( HB_ITEM ) ); + HB_ITEM_PTR pItem = ( HB_ITEM_PTR ) HB_BLOCK_PTR( pAlloc ); - pAlloc = HB_GARBAGE_NEW( sizeof( HB_ITEM ) ); - if( pAlloc ) - { - HB_ITEM_PTR pItem = ( HB_ITEM_PTR ) HB_BLOCK_PTR( pAlloc ); + pAlloc->pFuncs = &s_gcGripFuncs; + pAlloc->locked = 1; + pAlloc->used = s_uUsedFlag; - pAlloc->pFuncs = &s_gcGripFuncs; - pAlloc->locked = 1; - pAlloc->used = s_uUsedFlag; + pItem->type = HB_IT_NIL; - pItem->type = HB_IT_NIL; + HB_GC_LOCK + hb_gcLink( &s_pLockedBlock, pAlloc ); + HB_GC_UNLOCK - HB_GC_LOCK - hb_gcLink( &s_pLockedBlock, pAlloc ); - HB_GC_UNLOCK + if( pOrigin ) + hb_itemCopy( pItem, pOrigin ); - if( pOrigin ) - hb_itemCopy( pItem, pOrigin ); - - return pItem; - } - else - return NULL; + return pItem; } void hb_gcGripDrop( HB_ITEM_PTR pItem ) @@ -701,9 +676,14 @@ void hb_gcCollectAll( HB_BOOL fForce ) #ifdef HB_GC_AUTO /* store number of marked blocks for automatic GC activation */ s_ulBlocksMarked = s_ulBlocks; - s_ulBlocksCheck = s_ulBlocksMarked + HB_GC_AUTO_CHECK; - if( s_ulBlocksCheck <= s_ulBlocksMarked ) + if( s_ulBlocksAuto == 0 ) s_ulBlocksCheck = HB_GC_AUTO_MAX; + else + { + s_ulBlocksCheck = s_ulBlocksMarked + s_ulBlocksAuto; + if( s_ulBlocksCheck <= s_ulBlocksMarked ) + s_ulBlocksCheck = HB_GC_AUTO_MAX; + } #endif /* call memory manager cleanup function */ @@ -814,3 +794,31 @@ HB_FUNC( HB_GCALL ) hb_gcCollectAll( hb_pcount() < 1 || hb_parl( 1 ) ); } + +#ifdef HB_GC_AUTO +HB_FUNC( HB_GCSETAUTO ) +{ + HB_PTRUINT nBlocks, nPrevBlocks; + HB_BOOL fSet = HB_ISNUM( 1 ); + + nBlocks = fSet ? hb_parnint( 1 ) * 1000 : 0; + + HB_GC_LOCK + nPrevBlocks = s_ulBlocksAuto; + if( fSet ) + { + s_ulBlocksAuto = nBlocks; + if( s_ulBlocksAuto == 0 ) + s_ulBlocksCheck = HB_GC_AUTO_MAX; + else + { + s_ulBlocksCheck = s_ulBlocksMarked + s_ulBlocksAuto; + if( s_ulBlocksCheck <= s_ulBlocksMarked ) + s_ulBlocksCheck = HB_GC_AUTO_MAX; + } + } + HB_GC_UNLOCK + + hb_retnint( nPrevBlocks / 1000 ); +} +#endif