diff --git a/pkg/lwip/contrib/sock/lwip_sock.c b/pkg/lwip/contrib/sock/lwip_sock.c index 8ae799bced..20b5faa12b 100644 --- a/pkg/lwip/contrib/sock/lwip_sock.c +++ b/pkg/lwip/contrib/sock/lwip_sock.c @@ -19,6 +19,7 @@ #include "net/ipv4/addr.h" #include "net/ipv6/addr.h" #include "net/sock.h" +#include "timex.h" #include "lwip/err.h" #include "lwip/ip.h" diff --git a/pkg/lwip/contrib/sys_arch.c b/pkg/lwip/contrib/sys_arch.c index 228ac6aacd..7513879b41 100644 --- a/pkg/lwip/contrib/sys_arch.c +++ b/pkg/lwip/contrib/sys_arch.c @@ -59,9 +59,7 @@ void sys_mutex_free(sys_mutex_t *mutex) err_t sys_sem_new(sys_sem_t *sem, u8_t count) { - if (sema_create((sema_t *)sem, (unsigned int)count) < 0) { - return ERR_VAL; - } + sema_create((sema_t *)sem, (unsigned int)count); return ERR_OK; } diff --git a/sys/include/sema.h b/sys/include/sema.h index e6545ecf75..f8cec50b25 100644 --- a/sys/include/sema.h +++ b/sys/include/sema.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2015 Martine Lenders + * Copyright (C) 2016 TriaGnoSys GmbH + * 2015 Martine Lenders * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -18,13 +19,15 @@ * @author Martine Lenders * @author Christian Mehlis * @author René Kijewski + * @author Víctor Ariño */ -#ifndef SEM_H_ -#define SEM_H_ -#include "msg.h" -#include "priority_queue.h" -#include "timex.h" +#ifndef SEMA_H +#define SEMA_H + +#include + +#include "mutex.h" #ifdef __cplusplus extern "C" { @@ -33,103 +36,89 @@ extern "C" { /** * @brief Creates semaphore statically. * - * @param[in] value Initial value for the semaphore. + * @param[in] value Initial value for the semaphore (can't be 0). For a 0 + * initialized semaphore @see SEMA_CREATE_LOCKED * * @return Statically initialized semaphore. */ -#define SEMA_CREATE(value) { (value), PRIORITY_QUEUE_INIT } +#define SEMA_CREATE(value) { (value), SEMA_OK, MUTEX_INIT } + +/** + * @brief Creates semaphore statically initialized to 0 + * @return Statically initialized semaphore. + */ +#define SEMA_CREATE_LOCKED() { (0), SEMA_OK, MUTEX_INIT_LOCKED } + +/** + * @brief A Semaphore states. + */ +typedef enum { + SEMA_OK = 0, + SEMA_DESTROY, +} sema_state_t; /** * @brief A Semaphore. */ typedef struct { - volatile unsigned int value; /**< value of the semaphore */ - priority_queue_t queue; /**< list of threads waiting for the semaphore */ + unsigned int value; /**< value of the semaphore */ + sema_state_t state; /**< state of the semaphore */ + mutex_t mutex; /**< mutex of the semaphore */ } sema_t; /** * @brief Creates semaphore dynamically. * + * @pre `(sema != NULL)` + * * @see * The Open Group Base Specifications Issue 7, sem_init() * (without `pshared` parameter) * * @param[out] sema The created semaphore. * @param[in] value Initial value for the semaphore. - * - * @return 0 on success. - * @return -EINVAL, if semaphore is invalid. */ -int sema_create(sema_t *sema, unsigned int value); +void sema_create(sema_t *sema, unsigned int value); /** * @brief Destroys a semaphore. * + * @pre `(sema != NULL)` + * * @see * The Open Group Base Specifications Issue 7, sem_destroy() * * - * @param[in] sema The semaphore to destroy. + * Destroying a semaphore upon which other threads are currently blocked + * will wake the other threads causing the @ref sema_wait (or + * @ref sema_wait_timed) to return error (-ECANCELLED). * - * @return 0 on success. - * @return -EINVAL, if semaphore is invalid. + * @param[in] sema The semaphore to destroy. */ -int sema_destroy(sema_t *sema); +void sema_destroy(sema_t *sema); /** * @brief Wait for a semaphore being posted. * - * @pre Message queue of active thread is initialized (see @ref msg_init_queue()). - * - * @param[in] sema A semaphore. - * @param[in] timeout Time in microseconds until the semaphore times out. 0 for no timeout. - * @param[out] msg Container for a spurious message during the timed wait (result == -EAGAIN). - * - * @return 0 on success - * @return -EINVAL, if semaphore is invalid. - * @return -ETIMEDOUT, if the semaphore times out. - * @return -ECANCELED, if the semaphore was destroyed. - * @return -EAGAIN, if the thread received a message while waiting for the lock. - */ -int sema_wait_timed_msg(sema_t *sema, uint64_t timeout, msg_t *msg); - -/** - * @brief Wait for a semaphore being posted (without timeout). - * - * @param[in] sema A semaphore. - * @param[out] msg Container for a spurious message during the timed wait (result == -EAGAIN). - * - * @return 0 on success - * @return -EINVAL, if semaphore is invalid. - * @return -ECANCELED, if the semaphore was destroyed. - * @return -EAGAIN, if the thread received a message while waiting for the lock. - */ -static inline int sema_wait_msg(sema_t *sema, msg_t *msg) -{ - return sema_wait_timed_msg(sema, 0, msg); -} - -/** - * @brief Wait for a semaphore being posted (dropping spurious messages). - * @details Any spurious messages received while waiting for the semaphore are silently dropped. + * @pre `(sema != NULL)` * * @param[in] sema A semaphore. * @param[in] timeout Time in microseconds until the semaphore times out. 0 for no timeout. * * @return 0 on success - * @return -EINVAL, if semaphore is invalid. * @return -ETIMEDOUT, if the semaphore times out. * @return -ECANCELED, if the semaphore was destroyed. */ int sema_wait_timed(sema_t *sema, uint64_t timeout); /** - * @brief Wait for a semaphore being posted (without timeout, dropping spurious messages). + * @brief Wait for a semaphore being posted (without timeout). + * + * @pre `(sema != NULL)` * * @param[in] sema A semaphore. * * @return 0 on success - * @return -EINVAL, if semaphore is invalid. * @return -ECANCELED, if the semaphore was destroyed. */ static inline int sema_wait(sema_t *sema) @@ -137,13 +126,27 @@ static inline int sema_wait(sema_t *sema) return sema_wait_timed(sema, 0); } +/** + * @brief Test if the semaphore is posted + * + * @pre `(sema != NULL)` + * + * This is a non-blocking alternative to @ref sema_wait. + * + * @return 0 on success + * @return -EAGAIN, if the semaphore is not posted. + * @return -ECANCELED, if the semaphore was destroyed. + */ +int sema_try_wait(sema_t *sema); + /** * @brief Signal semaphore. * + * @pre `(sema != NULL)` + * * @param[in] sema A semaphore. * * @return 0, on success - * @return -EINVAL, if semaphore is invalid. * @return -EOVERFLOW, if the semaphore's value would overflow. */ int sema_post(sema_t *sema); @@ -152,5 +155,5 @@ int sema_post(sema_t *sema); } #endif -#endif /* SEM_H_ */ +#endif /* SEMA_H */ /** @} */ diff --git a/sys/posix/include/semaphore.h b/sys/posix/include/semaphore.h index 8ccb3de251..176d2b439b 100644 --- a/sys/posix/include/semaphore.h +++ b/sys/posix/include/semaphore.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 Freie Universität Berlin + * Copyright (C) 2017 TriaGnoSys GmbH + * 2013 Freie Universität Berlin * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -18,6 +19,7 @@ * @author Christian Mehlis * @author Martine Lenders * @author René Kijewski + * @author Víctor Ariño */ #ifndef POSIX_SEMAPHORE_H_ @@ -62,12 +64,8 @@ typedef sema_t sem_t; */ static inline int sem_init(sem_t *sem, int pshared, unsigned value) { - int res = sema_create((sema_t *)sem, value); + sema_create((sema_t *)sem, value); (void)pshared; - if (res < 0) { - errno = -res; - return -1; - } return 0; } @@ -94,11 +92,7 @@ static inline int sem_init(sem_t *sem, int pshared, unsigned value) */ static inline int sem_destroy(sem_t *sem) { - int res = sema_destroy((sema_t *)sem); - if (res < 0) { - errno = -res; - return -1; - } + sema_destroy((sema_t *)sem); return 0; } @@ -127,6 +121,7 @@ static inline int sem_destroy(sem_t *sem) static inline int sem_post(sem_t *sem) { int res = sema_post((sema_t *)sem); + if (res < 0) { errno = -res; return -1; @@ -154,6 +149,7 @@ static inline int sem_post(sem_t *sem) static inline int sem_wait(sem_t *sem) { int res = sema_wait((sema_t *)sem); + if (res < 0) { errno = -res; return -1; @@ -257,7 +253,16 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime); * @return 0 on success. * @return -1, on error and errno set to indicate the error. */ -int sem_trywait(sem_t *sem); +static inline int sem_trywait(sem_t *sem) +{ + int res = sema_try_wait((sema_t *)sem); + + if (res < 0) { + errno = -res; + return -1; + } + return 0; +} /** * @brief Get current value of @p sem and store it in @p sval. diff --git a/sys/posix/semaphore/posix_semaphore.c b/sys/posix/semaphore/posix_semaphore.c index 1286afe471..fd5a095637 100644 --- a/sys/posix/semaphore/posix_semaphore.c +++ b/sys/posix/semaphore/posix_semaphore.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 Freie Universität Berlin + * Copyright (C) 2017 TriaGnoSys GmbH + * 2013 Freie Universität Berlin * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -14,6 +15,7 @@ * @author Christian Mehlis * @author Martine Lenders * @author René Kijewski + * @author Víctor Ariño */ #include @@ -34,8 +36,9 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime) { uint64_t timeout = (((uint64_t)abstime->tv_sec) * SEC_IN_USEC) + - (abstime->tv_nsec / USEC_IN_NS); + (abstime->tv_nsec / USEC_IN_NS); uint64_t now = xtimer_now_usec64(); + if (now > timeout) { errno = ETIMEDOUT; return -1; @@ -49,27 +52,4 @@ int sem_timedwait(sem_t *sem, const struct timespec *abstime) return 0; } -int sem_trywait(sem_t *sem) -{ - unsigned int old_state, value; - int result; - if (sem == NULL) { - errno = EINVAL; - return -1; - } - old_state = irq_disable(); - value = sem->value; - if (value == 0) { - errno = EAGAIN; - result = -1; - } - else { - result = 0; - sem->value = value - 1; - } - - irq_restore(old_state); - return result; -} - /** @} */ diff --git a/sys/sema/sema.c b/sys/sema/sema.c index 1025a7f103..950b374ab3 100644 --- a/sys/sema/sema.c +++ b/sys/sema/sema.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013-15 Freie Universität Berlin + * Copyright (C) 2016 TriaGnoSys GmbH + * 2013-15 Freie Universität Berlin * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -11,169 +12,108 @@ * * @file * - * @author Christian Mehlis - * @author Martine Lenders - * @author René Kijewski + * @author Víctor Ariño */ -#include #include -#include - #include "irq.h" -#include "msg.h" -#include "xtimer.h" - +#include "assert.h" #include "sema.h" +#include "xtimer.h" #define ENABLE_DEBUG (0) #include "debug.h" -#define MSG_SIGNAL (0x0501) -#define MSG_TIMEOUT (0x0502) -#define MSG_DESTROYED (0x0503) - -int sema_create(sema_t *sema, unsigned int value) +void sema_create(sema_t *sema, unsigned int value) { - if (sema == NULL) { - return -EINVAL; - } + assert(sema != NULL); + sema->value = value; - /* waiters for the mutex */ - sema->queue.first = NULL; + sema->state = SEMA_OK; + mutex_init(&sema->mutex); + if (value == 0) { + mutex_lock(&sema->mutex); + } +} + +void sema_destroy(sema_t *sema) +{ + assert(sema != NULL); + + sema->state = SEMA_DESTROY; + mutex_unlock(&sema->mutex); +} + +int sema_try_wait(sema_t *sema) +{ + assert(sema != NULL); + + int ret = -ECANCELED; + if (sema->state == SEMA_OK) { + ret = -EAGAIN; + unsigned old = irq_disable(); + if (sema->value > 0) { + --sema->value; + ret = 0; + } + irq_restore(old); + } + + return ret; +} + +int sema_wait_timed(sema_t *sema, uint64_t us) +{ + assert(sema != NULL); + + if (sema->state != SEMA_OK) { + return -ECANCELED; + } + + unsigned old = irq_disable(); + if (sema->value == 0) { + irq_restore(old); + int timeout = xtimer_mutex_lock_timeout(&sema->mutex, us); + + if (sema->state != SEMA_OK) { + mutex_unlock(&sema->mutex); + return -ECANCELED; + } + + if (timeout) { + return -ETIMEDOUT; + } + + old = irq_disable(); + } + + unsigned int value = --sema->value; + irq_restore(old); + + if (value > 0) { + mutex_unlock(&sema->mutex); + } + return 0; } -int sema_destroy(sema_t *sema) -{ - unsigned int old_state; - priority_queue_node_t *next; - - if (sema == NULL) { - return -EINVAL; - } - old_state = irq_disable(); - while ((next = priority_queue_remove_head(&sema->queue)) != NULL) { - msg_t msg; - kernel_pid_t pid = (kernel_pid_t)next->data; - msg.type = MSG_DESTROYED; - msg.content.ptr = sema; - msg_send_int(&msg, pid); - } - irq_restore(old_state); - return 0; -} - -int sema_wait_timed_msg(sema_t *sema, uint64_t timeout, msg_t *msg) -{ - unsigned old_state; - msg_t timeout_msg; - xtimer_t timeout_timer; - - if (sema == NULL) { - return -EINVAL; - } - if (timeout != 0) { - old_state = irq_disable(); - timeout_timer.target = 0, timeout_timer.long_target = 0; - timeout_msg.type = MSG_TIMEOUT; - timeout_msg.content.ptr = sema; - /* we will stay in the same stack context so we can use timeout_msg */ - xtimer_set_msg64(&timeout_timer, timeout, &timeout_msg, sched_active_pid); - irq_restore(old_state); - } - while (1) { - priority_queue_node_t n; - unsigned value; - - old_state = irq_disable(); - value = sema->value; - if (value != 0) { - sema->value = value - 1; - irq_restore(old_state); - return 0; - } - - /* I'm going blocked */ - n.priority = (uint32_t)sched_active_thread->priority; - n.data = (unsigned int)sched_active_pid; - n.next = NULL; - priority_queue_add(&sema->queue, &n); - - DEBUG("sema_wait: %" PRIkernel_pid ": Adding node to semaphore queue: prio: %" PRIu32 "\n", - sched_active_thread->pid, sched_active_thread->priority); - - irq_restore(old_state); - msg_receive(msg); - old_state = irq_disable(); - if (timeout != 0) { - xtimer_remove(&timeout_timer); - } - priority_queue_remove(&sema->queue, &n); - irq_restore(old_state); - if (msg->content.ptr != sema) { - return -EAGAIN; - } - - switch (msg->type) { - case MSG_SIGNAL: - continue; - case MSG_TIMEOUT: - return -ETIMEDOUT; - case MSG_DESTROYED: - return -ECANCELED; - default: - return -EAGAIN; - } - } -} - -int sema_wait_timed(sema_t *sema, uint64_t timeout) -{ - int result; - - do { - msg_t msg; - result = sema_wait_timed_msg(sema, timeout, &msg); - DEBUG("sema_wait: %" PRIkernel_pid ": Discarding message from %" PRIkernel_pid "\n", - sched_active_thread->pid, msg->sender_pid); - } while (result == -EAGAIN); - return result; -} - int sema_post(sema_t *sema) { - unsigned int old_state, value; - priority_queue_node_t *next; + assert(sema != NULL); - if (sema == NULL) { - return -EINVAL; - } - old_state = irq_disable(); - value = sema->value; - if (value == UINT_MAX) { - irq_restore(old_state); + unsigned old = irq_disable(); + if (sema->value == UINT_MAX) { + irq_restore(old); return -EOVERFLOW; } - ++sema->value; - next = priority_queue_remove_head(&sema->queue); - if (next) { - uint16_t prio = (uint16_t)next->priority; - kernel_pid_t pid = (kernel_pid_t) next->data; - msg_t msg; - DEBUG("sema_post: %" PRIkernel_pid ": waking up %" PRIkernel_pid "\n", - sched_active_thread->pid, next_process->pid); - msg.type = MSG_SIGNAL; - msg.content.ptr = sema; - msg_send_int(&msg, pid); - irq_restore(old_state); - sched_switch(prio); - } - else { - irq_restore(old_state); + + unsigned value = sema->value++; + irq_restore(old); + + if (value == 0) { + mutex_unlock(&sema->mutex); } return 0; } - /** @} */