diff --git a/sys/posix/pthread/pthread_cond.c b/sys/posix/pthread/pthread_cond.c index a51cc50c61aec7abe235668127a3193165447098..f03e4a9c0cc65230cc9164b7e239795f273de06f 100644 --- a/sys/posix/pthread/pthread_cond.c +++ b/sys/posix/pthread/pthread_cond.c @@ -18,6 +18,7 @@ * * @} */ +#include <errno.h> #include "pthread_cond.h" #include "thread.h" @@ -92,44 +93,69 @@ int pthread_cond_destroy(pthread_cond_t *cond) return 0; } -int pthread_cond_wait(pthread_cond_t *cond, mutex_t *mutex) +void _init_cond_wait(pthread_cond_t *cond, priority_queue_node_t *n) { - priority_queue_node_t n; - n.priority = sched_active_thread->priority; - n.data = sched_active_pid; - n.next = NULL; + n->priority = sched_active_thread->priority; + n->data = sched_active_pid; + n->next = NULL; /* the signaling thread may not hold the mutex, the queue is not thread safe */ unsigned old_state = irq_disable(); - priority_queue_add(&(cond->queue), &n); + priority_queue_add(&(cond->queue), n); irq_restore(old_state); +} - mutex_unlock_and_sleep(mutex); - - if (n.data != -1u) { - /* on signaling n.data is set to -1u */ - /* if it isn't set, then the wakeup is either spurious or a timer wakeup */ - old_state = irq_disable(); - priority_queue_remove(&(cond->queue), &n); - irq_restore(old_state); +int pthread_cond_wait(pthread_cond_t *cond, mutex_t *mutex) +{ + if (cond == NULL) { + return EINVAL; } + priority_queue_node_t n; + _init_cond_wait(cond, &n); + + mutex_unlock_and_sleep(mutex); mutex_lock(mutex); + return 0; } int pthread_cond_timedwait(pthread_cond_t *cond, mutex_t *mutex, const struct timespec *abstime) { + if ((cond == NULL) || (abstime->tv_sec < 0)) { + return EINVAL; + } + uint64_t now = xtimer_now_usec64(); uint64_t then = ((uint64_t)abstime->tv_sec * US_PER_SEC) + (abstime->tv_nsec / NS_PER_US); - xtimer_t timer; - xtimer_set_wakeup64(&timer, (then - now) , sched_active_pid); - int result = pthread_cond_wait(cond, mutex); - xtimer_remove(&timer); + int ret = 0; + if (then > now) { + xtimer_t timer; + priority_queue_node_t n; + + _init_cond_wait(cond, &n); + xtimer_set_wakeup64(&timer, (then - now), sched_active_pid); + + mutex_unlock_and_sleep(mutex); - return result; + if (n.data != -1u) { + /* on signaling n.data is set to -1u */ + /* if it isn't set, then the wakeup is either spurious or a timer wakeup */ + unsigned old_state = irq_disable(); + priority_queue_remove(&(cond->queue), &n); + irq_restore(old_state); + ret = ETIMEDOUT; + } + xtimer_remove(&timer); + } + else { + mutex_unlock(mutex); + ret = ETIMEDOUT; + } + mutex_lock(mutex); + return ret; } int pthread_cond_signal(pthread_cond_t *cond)