2009-06-05 06:10 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)

* harbour/include/hbclass.ch
    + extended support for xbase++ compatible method declaration:
         [SYNC] METHOD <methodName1>[([<params>])] ;
                       [ , <methodNameN>[([<params>])] ]

  * harbour/include/hbthread.h
  * harbour/source/vm/thread.c
  * harbour/source/vm/classes.c
    + added alternative support for SYNC method which does not use
      sync mutexes. The old method is still present. I'll remove it
      when xbase++ users confirm that the new one exactly emulates
      xbase++ behavior.

  * harbour/source/vm/classes.c
  * harbour/source/rtl/tthreadx.prg
    * switch to alternative SYNC method implementation which seems to be
      xbase++ compatible - please test
    ! fixed missing thread interrupt in recent modification for ::setInterval
This commit is contained in:
Przemyslaw Czerpak
2009-06-05 04:01:40 +00:00
parent 65f22b4baa
commit 8e70525b66
6 changed files with 284 additions and 50 deletions

View File

@@ -17,6 +17,26 @@
past entries belonging to these authors: Viktor Szakats.
*/
2009-06-05 06:10 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/include/hbclass.ch
+ extended support for xbase++ compatible method declaration:
[SYNC] METHOD <methodName1>[([<params>])] ;
[ , <methodNameN>[([<params>])] ]
* harbour/include/hbthread.h
* harbour/source/vm/thread.c
* harbour/source/vm/classes.c
+ added alternative support for SYNC method which does not use
sync mutexes. The old method is still present. I'll remove it
when xbase++ users confirm that the new one exactly emulates
xbase++ behavior.
* harbour/source/vm/classes.c
* harbour/source/rtl/tthreadx.prg
* switch to alternative SYNC method implementation which seems to be
xbase++ compatible - please test
! fixed missing thread interrupt in recent modification for ::setInterval
2009-06-04 23:00 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
* utils/hbmk2/hbmk2.prg
+ Added support for hbcs= lins in .hbc files. This means

View File

@@ -571,8 +571,10 @@ DECLARE HBClass ;
#xcommand SYNC METHOD <MethodName> [<decl,...>] => METHOD <MethodName> [<decl>] SYNC
#xcommand SYNC CLASS METHOD <MethodName> [<decl,...>] => CLASSMETHOD <MethodName> [<decl>] SYNC
#xcommand METHOD <!MethodName1!>, <!MethodName2!> [, <!MethodNameN!>] => ;
#xcommand METHOD <!MethodName1!>[([<params,...>])], <!MethodName2!>[([<params,...>])] [, <!MethodNameN!>[([<params,...>])]] => ;
METHOD <MethodName1> [ ; METHOD <MethodName2> ] [ ; METHOD <MethodNameN> ]
#xcommand SYNC METHOD <!MethodName1!>[([<params,...>])], <!MethodName2!>[([<params,...>])] [, <!MethodNameN!>[([<params,...>])]] => ;
SYNC METHOD <MethodName1> [ ; SYNC METHOD <MethodName2> ] [ ; SYNC METHOD <MethodNameN> ]
#xcommand METHOD <!className!>:<!methodName!>[([<params,...>])] => ;
METHOD <methodName>( <params> ) CLASS <className>

View File

