diff options
author | wchang0222%aol.com <devnull@localhost> | 2004-04-12 23:41:15 +0000 |
---|---|---|
committer | wchang0222%aol.com <devnull@localhost> | 2004-04-12 23:41:15 +0000 |
commit | 7527f8fb09a2647f7e4a1a62f949a4bd6aec7541 (patch) | |
tree | 513ada980b1cc6324ec31920d6b5da061e049c92 | |
parent | 7667c3a91c3c01999f52a95a8686752b91b670ab (diff) | |
download | nspr-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.h | 8 | ||||
-rw-r--r-- | pr/src/bthreads/btcvar.c | 171 |
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; } |