mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-19 15:51:33 +00:00
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:
parent
0d37d31a30
commit
3b31eab500
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user