2009-02-18 20:00 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)

* harbour/include/hbthread.h
  * harbour/source/vm/thread.c
    ! added support for conditional variables working like in PTHREADS
      in OS2 builds - it fixes the problem with possible dead lock or
      starvation effect which can also cause dead lock in some cases.
      OS2 users please test current code.
This commit is contained in:
Przemyslaw Czerpak
2009-02-18 18:55:32 +00:00
parent 6750dfb8c1
commit 844cf0e16b
3 changed files with 207 additions and 33 deletions

View File

@@ -8,6 +8,14 @@
2009-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org)
*/
2009-02-18 20:00 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/include/hbthread.h
* harbour/source/vm/thread.c
! added support for conditional variables working like in PTHREADS
in OS2 builds - it fixes the problem with possible dead lock or
starvation effect which can also cause dead lock in some cases.
OS2 users please test current code.
2009-02-18 18:59 UTC+0100 Viktor Szakats (harbour.01 syenar hu)
* utils/hbmk/hbmk2.prg
% Optimizations in FindInPath().

View File

@@ -169,10 +169,24 @@ HB_EXTERN_BEGIN
typedef TID HB_THREAD_ID;
typedef TID HB_THREAD_HANDLE;
typedef HMTX HB_RAWCRITICAL_T;
typedef HEV HB_RAWCOND_T;
extern ULONG _hb_gettid( void );
typedef struct _HB_WAIT_LIST
{
struct _HB_WAIT_LIST * prev;
struct _HB_WAIT_LIST * next;
HEV cond;
BOOL signaled;
} HB_WAIT_LIST, * PHB_WAIT_LIST;
typedef struct
{
PHB_WAIT_LIST waiters;
} HB_COND_T, HB_RAWCOND_T;
# define HB_COND_NEW( name ) HB_COND_T name = { NULL }
# define HB_THREAD_STARTFUNC( func ) void func( void * Cargo )
# define HB_THREAD_END _endthread(); return;
# define HB_THREAD_RAWEND return;
@@ -189,16 +203,15 @@ HB_EXTERN_BEGIN
# define HB_CRITICAL_DESTROY(v) DosCloseMutexSem( v )
# define HB_CRITICAL_LOCK(v) DosRequestMutexSem( (v), SEM_INDEFINITE_WAIT )
# define HB_CRITICAL_UNLOCK(v) DosReleaseMutexSem( v )
# define HB_COND_INIT(v) DosCreateEventSem( NULL, &(v), 0L, FALSE );
# define HB_COND_DESTROY(v) DosCloseEventSem( v )
# define HB_COND_SIGNAL(v) DosPostEventSem( v )
# define HB_COND_SIGNALN(v,n) do { int i = (n); while( --i >= 0 ) DosPostEventSem( v ); } while(0)
# define HB_COND_WAIT(v) _hb_cond_timed_wait( (v), SEM_INDEFINITE_WAIT )
# define HB_COND_TIMEDWAIT(v,n) _hb_cond_timed_wait( (v), (n) )
# define HB_COND_SIGNAL(v) _hb_thread_cond_signal( &(v) )
# define HB_COND_SIGNALN(v,n) _hb_thread_cond_broadcast( &(v) )
# define HB_COND_WAIT(v) _hb_thread_cond_wait( (v), SEM_INDEFINITE_WAIT )
# define HB_COND_TIMEDWAIT(v,n) _hb_thread_cond_wait( (v), (n) )
# undef HB_COND_OS_SUPPORT
# undef HB_COND_NEED_INIT
# define HB_COND_HARBOUR_SUPPORT
# define HB_CRITICAL_NEED_INIT
# define HB_COND_NEED_INIT
# define HB_THREAD_INFINITE_WAIT SEM_INDEFINITE_WAIT
@@ -243,15 +256,15 @@ HB_EXTERN_BEGIN
# if defined( HB_COND_OS_SUPPORT )
typedef struct
{
BOOL fInit;
BOOL fInit;
HB_RAWCOND_T cond;
} HB_COND_T;
# define HB_COND_NEW( name ) HB_COND_T name = { FALSE, HB_COND_INITVAL }
# else
typedef struct
{
BOOL fInit;
int waiters;
BOOL fInit;
int waiters;
HB_RAWCOND_T cond;
HB_RAWCRITICAL_T critical;
} HB_COND_T;
@@ -289,6 +302,9 @@ typedef struct _HB_THREADSTATE
HB_THREAD_HANDLE th_h;
struct _HB_THREADSTATE * pPrev;
struct _HB_THREADSTATE * pNext;
#if defined( HB_COND_HARBOUR_SUPPORT )
HB_WAIT_LIST pWaitList;
#endif
} HB_THREADSTATE, * PHB_THREADSTATE;
extern void hb_threadInit( void );

