diff options
author | rpj <rpj> | 1999-11-04 14:56:51 +0000 |
---|---|---|
committer | rpj <rpj> | 1999-11-04 14:56:51 +0000 |
commit | c614567b4940f31a7ce98ceb9eb48b1241b4727a (patch) | |
tree | aaa362d4c46c13f7fb7546b1ee14264e32b22ec1 /condvar.c | |
parent | efa438832bc1343c08c334e88aec4266040ddec3 (diff) |
Add WinCE patches to snap-1999-05-30-wince-patches branch.
Diffstat (limited to 'condvar.c')
-rw-r--r-- | condvar.c | 231 |
1 files changed, 66 insertions, 165 deletions
@@ -65,15 +65,6 @@ _cond_check_need_init(pthread_cond_t *cond) { result = pthread_cond_init(cond, NULL); } - else if (*cond == NULL) - { - /* - * The cv has been destroyed while we were waiting to - * initialise it, so the operation that caused the - * auto-initialisation should fail. - */ - result = EINVAL; - } LeaveCriticalSection(&_pthread_cond_test_init_lock); @@ -464,126 +455,27 @@ pthread_cond_destroy (pthread_cond_t * cond) return EINVAL; } - if (*cond != (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) - { - cv = *cond; - - if (pthread_mutex_lock(&(cv->waitersLock)) != 0) - { - return EINVAL; - } + cv = *cond; + if (cv != (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) + { if (cv->waiters > 0) { - (void) pthread_mutex_unlock(&(cv->waitersLock)); return EBUSY; } (void) sem_destroy (&(cv->sema)); - (void) CloseHandle (cv->waitersDone); - (void) pthread_mutex_unlock(&(cv->waitersLock)); (void) pthread_mutex_destroy (&(cv->waitersLock)); + (void) CloseHandle (cv->waitersDone); free(cv); - *cond = NULL; } - else - { - /* - * See notes in _cond_check_need_init() above also. - */ - EnterCriticalSection(&_pthread_cond_test_init_lock); - /* - * Check again. - */ - if (*cond == (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) - { - /* - * This is all we need to do to destroy a statically - * initialised cond that has not yet been used (initialised). - * If we get to here, another thread - * waiting to initialise this cond will get an EINVAL. - */ - *cond = NULL; - } - else - { - /* - * The cv has been initialised while we were waiting - * so assume it's in use. - */ - result = EBUSY; - } - - LeaveCriticalSection(&_pthread_cond_test_init_lock); - } + *cond = NULL; return (result); } -/* - * Arguments for cond_wait_cleanup, since we can only pass a - * single void * to it. - */ -typedef struct { - pthread_mutex_t * mutexPtr; - pthread_cond_t cv; - int * resultPtr; -} cond_wait_cleanup_args_t; - -static void -cond_wait_cleanup(void * args) -{ - cond_wait_cleanup_args_t * cleanup_args = (cond_wait_cleanup_args_t *) args; - pthread_mutex_t * mutexPtr = cleanup_args->mutexPtr; - pthread_cond_t cv = cleanup_args->cv; - int * resultPtr = cleanup_args->resultPtr; - int lock_result; - int lastWaiter; - - if ((lock_result = pthread_mutex_lock (&(cv->waitersLock))) == 0) - { - /* - * The waiter is responsible for decrementing - * its count, protected by an internal mutex. - */ - - cv->waiters--; - - lastWaiter = cv->wasBroadcast && (cv->waiters == 0); - - if (lastWaiter) - { - cv->wasBroadcast = FALSE; - } - - lock_result = pthread_mutex_unlock (&(cv->waitersLock)); - } - - if ((*resultPtr == 0 || *resultPtr == ETIMEDOUT) && lock_result == 0) - { - if (lastWaiter) - { - /* - * If we are the last waiter on this broadcast - * let the thread doing the broadcast proceed - */ - if (!SetEvent (cv->waitersDone)) - { - *resultPtr = EINVAL; - } - } - } - - /* - * We must always regain the external mutex, even when - * errors occur, because that's the guarantee that we give - * to our callers - */ - (void) pthread_mutex_lock (mutexPtr); -} - static int cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, @@ -593,7 +485,6 @@ cond_timedwait (pthread_cond_t * cond, int internal_result = 0; int lastWaiter = FALSE; pthread_cond_t cv; - cond_wait_cleanup_args_t cleanup_args; if (cond == NULL || *cond == NULL) { @@ -619,22 +510,10 @@ cond_timedwait (pthread_cond_t * cond, cv = *cond; /* - * 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. + * OK to increment cond->waiters because the caller locked 'mutex' */ - 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). @@ -642,41 +521,67 @@ cond_timedwait (pthread_cond_t * cond, * call to sem_wait since that will deadlock other calls * to pthread_cond_signal */ - cleanup_args.mutexPtr = mutex; - cleanup_args.cv = cv; - cleanup_args.resultPtr = &result; - - pthread_cleanup_push (cond_wait_cleanup, (void *) &cleanup_args); - if ((result = pthread_mutex_unlock (mutex)) == 0) { /* * Wait to be awakened by * pthread_cond_signal, or * pthread_cond_broadcast - * timeout * * Note: - * _pthread_sem_timedwait is a cancelation point, + * _pthread_sem_timedwait is a cancellation point, * hence providing the - * mechanism for making pthread_cond_wait a cancelation + * mechanism for making pthread_cond_wait a cancellation * point. We use the cleanup mechanism to ensure we - * re-lock the mutex and decrement the waiters count - * if we are canceled. + * re-lock the mutex if we are cancelled. */ + pthread_cleanup_push (pthread_mutex_lock, mutex); + if (_pthread_sem_timedwait (&(cv->sema), abstime) == -1) { result = errno; } + + pthread_cleanup_pop (0); } - pthread_cleanup_pop (1); + 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. + */ + cv->waiters--; + + lastWaiter = cv->wasBroadcast && (cv->waiters == 0); + + internal_result = pthread_mutex_unlock (&(cv->waitersLock)); + } + + if (result == 0 && internal_result == 0) + { + if (lastWaiter) + { + /* + * If we are the last waiter on this broadcast + * let the thread doing the broadcast proceed + */ + if (!SetEvent (cv->waitersDone)) + { + result = EINVAL; + } + } + } /* - * "result" can be modified by the cleanup handler. - * Specifically, if we are the last waiting thread and failed - * to notify the broadcast thread to proceed. + * We must always regain the external mutex, even when + * errors occur because that's the guarantee that we give + * to our callers */ + (void) pthread_mutex_lock (mutex); + + return (result); } /* cond_timedwait */ @@ -855,7 +760,6 @@ 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) { @@ -864,7 +768,6 @@ 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) { @@ -914,7 +817,6 @@ pthread_cond_broadcast (pthread_cond_t * cond) */ { int result = 0; - int wereWaiters = FALSE; pthread_cond_t cv; if (cond == NULL || *cond == NULL) @@ -926,41 +828,40 @@ 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); - if (wereWaiters) - { - /* - * Wake up all waiters - */ - result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL ) - ? 0 - : EINVAL ); - } + /* + * Wake up all waiters + */ + +#ifdef NEED_SEM + + result = (_pthread_increase_semaphore( &cv->sema, cv->waiters ) + ? 0 + : EINVAL); + +#else /* NEED_SEM */ + + result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL ) + ? 0 + : EINVAL); - (void) pthread_mutex_unlock(&(cv->waitersLock)); +#endif /* NEED_SEM */ - if (wereWaiters && result == 0) + if (cv->waiters > 0 && 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; } |