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
This commit is contained in:
Przemyslaw Czerpak
2008-09-29 09:19:46 +00:00
parent 7ccf493b55
commit cce3e73961
7 changed files with 299 additions and 218 deletions

View File

@@ -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

View File

@@ -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 );

View File

@@ -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 */

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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()