View File

@@ -184,19 +184,111 @@ void hb_threadExit( void )
}
}
#if defined( HB_OS_OS2 )
BOOL _hb_cond_timed_wait( HEV v, ULONG n )
#if defined( HB_OS_OS2 ) && defined( HB_MT_VM )
static PHB_WAIT_LIST _hb_thread_wait_list( void )
{
ULONG ulPostCount = 0;
APIRET rc;
PHB_THREADSTATE pThread = ( PHB_THREADSTATE ) hb_vmThreadState();
rc = DosWaitEventSem( v, n );
DosResetEventSem( v, &ulPostCount );
return rc == NO_ERROR;
if( pThread )
return &pThread->pWaitList;
else
return NULL;
}
static void _hb_thread_wait_add( HB_COND_T * cond, PHB_WAIT_LIST pWaiting )
{
ULONG ulPostCount = 0;
if( cond->waiters == NULL )
{
cond->waiters = pWaiting->next = pWaiting->prev = pWaiting;
}
else
{
pWaiting->next = cond->waiters;
pWaiting->prev = cond->waiters->prev;
cond->waiters->prev = pWaiting->prev->next = pWaiting;
}
pWaiting->signaled = FALSE;
DosResetEventSem( pWaiting->cond, &ulPostCount );
}
static void _hb_thread_wait_del( HB_COND_T * cond, PHB_WAIT_LIST pWaiting )
{
if( pWaiting->next == pWaiting->prev )
cond->waiters = NULL;
else
{
pWaiting->next->prev = pWaiting->prev;
pWaiting->prev->next = pWaiting->next;
if( pWaiting == cond->waiters )
cond->waiters = pWaiting->next;
}
}
static BOOL _hb_thread_cond_signal( HB_COND_T * cond )
{
if( cond->waiters )
{
PHB_WAIT_LIST pWaiting = cond->waiters;
do
{
if( !pWaiting->signaled )
{
DosPostEventSem( pWaiting->cond );
pWaiting->signaled = TRUE;
/* signal only single thread */
break;
}
pWaiting = pWaiting->prev;
}
while( pWaiting != cond->waiters );
}
return TRUE;
}
static BOOL _hb_thread_cond_broadcast( HB_COND_T * cond )
{
if( cond->waiters )
{
PHB_WAIT_LIST pWaiting = cond->waiters;
do
{
if( !pWaiting->signaled )
{
DosPostEventSem( pWaiting->cond );
pWaiting->signaled = TRUE;
}
pWaiting = pWaiting->prev;
}
while( pWaiting != cond->waiters );
}
return TRUE;
}
static BOOL _hb_thread_cond_wait( HB_COND_T * cond, HB_RAWCRITICAL_T * critical, ULONG ulMillisec )
{
PHB_WAIT_LIST pWaiting = _hb_thread_wait_list();
BOOL fResult = FALSE;
if( pWaiting )
{
_hb_thread_wait_add( cond, pWaiting );
DosReleaseMutexSem( *critical );
fResult = DosWaitEventSem( pWaiting->cond, ulMillisec ) == NO_ERROR;
DosRequestMutexSem( *critical, SEM_INDEFINITE_WAIT );
_hb_thread_wait_del( cond, pWaiting );
}
return fResult;
}
#endif
#if defined( HB_OS_OS2 ) && !defined( __GNUC__ )
ULONG _hb_gettid( void )
{
ULONG tid = 0;
@@ -329,6 +421,10 @@ BOOL hb_threadCondSignal( HB_COND_T * cond )
# endif
return pthread_cond_signal( HB_COND_GET( cond ) ) == 0;
#elif defined( HB_COND_HARBOUR_SUPPORT )
return _hb_thread_cond_signal( cond );
#else
if( !cond->fInit )
@@ -362,6 +458,10 @@ BOOL hb_threadCondBroadcast( HB_COND_T * cond )
# endif
return pthread_cond_broadcast( HB_COND_GET( cond ) ) == 0;
#elif defined( HB_COND_HARBOUR_SUPPORT )
return _hb_thread_cond_broadcast( cond );
#else
if( !cond->fInit )
@@ -396,6 +496,10 @@ BOOL hb_threadCondWait( HB_COND_T * cond, HB_CRITICAL_T * mutex )
# endif
return pthread_cond_wait( HB_COND_GET( cond ), HB_CRITICAL_GET( mutex ) ) == 0;
#elif defined( HB_COND_HARBOUR_SUPPORT )
return _hb_thread_cond_wait( cond, &mutex->critical, HB_THREAD_INFINITE_WAIT );
#else
BOOL fResult;
@@ -449,6 +553,10 @@ BOOL hb_threadCondTimedWait( HB_COND_T * cond, HB_CRITICAL_T * mutex, ULONG ulMi
hb_threadTimeInit( &ts, ulMilliSec );
return pthread_cond_timedwait( HB_COND_GET( cond ), HB_CRITICAL_GET( mutex ), &ts ) == 0;
#elif defined( HB_COND_HARBOUR_SUPPORT )
return _hb_thread_cond_wait( cond, &mutex->critical, ulMilliSec );
#else
BOOL fResult;
@@ -603,6 +711,13 @@ static HB_GARBAGE_FUNC( hb_threadDestructor )
hb_gtRelease( pThread->hGT );
pThread->hGT = NULL;
}
#if defined( HB_OS_OS2 )
if( pThread->pWaitList.cond )
{
DosCloseEventSem( pThread->pWaitList.cond );
pThread->pWaitList.cond = ( HEV ) 0;
}
#endif
}
static HB_THREAD_STARTFUNC( hb_threadStartVM )
@@ -700,6 +815,10 @@ PHB_THREADSTATE hb_threadStateNew( void )
pThread->pThItm = pThItm;
pThread->hGT = hb_gtAlloc( NULL );
#if defined( HB_OS_OS2 )
DosCreateEventSem( NULL, &pThread->pWaitList.cond, 0L, FALSE );
#endif
return pThread;
}
@@ -926,6 +1045,12 @@ static int hb_threadWait( PHB_THREADSTATE * pThreads, int iThreads,
fExit = pthread_cond_wait( &s_thread_cond, &s_thread_mtx ) != 0;
hb_vmLock();
#else
# if defined( HB_COND_HARBOUR_SUPPORT )
hb_vmUnlock();
fResult = !_hb_thread_cond_wait( &s_thread_cond, &s_thread_mtx, ulMilliSec );
hb_vmLock();
# else
HB_CRITICAL_UNLOCK( s_thread_mtx );
hb_vmUnlock();
fResult = HB_COND_TIMEDWAIT( s_thread_cond, ulMilliSec );
@@ -933,6 +1058,7 @@ static int hb_threadWait( PHB_THREADSTATE * pThreads, int iThreads,
HB_CRITICAL_LOCK( s_thread_mtx );
if( !fResult )
s_waiting_for_threads--;
# endif
if( timer )
{
HB_ULONG curr = hb_dateMilliSeconds();
@@ -1257,12 +1383,14 @@ static void hb_mutexListLock( PHB_MTXLST pList )
pMutex->lockers++;
#if defined( HB_PTHREAD_API )
pthread_cond_wait( &pMutex->cond_l, &pMutex->mutex );
#elif defined( HB_COND_HARBOUR_SUPPORT )
_hb_thread_cond_wait( &pMutex->cond_l, &pMutex->mutex, HB_THREAD_INFINITE_WAIT );
#else
HB_CRITICAL_UNLOCK( pMutex->mutex );
( void ) HB_COND_WAIT( pMutex->cond_l );
HB_CRITICAL_LOCK( pMutex->mutex );
pMutex->lockers--;
#endif
pMutex->lockers--;
}
pMutex->lock_count = pList->lock_count;
pMutex->owner = HB_THREAD_SELF();
@@ -1302,8 +1430,10 @@ static HB_GARBAGE_FUNC( hb_mutexDestructor )
/* nothing */
#else
HB_CRITICAL_DESTROY( pMutex->mutex );
# if !defined( HB_COND_HARBOUR_SUPPORT )
HB_COND_DESTROY( pMutex->cond_l );
HB_COND_DESTROY( pMutex->cond_w );
# endif
#endif
}
@@ -1337,8 +1467,10 @@ PHB_ITEM hb_threadMutexCreate( BOOL fSync )
/* nothing */
#else
HB_CRITICAL_INIT( pMutex->mutex );
# if !defined( HB_COND_HARBOUR_SUPPORT )
HB_COND_INIT( pMutex->cond_l );
HB_COND_INIT( pMutex->cond_w );
# endif
#endif
pMutex->fSync = fSync;
@@ -1410,13 +1542,15 @@ BOOL hb_threadMutexLock( PHB_ITEM pItem )
while( pMutex->lock_count != 0 )
{
pMutex->lockers++;
#if defined( HB_PTHREAD_API )
# if defined( HB_PTHREAD_API )
pthread_cond_wait( &pMutex->cond_l, &pMutex->mutex );
#else
# elif defined( HB_COND_HARBOUR_SUPPORT )
_hb_thread_cond_wait( &pMutex->cond_l, &pMutex->mutex, HB_THREAD_INFINITE_WAIT );
# else
HB_CRITICAL_UNLOCK( pMutex->mutex );
( void ) HB_COND_WAIT( pMutex->cond_l );
HB_CRITICAL_LOCK( pMutex->mutex );
#endif
# endif
pMutex->lockers--;
}
pMutex->lock_count = 1;
@@ -1455,7 +1589,7 @@ BOOL hb_threadMutexTimedLock( PHB_ITEM pItem, ULONG ulMilliSec )
HB_CRITICAL_LOCK( pMutex->mutex );
if( ulMilliSec && pMutex->lock_count != 0 )
{
#if defined( HB_PTHREAD_API )
# if defined( HB_PTHREAD_API )
struct timespec ts;
hb_threadTimeInit( &ts, ulMilliSec );
@@ -1472,17 +1606,23 @@ BOOL hb_threadMutexTimedLock( PHB_ITEM pItem, ULONG ulMilliSec )
}
while( pMutex->lock_count != 0 );
pMutex->lockers--;
#else
# 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 )
pMutex->lockers++;
_hb_thread_cond_wait( &pMutex->cond_l, &pMutex->mutex, ulMilliSec );
pMutex->lockers--;
# else
pMutex->lockers++;
HB_CRITICAL_UNLOCK( pMutex->mutex );
( void ) HB_COND_TIMEDWAIT( pMutex->cond_l, ulMilliSec );
HB_CRITICAL_LOCK( pMutex->mutex );
pMutex->lockers--;
#endif
# endif
# endif
}
if( pMutex->lock_count == 0 )
{
@@ -1657,12 +1797,14 @@ PHB_ITEM hb_threadMutexSubscribe( PHB_ITEM pItem, BOOL fClear )
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 );
pMutex->waiters--;
# endif
pMutex->waiters--;
}
if( pMutex->events && hb_arrayLen( pMutex->events ) > 0 )
@@ -1681,13 +1823,15 @@ PHB_ITEM hb_threadMutexSubscribe( PHB_ITEM pItem, BOOL fClear )
pMutex->lockers++;
while( pMutex->lock_count != 0 )
{
#if defined( HB_PTHREAD_API )
# if defined( HB_PTHREAD_API )
pthread_cond_wait( &pMutex->cond_l, &pMutex->mutex );
#else
# elif defined( HB_COND_HARBOUR_SUPPORT )
_hb_thread_cond_wait( &pMutex->cond_l, &pMutex->mutex, HB_THREAD_INFINITE_WAIT );
# else
HB_CRITICAL_UNLOCK( pMutex->mutex );
( void ) HB_COND_WAIT( pMutex->cond_l );
HB_CRITICAL_LOCK( pMutex->mutex );
#endif
# endif
}
pMutex->lockers--;
}
@@ -1773,9 +1917,13 @@ PHB_ITEM hb_threadMutexTimedSubscribe( PHB_ITEM pItem, ULONG ulMilliSec, BOOL fC
* 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--;
@@ -1797,13 +1945,15 @@ PHB_ITEM hb_threadMutexTimedSubscribe( PHB_ITEM pItem, ULONG ulMilliSec, BOOL fC
pMutex->lockers++;
while( pMutex->lock_count != 0 )
{
#if defined( HB_PTHREAD_API )
# if defined( HB_PTHREAD_API )
pthread_cond_wait( &pMutex->cond_l, &pMutex->mutex );
#else
# elif defined( HB_COND_HARBOUR_SUPPORT )
_hb_thread_cond_wait( &pMutex->cond_l, &pMutex->mutex, HB_THREAD_INFINITE_WAIT );
# else
HB_CRITICAL_UNLOCK( pMutex->mutex );
( void ) HB_COND_WAIT( pMutex->cond_l );
HB_CRITICAL_LOCK( pMutex->mutex );
#endif
# endif
}
pMutex->lockers--;
}