diff options
Diffstat (limited to 'lib/libthr/thread/thr_cond.c')
-rw-r--r-- | lib/libthr/thread/thr_cond.c | 235 |
1 files changed, 89 insertions, 146 deletions
diff --git a/lib/libthr/thread/thr_cond.c b/lib/libthr/thread/thr_cond.c index 9597816..dedd3c2 100644 --- a/lib/libthr/thread/thr_cond.c +++ b/lib/libthr/thread/thr_cond.c @@ -200,13 +200,9 @@ cond_wait_common(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime) { int rval = 0; - int done = 0; - int seqno; int mtxrval; - _thread_enter_cancellation_point(); - if (cond == NULL) return (EINVAL); /* @@ -216,6 +212,8 @@ cond_wait_common(pthread_cond_t * cond, pthread_mutex_t * mutex, if (*cond == PTHREAD_COND_INITIALIZER && (rval = cond_init(cond)) != 0) return (rval); + if ((*cond)->c_type != COND_TYPE_FAST) + return (EINVAL); COND_LOCK(*cond); @@ -228,124 +226,86 @@ cond_wait_common(pthread_cond_t * cond, pthread_mutex_t * mutex, (*cond)->c_flags |= COND_FLAGS_INITED; } - /* Process according to condition variable type. */ + if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && + ((*cond)->c_mutex != *mutex))) { + COND_UNLOCK(*cond); + return (EINVAL); + } + /* Remember the mutex */ + (*cond)->c_mutex = *mutex; - switch ((*cond)->c_type) { - /* Fast condition variable: */ - case COND_TYPE_FAST: - if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && - ((*cond)->c_mutex != *mutex))) { - COND_UNLOCK(*cond); - rval = EINVAL; - break; - } - /* Remember the mutex */ - (*cond)->c_mutex = *mutex; - - if ((rval = _mutex_cv_unlock(mutex)) != 0) { - if (rval == -1){ - printf("foo"); - fflush(stdout); - abort(); - } - - COND_UNLOCK(*cond); - break; + _thread_enter_cancellation_point(); + if ((rval = _mutex_cv_unlock(mutex)) != 0) { + if (rval == -1){ + printf("mutex unlock by condvar failed!"); + fflush(stdout); + abort(); } + _thread_leave_cancellation_point(); + COND_UNLOCK(*cond); + return (rval); + } - /* - * We need to protect the queue operations. It also - * protects c_seqno and the pthread flag fields. This is - * dropped before calling _thread_suspend() and reaquired - * when we return. - */ - - _thread_critical_enter(curthread); - /* - * c_seqno is protected. - */ - seqno = (*cond)->c_seqno; - - do { - /* - * Queue the running thread on the condition - * variable. - */ - cond_queue_enq(*cond, curthread); - - if (curthread->cancelflags & PTHREAD_CANCELLING) { - /* - * POSIX Says that we must relock the mutex - * even if we're being canceled. - */ - _thread_critical_exit(curthread); - COND_UNLOCK(*cond); - _mutex_cv_lock(mutex); - pthread_testcancel(); - PANIC("Shouldn't have come back."); - } - - PTHREAD_SET_STATE(curthread, PS_COND_WAIT); - _thread_critical_exit(curthread); - COND_UNLOCK(*cond); - rval = _thread_suspend(curthread, (struct timespec *)abstime); - if (rval != 0 && rval != ETIMEDOUT && rval != EINTR) { - printf("foo"); - fflush(stdout); - abort(); - } - COND_LOCK(*cond); - _thread_critical_enter(curthread); - - done = (seqno != (*cond)->c_seqno); + /* + * We need to protect the queue operations. It also + * protects the pthread flag field. This is + * dropped before calling _thread_suspend() and reaquired + * when we return. + */ + PTHREAD_LOCK(curthread); + /* + * Queue the running thread on the condition + * variable and wait to be signaled. + */ + cond_queue_enq(*cond, curthread); + do { + PTHREAD_UNLOCK(curthread); + COND_UNLOCK(*cond); + if (curthread->cancellation == CS_PENDING) { /* - * If we timed out, this will remove us from the - * queue. Otherwise, if we were signaled it does - * nothing because this thread won't be on the queue. + * Posix says we must lock the mutex + * even if we're being canceled. */ - cond_queue_remove(*cond, curthread); - - } while ((done == 0) && (rval == 0)); - /* - * If we timed out someone still may have signaled us - * before we got a chance to run again. We check for - * this by looking to see if our state is RUNNING. - */ - if (rval == ETIMEDOUT) { - if (curthread->state != PS_RUNNING) { - PTHREAD_SET_STATE(curthread, PS_RUNNING); - } else - rval = 0; + _mutex_cv_lock(mutex); + _thread_leave_cancellation_point(); + PANIC("Shouldn't have come back."); } - _thread_critical_exit(curthread); - COND_UNLOCK(*cond); - - mtxrval = _mutex_cv_lock(mutex); - - /* - * If the mutex failed return that error, otherwise we're - * returning ETIMEDOUT. - */ - if (mtxrval == -1) { - printf("foo"); + rval = _thread_suspend(curthread, (struct timespec *)abstime); + if (rval != 0 && rval != ETIMEDOUT && rval != EINTR) { + printf("thread suspend returned an invalid value"); fflush(stdout); abort(); } - if (mtxrval != 0) - rval = mtxrval; + COND_LOCK(*cond); + PTHREAD_LOCK(curthread); + if (rval == ETIMEDOUT) { + /* + * Condition may have been signaled between the + * time the thread timed out and locked the condvar. + * If it wasn't, manually remove it from the queue. + */ + if ((curthread->flags & PTHREAD_FLAGS_IN_CONDQ) == 0) + rval = 0; + else + cond_queue_remove(*cond, curthread); + } + } while ((curthread->flags & PTHREAD_FLAGS_IN_CONDQ) != 0); - break; + PTHREAD_UNLOCK(curthread); + COND_UNLOCK(*cond); + mtxrval = _mutex_cv_lock(mutex); - /* Trap invalid condition variable types: */ - default: - COND_UNLOCK(*cond); - rval = EINVAL; - break; + /* If the mutex failed return that error. */ + if (mtxrval == -1) { + printf("mutex lock from condvar failed!"); + fflush(stdout); + abort(); } + if (mtxrval != 0) + rval = mtxrval; _thread_leave_cancellation_point(); - return (rval); } @@ -376,40 +336,26 @@ cond_signal(pthread_cond_t * cond, int broadcast) if (*cond == PTHREAD_COND_INITIALIZER && (rval = cond_init(cond)) != 0) return (rval); + if ((*cond)->c_type != COND_TYPE_FAST) + return (EINVAL); COND_LOCK(*cond); - /* Process according to condition variable type: */ - switch ((*cond)->c_type) { - /* Fast condition variable: */ - case COND_TYPE_FAST: - (*cond)->c_seqno++; - + /* + * Enter a loop to bring all (or only one) threads off the + * condition queue: + */ + do { /* - * Enter a loop to bring all (or only one) threads off the - * condition queue: + * Wake up the signaled thread. It will be returned + * to us locked. */ - do { - /* - * Wake up the signaled thread. It will be returned - * to us locked, and with signals disabled. - */ - if ((pthread = cond_queue_deq(*cond)) != NULL) { - PTHREAD_NEW_STATE(pthread, PS_RUNNING); - _thread_critical_exit(pthread); - } - } while (broadcast && pthread != NULL); - - break; - - /* Trap invalid condition variable types: */ - default: - rval = EINVAL; - break; - } + if ((pthread = cond_queue_deq(*cond)) != NULL) { + PTHREAD_WAKE(pthread); + PTHREAD_UNLOCK(pthread); + } + } while (broadcast && pthread != NULL); COND_UNLOCK(*cond); - - return (rval); } @@ -443,20 +389,17 @@ cond_queue_deq(pthread_cond_t cond) pthread_t pthread; while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { - _thread_critical_enter(pthread); - TAILQ_REMOVE(&cond->c_queue, pthread, sqe); + PTHREAD_LOCK(pthread); cond_queue_remove(cond, pthread); - if ((pthread->cancelflags & PTHREAD_CANCELLING) == 0 && - pthread->state == PS_COND_WAIT) - /* - * Only exit the loop when we find a thread - * that hasn't timed out or been canceled; - * those threads are already running and don't - * need their run state changed. - */ + + /* + * Only exit the loop when we find a thread + * that hasn't been canceled. + */ + if (pthread->cancellation == CS_NULL) break; else - _thread_critical_exit(pthread); + PTHREAD_UNLOCK(pthread); } return(pthread); |