From 9af51e470791639995bb34bd3198014dc11e2fef Mon Sep 17 00:00:00 2001 From: rpj Date: Thu, 12 Aug 1999 01:32:02 +0000 Subject: Merged patches to main trunk. --- condvar.c | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) (limited to 'condvar.c') diff --git a/condvar.c b/condvar.c index 580c379..c84a32a 100644 --- a/condvar.c +++ b/condvar.c @@ -459,14 +459,21 @@ pthread_cond_destroy (pthread_cond_t * cond) if (cv != (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) { + if (pthread_mutex_lock(&(cv->waitersLock)) != 0) + { + return EINVAL; + } + if (cv->waiters > 0) { + (void) pthread_mutex_unlock(&(cv->waitersLock)); return EBUSY; } (void) sem_destroy (&(cv->sema)); - (void) pthread_mutex_destroy (&(cv->waitersLock)); (void) CloseHandle (cv->waitersDone); + (void) pthread_mutex_unlock(&(cv->waitersLock)); + (void) pthread_mutex_destroy (&(cv->waitersLock)); free(cv); } @@ -510,10 +517,22 @@ cond_timedwait (pthread_cond_t * cond, cv = *cond; /* - * OK to increment cond->waiters because the caller locked 'mutex' + * It's not OK to increment cond->waiters while the caller locked 'mutex', + * there may be other threads just waking up (with 'mutex' unlocked) + * and cv->... data is not protected. */ + if (pthread_mutex_lock(&(cv->waitersLock)) != 0) + { + return EINVAL; + } + cv->waiters++; + if (pthread_mutex_unlock(&(cv->waitersLock)) != 0) + { + return EINVAL; + } + /* * We keep the lock held just long enough to increment the count of * waiters by one (above). @@ -527,6 +546,7 @@ cond_timedwait (pthread_cond_t * cond, * Wait to be awakened by * pthread_cond_signal, or * pthread_cond_broadcast + * timeout * * Note: * _pthread_sem_timedwait is a cancellation point, @@ -548,10 +568,10 @@ cond_timedwait (pthread_cond_t * cond, if ((internal_result = pthread_mutex_lock (&(cv->waitersLock))) == 0) { /* - * By making the waiter responsible for decrementing - * its count we don't have to worry about having an internal - * mutex. + * The waiter is responsible for decrementing + * its count, protected by an internal mutex. */ + cv->waiters--; lastWaiter = cv->wasBroadcast && (cv->waiters == 0); @@ -559,7 +579,7 @@ cond_timedwait (pthread_cond_t * cond, internal_result = pthread_mutex_unlock (&(cv->waitersLock)); } - if (result == 0 && internal_result == 0) + if ((result == 0 || result == ETIMEDOUT) && internal_result == 0) { if (lastWaiter) { @@ -576,7 +596,7 @@ cond_timedwait (pthread_cond_t * cond, /* * We must always regain the external mutex, even when - * errors occur because that's the guarantee that we give + * errors occur, because that's the guarantee that we give * to our callers */ (void) pthread_mutex_lock (mutex); @@ -760,6 +780,7 @@ pthread_cond_signal (pthread_cond_t * cond) /* * No-op if the CV is static and hasn't been initialised yet. + * Assuming that race conditions are harmless. */ if (cv == (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) { @@ -768,6 +789,7 @@ pthread_cond_signal (pthread_cond_t * cond) /* * If there aren't any waiters, then this is a no-op. + * Assuming that race conditions are harmless. */ if (cv->waiters > 0) { @@ -817,6 +839,7 @@ pthread_cond_broadcast (pthread_cond_t * cond) */ { int result = 0; + int wereWaiters = FALSE; pthread_cond_t cv; if (cond == NULL || *cond == NULL) @@ -828,13 +851,20 @@ pthread_cond_broadcast (pthread_cond_t * cond) /* * No-op if the CV is static and hasn't been initialised yet. + * Assuming that any race condition is harmless. */ if (cv == (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) { return 0; } + if (pthread_mutex_lock(&(cv->waitersLock)) == EINVAL) + { + return EINVAL; + } + cv->wasBroadcast = TRUE; + wereWaiters = (cv->waiters > 0); /* * Wake up all waiters @@ -843,14 +873,16 @@ pthread_cond_broadcast (pthread_cond_t * cond) ? 0 : EINVAL); - if (cv->waiters > 0 && result == 0) + (void) pthread_mutex_unlock(&(cv->waitersLock)); + + if (wereWaiters && result == 0) { /* * Wait for all the awakened threads to acquire their part of * the counting semaphore */ - if (WaitForSingleObject (cv->waitersDone, INFINITE) == - WAIT_OBJECT_0) + if (WaitForSingleObject (cv->waitersDone, INFINITE) + == WAIT_OBJECT_0) { result = 0; } -- cgit v1.2.3