@@ -340,6 +340,8 @@ extern PHB_ITEM hb_threadMutexTimedSubscribe( PHB_ITEM pItem, ULONG ulMilliSec,
#if defined( HB_MT_VM ) && defined( _HB_API_INTERNAL_ )
extern void hb_threadMutexUnlockAll( void );
extern void hb_threadMutexSyncSignal( PHB_ITEM pItemMtx );
extern BOOL hb_threadMutexSyncWait( PHB_ITEM pItemMtx, ULONG ulMilliSec, PHB_ITEM pItemSync );
#if defined( HB_NO_TLS )
# undef HB_USE_TLS

View File

@@ -86,15 +86,10 @@ METHOD new( ... ) CLASS TSIGNAL
RETURN Self
METHOD wait( nTimeOut ) CLASS TSIGNAL
/* TOCHECK: I do not know if strict Xbase++ compatibility needs
* hb_mutexSubscribe() or hb_mutexSubscribeNow()
* Please change it if necessary
*/
RETURN hb_mutexSubscribe( ::mutex, ;
iif( ISNUMBER( nTimeOut ), nTimeOut / 100, ) )
RETURN __ClsSyncWait( ::mutex, nTimeOut )
METHOD signal() CLASS TSIGNAL
hb_mutexNotify( ::mutex )
__ClsSyncSignal( ::mutex )
RETURN Self
@@ -105,22 +100,22 @@ METHOD signal() CLASS TSIGNAL
CREATE CLASS TThread FUNCTION Thread
EXPORTED:
VAR cargo AS USUAL SYNC
VAR cargo AS USUAL
VAR active AS LOGICAL READONLY INIT .f.
VAR deltaTime AS NUMERIC READONLY INIT 0
VAR interval AS USUAL READONLY INIT NIL
VAR priority AS NUMERIC READONLY INIT 0
VAR startCount AS NUMERIC READONLY INIT 0
VAR startTime AS USUAL READONLY INIT NIL
VAR atEnd AS USUAL INIT NIL SYNC
VAR atStart AS USUAL INIT NIL SYNC
VAR result AS USUAL INIT NIL SYNC
VAR atEnd AS USUAL INIT NIL
VAR atStart AS USUAL INIT NIL
VAR result AS USUAL INIT NIL
PROTECTED:
VAR maxStackSize AS USUAL INIT 50000
HIDDEN:
VAR pThreadID AS USUAL INIT NIL SYNC
VAR pThreadID AS USUAL INIT NIL
EXPORTED:
METHOD new()
@@ -131,11 +126,11 @@ PROTECTED:
METHOD execute()
EXPORTED:
METHOD quit( xResult, nRestart ) SYNC
METHOD quit( xResult, nRestart )
METHOD setInterval( nHSeconds )
METHOD setPriority( nPriority )
METHOD setStartTime( nSeconds )
METHOD start() SYNC
METHOD start()
METHOD synchronize( nTimeOut )
METHOD threadSelf()
METHOD threadID()
@@ -179,7 +174,7 @@ METHOD quit( xResult, nRestart ) CLASS TTHREAD
RETURN NIL
METHOD setInterval( nHSeconds ) CLASS TTHREAD
IF ISNUMBER( nHSeconds )
IF nHSeconds == NIL .OR. ISNUMBER( nHSeconds )
::interval := nHSeconds
ENDIF
RETURN .F.
@@ -212,11 +207,12 @@ METHOD start( xAction, ... ) CLASS TTHREAD
::startTime := Seconds()
ThreadObject( Self )
::result := ::execute( ... )
::startTime := NIL
IF ISNUMBER( ::interval )
hb_idleSleep( ::interval / 100 )
LOOP
ENDIF
::startTime := NIL
EXIT
ENDDO
RETURN NIL
}, ... )
@@ -239,6 +235,7 @@ METHOD start( xAction, ... ) CLASS TTHREAD
hb_idleSleep( ::interval / 100 )
LOOP
ENDIF
EXIT
ENDDO
RETURN NIL
}, ... )

View File

