From 7349602fcbd9b336183d2fa355454c60cb2f91e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Czerpak?= Date: Tue, 1 Apr 2014 12:33:17 +0200 Subject: [PATCH] 2014-04-01 12:33 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * src/rtl/filebuf.c ! unlock HVM stack before locking local mutex and calling hb_fs*() functions which also unlocks HVM. It fixes possible deadlock condition when hb_gcAll( .T. ) is executed. * include/hbapi.h * src/vm/garbage.c ! changed mark function semantic. Adding support for user defined mark function I created race condition in MT GC code. It happens because blocks marked as deleted were not scanned by GC mark code so their subitems where not accessible. To fix it we have to change mark function semantic. Now mark function can be executed also for blocks currently deleted. It means that GC block destructor should clean references to just removed items and subblocks. The best place to make it is clearing pointers to GC blocks just after hb_itemRelease() or hb_gcRefFree(). It is save to clean the reference just before hb_itemRelease() or hb_gcRefFree() but only for the single block passed to these functions. It is not save to clear reference to more then one block and then execute above functions. + check reference count after destructor execution for all blocks not only arrays - warning it may exploit some wrong C code. - removed not longer used hb_gcRefCheck() function. * include/hbvm.h * src/vm/hvm.c + added new internal function hb_vmLockForce() ! fixed to mark GC blocks with active threads * src/vm/thread.c * include/hbthread.h % modified sync mutexes used by xBase++ signal class emulation to not use item array internally * updated mutex destructor to new GC mark semantic ! mark GT items if GT is bound with thread item ! fixed mutex notify/subscribe code to not change GC items when HVM stack is unlocked ! use hb_vmLockForce() to eliminate potential deadlock + added new C function hb_threadEnterCriticalSectionGC(). It should be used instead of hb_threadEnterCriticalSection() in code which manipulates GC items inside critical section. It's slower but eliminates possible deadlock condition. Please remember that remember that both functions cannot be used for the same mutex. So if it's necessary to use hb_threadEnterCriticalSectionGC() in one place then it has to be used in all others when the same mutex is locked. * src/vm/arrays.c * src/vm/codebloc.c * src/vm/hashes.c * src/rtl/hbgtcore.c * contrib/hbcurl/core.c * contrib/hbexpat/core.c * updated destructors to new GC mark semantic * contrib/hbxpp/dllx.c ! fixed destructor for pointer item created by DllPrepareCall() Now it respects reference counter. ; added note about real behavior of library handle destructor, I haven't changed existing code behavior but maybe it should be done. * contrib/xhb/hbserv.c * src/debug/dbgentry.c * src/rdd/wacore.c ! fixed possible deadlocks by using hb_threadEnterCriticalSectionGC() instead of hb_threadEnterCriticalSection(). * contrib/hbmemio/memio.c ! slightly modified hb_memfsDirectory() code to avoid race condition without using hb_threadEnterCriticalSectionGC() * src/vm/fm.c % reduce the lock range in HB_FM_STAT builds * src/rtl/hbsocket.c ! added missing HVM stack unlocking in hb_socketSelect() function * src/rtl/gtxwc/gtxwc.c ! added few missing locks for version compiled with HB_XWC_XLIB_NEEDLOCKS * src/rdd/dbtotal.prg * allow to use symbols instead of codeblocks * modified Harbour extension which uses ordKey() as default group signature to work also without index. In such case all records are summarized into single one. ; Most of above modifications were critical for stability of MT programs. They should allow to activate GC in any place. --- ChangeLog.txt | 91 +++++++++++++++++ contrib/hbcurl/core.c | 16 +-- contrib/hbexpat/core.c | 8 +- contrib/hbmemio/memio.c | 45 ++++++--- contrib/hbxpp/dllx.c | 72 ++++++++------ contrib/xhb/hbserv.c | 8 +- include/hbapi.h | 1 - include/hbthread.h | 1 + include/hbvm.h | 1 + src/debug/dbgentry.c | 2 +- src/rdd/dbtotal.prg | 31 +++--- src/rdd/wacore.c | 8 +- src/rtl/filebuf.c | 17 +++- src/rtl/gtxwc/gtxwc.c | 31 ++++-- src/rtl/hbgtcore.c | 39 +++++--- src/rtl/hbsocket.c | 2 + src/vm/arrays.c | 41 +++----- src/vm/codebloc.c | 19 ++-- src/vm/fm.c | 80 +++++++-------- src/vm/garbage.c | 75 ++++++-------- src/vm/hashes.c | 43 +++++--- src/vm/hvm.c | 26 ++++- src/vm/thread.c | 212 ++++++++++++++++++++++++++-------------- 23 files changed, 542 insertions(+), 327 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 8f36762120..1341c77bd8 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,97 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ +2014-04-01 12:33 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * src/rtl/filebuf.c + ! unlock HVM stack before locking local mutex and calling hb_fs*() + functions which also unlocks HVM. It fixes possible deadlock condition + when hb_gcAll( .T. ) is executed. + + * include/hbapi.h + * src/vm/garbage.c + ! changed mark function semantic. + Adding support for user defined mark function I created race condition + in MT GC code. It happens because blocks marked as deleted were not + scanned by GC mark code so their subitems where not accessible. + To fix it we have to change mark function semantic. Now mark function + can be executed also for blocks currently deleted. It means that GC + block destructor should clean references to just removed items and + subblocks. The best place to make it is clearing pointers to GC blocks + just after hb_itemRelease() or hb_gcRefFree(). + It is save to clean the reference just before hb_itemRelease() or + hb_gcRefFree() but only for the single block passed to these functions. + It is not save to clear reference to more then one block and then + execute above functions. + + check reference count after destructor execution for all blocks + not only arrays - warning it may exploit some wrong C code. + - removed not longer used hb_gcRefCheck() function. + + * include/hbvm.h + * src/vm/hvm.c + + added new internal function hb_vmLockForce() + ! fixed to mark GC blocks with active threads + + * src/vm/thread.c + * include/hbthread.h + % modified sync mutexes used by xBase++ signal class emulation + to not use item array internally + * updated mutex destructor to new GC mark semantic + ! mark GT items if GT is bound with thread item + ! fixed mutex notify/subscribe code to not change GC items + when HVM stack is unlocked + ! use hb_vmLockForce() to eliminate potential deadlock + + added new C function hb_threadEnterCriticalSectionGC(). + It should be used instead of hb_threadEnterCriticalSection() + in code which manipulates GC items inside critical section. + It's slower but eliminates possible deadlock condition. + Please remember that remember that both functions cannot + be used for the same mutex. So if it's necessary to use + hb_threadEnterCriticalSectionGC() in one place then it + has to be used in all others when the same mutex is locked. + + * src/vm/arrays.c + * src/vm/codebloc.c + * src/vm/hashes.c + * src/rtl/hbgtcore.c + * contrib/hbcurl/core.c + * contrib/hbexpat/core.c + * updated destructors to new GC mark semantic + + * contrib/hbxpp/dllx.c + ! fixed destructor for pointer item created by DllPrepareCall() + Now it respects reference counter. + ; added note about real behavior of library handle destructor, + I haven't changed existing code behavior but maybe it should + be done. + + * contrib/xhb/hbserv.c + * src/debug/dbgentry.c + * src/rdd/wacore.c + ! fixed possible deadlocks by using hb_threadEnterCriticalSectionGC() + instead of hb_threadEnterCriticalSection(). + + * contrib/hbmemio/memio.c + ! slightly modified hb_memfsDirectory() code to avoid race condition + without using hb_threadEnterCriticalSectionGC() + + * src/vm/fm.c + % reduce the lock range in HB_FM_STAT builds + + * src/rtl/hbsocket.c + ! added missing HVM stack unlocking in hb_socketSelect() function + + * src/rtl/gtxwc/gtxwc.c + ! added few missing locks for version compiled with HB_XWC_XLIB_NEEDLOCKS + + * src/rdd/dbtotal.prg + * allow to use symbols instead of codeblocks + * modified Harbour extension which uses ordKey() as default group + signature to work also without index. In such case all records + are summarized into single one. + + ; Most of above modifications were critical for stability of MT programs. + They should allow to activate GC in any place. + 2014-03-27 16:13 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * contrib/hbpgsql/rddcopy.c ! fixed typos in my recent modification and potential memory corruption diff --git a/contrib/hbcurl/core.c b/contrib/hbcurl/core.c index 32f5cc885e..212afeb205 100644 --- a/contrib/hbcurl/core.c +++ b/contrib/hbcurl/core.c @@ -567,13 +567,9 @@ static HB_GARBAGE_FUNC( PHB_CURL_release ) /* Check if pointer is not NULL to avoid multiple freeing */ if( hb_curl_ptr && *hb_curl_ptr ) { - PHB_CURL hb_curl = *hb_curl_ptr; - - /* set pointer to NULL to avoid multiple freeing */ - *hb_curl_ptr = NULL; - /* Destroy the object */ - PHB_CURL_free( hb_curl, HB_TRUE ); + PHB_CURL_free( *hb_curl_ptr, HB_TRUE ); + *hb_curl_ptr = NULL; } } @@ -642,13 +638,9 @@ HB_FUNC( CURL_EASY_CLEANUP ) if( ph && *ph ) { - PHB_CURL hb_curl = ( PHB_CURL ) *ph; - - /* set pointer to NULL to avoid multiple freeing */ - *ph = NULL; - /* Destroy the object */ - PHB_CURL_free( hb_curl, HB_TRUE ); + PHB_CURL_free( ( PHB_CURL ) *ph, HB_TRUE ); + *ph = NULL; } } else diff --git a/contrib/hbexpat/core.c b/contrib/hbexpat/core.c index 01108e428d..8b4bd05e30 100644 --- a/contrib/hbexpat/core.c +++ b/contrib/hbexpat/core.c @@ -678,11 +678,9 @@ static HB_GARBAGE_FUNC( PHB_EXPAT_release ) { PHB_EXPAT hb_expat = *hb_expat_ptr; - /* set pointer to NULL to avoid multiple freeing */ - *hb_expat_ptr = NULL; - /* Destroy the object */ PHB_EXPAT_free( hb_expat, HB_TRUE ); + *hb_expat_ptr = NULL; } } @@ -810,11 +808,9 @@ HB_FUNC( XML_PARSERFREE ) { PHB_EXPAT hb_expat = ( PHB_EXPAT ) *ph; - /* set pointer to NULL to avoid multiple freeing */ - *ph = NULL; - /* Destroy the object */ PHB_EXPAT_free( hb_expat, HB_TRUE ); + *ph = NULL; } } else diff --git a/contrib/hbmemio/memio.c b/contrib/hbmemio/memio.c index 9609119b9f..9fbde715cb 100644 --- a/contrib/hbmemio/memio.c +++ b/contrib/hbmemio/memio.c @@ -118,6 +118,11 @@ typedef struct _HB_MEMFS_FS PHB_MEMFS_FILE * pFiles; } HB_MEMFS_FS, * PHB_MEMFS_FS; +typedef struct _HB_MEMFS_DIRENTRY +{ + char * szName; + HB_FOFFSET llSize; +} HB_MEMFS_DIRENTRY, * PHB_MEMFS_DIRENTRY; static HB_MEMFS_FS s_fs; static HB_ERRCODE s_error; @@ -365,10 +370,11 @@ HB_MEMFS_EXPORT HB_BOOL hb_memfsRename( const char * szName, const char * szNewN HB_MEMFS_EXPORT PHB_ITEM hb_memfsDirectory( const char * pszDirSpec, const char * pszAttr ) { + PHB_MEMFS_DIRENTRY pDirEn = NULL; char * pszFree = NULL; PHB_ITEM pDirArray; HB_SIZE nLen; - HB_ULONG ul; + HB_ULONG ulCount, ul; HB_SYMBOL_UNUSED( pszAttr ); @@ -387,25 +393,38 @@ HB_MEMFS_EXPORT PHB_ITEM hb_memfsDirectory( const char * pszDirSpec, const char pszDirSpec = HB_OS_ALLFILE_MASK; HB_MEMFSMT_LOCK(); - pDirArray = hb_itemArrayNew( s_fs.ulInodeCount ); + ulCount = s_fs.ulInodeCount; nLen = 0; - for( ul = 0; ul < s_fs.ulInodeCount; ul++ ) + if( ulCount ) { - if( hb_strMatchFile( s_fs.pInodes[ ul ]->szName, pszDirSpec ) ) + pDirEn = ( PHB_MEMFS_DIRENTRY ) hb_xgrab( ulCount * sizeof( HB_MEMFS_DIRENTRY ) ); + for( ul = 0; ul < ulCount; ul++ ) { - PHB_ITEM pSubarray = hb_arrayGetItemPtr( pDirArray, ++nLen ); - - hb_arrayNew ( pSubarray, F_LEN ); - hb_arraySetC ( pSubarray, F_NAME, s_fs.pInodes[ ul ]->szName ); - hb_arraySetNInt( pSubarray, F_SIZE, s_fs.pInodes[ ul ]->llSize ); - hb_arraySetDL ( pSubarray, F_DATE, 0 ); - hb_arraySetC ( pSubarray, F_TIME, "00:00:00" ); - hb_arraySetC ( pSubarray, F_ATTR, "" ); + if( hb_strMatchFile( s_fs.pInodes[ ul ]->szName, pszDirSpec ) ) + { + pDirEn[ nLen ].szName = hb_strdup( s_fs.pInodes[ ul ]->szName ); + pDirEn[ nLen ].llSize = s_fs.pInodes[ ul ]->llSize; + nLen++; + } } } HB_MEMFSMT_UNLOCK(); - hb_arraySize( pDirArray, nLen ); + pDirArray = hb_itemArrayNew( nLen ); + for( ul = 0; ( HB_SIZE ) ul < nLen; ul++ ) + { + PHB_ITEM pSubarray = hb_arrayGetItemPtr( pDirArray, ++nLen ); + + hb_arrayNew ( pSubarray, F_LEN ); + hb_arraySetCPtr( pSubarray, F_NAME, pDirEn[ ul ].szName ); + hb_arraySetNInt( pSubarray, F_SIZE, pDirEn[ ul ].llSize ); + hb_arraySetDL ( pSubarray, F_DATE, 0 ); + hb_arraySetC ( pSubarray, F_TIME, "00:00:00" ); + hb_arraySetC ( pSubarray, F_ATTR, "" ); + } + + if( pDirEn ) + hb_xfree( pDirEn ); if( pszFree ) hb_xfree( pszFree ); diff --git a/contrib/hbxpp/dllx.c b/contrib/hbxpp/dllx.c index 9fb1b90b2c..297e04fb23 100644 --- a/contrib/hbxpp/dllx.c +++ b/contrib/hbxpp/dllx.c @@ -62,7 +62,6 @@ typedef struct { PHB_ITEM pLibraryHandle; - HB_BOOL bFreeLibrary; /* Free library handle on destroy? */ int iFuncFlags; void * pFunctionPtr; /* Function Address */ } HB_DLLEXEC, * PHB_DLLEXEC; @@ -71,8 +70,12 @@ static HB_GARBAGE_FUNC( _DLLUnload ) { PHB_DLLEXEC xec = ( PHB_DLLEXEC ) Cargo; - if( xec->pLibraryHandle && xec->bFreeLibrary ) + if( xec->pLibraryHandle ) { + /* by default we do not free library in pLibraryHandle destructor + * (look at hb_libRelease() in dynlibhb.c). If you want to free + * library call here hb_libFree( xec->pLibraryHandle ). + */ hb_gcRefFree( xec->pLibraryHandle ); xec->pLibraryHandle = NULL; } @@ -105,14 +108,17 @@ HB_FUNC( DLLCALL ) PHB_ITEM pLibraryHandle = NULL; HB_BOOL bFreeLibrary = HB_FALSE; - if( HB_IS_STRING( pLibrary ) ) + if( pLibrary ) { - pLibraryHandle = hb_libLoad( pLibrary, NULL ); - if( pLibraryHandle ) - bFreeLibrary = HB_TRUE; + if( HB_IS_STRING( pLibrary ) ) + { + pLibraryHandle = hb_libLoad( pLibrary, NULL ); + if( pLibraryHandle ) + bFreeLibrary = HB_TRUE; + } + else if( hb_libHandle( pLibrary ) ) + pLibraryHandle = pLibrary; } - else if( hb_libHandle( pLibrary ) ) - pLibraryHandle = pLibrary; if( pLibraryHandle ) { @@ -143,41 +149,46 @@ HB_FUNC( DLLCALL ) HB_FUNC( DLLPREPARECALL ) { - PHB_DLLEXEC xec = ( PHB_DLLEXEC ) hb_gcAllocate( sizeof( HB_DLLEXEC ), &s_gcDllFuncs ); - PHB_ITEM pLibrary = hb_param( 1, HB_IT_ANY ); + PHB_ITEM pLibrary = hb_param( 1, HB_IT_ANY ); + PHB_ITEM pLibraryHandle = NULL; + HB_BOOL bFreeLibrary = HB_FALSE; const char * pszErrorText; - memset( xec, 0, sizeof( HB_DLLEXEC ) ); - - if( HB_IS_STRING( pLibrary ) ) + if( pLibrary ) { - xec->pLibraryHandle = hb_libLoad( pLibrary, NULL ); - if( xec->pLibraryHandle ) + if( HB_IS_STRING( pLibrary ) ) { - hb_gcRefInc( xec->pLibraryHandle ); - xec->bFreeLibrary = HB_TRUE; + pLibraryHandle = hb_libLoad( pLibrary, NULL ); + if( pLibraryHandle ) + bFreeLibrary = HB_TRUE; } - } - else if( hb_libHandle( pLibrary ) ) - { - xec->pLibraryHandle = pLibrary; - hb_gcRefInc( xec->pLibraryHandle ); + else if( hb_libHandle( pLibrary ) ) + pLibraryHandle = pLibrary; } - if( xec->pLibraryHandle ) + if( pLibraryHandle ) { - xec->pFunctionPtr = hb_libSymAddr( xec->pLibraryHandle, hb_parcx( 3 ) ); - if( xec->pFunctionPtr ) + void * pFunctionPtr = hb_libSymAddr( pLibraryHandle, hb_parcx( 3 ) ); + + if( pFunctionPtr ) { - int iXPPFlags = hb_parni( 2 ); + int iXPPFlags = hb_parni( 2 ), iFuncFlags = 0; + PHB_DLLEXEC xec; if( ( iXPPFlags & DLL_CDECL ) != 0 ) - xec->iFuncFlags |= HB_DYN_CALLCONV_CDECL; + iFuncFlags |= HB_DYN_CALLCONV_CDECL; if( ( iXPPFlags & DLL_STDCALL ) != 0 ) - xec->iFuncFlags |= HB_DYN_CALLCONV_STDCALL; + iFuncFlags |= HB_DYN_CALLCONV_STDCALL; if( ( iXPPFlags & DLL_SYSTEM ) != 0 ) - xec->iFuncFlags |= HB_DYN_CALLCONV_SYSCALL; + iFuncFlags |= HB_DYN_CALLCONV_SYSCALL; + if( !bFreeLibrary ) + hb_gcRefInc( pLibraryHandle ); + + xec = ( PHB_DLLEXEC ) hb_gcAllocate( sizeof( HB_DLLEXEC ), &s_gcDllFuncs ); + xec->pLibraryHandle = pLibraryHandle; + xec->iFuncFlags = iFuncFlags; + xec->pFunctionPtr = pFunctionPtr; hb_retptrGC( xec ); return; } @@ -186,7 +197,8 @@ HB_FUNC( DLLPREPARECALL ) else pszErrorText = HB_ISCHAR( 1 ) ? "Invalid library name" : "Invalid library handle"; - hb_gcFree( xec ); + if( bFreeLibrary ) + hb_libFree( pLibraryHandle ); hb_errRT_BASE( EG_ARG, 2010, pszErrorText, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } diff --git a/contrib/xhb/hbserv.c b/contrib/xhb/hbserv.c index 02689e583e..c3b57cbcb8 100644 --- a/contrib/xhb/hbserv.c +++ b/contrib/xhb/hbserv.c @@ -163,7 +163,7 @@ static void s_signalHandler( int sig, siginfo_t * info, void * v ) #endif /* let's find the right signal handler. */ - hb_threadEnterCriticalSection( &s_ServiceMutex ); + hb_threadEnterCriticalSectionGC( &s_ServiceMutex ); /* avoid working if PRG signal handling has been disabled */ if( ! bSignalEnabled ) @@ -417,7 +417,7 @@ static LONG s_signalHandler( int type, int sig, PEXCEPTION_RECORD exc ) int iRet; /* let's find the right signal handler. */ - hb_threadEnterCriticalSection( &s_ServiceMutex ); + hb_threadEnterCriticalSectionGC( &s_ServiceMutex ); /* avoid working if PRG signal handling has been disabled */ if( ! bSignalEnabled ) @@ -885,7 +885,7 @@ HB_FUNC( HB_PUSHSIGNALHANDLER ) s_signalHandlersInit(); } - hb_threadEnterCriticalSection( &s_ServiceMutex ); + hb_threadEnterCriticalSectionGC( &s_ServiceMutex ); hb_arrayAddForward( sp_hooks, pHandEntry ); @@ -901,7 +901,7 @@ HB_FUNC( HB_POPSIGNALHANDLER ) if( sp_hooks != NULL ) { - hb_threadEnterCriticalSection( &s_ServiceMutex ); + hb_threadEnterCriticalSectionGC( &s_ServiceMutex ); nLen = hb_arrayLen( sp_hooks ); if( nLen > 0 ) diff --git a/include/hbapi.h b/include/hbapi.h index cf50af7956..5853a78706 100644 --- a/include/hbapi.h +++ b/include/hbapi.h @@ -607,7 +607,6 @@ extern void hb_vmIsStackRef( void ); /* hvm.c - mark all local variables a extern void hb_vmIsStaticRef( void ); /* hvm.c - mark all static variables as used */ extern void hb_gcReleaseAll( void ); /* release all memory blocks unconditionally */ -extern void hb_gcRefCheck( void * pBlock ); /* Check if block still cannot be access after destructor execution */ extern HB_COUNTER hb_gcRefCount( void * pAlloc ); /* return number of references */ #if 0 diff --git a/include/hbthread.h b/include/hbthread.h index 38d8cd0410..25c3b00071 100644 --- a/include/hbthread.h +++ b/include/hbthread.h @@ -375,6 +375,7 @@ extern HB_EXPORT HB_BOOL hb_atomic_dec( volatile HB_COUNTER * pCounter ); /* /* Critical sections or fast non recursive MUTEXes */ extern HB_EXPORT void hb_threadEnterCriticalSection( HB_CRITICAL_T * critical ); +extern HB_EXPORT void hb_threadEnterCriticalSectionGC( HB_CRITICAL_T * critical ); extern HB_EXPORT void hb_threadLeaveCriticalSection( HB_CRITICAL_T * critical ); /* conditional variables */ diff --git a/include/hbvm.h b/include/hbvm.h index 37be398067..b31049b3e6 100644 --- a/include/hbvm.h +++ b/include/hbvm.h @@ -175,6 +175,7 @@ extern HB_EXPORT void hb_vmPushItemRef( PHB_ITEM pItem ); /* push item refer extern HB_EXPORT HB_BOOL hb_vmIsMt( void ); /* return HB_TRUE if HVM is compiled with thread support */ extern HB_EXPORT void hb_vmLock( void ); /* lock VM blocking GC execution by other threads */ +extern HB_EXPORT void hb_vmLockForce( void ); /* lock VM blocking GC execution by other threads, ignore GC request */ extern HB_EXPORT void hb_vmUnlock( void ); /* unlock VM, allow GC execution */ #ifdef _HB_API_INTERNAL_ extern HB_EXPORT HB_BOOL hb_vmSuspendThreads( HB_BOOL fWait ); /* (try to) stop all threads except current one */ diff --git a/src/debug/dbgentry.c b/src/debug/dbgentry.c index f255a4d1fd..6e64c4bab5 100644 --- a/src/debug/dbgentry.c +++ b/src/debug/dbgentry.c @@ -84,7 +84,7 @@ static HB_BOOL hb_clsSetScope( HB_BOOL fScope ) memmove( array + index, array + index + 1, sizeof( type ) * ( length - index ) ); \ } while( 0 ) -#define HB_DBGCOMMON_LOCK() hb_threadEnterCriticalSection( &s_dbgMtx ) +#define HB_DBGCOMMON_LOCK() hb_threadEnterCriticalSectionGC( &s_dbgMtx ) #define HB_DBGCOMMON_UNLOCK() hb_threadLeaveCriticalSection( &s_dbgMtx ) static HB_CRITICAL_NEW( s_dbgMtx ); diff --git a/src/rdd/dbtotal.prg b/src/rdd/dbtotal.prg index 72ebe8d50d..2b404fc615 100644 --- a/src/rdd/dbtotal.prg +++ b/src/rdd/dbtotal.prg @@ -76,20 +76,20 @@ FUNCTION __dbTotal( cFile, xKey, aFields,; LOCAL oError LOCAL lError := .F. - IF HB_ISSTRING( xWhile ) - bWhileBlock := hb_macroBlock( xWhile ) - lRest := .T. - ELSEIF HB_ISBLOCK( xWhile ) + IF HB_ISEVALITEM( xWhile ) bWhileBlock := xWhile lRest := .T. + ELSEIF HB_ISSTRING( xWhile ) .AND. ! Empty( xWhile ) + bWhileBlock := hb_macroBlock( xWhile ) + lRest := .T. ELSE bWhileBlock := {|| .T. } ENDIF - IF HB_ISSTRING( xFor ) - bForBlock := hb_macroBlock( xFor ) - ELSEIF HB_ISBLOCK( xFor ) + IF HB_ISEVALITEM( xFor ) bForBlock := xFor + ELSEIF HB_ISSTRING( xFor ) .AND. ! Empty( xFor ) + bForBlock := hb_macroBlock( xFor ) ELSE bForBlock := {|| .T. } ENDIF @@ -120,16 +120,17 @@ FUNCTION __dbTotal( cFile, xKey, aFields,; BEGIN SEQUENCE - IF Empty( xKey ) - xKey := ordKey() - ENDIF - - IF HB_ISSTRING( xKey ) - bKeyBlock := hb_macroBlock( xKey ) - ELSEIF HB_ISBLOCK( xKey ) + IF HB_ISEVALITEM( xKey ) bKeyBlock := xKey ELSE - bKeyBlock := {|| .T. } + IF Empty( xKey ) + xKey := ordKey() + ENDIF + IF HB_ISSTRING( xKey ) .AND. ! Empty( xKey ) + bKeyBlock := hb_macroBlock( xKey ) + ELSE + bKeyBlock := {|| NIL } + ENDIF ENDIF aGetField := {} diff --git a/src/rdd/wacore.c b/src/rdd/wacore.c index 2b27cbea64..53e26f6d94 100644 --- a/src/rdd/wacore.c +++ b/src/rdd/wacore.c @@ -498,7 +498,7 @@ void hb_rddCloseDetachedAreas( void ) PHB_ITEM pDetachedArea; /* protect by critical section access to s_pDetachedAreas array */ - hb_threadEnterCriticalSection( &s_waMtx ); + hb_threadEnterCriticalSectionGC( &s_waMtx ); pDetachedArea = s_pDetachedAreas; s_pDetachedAreas = NULL; /* leave critical section */ @@ -545,7 +545,7 @@ HB_ERRCODE hb_rddDetachArea( AREAP pArea, PHB_ITEM pCargo ) hb_rddSelectWorkAreaNumber( iArea ); /* protect by critical section access to s_pDetachedAreas array */ - hb_threadEnterCriticalSection( &s_waMtx ); + hb_threadEnterCriticalSectionGC( &s_waMtx ); if( ! s_pDetachedAreas ) { s_pDetachedAreas = hb_itemArrayNew( 1 ); @@ -610,7 +610,7 @@ AREAP hb_rddRequestArea( const char * szAlias, PHB_ITEM pCargo, } /* protect by critical section access to s_pDetachedAreas array */ - hb_threadEnterCriticalSection( &s_waMtx ); + hb_threadEnterCriticalSectionGC( &s_waMtx ); for( ;; ) { if( s_pDetachedAreas ) @@ -677,7 +677,7 @@ PHB_ITEM hb_rddDetachedList( void ) pArray = hb_itemArrayNew( 0 ); /* protect by critical section access to s_pDetachedAreas array */ - hb_threadEnterCriticalSection( &s_waMtx ); + hb_threadEnterCriticalSectionGC( &s_waMtx ); if( s_pDetachedAreas ) { HB_SIZE nLen = hb_arrayLen( s_pDetachedAreas ), nPos; diff --git a/src/rtl/filebuf.c b/src/rtl/filebuf.c index 7822073664..8396584a6d 100644 --- a/src/rtl/filebuf.c +++ b/src/rtl/filebuf.c @@ -467,11 +467,10 @@ static PHB_FILE s_fileExtOpen( PHB_FILE_FUNCS pFuncs, const char * pszFileName, fReadonly = ( uiExFlags & ( FO_READ | FO_WRITE | FO_READWRITE ) ) == FO_READ; pszFile = hb_fsExtName( pszFileName, pDefExt, uiExFlags, pPaths ); -#if defined( HB_OS_UNIX ) hb_vmUnlock(); +#if defined( HB_OS_UNIX ) fResult = stat( ( char * ) pszFile, &statbuf ) == 0; hb_fsSetIOError( fResult, 0 ); - hb_vmLock(); if( fResult ) { @@ -526,7 +525,6 @@ static PHB_FILE s_fileExtOpen( PHB_FILE_FUNCS pFuncs, const char * pszFileName, { HB_ULONG device = 0, inode = 0; #if defined( HB_OS_UNIX ) - hb_vmUnlock(); if( fstat( hFile, &statbuf ) == 0 ) { device = ( HB_ULONG ) statbuf.st_dev; @@ -540,7 +538,6 @@ static PHB_FILE s_fileExtOpen( PHB_FILE_FUNCS pFuncs, const char * pszFileName, # endif } } - hb_vmLock(); #endif hb_threadEnterCriticalSection( &s_fileMtx ); @@ -594,7 +591,9 @@ static PHB_FILE s_fileExtOpen( PHB_FILE_FUNCS pFuncs, const char * pszFileName, #if defined( HB_OS_UNIX ) if( pFile && fSeek ) pFile = hb_fileposNew( pFile ); + #endif + hb_vmLock(); return pFile; } @@ -603,6 +602,7 @@ static void s_fileClose( PHB_FILE pFile ) { HB_FHANDLE hFile = FS_ERROR, hFileRO = FS_ERROR; + hb_vmUnlock(); hb_threadEnterCriticalSection( &s_fileMtx ); if( --pFile->used == 0 ) @@ -629,6 +629,7 @@ static void s_fileClose( PHB_FILE pFile ) } hb_threadLeaveCriticalSection( &s_fileMtx ); + hb_vmLock(); hb_fsSetError( 0 ); @@ -643,6 +644,7 @@ static HB_BOOL s_fileLock( PHB_FILE pFile, HB_FOFFSET nStart, HB_FOFFSET nLen, { HB_BOOL fResult, fLockFS = HB_FALSE; + hb_vmUnlock(); if( ( iType & FL_MASK ) == FL_UNLOCK ) { hb_threadEnterCriticalSection( &s_fileMtx ); @@ -680,6 +682,7 @@ static HB_BOOL s_fileLock( PHB_FILE pFile, HB_FOFFSET nStart, HB_FOFFSET nLen, else hb_fsSetError( fResult ? 0 : 33 ); } + hb_vmLock(); return fResult; } @@ -690,6 +693,8 @@ static int s_fileLockTest( PHB_FILE pFile, HB_FOFFSET nStart, HB_FOFFSET nLen, HB_BOOL fLocked; int iResult; + hb_vmUnlock(); + hb_threadEnterCriticalSection( &s_fileMtx ); fLocked = hb_fileTestLock( pFile, nStart, nLen ); hb_threadLeaveCriticalSection( &s_fileMtx ); @@ -704,6 +709,8 @@ static int s_fileLockTest( PHB_FILE pFile, HB_FOFFSET nStart, HB_FOFFSET nLen, else iResult = hb_fsLockTest( pFile->hFile, nStart, nLen, ( HB_USHORT ) iType ); + hb_vmLock(); + return iResult; } @@ -1037,6 +1044,7 @@ HB_BOOL hb_fileRegisterFull( const HB_FILE_FUNCS * pFuncs ) { HB_BOOL fResult = HB_FALSE; + hb_vmUnlock(); hb_threadEnterCriticalSection( &s_fileMtx ); if( s_iFileTypes < HB_FILE_TYPE_MAX ) @@ -1047,6 +1055,7 @@ HB_BOOL hb_fileRegisterFull( const HB_FILE_FUNCS * pFuncs ) } hb_threadLeaveCriticalSection( &s_fileMtx ); + hb_vmLock(); return fResult; } diff --git a/src/rtl/gtxwc/gtxwc.c b/src/rtl/gtxwc/gtxwc.c index 83e3bd9720..b4ae4b1b67 100644 --- a/src/rtl/gtxwc/gtxwc.c +++ b/src/rtl/gtxwc/gtxwc.c @@ -5420,6 +5420,8 @@ static HB_BOOL hb_gt_xwc_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) if( wnd->window ) { XWindowAttributes wndAttr; + + HB_XWC_XLIB_LOCK(); if( XGetWindowAttributes( wnd->dpy, wnd->window, &wndAttr ) ) { Window wndChild; @@ -5431,6 +5433,7 @@ static HB_BOOL hb_gt_xwc_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) y = wndAttr.y; } } + HB_XWC_XLIB_UNLOCK(); } if( ! pInfo->pResult ) @@ -5438,7 +5441,11 @@ static HB_BOOL hb_gt_xwc_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) hb_arrayNew( pInfo->pResult, 2 ); if( wnd->fInit ) + { + HB_XWC_XLIB_LOCK(); hb_gt_xwc_UpdateWindowCords( wnd, &x, &y ); + HB_XWC_XLIB_UNLOCK(); + } if( iType == HB_GTI_SETPOS_ROWCOL ) { @@ -5472,7 +5479,9 @@ static HB_BOOL hb_gt_xwc_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) } if( wnd->fInit ) { + HB_XWC_XLIB_LOCK(); XMoveWindow( wnd->dpy, wnd->window, x, y ); + HB_XWC_XLIB_UNLOCK(); } else { @@ -5495,10 +5504,15 @@ static HB_BOOL hb_gt_xwc_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) { wnd->colors[ iVal ].value = iColor; wnd->colors[ iVal ].set = HB_FALSE; - if( wnd->fInit && hb_gt_xwc_setPalette( wnd ) ) + if( wnd->fInit ) { - memset( wnd->pCurrScr, 0xFF, wnd->cols * wnd->rows * sizeof( HB_U32 ) ); - hb_gt_xwc_InvalidateChar( wnd, 0, 0, wnd->cols - 1, wnd->rows - 1 ); + HB_XWC_XLIB_LOCK(); + if( hb_gt_xwc_setPalette( wnd ) ) + { + memset( wnd->pCurrScr, 0xFF, wnd->cols * wnd->rows * sizeof( HB_U32 ) ); + hb_gt_xwc_InvalidateChar( wnd, 0, 0, wnd->cols - 1, wnd->rows - 1 ); + } + HB_XWC_XLIB_UNLOCK(); } } } @@ -5523,10 +5537,15 @@ static HB_BOOL hb_gt_xwc_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) wnd->colors[ iVal ].set = HB_FALSE; } } - if( wnd->fInit && hb_gt_xwc_setPalette( wnd ) ) + if( wnd->fInit ) { - memset( wnd->pCurrScr, 0xFF, wnd->cols * wnd->rows * sizeof( HB_U32 ) ); - hb_gt_xwc_InvalidateChar( wnd, 0, 0, wnd->cols - 1, wnd->rows - 1 ); + HB_XWC_XLIB_LOCK(); + if( hb_gt_xwc_setPalette( wnd ) ) + { + memset( wnd->pCurrScr, 0xFF, wnd->cols * wnd->rows * sizeof( HB_U32 ) ); + hb_gt_xwc_InvalidateChar( wnd, 0, 0, wnd->cols - 1, wnd->rows - 1 ); + } + HB_XWC_XLIB_UNLOCK(); } } } diff --git a/src/rtl/hbgtcore.c b/src/rtl/hbgtcore.c index 03718a0fc7..ea07a64aca 100644 --- a/src/rtl/hbgtcore.c +++ b/src/rtl/hbgtcore.c @@ -160,6 +160,32 @@ static void hb_gt_def_Free( PHB_GT pGT ) if( pGT == ( PHB_GT ) hb_stackGetGT() ) hb_stackSetGT( NULL ); + if( pGT->pNotifierBlock ) + { + hb_itemRelease( pGT->pNotifierBlock ); + pGT->pNotifierBlock = NULL; + } + if( pGT->pInkeyFilterBlock ) + { + hb_itemRelease( pGT->pInkeyFilterBlock ); + pGT->pInkeyFilterBlock = NULL; + } + if( pGT->pInkeyReadBlock ) + { + hb_itemRelease( pGT->pInkeyReadBlock ); + pGT->pInkeyReadBlock = NULL; + } + if( pGT->pCargo ) + { + hb_itemRelease( pGT->pCargo ); + pGT->pCargo = NULL; + } + if( pGT->pMutex ) + { + hb_itemRelease( pGT->pMutex ); + pGT->pMutex = NULL; + } + if( pGT->screenBuffer ) hb_xfree( pGT->screenBuffer ); if( pGT->prevBuffer ) @@ -168,19 +194,6 @@ static void hb_gt_def_Free( PHB_GT pGT ) hb_xfree( pGT->pLines ); if( pGT->iColorCount > 0 ) hb_xfree( pGT->pColor ); - - if( pGT->pNotifierBlock ) - hb_itemRelease( pGT->pNotifierBlock ); - if( pGT->pInkeyFilterBlock ) - hb_itemRelease( pGT->pInkeyFilterBlock ); - if( pGT->pInkeyReadBlock ) - hb_itemRelease( pGT->pInkeyReadBlock ); - if( pGT->pCargo ) - hb_itemRelease( pGT->pCargo ); - - if( pGT->pMutex ) - hb_itemRelease( pGT->pMutex ); - if( pGT->pFuncTable ) hb_xfree( pGT->pFuncTable ); diff --git a/src/rtl/hbsocket.c b/src/rtl/hbsocket.c index d71fcaddd8..b99b1b7089 100644 --- a/src/rtl/hbsocket.c +++ b/src/rtl/hbsocket.c @@ -2806,8 +2806,10 @@ int hb_socketSelect( PHB_ITEM pArrayRD, HB_BOOL fSetRD, else ptv = NULL; + hb_vmUnlock(); ret = select( ( int ) ( maxsd + 1 ), pfds[ 0 ], pfds[ 1 ], pfds[ 2 ], ptv ); hb_socketSetOsError( ret == -1 ? HB_SOCK_GETERROR() : 0 ); + hb_vmLock(); for( i = 0; i < 3; i++ ) { diff --git a/src/vm/arrays.c b/src/vm/arrays.c index 7dc12bd9f3..ffd723a69c 100644 --- a/src/vm/arrays.c +++ b/src/vm/arrays.c @@ -77,23 +77,20 @@ static void hb_arrayReleaseItems( PHB_BASEARRAY pBaseArray ) { if( pBaseArray->nLen ) { - PHB_ITEM pItems = pBaseArray->pItems; - HB_SIZE nLen = pBaseArray->nLen; - - /* - * clear the pBaseArray->pItems to avoid infinite loop in cross - * referenced items when pBaseArray is not freed due to buggy - * object destructor [druzus] - */ - pBaseArray->pItems = NULL; - pBaseArray->nLen = 0; - - while( nLen-- ) + do { - if( HB_IS_COMPLEX( pItems + nLen ) ) - hb_itemClear( pItems + nLen ); + pBaseArray->nLen--; + if( HB_IS_COMPLEX( pBaseArray->pItems + pBaseArray->nLen ) ) + hb_itemClear( pBaseArray->pItems + pBaseArray->nLen ); + } + while( pBaseArray->nLen ); + + /* protection against possible base array resizing in user destructors */ + if( pBaseArray->pItems ) + { + hb_xfree( pBaseArray->pItems ); + pBaseArray->pItems = NULL; } - hb_xfree( pItems ); } } @@ -123,19 +120,9 @@ static HB_GARBAGE_FUNC( hb_arrayGarbageRelease ) HB_STACK_TLS_PRELOAD hb_arrayPushBase( pBaseArray ); hb_objDestructorCall( hb_stackItemFromTop( -1 ) ); - - /* Clear object properities before hb_stackPop(), [druzus] */ - pBaseArray->uiClass = 0; +// /* Clear object properities before hb_stackPop(), [druzus] */ +// pBaseArray->uiClass = 0; hb_stackPop(); - - /* - * release array items before hb_gcRefCheck() to avoid double - * pBaseArray freeing when it will have cross references to - * self after executing buggy destructor [druzus] - */ - hb_arrayReleaseItems( pBaseArray ); - hb_gcRefCheck( pBaseArray ); - return; } /* diff --git a/src/vm/codebloc.c b/src/vm/codebloc.c index 454db7ac93..e359fd0cbb 100644 --- a/src/vm/codebloc.c +++ b/src/vm/codebloc.c @@ -83,21 +83,14 @@ static HB_GARBAGE_FUNC( hb_codeblockGarbageDelete ) */ if( pCBlock->pLocals ) { - PHB_ITEM pLocals = pCBlock->pLocals; - HB_USHORT uiLocals = pCBlock->uiLocals; - - /* clear pCBlock->pLocals to avoid infinit loop in cross - * referenced items - */ + if( hb_xRefDec( pCBlock->pLocals ) ) + { + while( pCBlock->uiLocals ) + hb_memvarValueDecRef( pCBlock->pLocals[ pCBlock->uiLocals-- ].item.asMemvar.value ); + hb_xfree( pCBlock->pLocals ); + } pCBlock->pLocals = NULL; pCBlock->uiLocals = 0; - - if( hb_xRefDec( pLocals ) ) - { - while( uiLocals ) - hb_memvarValueDecRef( pLocals[ uiLocals-- ].item.asMemvar.value ); - hb_xfree( pLocals ); - } } } diff --git a/src/vm/fm.c b/src/vm/fm.c index e0abdb817c..1387028cc8 100644 --- a/src/vm/fm.c +++ b/src/vm/fm.c @@ -616,25 +616,6 @@ void * hb_xalloc( HB_SIZE nSize ) /* allocates fixed memory, returns NUL { PHB_TRACEINFO pTrace; - HB_FM_LOCK(); - - if( ! s_pFirstBlock ) - { - pMem->pPrevBlock = NULL; - s_pFirstBlock = pMem; - } - else - { - pMem->pPrevBlock = s_pLastBlock; - s_pLastBlock->pNextBlock = pMem; - } - s_pLastBlock = pMem; - - pMem->pNextBlock = NULL; - pMem->u32Signature = HB_MEMINFO_SIGNATURE; - HB_FM_SETSIG( HB_MEM_PTR( pMem ), nSize ); - pMem->nSize = nSize; /* size of the memory block */ - pTrace = hb_traceinfo(); if( hb_tr_level() >= HB_TR_DEBUG || pTrace->level == HB_TR_FM ) { @@ -655,6 +636,25 @@ void * hb_xalloc( HB_SIZE nSize ) /* allocates fixed memory, returns NUL hb_stackBaseProcInfo( pMem->szProcName, &pMem->uiProcLine ); } + HB_FM_LOCK(); + + if( ! s_pFirstBlock ) + { + pMem->pPrevBlock = NULL; + s_pFirstBlock = pMem; + } + else + { + pMem->pPrevBlock = s_pLastBlock; + s_pLastBlock->pNextBlock = pMem; + } + s_pLastBlock = pMem; + + pMem->pNextBlock = NULL; + pMem->u32Signature = HB_MEMINFO_SIGNATURE; + HB_FM_SETSIG( HB_MEM_PTR( pMem ), nSize ); + pMem->nSize = nSize; /* size of the memory block */ + s_nMemoryConsumed += nSize + sizeof( HB_COUNTER ); if( s_nMemoryMaxConsumed < s_nMemoryConsumed ) s_nMemoryMaxConsumed = s_nMemoryConsumed; @@ -702,25 +702,6 @@ void * hb_xgrab( HB_SIZE nSize ) /* allocates fixed memory, exits on fai { PHB_TRACEINFO pTrace; - HB_FM_LOCK(); - - if( ! s_pFirstBlock ) - { - pMem->pPrevBlock = NULL; - s_pFirstBlock = pMem; - } - else - { - pMem->pPrevBlock = s_pLastBlock; - s_pLastBlock->pNextBlock = pMem; - } - s_pLastBlock = pMem; - - pMem->pNextBlock = NULL; - pMem->u32Signature = HB_MEMINFO_SIGNATURE; - HB_FM_SETSIG( HB_MEM_PTR( pMem ), nSize ); - pMem->nSize = nSize; /* size of the memory block */ - pTrace = hb_traceinfo(); if( hb_tr_level() >= HB_TR_DEBUG || pTrace->level == HB_TR_FM ) { @@ -741,6 +722,25 @@ void * hb_xgrab( HB_SIZE nSize ) /* allocates fixed memory, exits on fai hb_stackBaseProcInfo( pMem->szProcName, &pMem->uiProcLine ); } + HB_FM_LOCK(); + + if( ! s_pFirstBlock ) + { + pMem->pPrevBlock = NULL; + s_pFirstBlock = pMem; + } + else + { + pMem->pPrevBlock = s_pLastBlock; + s_pLastBlock->pNextBlock = pMem; + } + s_pLastBlock = pMem; + + pMem->pNextBlock = NULL; + pMem->u32Signature = HB_MEMINFO_SIGNATURE; + HB_FM_SETSIG( HB_MEM_PTR( pMem ), nSize ); + pMem->nSize = nSize; /* size of the memory block */ + s_nMemoryConsumed += nSize + sizeof( HB_COUNTER ); if( s_nMemoryMaxConsumed < s_nMemoryConsumed ) s_nMemoryMaxConsumed = s_nMemoryConsumed; @@ -805,8 +805,6 @@ void * hb_xrealloc( void * pMem, HB_SIZE nSize ) /* reallocates memory */ HB_FM_CLRSIG( pMem, nMemSize ); - HB_FM_LOCK(); - #ifdef HB_PARANOID_MEM_CHECK pMem = malloc( HB_ALLOC_SIZE( nSize ) ); if( pMem ) @@ -826,6 +824,8 @@ void * hb_xrealloc( void * pMem, HB_SIZE nSize ) /* reallocates memory */ pMem = realloc( pMemBlock, HB_ALLOC_SIZE( nSize ) ); #endif + HB_FM_LOCK(); + s_nMemoryConsumed += ( nSize - nMemSize ); if( s_nMemoryMaxConsumed < s_nMemoryConsumed ) s_nMemoryMaxConsumed = s_nMemoryConsumed; diff --git a/src/vm/garbage.c b/src/vm/garbage.c index 9a06cc91d1..dde1eb8dcc 100644 --- a/src/vm/garbage.c +++ b/src/vm/garbage.c @@ -224,7 +224,7 @@ void * hb_gcAllocRaw( HB_SIZE nSize, const HB_GC_FUNCS * pFuncs ) HB_GC_UNLOCK(); hb_gcCollectAll( HB_TRUE ); HB_GC_LOCK(); - pAlloc->used = s_uUsedFlag; + pAlloc->used = s_uUsedFlag; } HB_GC_AUTO_INC(); #endif @@ -289,26 +289,33 @@ void hb_gcRefFree( void * pBlock ) /* Don't release the block that will be deleted during finalization */ if( ! ( pAlloc->used & HB_GC_DELETE ) ) { - /* unlink the block first to avoid possible problems - * if cleanup function activate GC - */ - HB_GC_LOCK(); - if( pAlloc->locked ) - hb_gcUnlink( &s_pLockedBlock, pAlloc ); - else - { - hb_gcUnlink( &s_pCurrBlock, pAlloc ); - HB_GC_AUTO_DEC(); - } - HB_GC_UNLOCK(); - pAlloc->used |= HB_GC_DELETE; /* execute clean-up function */ pAlloc->pFuncs->clear( pBlock ); - if( pAlloc->used & HB_GC_DELETE ) + 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 ); + } } } } @@ -327,32 +334,6 @@ HB_COUNTER hb_gcRefCount( void * pBlock ) } -/* - * Check if block still cannot be accessed after destructor execution - */ -void hb_gcRefCheck( void * pBlock ) -{ - PHB_GARBAGE pAlloc = HB_GC_PTR( pBlock ); - - if( ! ( pAlloc->used & HB_GC_DELETELST ) ) - { - if( hb_xRefCount( pAlloc ) != 0 ) - { - pAlloc->used = s_uUsedFlag; - pAlloc->locked = 0; - - HB_GC_LOCK(); - hb_gcLink( &s_pCurrBlock, pAlloc ); - HB_GC_AUTO_INC(); - HB_GC_UNLOCK(); - - if( hb_vmRequestQuery() == 0 ) - hb_errRT_BASE( EG_DESTRUCTOR, 1301, NULL, "Reference to freed block", 0 ); - } - } -} - - HB_GARBAGE_FUNC( hb_gcDummyMark ) { HB_SYMBOL_UNUSED( Cargo ); @@ -483,7 +464,7 @@ void hb_gcMark( void * pBlock ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pBlock ); - if( pAlloc->used == s_uUsedFlag ) + if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { pAlloc->used ^= HB_GC_USED_FLAG; /* mark this codeblock as used */ pAlloc->pFuncs->mark( pBlock ); @@ -509,7 +490,7 @@ void hb_gcItemRef( PHB_ITEM pItem ) { /* array item reference */ PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asRefer.BasePtr.array ); - if( pAlloc->used == s_uUsedFlag ) + if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this array as used */ pAlloc->used ^= HB_GC_USED_FLAG; @@ -526,7 +507,7 @@ void hb_gcItemRef( PHB_ITEM pItem ) PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asArray.value ); /* Check this array only if it was not checked yet */ - if( pAlloc->used == s_uUsedFlag ) + if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this array as used so it will be no re-checked from * other references @@ -541,7 +522,7 @@ void hb_gcItemRef( PHB_ITEM 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 == s_uUsedFlag ) + if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this hash table as used */ pAlloc->used ^= HB_GC_USED_FLAG; @@ -553,7 +534,7 @@ void hb_gcItemRef( PHB_ITEM pItem ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asBlock.value ); - if( pAlloc->used == s_uUsedFlag ) + if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this codeblock as used */ pAlloc->used ^= HB_GC_USED_FLAG; @@ -567,7 +548,7 @@ void hb_gcItemRef( PHB_ITEM pItem ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asPointer.value ); - if( pAlloc->used == s_uUsedFlag ) + if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this memory block as used */ pAlloc->used ^= HB_GC_USED_FLAG; diff --git a/src/vm/hashes.c b/src/vm/hashes.c index 054d231ee7..539a82285e 100644 --- a/src/vm/hashes.c +++ b/src/vm/hashes.c @@ -88,16 +88,31 @@ static HB_GARBAGE_FUNC( hb_hashGarbageRelease ) if( pBaseHash->nSize > 0 ) { - PHB_HASHPAIR pPairs = pBaseHash->pPairs; - HB_SIZE nLen = pBaseHash->nLen; + while( pBaseHash->nLen ) + { + PHB_ITEM pKey, pVal; - /* - * clear the pBaseHash->pPairs to avoid infinite loop in cross - * referenced items when pBaseArray is not freed due to buggy - * object destructor [druzus] - */ - pBaseHash->pPairs = NULL; - pBaseHash->nLen = 0; + pBaseHash->nLen--; + pKey = &pBaseHash->pPairs[ pBaseHash->nLen ].key; + pVal = &pBaseHash->pPairs[ pBaseHash->nLen ].value; + + /* small hack for buggy destructors in hash items */ + pBaseHash->iFlags |= HB_HASH_RESORT; + + if( HB_IS_GCITEM( pKey ) && HB_IS_GCITEM( pVal ) ) + { + hb_itemRawMove( hb_stackAllocItem(), pVal ); + hb_itemClear( pKey ); + hb_stackPop(); + } + else + { + if( HB_IS_COMPLEX( pKey ) ) + hb_itemClear( pKey ); + if( HB_IS_COMPLEX( pVal ) ) + hb_itemClear( pVal ); + } + } if( pBaseHash->pnPos ) { @@ -105,15 +120,13 @@ static HB_GARBAGE_FUNC( hb_hashGarbageRelease ) pBaseHash->pnPos = NULL; } - while( nLen-- ) + if( pBaseHash->pPairs ) { - if( HB_IS_COMPLEX( &pPairs[ nLen ].key ) ) - hb_itemClear( &pPairs[ nLen ].key ); - if( HB_IS_COMPLEX( &pPairs[ nLen ].value ) ) - hb_itemClear( &pPairs[ nLen ].value ); + hb_xfree( pBaseHash->pPairs ); + pBaseHash->pPairs = NULL; } - hb_xfree( pPairs ); } + if( pBaseHash->pDefault ) { PHB_ITEM pDefault = pBaseHash->pDefault; diff --git a/src/vm/hvm.c b/src/vm/hvm.c index 217bb8f269..8287c193d9 100644 --- a/src/vm/hvm.c +++ b/src/vm/hvm.c @@ -520,6 +520,29 @@ void hb_vmLock( void ) } } +void hb_vmLockForce( void ) +{ + HB_STACK_TLS_PRELOAD + + if( hb_stackId() ) /* check if thread has associated HVM stack */ + { + if( hb_stackLock() == 0 ) + { + HB_VM_LOCK(); + if( hb_vmThreadRequest & HB_THREQUEST_QUIT ) + { + if( ! hb_stackQuitState() ) + { + hb_stackSetQuitState( HB_TRUE ); + hb_stackSetActionRequest( HB_QUIT_REQUESTED ); + } + } + s_iRunningCount++; + HB_VM_UNLOCK(); + } + } +} + /* (try to) stop all threads except current one */ HB_BOOL hb_vmSuspendThreads( HB_BOOL fWait ) { @@ -542,8 +565,8 @@ HB_BOOL hb_vmSuspendThreads( HB_BOOL fWait ) if( hb_vmThreadRequest & HB_THREQUEST_QUIT ) break; } - hb_vmThreadRequest &= ~HB_THREQUEST_STOP; ++s_iRunningCount; + hb_vmThreadRequest &= ~HB_THREQUEST_STOP; hb_threadCondBroadcast( &s_vmCond ); } @@ -12025,6 +12048,7 @@ void hb_vmIsStackRef( void ) PHB_THREADSTATE pStack = s_vmStackLst; do { + hb_gcMark( pStack ); if( pStack->fActive && pStack->pStackId ) hb_stackIsStackRef( pStack->pStackId, hb_vmTSVarClean ); pStack = pStack->pNext; diff --git a/src/vm/thread.c b/src/vm/thread.c index a35bbdd88c..e1df1c645f 100644 --- a/src/vm/thread.c +++ b/src/vm/thread.c @@ -574,6 +574,23 @@ void hb_threadEnterCriticalSection( HB_CRITICAL_T * critical ) #endif } +void hb_threadEnterCriticalSectionGC( HB_CRITICAL_T * critical ) +{ +#if ! defined( HB_MT_VM ) + HB_SYMBOL_UNUSED( critical ); +#elif defined( HB_CRITICAL_NEED_INIT ) + if( ! critical->fInit ) + hb_threadCriticalInit( critical ); + hb_vmUnlock(); + HB_CRITICAL_LOCK( critical->critical.value ); + hb_vmLockForce(); +#else + hb_vmUnlock(); + HB_CRITICAL_LOCK( *critical ); + hb_vmLockForce(); +#endif +} + void hb_threadLeaveCriticalSection( HB_CRITICAL_T * critical ) { #if ! defined( HB_MT_VM ) @@ -954,6 +971,8 @@ static HB_GARBAGE_FUNC( hb_threadMark ) if( pThread->pResult ) hb_gcMark( pThread->pResult ); + if( pThread->hGT ) + hb_gtIsGtRef( pThread->hGT ); } static const HB_GC_FUNCS s_gcThreadFuncs = @@ -1647,6 +1666,7 @@ typedef struct _HB_MUTEX int lock_count; int lockers; int waiters; + int syncsignals; PHB_ITEM events; HB_THREAD_ID owner; HB_RAWCRITICAL_T mutex; @@ -1750,7 +1770,10 @@ static HB_GARBAGE_FUNC( hb_mutexDestructor ) #endif if( pMutex->events ) + { hb_itemRelease( pMutex->events ); + pMutex->events = NULL; + } #if ! defined( HB_MT_VM ) /* nothing */ @@ -1831,36 +1854,21 @@ void hb_threadMutexSyncSignal( PHB_ITEM pItemMtx ) if( pMutex ) { + hb_vmUnlock(); HB_CRITICAL_LOCK( pMutex->mutex ); if( pMutex->waiters ) { - int iCount = pMutex->waiters; + int iCount = pMutex->waiters - pMutex->syncsignals; - if( ! pMutex->events ) - { - pMutex->events = hb_itemArrayNew( iCount ); - hb_gcUnlock( pMutex->events ); - } - else - { - HB_ULONG ulLen = ( HB_ULONG ) hb_arrayLen( pMutex->events ); - iCount -= ulLen; - if( iCount > 0 ) - hb_arraySize( pMutex->events, ulLen + iCount ); - } if( iCount == 1 ) HB_COND_SIGNAL( pMutex->cond_w ); else if( iCount > 0 ) HB_COND_SIGNALN( pMutex->cond_w, iCount ); } - else if( ! pMutex->events ) - { - pMutex->events = hb_itemArrayNew( 1 ); - hb_gcUnlock( pMutex->events ); - } HB_CRITICAL_UNLOCK( pMutex->mutex ); + hb_vmLock(); } } @@ -1888,7 +1896,7 @@ HB_BOOL hb_threadMutexSyncWait( PHB_ITEM pItemMtx, HB_ULONG ulMilliSec, HB_CRITICAL_LOCK( pMutex->mutex ); - if( ulMilliSec && ! ( pMutex->events && hb_arrayLen( pMutex->events ) > 0 ) ) + if( ulMilliSec && pMutex->syncsignals == 0 ) { /* release own lock from sync mutex */ if( pSyncMutex && HB_THREAD_EQUAL( pSyncMutex->owner, HB_THREAD_SELF() ) ) @@ -1904,7 +1912,7 @@ HB_BOOL hb_threadMutexSyncWait( PHB_ITEM pItemMtx, HB_ULONG ulMilliSec, if( ulMilliSec == HB_THREAD_INFINITE_WAIT ) { - while( ! pMutex->events || hb_arrayLen( pMutex->events ) == 0 ) + while( pMutex->syncsignals == 0 ) { pMutex->waiters++; # if defined( HB_PTHREAD_API ) @@ -1929,7 +1937,7 @@ HB_BOOL hb_threadMutexSyncWait( PHB_ITEM pItemMtx, HB_ULONG ulMilliSec, struct timespec ts; hb_threadTimeInit( &ts, ulMilliSec ); - while( ! pMutex->events || hb_arrayLen( pMutex->events ) == 0 ) + while( pMutex->syncsignals == 0 ) { if( pthread_cond_timedwait( &pMutex->cond_w, &pMutex->mutex, &ts ) != 0 ) break; @@ -1956,9 +1964,9 @@ HB_BOOL hb_threadMutexSyncWait( PHB_ITEM pItemMtx, HB_ULONG ulMilliSec, } } - if( pMutex->events && hb_arrayLen( pMutex->events ) > 0 ) + if( pMutex->syncsignals > 0 ) { - hb_arraySize( pMutex->events, hb_arrayLen( pMutex->events ) - 1 ); + pMutex->syncsignals--; fResult = HB_TRUE; } @@ -2014,6 +2022,7 @@ HB_BOOL hb_threadMutexUnlock( PHB_ITEM pItem ) fResult = HB_TRUE; } #else + hb_vmUnlock(); HB_CRITICAL_LOCK( pMutex->mutex ); if( HB_THREAD_EQUAL( pMutex->owner, HB_THREAD_SELF() ) ) { @@ -2026,6 +2035,7 @@ HB_BOOL hb_threadMutexUnlock( PHB_ITEM pItem ) fResult = HB_TRUE; } HB_CRITICAL_UNLOCK( pMutex->mutex ); + hb_vmLock(); #endif } return fResult; @@ -2160,6 +2170,34 @@ HB_BOOL hb_threadMutexTimedLock( PHB_ITEM pItem, HB_ULONG ulMilliSec ) return fResult; } +#if defined( HB_MT_VM ) +static void hb_thredMutexEventInit( PHB_MUTEX pMutex ) +{ + PHB_ITEM pEvents; + + HB_CRITICAL_UNLOCK( pMutex->mutex ); + hb_vmLock(); + pEvents = hb_itemArrayNew( 0 ); + hb_vmUnlock(); + HB_CRITICAL_LOCK( pMutex->mutex ); + if( pMutex->events == NULL ) + { + hb_vmLockForce(); + pMutex->events = pEvents; + hb_gcUnlock( pMutex->events ); + hb_vmUnlock(); + } + else + { + HB_CRITICAL_UNLOCK( pMutex->mutex ); + hb_vmLock(); + hb_itemRelease( pEvents ); + hb_vmUnlock(); + HB_CRITICAL_LOCK( pMutex->mutex ); + } +} +#endif + void hb_threadMutexNotify( PHB_ITEM pItem, PHB_ITEM pNotifier, HB_BOOL fWaiting ) { PHB_MUTEX pMutex = hb_mutexPtr( pItem ); @@ -2213,59 +2251,53 @@ void hb_threadMutexNotify( PHB_ITEM pItem, PHB_ITEM pNotifier, HB_BOOL fWaiting } } #else + hb_vmUnlock(); HB_CRITICAL_LOCK( pMutex->mutex ); - if( ! fWaiting ) + + if( ! fWaiting || pMutex->waiters ) { if( ! pMutex->events ) - { - pMutex->events = hb_itemArrayNew( 1 ); - hb_gcUnlock( pMutex->events ); - if( pNotifier && ! HB_IS_NIL( pNotifier ) ) - hb_arraySet( pMutex->events, 1, pNotifier ); - } - else if( pNotifier ) - hb_arrayAdd( pMutex->events, pNotifier ); - else - hb_arraySize( pMutex->events, hb_arrayLen( pMutex->events ) + 1 ); - if( pMutex->waiters ) - HB_COND_SIGNAL( pMutex->cond_w ); - } - else if( pMutex->waiters ) - { - int iCount = pMutex->waiters; - HB_ULONG ulLen; + hb_thredMutexEventInit( pMutex ); - if( pMutex->events ) + if( ! fWaiting ) { - ulLen = ( HB_ULONG ) hb_arrayLen( pMutex->events ); - iCount -= ulLen; - if( iCount > 0 ) - hb_arraySize( pMutex->events, ulLen + iCount ); - } - else - { - ulLen = 0; - pMutex->events = hb_itemArrayNew( iCount ); - hb_gcUnlock( pMutex->events ); - } - if( iCount > 0 ) - { - if( pNotifier && ! HB_IS_NIL( pNotifier ) ) - { - int iSet = iCount; - do - { - hb_arraySet( pMutex->events, ++ulLen, pNotifier ); - } - while( --iSet ); - } - if( iCount == 1 ) - HB_COND_SIGNAL( pMutex->cond_w ); + hb_vmLockForce(); + if( pNotifier ) + hb_arrayAdd( pMutex->events, pNotifier ); else - HB_COND_SIGNALN( pMutex->cond_w, iCount ); + hb_arraySize( pMutex->events, hb_arrayLen( pMutex->events ) + 1 ); + hb_vmUnlock(); + if( pMutex->waiters ) + HB_COND_SIGNAL( pMutex->cond_w ); + } + else if( pMutex->waiters ) + { + int iLen = ( int ) hb_arrayLen( pMutex->events ); + int iCount = pMutex->waiters - iLen; + + if( iCount > 0 ) + { + hb_vmLockForce(); + hb_arraySize( pMutex->events, iLen + iCount ); + if( pNotifier && ! HB_IS_NIL( pNotifier ) ) + { + int iSet = iCount; + do + { + hb_arraySet( pMutex->events, ++iLen, pNotifier ); + } + while( --iSet ); + } + hb_vmUnlock(); + if( iCount == 1 ) + HB_COND_SIGNAL( pMutex->cond_w ); + else + HB_COND_SIGNALN( pMutex->cond_w, iCount ); + } } } HB_CRITICAL_UNLOCK( pMutex->mutex ); + hb_vmLock(); #endif } } @@ -2291,14 +2323,22 @@ PHB_ITEM hb_threadMutexSubscribe( PHB_ITEM pItem, HB_BOOL fClear ) } } #else + HB_STACK_TLS_PRELOAD int lock_count = 0; hb_vmUnlock(); - HB_CRITICAL_LOCK( pMutex->mutex ); if( fClear && pMutex->events ) - hb_arraySize( pMutex->events, 0 ); + { + hb_vmLockForce(); + hb_itemMove( hb_stackAllocItem(), pMutex->events ); + pMutex->events = NULL; + HB_CRITICAL_UNLOCK( pMutex->mutex ); + hb_stackPop(); + hb_vmUnlock(); + HB_CRITICAL_LOCK( pMutex->mutex ); + } /* release own lock from this mutex */ if( HB_THREAD_EQUAL( pMutex->owner, HB_THREAD_SELF() ) ) @@ -2330,10 +2370,12 @@ PHB_ITEM hb_threadMutexSubscribe( PHB_ITEM pItem, HB_BOOL fClear ) if( pMutex->events && hb_arrayLen( pMutex->events ) > 0 ) { - pResult = hb_itemNew( NULL ); + hb_vmLockForce(); + pResult = hb_stackAllocItem(); hb_arrayGet( pMutex->events, 1, pResult ); hb_arrayDel( pMutex->events, 1 ); hb_arraySize( pMutex->events, hb_arrayLen( pMutex->events ) - 1 ); + hb_vmUnlock(); } /* restore the own lock on this mutex if necessary */ @@ -2363,8 +2405,13 @@ PHB_ITEM hb_threadMutexSubscribe( PHB_ITEM pItem, HB_BOOL fClear ) } HB_CRITICAL_UNLOCK( pMutex->mutex ); - hb_vmLock(); + + if( pResult ) + { + pResult = hb_itemNew( pResult ); + hb_stackPop(); + } #endif } return pResult; @@ -2393,14 +2440,22 @@ PHB_ITEM hb_threadMutexTimedSubscribe( PHB_ITEM pItem, HB_ULONG ulMilliSec, HB_B } } #else + HB_STACK_TLS_PRELOAD int lock_count = 0; hb_vmUnlock(); - HB_CRITICAL_LOCK( pMutex->mutex ); if( fClear && pMutex->events ) - hb_arraySize( pMutex->events, 0 ); + { + hb_vmLockForce(); + hb_itemMove( hb_stackAllocItem(), pMutex->events ); + pMutex->events = NULL; + HB_CRITICAL_UNLOCK( pMutex->mutex ); + hb_stackPop(); + hb_vmUnlock(); + HB_CRITICAL_LOCK( pMutex->mutex ); + } if( ulMilliSec && ! ( pMutex->events && hb_arrayLen( pMutex->events ) > 0 ) ) { @@ -2449,10 +2504,12 @@ PHB_ITEM hb_threadMutexTimedSubscribe( PHB_ITEM pItem, HB_ULONG ulMilliSec, HB_B if( pMutex->events && hb_arrayLen( pMutex->events ) > 0 ) { - pResult = hb_itemNew( NULL ); + hb_vmLockForce(); + pResult = hb_stackAllocItem(); hb_arrayGet( pMutex->events, 1, pResult ); hb_arrayDel( pMutex->events, 1 ); hb_arraySize( pMutex->events, hb_arrayLen( pMutex->events ) - 1 ); + hb_vmUnlock(); } /* restore the own lock on this mutex if necessary */ @@ -2482,8 +2539,13 @@ PHB_ITEM hb_threadMutexTimedSubscribe( PHB_ITEM pItem, HB_ULONG ulMilliSec, HB_B } HB_CRITICAL_UNLOCK( pMutex->mutex ); - hb_vmLock(); + + if( pResult ) + { + pResult = hb_itemNew( pResult ); + hb_stackPop(); + } #endif } return pResult;