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;