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