diff --git a/harbour/ChangeLog b/harbour/ChangeLog index d7524d962c..15536336f9 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,30 @@ 2008-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org) */ +2008-09-29 11:18 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/include/hbvm.h + * harbour/include/hbthread.h + * harbour/source/vm/hvm.c + * harbour/source/vm/thread.c + + added hb_vmThreadRegister() funtion which allows to register new + thread in HVM without HVM stack allocation + + added hb_vmThreadRelease() which removes registered thread which + does not have allocated HVM stack yet + + added hb_threadStateNew() which returns new thread control state + which can be used as parameter to hb_vmThreadInit(), + hb_vmThreadRegister(), hb_vmThreadRelease() + * register thread control state also for main thread + Now hb_threadSelf() returns thread pointer also for main thread + ! fixed possible race condition in hb_threadWaitForAll() and + hb_threadTerminateAll() by using hb_vmThreadRegister() before + starting thread. + + * harbour/source/rtl/idle.c + * interrupt hb_idleSleep() on QUIT or BREAK requests + + * harbour/tests/mt/mttest09.prg + * small cleanup + 2008-09-29 10:13 UTC+0200 Viktor Szakats (harbour.01 syenar hu) * make_b32.mak * make_vc.mak diff --git a/harbour/include/hbthread.h b/harbour/include/hbthread.h index 691c374306..186ca43f52 100644 --- a/harbour/include/hbthread.h +++ b/harbour/include/hbthread.h @@ -275,11 +275,15 @@ typedef struct _HB_THREADSTATE PHB_ITEM pResult; PHB_ITEM pThItm; HB_THREAD_T th_id; + struct _HB_THREADSTATE * pPrev; + struct _HB_THREADSTATE * pNext; } HB_THREADSTATE, * PHB_THREADSTATE; extern void hb_threadInit( void ); extern void hb_threadExit( void ); +extern PHB_THREADSTATE hb_threadStateNew( void ); + /* Critical sections or fast non recursive MUTEXes */ extern void hb_threadEnterCriticalSection( HB_CRITICAL_T * critical ); extern void hb_threadLeaveCriticalSection( HB_CRITICAL_T * critical ); diff --git a/harbour/include/hbvm.h b/harbour/include/hbvm.h index 5f3bbadfb6..657ee04764 100644 --- a/harbour/include/hbvm.h +++ b/harbour/include/hbvm.h @@ -159,6 +159,8 @@ extern HB_EXPORT void hb_vmUnlock( void ); /* unlock VM, allow GC execution extern HB_EXPORT BOOL hb_vmSuspendThreads( BOOL fWait ); /* (try to) stop all threads except current one */ extern HB_EXPORT void hb_vmResumeThreads( void ); /* unblock execution of threads stopped by hb_vmSuspendThreads() */ #endif +extern HB_EXPORT BOOL hb_vmThreadRegister( void * ); /* Register new thread without local thread HVM stack */ +extern HB_EXPORT void hb_vmThreadRelease( void * ); /* Remove registered thread which does not have local thread HVM stack yet */ extern HB_EXPORT void hb_vmThreadInit( void * ); /* allocate local thread HVM stack */ extern HB_EXPORT void hb_vmThreadQuit( void ); /* destroy local thread HVM stack */ extern HB_EXPORT void hb_vmThreadQuitRequest( void * ); /* send QUIT request to given thread */ diff --git a/harbour/source/rtl/idle.c b/harbour/source/rtl/idle.c index 56b6491b87..2f6a4b8f7d 100644 --- a/harbour/source/rtl/idle.c +++ b/harbour/source/rtl/idle.c @@ -188,24 +188,26 @@ void hb_idleState( void ) hb_vmUnlock(); hb_releaseCPU(); hb_vmLock(); - - if( pIdleData->fCollectGarbage ) + if( hb_vmRequestQuery() == 0 ) { - hb_gcCollectAll( FALSE ); - pIdleData->fCollectGarbage = FALSE; - } - - if( pIdleData->pIdleTasks && pIdleData->iIdleTask < pIdleData->iIdleMaxTask ) - { - hb_itemRelease( hb_itemDo( pIdleData->pIdleTasks[ pIdleData->iIdleTask ], 0 ) ); - ++pIdleData->iIdleTask; - if( pIdleData->iIdleTask == pIdleData->iIdleMaxTask && hb_setGetIdleRepeat() ) + if( pIdleData->fCollectGarbage ) { - pIdleData->iIdleTask = 0; /* restart processing of idle tasks */ - pIdleData->fCollectGarbage = TRUE; + hb_gcCollectAll( FALSE ); + pIdleData->fCollectGarbage = FALSE; } + + if( pIdleData->pIdleTasks && pIdleData->iIdleTask < pIdleData->iIdleMaxTask ) + { + hb_itemRelease( hb_itemDo( pIdleData->pIdleTasks[ pIdleData->iIdleTask ], 0 ) ); + ++pIdleData->iIdleTask; + if( pIdleData->iIdleTask == pIdleData->iIdleMaxTask && hb_setGetIdleRepeat() ) + { + pIdleData->iIdleTask = 0; /* restart processing of idle tasks */ + pIdleData->fCollectGarbage = TRUE; + } + } + pIdleData->fIamIdle = FALSE; } - pIdleData->fIamIdle = FALSE; } } @@ -227,7 +229,7 @@ void hb_idleSleep( double dSeconds ) { HB_ULONG end_timer = hb_dateMilliSeconds() + ( HB_ULONG ) ( dSeconds * 1000 ); - while( hb_dateMilliSeconds() < end_timer ) + while( hb_dateMilliSeconds() < end_timer && hb_vmRequestQuery() == 0 ) hb_idleState(); hb_idleReset(); diff --git a/harbour/source/vm/hvm.c b/harbour/source/vm/hvm.c index 95c62790cc..5ce3156012 100644 --- a/harbour/source/vm/hvm.c +++ b/harbour/source/vm/hvm.c @@ -381,14 +381,6 @@ void hb_vmResumeThreads( void ) {} #else -typedef struct _HB_VM_STACKLST -{ - void * pStackId; - PHB_THREADSTATE pState; - struct _HB_VM_STACKLST * pNext; - struct _HB_VM_STACKLST * pPrev; -} HB_VM_STACKLST, * PHB_VM_STACKLST; - static HB_CRITICAL_NEW( s_vmMtx ); static HB_COND_NEW( s_vmCond ); @@ -397,7 +389,7 @@ static int volatile s_iStackCount = 0; /* number of running HVM threads */ static int volatile s_iRunningCount = 0; /* active HVM stacks list */ -static PHB_VM_STACKLST s_vmStackLst = NULL; +static PHB_THREADSTATE s_vmStackLst = NULL; # define HB_THREQUEST_STOP 1 # define HB_THREQUEST_QUIT 2 @@ -594,93 +586,131 @@ void * hb_vmThreadState( void ) HB_TRACE(HB_TR_DEBUG, ("hb_vmThreadState()")); - return ( void * ) ( ( PHB_VM_STACKLST ) hb_stackList() )->pState; + return hb_stackList(); } static void hb_vmStackAdd( PHB_THREADSTATE pState ) { - HB_STACK_TLS_PRELOAD - PHB_VM_STACKLST pStack; - HB_TRACE(HB_TR_DEBUG, ("hb_vmStackAdd(%p)", pState)); - pStack = ( PHB_VM_STACKLST ) hb_xgrab( sizeof( HB_VM_STACKLST ) ); - pStack->pStackId = hb_stackId(); - pStack->pState = pState; + if( !pState->pPrev ) + { + if( s_vmStackLst ) + { + pState->pNext = s_vmStackLst; + pState->pPrev = s_vmStackLst->pPrev; + pState->pPrev->pNext = pState; + s_vmStackLst->pPrev = pState; + } + else + { + s_vmStackLst = pState->pNext = pState->pPrev = pState; + } + s_iStackCount++; + } +} + +static void hb_vmStackDel( PHB_THREADSTATE pState ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_vmStackDel(%p)", pState)); + + pState->fActive = FALSE; + pState->pStackId = NULL; + + if( pState->pPrev ) + { + pState->pPrev->pNext = pState->pNext; + pState->pNext->pPrev = pState->pPrev; + if( s_vmStackLst == pState ) + { + s_vmStackLst = pState->pNext; + if( s_vmStackLst == pState ) + s_vmStackLst = NULL; + } + pState->pPrev = pState->pNext = NULL; + s_iStackCount--; + } + + if( pState->pThItm ) + { + PHB_ITEM pThItm = pState->pThItm; + pState->pThItm = NULL; + /* NOTE: releasing pThItm may force pState freeing if parent + * thread does not keep thread pointer item. So it's + * important to not access it later. [druzus] + */ + hb_itemRelease( pThItm ); + } +} + +static void hb_vmStackInit( PHB_THREADSTATE pState ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_vmStackInit(%p)", pState)); HB_VM_LOCK - if( s_vmStackLst ) + hb_stackInit(); /* initialize HVM thread stack */ { - pStack->pNext = s_vmStackLst; - pStack->pPrev = s_vmStackLst->pPrev; - pStack->pPrev->pNext = pStack; - s_vmStackLst->pPrev = pStack; - } - else - { - s_vmStackLst = pStack->pNext = pStack->pPrev = pStack; - } - hb_stackListSet( ( void * ) ( pStack ) ); - s_iStackCount++; - if( pState ) - { - pState->pStackId = pStack->pStackId; - pState->fActive = TRUE; - } + HB_STACK_TLS_PRELOAD + hb_stackUnlock(); + pState->pStackId = hb_stackId(); + hb_stackListSet( ( void * ) ( pState ) ); + pState->fActive = TRUE; + hb_vmStackAdd( pState ); + } HB_VM_UNLOCK hb_vmLock(); } -static void hb_vmStackDel( void ) +static void hb_vmStackRelease( void ) { HB_STACK_TLS_PRELOAD - PHB_VM_STACKLST pStack; + BOOL fLocked; - HB_TRACE(HB_TR_DEBUG, ("hb_vmStackDel()")); - - hb_vmUnlock(); + HB_TRACE(HB_TR_DEBUG, ("hb_vmStackRelease()")); HB_VM_LOCK - pStack = ( PHB_VM_STACKLST ) hb_stackList(); - if( pStack->pState ) - { - pStack->pState->fActive = FALSE; - pStack->pState->pStackId = NULL; - if( pStack->pState->pThItm ) - { - PHB_ITEM pThItm = pStack->pState->pThItm; - pStack->pState->pThItm = NULL; - /* NOTE: releasing pThItm may force pState freeing if parent - * thread does not keep thread pointer item. So it's - * important to not access it later. [druzus] - * - */ - hb_itemRelease( pThItm ); - } - pStack->pState = NULL; - } + fLocked = hb_stackUnlock() == 1; + + hb_vmStackDel( ( PHB_THREADSTATE ) hb_stackList() ); hb_setRelease( hb_stackSetStruct() ); hb_stackFree(); - pStack->pPrev->pNext = pStack->pNext; - pStack->pNext->pPrev = pStack->pPrev; - if( s_vmStackLst == pStack ) - { - s_vmStackLst = pStack->pNext; - if( s_vmStackLst == pStack ) - s_vmStackLst = NULL; - } - hb_xfree( pStack ); - hb_threadMutexUnlockAll(); - s_iStackCount--; - hb_threadCondBroadcast( &s_vmCond ); + if( fLocked ) + { + s_iRunningCount--; + hb_threadCondBroadcast( &s_vmCond ); + } + + HB_VM_UNLOCK +} + +HB_EXPORT BOOL hb_vmThreadRegister( void * Cargo ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_vmThreadRegister(%p)", Cargo)); + + HB_VM_LOCK + + hb_vmStackAdd( ( PHB_THREADSTATE ) Cargo ); + + HB_VM_UNLOCK + + return TRUE; +} + +HB_EXPORT void hb_vmThreadRelease( void * Cargo ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_vmThreadRelease(%p)", Cargo)); + + HB_VM_LOCK + + hb_vmStackDel( ( PHB_THREADSTATE ) Cargo ); HB_VM_UNLOCK } @@ -692,22 +722,16 @@ HB_EXPORT void hb_vmThreadInit( void * Cargo ) HB_TRACE(HB_TR_DEBUG, ("hb_vmThreadInit(%p)", Cargo)); - hb_stackInit(); /* initialize HVM thread stack */ + pState = ( PHB_THREADSTATE ) Cargo; + if( !pState ) + pState = hb_threadStateNew(); + hb_vmStackInit( pState ); /* initialize HVM thread stack */ { HB_STACK_TLS_PRELOAD - pState = ( PHB_THREADSTATE ) Cargo; - - if( pState && pState->pszCDP ) - hb_cdpSelectID( pState->pszCDP ); - else - hb_cdpSelectID( HB_MACRO2STRING( HB_CODEPAGE_DEFAULT ) ); - - if( pState && pState->pszLang ) - hb_cdpSelectID( pState->pszLang ); - else - hb_langSelectID( HB_MACRO2STRING( HB_LANG_DEFAULT ) ); + hb_cdpSelectID( pState->pszCDP ); + hb_langSelectID( pState->pszLang ); if( pState && pState->pSet ) { @@ -719,17 +743,18 @@ HB_EXPORT void hb_vmThreadInit( void * Cargo ) else hb_setInitialize( hb_stackSetStruct() ); - if( pState && pState->pszDefRDD ) + if( pState->pszDefRDD ) hb_stackRDD()->szDefaultRDD = pState->pszDefRDD; - hb_vmStackAdd( pState ); + if( s_fHVMActive ) + { + /* call CLIPINIT function to initialize GetList PUBLIC variables + * ErrorBlock() and __SetHelpK() + */ + hb_vmDoInitClip(); + } - /* call CLIPINIT function to initialize GetList PUBLIC variables - * ErrorBlock() and __SetHelpK() - */ - hb_vmDoInitClip(); - - if( pState && pState->pMemvars ) + if( pState->pMemvars ) { hb_memvarRestoreFromArray( pState->pMemvars ); hb_itemRelease( pState->pMemvars ); @@ -746,10 +771,10 @@ HB_EXPORT void hb_vmThreadQuit( void ) HB_TRACE(HB_TR_DEBUG, ("hb_vmThreadQuit()")); + hb_stackSetQuitState( TRUE ); hb_stackSetActionRequest( 0 ); - pState = ( ( PHB_VM_STACKLST ) hb_stackList() )->pState; - if( pState ) + pState = ( PHB_THREADSTATE ) hb_stackList(); { PHB_ITEM pReturn = hb_stackReturnItem(); @@ -766,7 +791,7 @@ HB_EXPORT void hb_vmThreadQuit( void ) hb_rddCloseAll(); /* close all workareas */ hb_stackRemove( 1 ); /* clear stack items, leave only initial symbol item */ hb_memvarsClear(); /* clear all PUBLIC (and PRIVATE if any) variables */ - hb_vmStackDel(); /* remove stack from linked HVM stacks list */ + hb_vmStackRelease(); /* release HVM stack and remove it from linked HVM stacks list */ } /* send QUIT request to given thread */ @@ -804,118 +829,120 @@ HB_EXPORT void hb_vmInit( BOOL bStartMainProc ) s_pDynsDbgEntry = hb_dynsymFind( "__DBGENTRY" ); hb_xinit(); - hb_stackInit(); /* initialize HVM stack */ + +#if defined( HB_MT_VM ) + hb_vmStackInit( hb_threadStateNew() ); /* initialize HVM thread stack */ +#else + hb_stackInit(); /* initialize HVM stack */ +#endif + /* Set the language and codepage to the default */ + /* This trick is needed to stringify the macro value */ + hb_langSelectID( HB_MACRO2STRING( HB_LANG_DEFAULT ) ); + hb_cdpSelectID( HB_MACRO2STRING( HB_CODEPAGE_DEFAULT ) ); { HB_STACK_TLS_PRELOAD s_main_thread = hb_stackId(); -#if defined( HB_MT_VM ) - hb_vmStackAdd( NULL ); -#endif - - /* Set the language and codepage to the default */ - /* This trick is needed to stringify the macro value */ - hb_langSelectID( HB_MACRO2STRING( HB_LANG_DEFAULT ) ); - hb_cdpSelectID( HB_MACRO2STRING( HB_CODEPAGE_DEFAULT ) ); - - hb_clsInit(); /* initialize Classy/OO system */ - hb_errInit(); - - /* initialize dynamic symbol for evaluating codeblocks */ - hb_symEval.pDynSym = hb_dynsymGetCase( hb_symEval.szName ); - + /* _SET_* initialization */ hb_setInitialize( hb_stackSetStruct() ); - hb_conInit(); + } - /* Check for some internal switches */ - s_VMFlags = hb_cmdargProcessVM( &s_VMCancelKey, &s_VMCancelKeyEx ); - hb_inkeySetCancelKeys( s_VMCancelKey, s_VMCancelKeyEx ); + hb_clsInit(); /* initialize Classy/OO system */ + hb_errInit(); + + /* initialize dynamic symbol for evaluating codeblocks */ + hb_symEval.pDynSym = hb_dynsymGetCase( hb_symEval.szName ); + + hb_conInit(); + + /* Check for some internal switches */ + s_VMFlags = hb_cmdargProcessVM( &s_VMCancelKey, &s_VMCancelKeyEx ); + hb_inkeySetCancelKeys( s_VMCancelKey, s_VMCancelKeyEx ); #ifndef HB_NO_PROFILER - /* Initialize opcodes profiler support arrays */ - { - ULONG ul; + /* Initialize opcodes profiler support arrays */ + { + ULONG ul; - for( ul = 0; ul < HB_P_LAST_PCODE; ul++ ) - { - hb_ulOpcodesCalls[ ul ] = 0; - hb_ulOpcodesTime[ ul ] = 0; - } + for( ul = 0; ul < HB_P_LAST_PCODE; ul++ ) + { + hb_ulOpcodesCalls[ ul ] = 0; + hb_ulOpcodesTime[ ul ] = 0; } + } #endif - if( s_pDynsDbgEntry ) + if( s_pDynsDbgEntry ) + { + /* Try to get C dbgEntry() function pointer */ + if( !s_pFunDbgEntry ) + hb_vmDebugEntry( HB_DBG_GETENTRY, 0, NULL, 0, 0 ); + if( !s_pFunDbgEntry ) + s_pFunDbgEntry = hb_vmDebugEntry; + } + + /* enable executing PCODE (HVM reenter request) */ + s_fHVMActive = TRUE; + + /* Call functions that initializes static variables + * Static variables have to be initialized before any INIT functions + * because INIT function can use static variables + */ + hb_vmDoInitStatics(); + /* call CLIPINIT function to initialize GetList PUBLIC variables + * ErrorBlock() and __SetHelpK() + * Because on some platform the execution order of init functions + * is out of Harbour control then this function has to be called + * explicitly in VM initialization process before hb_vmDoInitFunctions() + * and not depends on INIT clause. + */ + hb_vmDoInitClip(); + hb_clsDoInit(); /* initialize Classy .prg functions */ + + hb_vmDoModuleInitFunctions(); /* process AtInit registered functions */ + hb_vmDoInitFunctions(); /* process defined INIT functions */ + + /* This is undocumented CA-Cl*pper, if there's a function called _APPMAIN + it will be executed first. [vszakats] */ + { + PHB_DYNS pDynSym = hb_dynsymFind( "_APPMAIN" ); + + if( pDynSym && pDynSym->pSymbol->value.pFunPtr ) + s_pSymStart = pDynSym->pSymbol; +#ifdef HB_START_PROCEDURE + else { - /* Try to get C dbgEntry() function pointer */ - if( !s_pFunDbgEntry ) - hb_vmDebugEntry( HB_DBG_GETENTRY, 0, NULL, 0, 0 ); - if( !s_pFunDbgEntry ) - s_pFunDbgEntry = hb_vmDebugEntry; - } + /* if first char is '@' then start procedure were set by + programmer explicitly and should have the highest priority + in other case it's the name of first public function in + first linked moudule which is used if there is no + HB_START_PROCEDURE in code */ + if( hb_vm_pszLinkedMain && *hb_vm_pszLinkedMain == '@' ) + pDynSym = hb_dynsymFind( hb_vm_pszLinkedMain + 1 ); + else + { + pDynSym = hb_dynsymFind( HB_START_PROCEDURE ); - /* enable executing PCODE (HVM reenter request) */ - s_fHVMActive = TRUE; - - /* Call functions that initializes static variables - * Static variables have to be initialized before any INIT functions - * because INIT function can use static variables - */ - hb_vmDoInitStatics(); - /* call CLIPINIT function to initialize GetList PUBLIC variables - * ErrorBlock() and __SetHelpK() - * Because on some platform the execution order of init functions - * is out of Harbour control then this function has to be called - * explicitly in VM initialization process before hb_vmDoInitFunctions() - * and not depends on INIT clause. - */ - hb_vmDoInitClip(); - hb_clsDoInit(); /* initialize Classy .prg functions */ - - hb_vmDoModuleInitFunctions(); /* process AtInit registered functions */ - hb_vmDoInitFunctions(); /* process defined INIT functions */ - - /* This is undocumented CA-Cl*pper, if there's a function called _APPMAIN - it will be executed first. [vszakats] */ - { - PHB_DYNS pDynSym = hb_dynsymFind( "_APPMAIN" ); + if( ! ( pDynSym && pDynSym->pSymbol->value.pFunPtr ) && hb_vm_pszLinkedMain ) + pDynSym = hb_dynsymFind( hb_vm_pszLinkedMain ); + } if( pDynSym && pDynSym->pSymbol->value.pFunPtr ) s_pSymStart = pDynSym->pSymbol; -#ifdef HB_START_PROCEDURE else - { - /* if first char is '@' then start procedure were set by - programmer explicitly and should have the highest priority - in other case it's the name of first public function in - first linked moudule which is used if there is no - HB_START_PROCEDURE in code */ - if( hb_vm_pszLinkedMain && *hb_vm_pszLinkedMain == '@' ) - pDynSym = hb_dynsymFind( hb_vm_pszLinkedMain + 1 ); - else - { - pDynSym = hb_dynsymFind( HB_START_PROCEDURE ); - - if( ! ( pDynSym && pDynSym->pSymbol->value.pFunPtr ) && hb_vm_pszLinkedMain ) - pDynSym = hb_dynsymFind( hb_vm_pszLinkedMain ); - } - - if( pDynSym && pDynSym->pSymbol->value.pFunPtr ) - s_pSymStart = pDynSym->pSymbol; - else - hb_errInternal( HB_EI_VMBADSTARTUP, NULL, HB_START_PROCEDURE, NULL ); - } -#else - else if( hb_vm_pszLinkedMain ) - { - pDynSym = hb_dynsymFind( hb_vm_pszLinkedMain + ( *hb_vm_pszLinkedMain == '@' ? 1 : 0 ) ); - if( pDynSym && pDynSym->pSymbol->value.pFunPtr ) - s_pSymStart = pDynSym->pSymbol; - } -#ifndef HB_C52_STRICT - if( bStartMainProc && ! s_pSymStart ) - hb_errInternal( HB_EI_VMNOSTARTUP, NULL, NULL, NULL ); -#endif -#endif + hb_errInternal( HB_EI_VMBADSTARTUP, NULL, HB_START_PROCEDURE, NULL ); } +#else + else if( hb_vm_pszLinkedMain ) + { + pDynSym = hb_dynsymFind( hb_vm_pszLinkedMain + ( *hb_vm_pszLinkedMain == '@' ? 1 : 0 ) ); + if( pDynSym && pDynSym->pSymbol->value.pFunPtr ) + s_pSymStart = pDynSym->pSymbol; + } +#ifndef HB_C52_STRICT + if( bStartMainProc && ! s_pSymStart ) + hb_errInternal( HB_EI_VMNOSTARTUP, NULL, NULL, NULL ); +#endif +#endif } if( bStartMainProc && s_pSymStart ) @@ -1005,18 +1032,18 @@ HB_EXPORT int hb_vmQuit( void ) #endif hb_itemClear( hb_stackReturnItem() ); - /* release all known garbage */ - if( hb_xquery( HB_MEM_USEDMAX ) ) /* check if fmstat is ON */ - hb_gcCollectAll( TRUE ); - else - hb_gcReleaseAll(); + hb_gcCollectAll( TRUE ); #if defined( HB_MT_VM ) - hb_vmStackDel(); /* remove stack from linked HVM stacks list */ + hb_vmStackRelease(); /* release HVM stack and remove it from linked HVM stacks list */ #else hb_setRelease( hb_stackSetStruct() ); /* releases Sets */ hb_stackFree(); #endif + + /* release all known garbage */ + if( hb_xquery( HB_MEM_USEDMAX ) == 0 ) /* check if fmstat is ON */ + hb_gcReleaseAll(); hb_xexit(); return s_nErrorLevel; @@ -10647,10 +10674,10 @@ void hb_vmIsStackRef( void ) #if defined( HB_MT_VM ) if( s_vmStackLst ) { - PHB_VM_STACKLST pStack = s_vmStackLst; + PHB_THREADSTATE pStack = s_vmStackLst; do { - if( pStack->pStackId ) + if( pStack->fActive && pStack->pStackId ) hb_stackIsStackRef( pStack->pStackId, hb_vmTSVarClean ); pStack = pStack->pNext; } diff --git a/harbour/source/vm/thread.c b/harbour/source/vm/thread.c index 0347684032..272247a200 100644 --- a/harbour/source/vm/thread.c +++ b/harbour/source/vm/thread.c @@ -453,8 +453,6 @@ static HB_THREAD_STARTFUNC( hb_threadStartVM ) pThread = ( PHB_THREADSTATE ) hb_itemGetPtrGC( pThItm, hb_threadDestructor ); - pThread->pThItm = pThItm; - hb_vmThreadInit( ( void * ) pThread ); ulPCount = hb_arrayLen( pThread->pParams ); @@ -517,6 +515,24 @@ static HB_THREAD_STARTFUNC( hb_threadStartVM ) #endif } +PHB_THREADSTATE hb_threadStateNew( void ) +{ + PHB_ITEM pThItm; + PHB_THREADSTATE pThread; + + pThItm = hb_itemNew( NULL ); + pThread = ( PHB_THREADSTATE ) + hb_gcAlloc( sizeof( HB_THREADSTATE ), hb_threadDestructor ); + memset( pThread, 0, sizeof( HB_THREADSTATE ) ); + hb_itemPutPtrGC( pThItm, pThread ); + + pThread->pszCDP = HB_MACRO2STRING( HB_CODEPAGE_DEFAULT ); + pThread->pszLang = HB_MACRO2STRING( HB_LANG_DEFAULT ); + pThread->pThItm = pThItm; + + return pThread; +} + static PHB_THREADSTATE hb_thParam( int iParam ) { PHB_THREADSTATE pThread = ( PHB_THREADSTATE ) hb_parptrGC( hb_threadDestructor, iParam ); @@ -573,11 +589,8 @@ HB_FUNC( HB_THREADSTART ) PHB_THREADSTATE pThread; ULONG ulPCount, ulParam; - pReturn = hb_itemNew( NULL ); - pThread = ( PHB_THREADSTATE ) - hb_gcAlloc( sizeof( HB_THREADSTATE ), hb_threadDestructor ); - memset( pThread, 0, sizeof( HB_THREADSTATE ) ); - hb_itemPutPtrGC( pReturn, pThread ); + pThread = hb_threadStateNew(); + pReturn = pThread->pThItm; pThread->pszCDP = hb_cdpID(); pThread->pszLang = hb_langID(); @@ -625,10 +638,18 @@ HB_FUNC( HB_THREADSTART ) */ hb_itemReturn( pReturn ); - pThread->th_id = hb_threadCreate( hb_threadStartVM, ( void * ) pReturn ); +#if defined( HB_MT_VM ) + if( hb_vmThreadRegister( ( void * ) pThread ) ) +#endif + pThread->th_id = hb_threadCreate( hb_threadStartVM, ( void * ) pReturn ); + if( pThread->th_id == 0 ) { +#if defined( HB_MT_VM ) + hb_vmThreadRelease( pThread ); +#else hb_itemRelease( pReturn ); +#endif hb_ret(); } } diff --git a/harbour/tests/mt/mttest09.prg b/harbour/tests/mt/mttest09.prg index 60dcd2de1d..13a90e8d59 100644 --- a/harbour/tests/mt/mttest09.prg +++ b/harbour/tests/mt/mttest09.prg @@ -28,9 +28,10 @@ proc main() F1 := chr( recno() ) enddo + ? "main thread ID:", s_mainThreadID thID := hb_threadStart( @thFunc() ) - ? "thread ID:", thID - ? "current work area detached, used() =>", used(), alias() + ? "current thread ID:", thID + ? "work area in use, used() =>", used(), alias() WAIT "Press a key to detach work area" hb_dbDetach( , {|| countRecords( {|| F1 == "A" } ) } ) ? "work area detached, used() =>", used(), alias()