/* Unlock a memory pointer so it can be released if there is no references inside of harbour variables */ void * hb_gcUnlock( void * pBlock ) { if( pBlock ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pBlock ); if( pAlloc->locked ) { HB_GC_LOCK(); if( pAlloc->locked ) { if( --pAlloc->locked == 0 ) { pAlloc->used = s_uUsedFlag; hb_gcUnlink( &s_pLockedBlock, pAlloc ); hb_gcLink( &s_pCurrBlock, pAlloc ); HB_GC_AUTO_INC(); } } HB_GC_UNLOCK(); } } return pBlock; }
/* release a memory block allocated with hb_gcAlloc*() */ void hb_gcFree( void * pBlock ) { if( pBlock ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pBlock ); /* Don't release the block that will be deleted during finalization */ if( ! ( pAlloc->used & HB_GC_DELETE ) ) { HB_GC_LOCK(); if( pAlloc->locked ) hb_gcUnlink( &s_pLockedBlock, pAlloc ); else { hb_gcUnlink( &s_pCurrBlock, pAlloc ); HB_GC_AUTO_DEC(); } HB_GC_UNLOCK(); HB_GARBAGE_FREE( pAlloc ); } } else { hb_errInternal( HB_EI_XFREENULL, NULL, NULL, NULL ); } }
/* mark passed memory block as used so it will be not released by the GC */ void hb_gcMark( void * pBlock ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pBlock ); if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { pAlloc->used ^= HB_GC_USED_FLAG; /* mark this codeblock as used */ pAlloc->pFuncs->mark( pBlock ); } }
void hb_gcRefFree( void * pBlock ) { if( pBlock ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pBlock ); if( hb_xRefDec( pAlloc ) ) { /* Don't release the block that will be deleted during finalization */ if( ! ( pAlloc->used & HB_GC_DELETE ) ) { pAlloc->used |= HB_GC_DELETE; /* execute clean-up function */ pAlloc->pFuncs->clear( pBlock ); if( hb_xRefCount( pAlloc ) != 0 ) { if( pAlloc->used & HB_GC_DELETE ) { pAlloc->used = s_uUsedFlag; if( hb_vmRequestQuery() == 0 ) hb_errRT_BASE( EG_DESTRUCTOR, 1301, NULL, "Reference to freed block", 0 ); } } else { HB_GC_LOCK(); if( pAlloc->locked ) hb_gcUnlink( &s_pLockedBlock, pAlloc ); else { hb_gcUnlink( &s_pCurrBlock, pAlloc ); HB_GC_AUTO_DEC(); } HB_GC_UNLOCK(); HB_GARBAGE_FREE( pAlloc ); } } } } else { hb_errInternal( HB_EI_XFREENULL, NULL, NULL, NULL ); } }
/* Lock a memory pointer so it will not be released if stored outside of harbour variables */ void * hb_gcLock( void * pBlock ) { if( pBlock ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pBlock ); HB_GC_LOCK(); if( ! pAlloc->locked ) { hb_gcUnlink( &s_pCurrBlock, pAlloc ); hb_gcLink( &s_pLockedBlock, pAlloc ); HB_GC_AUTO_DEC(); } ++pAlloc->locked; HB_GC_UNLOCK(); } return pBlock; }
void hb_gcAttach( void * pBlock ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pBlock ); if( pAlloc->locked ) { HB_GC_LOCK(); if( pAlloc->locked ) { if( --pAlloc->locked == 0 ) { pAlloc->used = s_uUsedFlag; hb_gcUnlink( &s_pLockedBlock, pAlloc ); hb_gcLink( &s_pCurrBlock, pAlloc ); HB_GC_AUTO_INC(); pAlloc = NULL; } } HB_GC_UNLOCK(); } if( pAlloc ) hb_xRefInc( pAlloc ); }
/* Mark a passed item as used so it will be not released by the GC */ void hb_gcItemRef( PHB_ITEM pItem ) { while( HB_IS_BYREF( pItem ) ) { if( HB_IS_ENUM( pItem ) ) return; else if( HB_IS_EXTREF( pItem ) ) { pItem->item.asExtRef.func->mark( pItem->item.asExtRef.value ); return; } else if( ! HB_IS_MEMVAR( pItem ) && pItem->item.asRefer.offset == 0 && pItem->item.asRefer.value >= 0 ) { /* array item reference */ PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asRefer.BasePtr.array ); if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this array as used */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark also all array elements */ pAlloc->pFuncs->mark( HB_BLOCK_PTR( pAlloc ) ); } return; } pItem = hb_itemUnRefOnce( pItem ); } if( HB_IS_ARRAY( pItem ) ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asArray.value ); /* Check this array only if it was not checked yet */ if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this array as used so it will be no re-checked from * other references */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark also all array elements */ pAlloc->pFuncs->mark( HB_BLOCK_PTR( pAlloc ) ); } } else if( HB_IS_HASH( pItem ) ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asHash.value ); /* Check this hash table only if it was not checked yet */ if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this hash table as used */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark also all hash elements */ pAlloc->pFuncs->mark( HB_BLOCK_PTR( pAlloc ) ); } } else if( HB_IS_BLOCK( pItem ) ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asBlock.value ); if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this codeblock as used */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark as used all detached variables in a codeblock */ pAlloc->pFuncs->mark( HB_BLOCK_PTR( pAlloc ) ); } } else if( HB_IS_POINTER( pItem ) ) { if( pItem->item.asPointer.collect ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asPointer.value ); if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this memory block as used */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark also all internal user blocks attached to this block */ pAlloc->pFuncs->mark( HB_BLOCK_PTR( pAlloc ) ); } } } /* all other data types don't need the GC */ }
HB_COUNTER hb_gcRefCount( void * pBlock ) { return hb_xRefCount( HB_GC_PTR( pBlock ) ); }
void hb_gcRefInc( void * pBlock ) { hb_xRefInc( HB_GC_PTR( pBlock ) ); }
/* return cleanup function pointer */ const HB_GC_FUNCS * hb_gcFuncs( void * pBlock ) { return HB_GC_PTR( pBlock )->pFuncs; }
/* return cleanup function pointer */ HB_GARBAGE_FUNC_PTR hb_gcFunc( void *pBlock ) { return HB_GC_PTR( pBlock )->pFunc; }