diff options
Diffstat (limited to 'lib/libpthread/thread/thr_cond.c')
-rw-r--r-- | lib/libpthread/thread/thr_cond.c | 72 |
1 files changed, 52 insertions, 20 deletions
diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c index e0360dde1b4ce..bacfb72173377 100644 --- a/lib/libpthread/thread/thr_cond.c +++ b/lib/libpthread/thread/thr_cond.c @@ -29,6 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id$ */ #include <stdlib.h> #include <errno.h> @@ -44,6 +45,28 @@ static inline pthread_t cond_queue_deq(pthread_cond_t); static inline void cond_queue_remove(pthread_cond_t, pthread_t); static inline void cond_queue_enq(pthread_cond_t, pthread_t); +/* Reinitialize a condition variable to defaults. */ +int +_cond_reinit(pthread_cond_t * cond) +{ + int ret = 0; + + if (cond == NULL) + ret = EINVAL; + else if (*cond == NULL) + ret = pthread_cond_init(cond, NULL); + else { + /* + * Initialize the condition variable structure: + */ + TAILQ_INIT(&(*cond)->c_queue); + (*cond)->c_flags = COND_FLAGS_INITED; + (*cond)->c_type = COND_TYPE_FAST; + (*cond)->c_mutex = NULL; + memset(&(*cond)->lock, 0, sizeof((*cond)->lock)); + } + return (ret); +} int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr) @@ -146,6 +169,9 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) */ else if (*cond != NULL || (rval = pthread_cond_init(cond,NULL)) == 0) { + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + /* * If the condvar was statically allocated, properly * initialize the tail queue. @@ -155,9 +181,6 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) (*cond)->c_flags |= COND_FLAGS_INITED; } - /* Lock the condition variable structure: */ - _SPINLOCK(&(*cond)->lock); - /* Process according to condition variable type: */ switch ((*cond)->c_type) { /* Fast condition variable: */ @@ -247,6 +270,9 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, */ else if (*cond != NULL || (rval = pthread_cond_init(cond,NULL)) == 0) { + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + /* * If the condvar was statically allocated, properly * initialize the tail queue. @@ -256,10 +282,6 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, (*cond)->c_flags |= COND_FLAGS_INITED; } - - /* Lock the condition variable structure: */ - _SPINLOCK(&(*cond)->lock); - /* Process according to condition variable type: */ switch ((*cond)->c_type) { /* Fast condition variable: */ @@ -375,6 +397,12 @@ pthread_cond_signal(pthread_cond_t * cond) if (cond == NULL || *cond == NULL) rval = EINVAL; else { + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + /* Lock the condition variable structure: */ _SPINLOCK(&(*cond)->lock); @@ -409,6 +437,12 @@ pthread_cond_signal(pthread_cond_t * cond) /* Unlock the condition variable structure: */ _SPINUNLOCK(&(*cond)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); } /* Return the completion status: */ @@ -425,14 +459,10 @@ pthread_cond_broadcast(pthread_cond_t * cond) rval = EINVAL; else { /* - * Guard against preemption by a scheduling signal. - * A change of thread state modifies the waiting - * and priority queues. In addition, we must assure - * that all threads currently waiting on the condition - * variable are signaled and are not timedout by a - * scheduling signal that causes a preemption. + * Defer signals to protect the scheduling queues + * from access by the signal handler: */ - _thread_kern_sched_defer(); + _thread_kern_sig_defer(); /* Lock the condition variable structure: */ _SPINLOCK(&(*cond)->lock); @@ -468,9 +498,11 @@ pthread_cond_broadcast(pthread_cond_t * cond) /* Unlock the condition variable structure: */ _SPINUNLOCK(&(*cond)->lock); - /* Reenable preemption and yield if necessary. + /* + * Undefer and handle pending signals, yielding if + * necessary: */ - _thread_kern_sched_undefer(); + _thread_kern_sig_undefer(); } /* Return the completion status: */ @@ -488,7 +520,7 @@ cond_queue_deq(pthread_cond_t cond) if ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { TAILQ_REMOVE(&cond->c_queue, pthread, qe); - pthread->flags &= ~PTHREAD_FLAGS_QUEUED; + pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; } return(pthread); @@ -507,9 +539,9 @@ cond_queue_remove(pthread_cond_t cond, pthread_t pthread) * guard against removing the thread from the queue if * it isn't in the queue. */ - if (pthread->flags & PTHREAD_FLAGS_QUEUED) { + if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) { TAILQ_REMOVE(&cond->c_queue, pthread, qe); - pthread->flags &= ~PTHREAD_FLAGS_QUEUED; + pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; } } @@ -535,6 +567,6 @@ cond_queue_enq(pthread_cond_t cond, pthread_t pthread) tid = TAILQ_NEXT(tid, qe); TAILQ_INSERT_BEFORE(tid, pthread, qe); } - pthread->flags |= PTHREAD_FLAGS_QUEUED; + pthread->flags |= PTHREAD_FLAGS_IN_CONDQ; } #endif |