diff --git a/sys/posix/pthread/include/pthreadtypes.h b/sys/posix/pthread/include/pthreadtypes.h index 3fdf0c7ad8..e0b92dd9b3 100644 --- a/sys/posix/pthread/include/pthreadtypes.h +++ b/sys/posix/pthread/include/pthreadtypes.h @@ -19,8 +19,24 @@ typedef int pthread_once_t; /* Single execution handling. */ #define PTHREAD_ONCE_INIT 0 -typedef unsigned long int pthread_barrier_t; -typedef unsigned long int pthread_barrierattr_t; +typedef struct pthread_barrier_waiting_node +{ + struct pthread_barrier_waiting_node *next; + int pid; + volatile int cont; +} pthread_barrier_waiting_node_t; + +typedef struct pthread_barrier +{ + struct pthread_barrier_waiting_node *next; + mutex_t mutex; + volatile int count; +} pthread_barrier_t; + +typedef struct pthread_barrierattr +{ + int pshared; +} pthread_barrierattr_t; typedef unsigned long int pthread_cond_t; typedef unsigned long int pthread_condattr_t; diff --git a/sys/posix/pthread/pthread_barrier.c b/sys/posix/pthread/pthread_barrier.c new file mode 100644 index 0000000000..591a03ba1d --- /dev/null +++ b/sys/posix/pthread/pthread_barrier.c @@ -0,0 +1,98 @@ +/** +* POSIX compatible implementation of barriers. +* +* Copyright (C) 2014 Freie Universität Berlin +* +* This file subject to the terms and conditions of the GNU Lesser General +* Public License. See the file LICENSE in the top level directory for more +* details. +* +* @ingroup posix +* @{ +* @file +* @brief Implementation of the pthread barrier. +* @author René Kijewski +* @} +*/ + +#include "sched.h" +#include "pthread.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +int pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned int count) +{ + (void) attr; + barrier->next = NULL; + mutex_init(&barrier->mutex); + barrier->count = count; + return 0; +} + +int pthread_barrier_destroy(pthread_barrier_t *barrier) +{ + barrier->count = -1; + return 0; +} + +int pthread_barrier_wait(pthread_barrier_t *barrier) +{ + /* Idea: the count is decreased by every thread that waits on the barrier. + * If the value is bigger than zero afterwards, then the thread has to wait + * to be woken up. Once the value reaches zero, everyone gets woken up. */ + + mutex_lock(&barrier->mutex); + DEBUG("%s: hit a synchronization barrier. pid=%u\n", + active_thread->name, active_thread->pid); + + if (--barrier->count > 0) { + /* need to wait for further threads */ + + DEBUG("%s: waiting for %u threads. pid=%u\n", + active_thread->name, barrier->count, active_thread->pid); + + pthread_barrier_waiting_node_t node; + node.pid = thread_pid; + node.next = barrier->next; + node.cont = 0; + + barrier->next = &node; + mutex_unlock(&barrier->mutex); + + while (1) { + /* The mutex is reacquired before checking if we should continue, + * so that the waiting thread don't accidentially run before the + * wake up loop has ended. Otherwise the thread could run into the + * the barrier again before `barrier->count` was reset. */ + mutex_lock(&barrier->mutex); + if (node.cont) { + break; + } + mutex_unlock_and_sleep(&barrier->mutex); + } + } + else { + /* all threads have arrived, wake everybody up */ + + DEBUG("%s: waking every other thread up. pid=%u\n", + active_thread->name, active_thread->pid); + + int count = 1; /* Count number of woken up threads. + * The first thread is the current thread. */ + pthread_barrier_waiting_node_t *next; + for (next = barrier->next; next; next = next->next) { + ++count; + + next->cont = 1; + sched_set_status((tcb_t *) sched_threads[next->pid], STATUS_PENDING); + } + barrier->next = NULL; + barrier->count = count; + } + + mutex_unlock(&barrier->mutex); + return 0; +} diff --git a/sys/posix/pthread/pthread_barrierattr.c b/sys/posix/pthread/pthread_barrierattr.c new file mode 100644 index 0000000000..e6f4e09a56 --- /dev/null +++ b/sys/posix/pthread/pthread_barrierattr.c @@ -0,0 +1,44 @@ +/** +* POSIX compatible implementation of barriers. +* +* Copyright (C) 2014 Freie Universität Berlin +* +* This file subject to the terms and conditions of the GNU Lesser General +* Public License. See the file LICENSE in the top level directory for more +* details. +* +* @ingroup posix +* @{ +* @file +* @brief Implementation of the pthread barrier attributes. +* @author René Kijewski +* @} +*/ + +#include "pthread.h" + +#include + +int pthread_barrierattr_init(pthread_barrierattr_t *attr) +{ + attr->pshared = 0; + return 0; +} + +int pthread_barrierattr_destroy(pthread_barrierattr_t *attr) +{ + (void) attr; + return 0; +} + +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared) +{ + *pshared = attr->pshared; + return 0; +} + +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) +{ + attr->pshared = pshared; + return 0; +}