@@ -926,7 +926,7 @@ static void hb_clsCopyClass( PCLASS pClsDst, PCLASS pClsSrc )
pClsDst->uiMutexOffset = pClsSrc->uiMutexOffset;
pClsDst->ulOpFlags = pClsSrc->ulOpFlags;
if( pClsSrc->pMutex )
pClsDst->pMutex = hb_threadMutexCreate( TRUE );
pClsDst->pMutex = hb_threadMutexCreate( FALSE );
if( pClsSrc->uiInitDatas )
{
@@ -2991,7 +2991,7 @@ static BOOL hb_clsAddMsg( USHORT uiClass, const char * szMessage,
if( uiScope & HB_OO_CLSTP_CLASS )
{
if( !pClass->pMutex )
pClass->pMutex = hb_threadMutexCreate( TRUE );
pClass->pMutex = hb_threadMutexCreate( FALSE );
pNewMeth->pFuncSym = &s___msgSyncClass;
}
else
@@ -3353,7 +3353,7 @@ static USHORT hb_clsNew( const char * szClassName, USHORT uiDatas,
if( pNewCls->uiMutexOffset )
pNewCls->uiMutexOffset = pNewCls->uiDatas + 1;
if( fClsMutex && !pNewCls->pMutex )
pNewCls->pMutex = hb_threadMutexCreate( TRUE );
pNewCls->pMutex = hb_threadMutexCreate( FALSE );
return s_uiClasses;
}
@@ -3479,7 +3479,7 @@ static PHB_ITEM hb_clsInst( USHORT uiClass )
if( pClass->uiMutexOffset )
{
PHB_ITEM pMutex = hb_threadMutexCreate( TRUE );
PHB_ITEM pMutex = hb_threadMutexCreate( FALSE );
hb_arraySet( pSelf, pClass->uiMutexOffset, pMutex );
hb_itemRelease( pMutex );
}
@@ -4090,6 +4090,60 @@ HB_FUNC( __SENDER )
}
}
HB_FUNC( __CLSSYNCSIGNAL )
{
#if defined( HB_MT_VM )
hb_threadMutexSyncSignal( hb_param( 1, HB_IT_ANY ) );
#endif /* HB_MT_VM */
}
HB_FUNC( __CLSSYNCWAIT )
{
#if defined( HB_MT_VM )
HB_STACK_TLS_PRELOAD
PHB_ITEM pMutex = NULL;
ULONG ulMilliSec = HB_THREAD_INFINITE_WAIT;
LONG lOffset = hb_stackBaseProcOffset( 2 );
if( lOffset > 0 )
{
PHB_ITEM pBase = hb_stackItem( lOffset );
PHB_STACK_STATE pStack = pBase->item.asSymbol.stackstate;
USHORT uiClass = pStack->uiClass;
if( uiClass && uiClass <= s_uiClasses )
{
PCLASS pClass = s_pClasses[ uiClass ];
PMETHOD pMethod = pClass->pMethods + pStack->uiMethod;
if( pMethod->pFuncSym == &s___msgSync )
{
PHB_ITEM pSelf = hb_stackItem( lOffset + 1 );
/* Is it inline method? */
if( HB_IS_BLOCK( pSelf ) && pBase->item.asSymbol.value == &hb_symEval )
pSelf = hb_stackItem( pBase->item.asSymbol.stackstate->lBaseItem + 1 );
uiClass = hb_objGetClass( pSelf );
if( uiClass && uiClass <= s_uiClasses )
pMutex = hb_arrayGetItemPtr( pSelf, s_pClasses[ uiClass ]->uiMutexOffset );
}
else if( pMethod->pFuncSym == &s___msgSyncClass )
pMutex = pClass->pMutex;
}
}
if( ISNUM( 2 ) )
{
double dTimeOut = hb_parnd( 2 );
if( dTimeOut > 0 )
ulMilliSec = ( ULONG ) ( dTimeOut * 10 );
}
hb_retl( hb_threadMutexSyncWait( hb_param( 1, HB_IT_ANY ), ulMilliSec, pMutex ) );
#endif /* HB_MT_VM */
}
/*
* ClassH( <obj> ) -> <hClass>
*
@@ -4136,32 +4190,37 @@ static HARBOUR hb___msgClassName( void )
static int hb_methodType( PMETHOD pMethod )
{
if ( pMethod->pFuncSym == &s___msgSetClsData ||
pMethod->pFuncSym == &s___msgGetClsData ||
pMethod->pFuncSym == &s___msgSetShrData ||
pMethod->pFuncSym == &s___msgGetShrData )
PHB_SYMB pFuncSym = pMethod->pFuncSym;
if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass )
pFuncSym = pMethod->pRealSym;
if ( pFuncSym == &s___msgSetClsData ||
pFuncSym == &s___msgGetClsData ||
pFuncSym == &s___msgSetShrData ||
pFuncSym == &s___msgGetShrData )
return HB_OO_MSG_CLASSDATA;
else if( pMethod->pFuncSym == &s___msgSetData ||
pMethod->pFuncSym == &s___msgGetData )
else if( pFuncSym == &s___msgSetData ||
pFuncSym == &s___msgGetData )
return HB_OO_MSG_DATA;
else if( pMethod->pFuncSym == &s___msgEvalInline )
else if( pFuncSym == &s___msgEvalInline )
return HB_OO_MSG_INLINE;
else if( pMethod->pFuncSym == &s___msgVirtual )
else if( pFuncSym == &s___msgVirtual )
return HB_OO_MSG_VIRTUAL;
else if( pMethod->pFuncSym == &s___msgSuper )
else if( pFuncSym == &s___msgSuper )
return HB_OO_MSG_SUPER;
else if( pMethod->pFuncSym == &s___msgRealClass )
else if( pFuncSym == &s___msgRealClass )
return HB_OO_MSG_REALCLASS;
else if( pMethod->pFuncSym == &s___msgDelegate )
else if( pFuncSym == &s___msgDelegate )
return HB_OO_MSG_DELEGATE;
else if( pMethod->pFuncSym == &s___msgPerform )
else if( pFuncSym == &s___msgPerform )
return HB_OO_MSG_PERFORM;
else if( pMethod->pMessage == s___msgOnError.pDynSym )
@@ -4204,22 +4263,9 @@ static HARBOUR hb___msgClassSel( void )
{
if( ( nParam == HB_MSGLISTALL ) ||
( nParam == HB_MSGLISTCLASS &&
(
( pMethod->pFuncSym == &s___msgSetClsData ) ||
( pMethod->pFuncSym == &s___msgGetClsData ) ||
( pMethod->pFuncSym == &s___msgSetShrData ) ||
( pMethod->pFuncSym == &s___msgGetShrData )
)
) ||
hb_methodType( pMethod ) == HB_OO_MSG_CLASSDATA ) ||
( nParam == HB_MSGLISTPURE &&
!(
( pMethod->pFuncSym == &s___msgSetClsData ) ||
( pMethod->pFuncSym == &s___msgGetClsData ) ||
( pMethod->pFuncSym == &s___msgSetShrData ) ||
( pMethod->pFuncSym == &s___msgGetShrData )
)
)
)
hb_methodType( pMethod ) != HB_OO_MSG_CLASSDATA ) )
{
if( nScope == 0 || ( pMethod->uiScope & nScope ) != 0 )
{

View File

@@ -1549,6 +1549,173 @@ PHB_ITEM hb_threadMutexCreate( BOOL fSync )
return pItem;
}
#if defined( HB_MT_VM )
void hb_threadMutexSyncSignal( PHB_ITEM pItemMtx )
{
PHB_MUTEX pMutex = hb_mutexPtr( pItemMtx );
if( pMutex )
{
HB_CRITICAL_LOCK( pMutex->mutex );
if( pMutex->waiters )
{
int iCount = pMutex->waiters;
ULONG ulLen;
if( pMutex->events )
{
ulLen = hb_arrayLen( pMutex->events );
iCount -= ulLen;
if( iCount > 0 )
hb_arraySize( pMutex->events, ulLen + iCount );
}
else
{
ulLen = 0;
pMutex->events = hb_itemArrayNew( 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_CRITICAL_UNLOCK( pMutex->mutex );
}
}
BOOL hb_threadMutexSyncWait( PHB_ITEM pItemMtx, ULONG ulMilliSec,
PHB_ITEM pItemSync )
{
PHB_MUTEX pMutex = hb_mutexPtr( pItemMtx ), pSyncMutex = NULL;
BOOL fResult = FALSE;
if( pMutex )
{
if( pItemSync )
{
pSyncMutex = hb_mutexPtr( pItemSync );
if( !pSyncMutex )
pMutex = NULL;
}
}
if( pMutex )
{
int lock_count = 0;
hb_vmUnlock();
HB_CRITICAL_LOCK( pMutex->mutex );
if( ulMilliSec && !( pMutex->events && hb_arrayLen( pMutex->events ) > 0 ) )
{
/* release own locks from sync mutex */
if( pSyncMutex && HB_THREAD_EQUAL( pSyncMutex->owner, HB_THREAD_SELF() ) )
{
HB_CRITICAL_LOCK( pSyncMutex->mutex );
lock_count = pSyncMutex->lock_count;
pSyncMutex->lock_count = 0;
pSyncMutex->owner = ( HB_THREAD_ID ) 0;
if( pSyncMutex->lockers )
HB_COND_SIGNAL( pSyncMutex->cond_l );
HB_CRITICAL_UNLOCK( pSyncMutex->mutex );
}
if( ulMilliSec == HB_THREAD_INFINITE_WAIT )
{
while( !pMutex->events || hb_arrayLen( pMutex->events ) == 0 )
{
pMutex->waiters++;
# if defined( HB_PTHREAD_API )
pthread_cond_wait( &pMutex->cond_w, &pMutex->mutex );
# elif defined( HB_COND_HARBOUR_SUPPORT )
_hb_thread_cond_wait( &pMutex->cond_w, &pMutex->mutex, HB_THREAD_INFINITE_WAIT );
# else
HB_CRITICAL_UNLOCK( pMutex->mutex );
( void ) HB_COND_WAIT( pMutex->cond_w );
HB_CRITICAL_LOCK( pMutex->mutex );
# endif
pMutex->waiters--;
}
}
else
{
pMutex->waiters++;
# if defined( HB_PTHREAD_API )
{
struct timespec ts;
hb_threadTimeInit( &ts, ulMilliSec );
while( !pMutex->events || hb_arrayLen( pMutex->events ) == 0 )
{
if( pthread_cond_timedwait( &pMutex->cond_w, &pMutex->mutex, &ts ) != 0 )
break;
}
}
# else
{
/* TODO: on some platforms HB_COND_SIGNAL() may wake up more then
* one thread so we should use while loop to check if wait
* condition is true.
*/
# if defined( HB_COND_HARBOUR_SUPPORT )
_hb_thread_cond_wait( &pMutex->cond_w, &pMutex->mutex, ulMilliSec );
# else
HB_CRITICAL_UNLOCK( pMutex->mutex );
( void ) HB_COND_TIMEDWAIT( pMutex->cond_w, ulMilliSec );
HB_CRITICAL_LOCK( pMutex->mutex );
# endif
}
# endif
pMutex->waiters--;
}
}
if( pMutex->events && hb_arrayLen( pMutex->events ) > 0 )
{
hb_arraySize( pMutex->events, hb_arrayLen( pMutex->events ) - 1 );
fResult = TRUE;
}
HB_CRITICAL_UNLOCK( pMutex->mutex );
/* restore the own locks on sync mutex if necessary */
if( lock_count )
{
HB_CRITICAL_LOCK( pSyncMutex->mutex );
if( pSyncMutex->owner )
{
pSyncMutex->lockers++;
while( pSyncMutex->lock_count != 0 )
{
# if defined( HB_PTHREAD_API )
pthread_cond_wait( &pSyncMutex->cond_l, &pSyncMutex->mutex );
# elif defined( HB_COND_HARBOUR_SUPPORT )
_hb_thread_cond_wait( &pSyncMutex->cond_l, &pSyncMutex->mutex, HB_THREAD_INFINITE_WAIT );
# else
HB_CRITICAL_UNLOCK( pSyncMutex->mutex );
( void ) HB_COND_WAIT( pSyncMutex->cond_l );
HB_CRITICAL_LOCK( pSyncMutex->mutex );
# endif
}
pSyncMutex->lockers--;
}
pSyncMutex->lock_count = lock_count;
pSyncMutex->owner = HB_THREAD_SELF();
HB_CRITICAL_UNLOCK( pSyncMutex->mutex );
}
hb_vmLock();
}
return fResult;
}
#endif /* HB_MT_VM */
BOOL hb_threadMutexUnlock( PHB_ITEM pItem )
{
PHB_MUTEX pMutex = hb_mutexPtr( pItem );
@@ -1838,7 +2005,7 @@ PHB_ITEM hb_threadMutexSubscribe( PHB_ITEM pItem, BOOL fClear )
if( fClear && pMutex->events )
hb_arraySize( pMutex->events, 0 );
/* release own locak from this mutex */
/* release own lock from this mutex */
if( HB_THREAD_EQUAL( pMutex->owner, HB_THREAD_SELF() ) )
{
lock_count = pMutex->lock_count;
@@ -1949,7 +2116,7 @@ PHB_ITEM hb_threadMutexTimedSubscribe( PHB_ITEM pItem, ULONG ulMilliSec, BOOL fC
if( ulMilliSec && !( pMutex->events && hb_arrayLen( pMutex->events ) > 0 ) )
{
/* release own locak from this mutex */
/* release own lock from this mutex */
if( HB_THREAD_EQUAL( pMutex->owner, HB_THREAD_SELF() ) )
{
lock_count = pMutex->lock_count;