From 3b31eab500fade21f763f2d5781b9a387b045678 Mon Sep 17 00:00:00 2001 From: "wchang0222%aol.com" Date: Mon, 12 Apr 2004 23:44:43 +0000 Subject: [PATCH] Bugzilla bug 232958: checked in a new condition variable implementation contributed by Fredrik Holmqvist . Modified Files: primpl.h btcvar.c --- nsprpub/pr/include/private/primpl.h | 8 +- nsprpub/pr/src/bthreads/btcvar.c | 171 ++++++++++++++++++++-------- 2 files changed, 128 insertions(+), 51 deletions(-) diff --git a/nsprpub/pr/include/private/primpl.h b/nsprpub/pr/include/private/primpl.h index 04f9d4c57729..db323306b9ee 100644 --- a/nsprpub/pr/include/private/primpl.h +++ b/nsprpub/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/nsprpub/pr/src/bthreads/btcvar.c b/nsprpub/pr/src/bthreads/btcvar.c index 3ca8c1f458ad..ce16de7850fb 100644 --- a/nsprpub/pr/src/bthreads/btcvar.c +++ b/nsprpub/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; - - 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; }