summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwchang0222%aol.com <devnull@localhost>2004-04-12 23:41:15 +0000
committerwchang0222%aol.com <devnull@localhost>2004-04-12 23:41:15 +0000
commit7527f8fb09a2647f7e4a1a62f949a4bd6aec7541 (patch)
tree513ada980b1cc6324ec31920d6b5da061e049c92
parent7667c3a91c3c01999f52a95a8686752b91b670ab (diff)
downloadnspr-hg-7527f8fb09a2647f7e4a1a62f949a4bd6aec7541.tar.gz
Bugzilla bug 232958: checked in a new condition variable implementation
contributed by Fredrik Holmqvist <thesuckiestemail@yahoo.se>. Modified Files: primpl.h btcvar.c Tag: NSPRPUB_PRE_4_2_CLIENT_BRANCH
-rw-r--r--pr/include/private/primpl.h8
-rw-r--r--pr/src/bthreads/btcvar.c171
2 files changed, 128 insertions, 51 deletions
diff --git a/pr/include/private/primpl.h b/pr/include/private/primpl.h
index 04f9d4c5..db323306 100644
--- a/pr/include/private/primpl.h
+++ b/pr/include/private/primpl.h
@@ -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 */
diff --git a/pr/src/bthreads/btcvar.c b/pr/src/bthreads/btcvar.c
index 3ca8c1f4..ce16de78 100644
--- a/pr/src/bthreads/btcvar.c
+++ b/pr/src/bthreads/btcvar.c
@@ -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;
+ 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->isem );
+ 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;
-
- 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( atomic_add( &cvar->signalBenCount, 1 ) > 0 )
+ {
+ while (acquire_sem(cvar->signalSem) == B_INTERRUPTED);
}
- PR_Lock( cvar->lock );
+ 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;
}