Bugzilla bug 232958: checked in a new condition variable implementation

contributed by Fredrik Holmqvist <thesuckiestemail@yahoo.com>.
Modified Files: primpl.h btcvar.c
This commit is contained in:
wchang0222%aol.com 2004-04-12 23:44:43 +00:00
parent 0d37d31a30
commit 3b31eab500
2 changed files with 128 additions and 51 deletions

View File

@ -1460,8 +1460,12 @@ struct PRCondVar {
pthread_cond_t cv; /* underlying pthreads condition */
PRInt32 notify_pending; /* CV has destroy pending notification */
#elif defined(_PR_BTHREADS)
sem_id isem; /* Semaphore used to lock threadQ */
int32 benaphoreCount; /* Number of people in lock */
sem_id sem; /* the underlying lock */
sem_id handshakeSem; /* the lock for 'notify'-threads waiting for confirmation */
sem_id signalSem; /* the lock for threads waiting for someone to notify */
volatile int32 nw; /* the number waiting */
volatile int32 ns; /* the number signalling */
long signalBenCount; /* the number waiting on the underlying sem */
#else /* not pthreads or Be threads */
PRCList condQ; /* Condition variable wait Q */
_MDLock ilock; /* Internal Lock to protect condQ */

View File

@ -55,8 +55,14 @@ PR_IMPLEMENT(PRCondVar*)
if( NULL != cv )
{
cv->lock = lock;
cv->isem = create_sem( 1, "nspr_sem");
PR_ASSERT( cv->isem >= B_NO_ERROR );
cv->sem = create_sem(0, "CVSem");
cv->handshakeSem = create_sem(0, "CVHandshake");
cv->signalSem = create_sem( 0, "CVSignal");
cv->signalBenCount = 0;
cv->ns = cv->nw = 0;
PR_ASSERT( cv->sem >= B_NO_ERROR );
PR_ASSERT( cv->handshakeSem >= B_NO_ERROR );
PR_ASSERT( cv->signalSem >= B_NO_ERROR );
}
return cv;
} /* PR_NewCondVar */
@ -70,10 +76,15 @@ PR_IMPLEMENT(PRCondVar*)
PR_IMPLEMENT(void)
PR_DestroyCondVar (PRCondVar *cvar)
{
status_t result;
result = delete_sem( cvar->isem );
status_t result = delete_sem( cvar->sem );
PR_ASSERT( result == B_NO_ERROR );
result = delete_sem( cvar->handshakeSem );
PR_ASSERT( result == B_NO_ERROR );
result = delete_sem( cvar->signalSem );
PR_ASSERT( result == B_NO_ERROR );
PR_DELETE( cvar );
}
@ -108,51 +119,59 @@ PR_IMPLEMENT(void)
PR_IMPLEMENT(PRStatus)
PR_WaitCondVar (PRCondVar *cvar, PRIntervalTime timeout)
{
status_t result;
bigtime_t interval;
status_t err;
if( timeout == PR_INTERVAL_NO_WAIT )
{
PR_Unlock( cvar->lock );
PR_Lock( cvar->lock );
return PR_SUCCESS;
}
if( atomic_add( &cvar->signalBenCount, 1 ) > 0 )
{
if (acquire_sem(cvar->signalSem) == B_INTERRUPTED)
{
atomic_add( &cvar->signalBenCount, -1 );
return PR_FAILURE;
}
}
cvar->nw += 1;
if( atomic_add( &cvar->signalBenCount, -1 ) > 1 )
{
release_sem(cvar->signalSem);
}
PR_Unlock( cvar->lock );
if( timeout==PR_INTERVAL_NO_TIMEOUT )
{
err = acquire_sem(cvar->sem);
}
else
{
err = acquire_sem_etc(cvar->sem, 1, B_RELATIVE_TIMEOUT, PR_IntervalToMicroseconds(timeout) );
}
switch (timeout) {
case PR_INTERVAL_NO_WAIT:
/* nothing to do */
break;
if( atomic_add( &cvar->signalBenCount, 1 ) > 0 )
{
while (acquire_sem(cvar->signalSem) == B_INTERRUPTED);
}
case PR_INTERVAL_NO_TIMEOUT:
/* wait as long as necessary */
if( acquire_sem( cvar->isem ) != B_NO_ERROR ) return PR_FAILURE;
break;
default:
interval = (bigtime_t)PR_IntervalToMicroseconds(timeout);
/*
** in R5, this problem seems to have been resolved, so we
** won't bother with it
*/
#if !defined(B_BEOS_VERSION_5) || (B_BEOS_VERSION < B_BEOS_VERSION_5)
/*
** This is an entirely stupid bug, but... If you call
** acquire_sem_etc with a timeout of exactly 1,000,000 microseconds
** it returns immediately with B_NO_ERROR. 1,000,010 microseconds
** returns as expected. Running BeOS/Intel R3.1 at this time.
** Forwarded to Be, Inc. for resolution, Bug ID 980624-225956
**
** Update: Be couldn't reproduce it, but removing timeout++ still
** exhibits the problem on BeOS/Intel R4 and BeOS/PPC R4.
*/
if (interval == 1000000)
interval = 1000010;
#endif /* !defined(B_BEOS_VERSION_5) || (B_BEOS_VERSION < B_BEOS_VERSION_5) */
result = acquire_sem_etc( cvar->isem, 1, B_RELATIVE_TIMEOUT, interval);
if( result != B_NO_ERROR && result != B_TIMED_OUT )
return PR_FAILURE;
break;
if (cvar->ns > 0)
{
release_sem(cvar->handshakeSem);
cvar->ns -= 1;
}
cvar->nw -= 1;
if( atomic_add( &cvar->signalBenCount, -1 ) > 1 )
{
release_sem(cvar->signalSem);
}
PR_Lock( cvar->lock );
if(err!=B_NO_ERROR)
{
return PR_FAILURE;
}
return PR_SUCCESS;
}
@ -172,8 +191,36 @@ PR_IMPLEMENT(PRStatus)
PR_IMPLEMENT(PRStatus)
PR_NotifyCondVar (PRCondVar *cvar)
{
if( release_sem( cvar->isem ) != B_NO_ERROR ) return PR_FAILURE;
status_t err ;
if( atomic_add( &cvar->signalBenCount, 1 ) > 0 )
{
if (acquire_sem(cvar->signalSem) == B_INTERRUPTED)
{
atomic_add( &cvar->signalBenCount, -1 );
return PR_FAILURE;
}
}
if (cvar->nw > cvar->ns)
{
cvar->ns += 1;
release_sem(cvar->sem);
if( atomic_add( &cvar->signalBenCount, -1 ) > 1 )
{
release_sem(cvar->signalSem);
}
while (acquire_sem(cvar->handshakeSem) == B_INTERRUPTED)
{
err = B_INTERRUPTED;
}
}
else
{
if( atomic_add( &cvar->signalBenCount, -1 ) > 1 )
{
release_sem(cvar->signalSem);
}
}
return PR_SUCCESS;
}
@ -188,13 +235,39 @@ PR_IMPLEMENT(PRStatus)
PR_IMPLEMENT(PRStatus)
PR_NotifyAllCondVar (PRCondVar *cvar)
{
sem_info semInfo;
int32 handshakes;
status_t err = B_OK;
if( get_sem_info( cvar->isem, &semInfo ) != B_NO_ERROR )
return PR_FAILURE;
if( atomic_add( &cvar->signalBenCount, 1 ) > 0 )
{
if (acquire_sem(cvar->signalSem) == B_INTERRUPTED)
{
atomic_add( &cvar->signalBenCount, -1 );
return PR_FAILURE;
}
}
if( release_sem_etc( cvar->isem, semInfo.count, 0 ) != B_NO_ERROR )
return PR_FAILURE;
if (cvar->nw > cvar->ns)
{
handshakes = cvar->nw - cvar->ns;
cvar->ns = cvar->nw;
release_sem_etc(cvar->sem, handshakes, 0);
if( atomic_add( &cvar->signalBenCount, -1 ) > 1 )
{
release_sem(cvar->signalSem);
}
while (acquire_sem_etc(cvar->handshakeSem, handshakes, 0, 0) == B_INTERRUPTED)
{
err = B_INTERRUPTED;
}
}
else
{
if( atomic_add( &cvar->signalBenCount, -1 ) > 1 )
{
release_sem(cvar->signalSem);
}
}
return PR_SUCCESS;
}