diff --git a/Makefile.dep b/Makefile.dep index 39bd45a516031f45a7045271b60e32e7041996bc..60614da7582ce1003c7bbe2bd09dd0dc1231ae0e 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -301,6 +301,11 @@ ifneq (,$(filter posix,$(USEMODULE))) USEMODULE += vtimer endif +ifneq (,$(filter posix_semaphore,$(USEMODULE))) + USEMODULE += sem + USEMODULE += vtimer +endif + ifneq (,$(filter sem,$(USEMODULE))) USEMODULE += vtimer endif diff --git a/sys/Makefile b/sys/Makefile index 78f375543289937500880f0dc7e2cb4d09747eae..8baba47737237ea1ede70f76fd767b467d10b92b 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -1,3 +1,6 @@ +ifneq (,$(filter posix_semaphore,$(USEMODULE))) + DIRS += posix/semaphore +endif ifneq (,$(filter posix_sockets,$(USEMODULE))) DIRS += posix/sockets endif diff --git a/sys/Makefile.include b/sys/Makefile.include index 1c4d405dee44b8b031c431af1b8dc73be549b5b7..eb3523ce0e3a36dea6d5032334467094749651c0 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -18,6 +18,9 @@ ifneq (,$(filter posix,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/sys/posix/include USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include endif +ifneq (,$(filter posix_semaphore,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/sys/posix/include +endif ifneq (,$(filter posix_sockets,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/sys/posix/include endif diff --git a/sys/posix/include/semaphore.h b/sys/posix/include/semaphore.h index 0c21e0fb42b20ee4d6b81150c4e3bfeb8b59850d..cbf3fd64f9e4979293a8ff44eec95104d9a6f6fb 100644 --- a/sys/posix/include/semaphore.h +++ b/sys/posix/include/semaphore.h @@ -6,117 +6,170 @@ * directory for more details. */ -#ifndef _SEMAPHORE_H -#define _SEMAPHORE_H 1 +/** + * @defgroup posix_semaphore POSIX semaphores + * @ingroup posix + * @{ + * @file + * @brief Semaphores + * @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/semaphore.h.html"> + * The Open Group Base Specifications Issue 7, <semaphore.h> + * </a> + * @author Christian Mehlis <mehlis@inf.fu-berlin.de> + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + * @author René Kijewski <kijewski@inf.fu-berlin.de> + */ +#ifndef POSIX_SEMAPHORE_H_ +#define POSIX_SEMAPHORE_H_ + +#include <errno.h> #include <time.h> -#include "priority_queue.h" +#include "sem.h" #ifdef __cplusplus extern "C" { #endif -/** Value returned if `sem_open' failed. */ -#define SEM_FAILED ((sem_t *) 0) - /** - * @brief Semaphore struct + * @brief Value returned if `sem_open' failed. */ -typedef struct sem { - /** the value of the semaphore */ - volatile unsigned int value; - /** list of threads waiting for the semaphore */ - priority_queue_t queue; -} sem_t; +#define SEM_FAILED ((sem_t *) 0) /** - * @brief Initialize semaphore object SEM to VALUE. + * @brief Initialize semaphore. * - * @param sem Semaphore to initialize - * @param pshared unused - * @param value Value to set - */ -int sem_init(sem_t *sem, int pshared, unsigned int value); - -/** - * @brief Free resources associated with semaphore object SEM. + * @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_init.html"> + * The Open Group Base Specifications Issue 7, sem_init() + * </a> * - * @param sem Semaphore to destroy - */ -int sem_destroy(sem_t *sem); - -/* - * @brief Open a named semaphore NAME with open flags OFLAG. + * The sem_init() function shall initialize the unnamed semaphore referred to by @p sem. The value + * of the initialized semaphore shall be @p value. Following a successful call to sem_init(), + * the semaphore may be used in subsequent calls to sem_wait(), sem_timedwait(), + * sem_trywait(), sem_post(), and sem_destroy(). This semaphore shall remain usable until the + * semaphore is destroyed. * - * @brief WARNING: named semaphore are currently not supported + * @param[out] sem Semaphore to initialize. + * @param[in] pshared **(unused, since RIOT only has threads)** + * Semaphore is shared between processes not threads. + * @param[in] value Value to set. * - * @param name Name to set - * @param oflag Flags to set + * @return 0 on success. + * @return -EINVAL, if semaphore is invalid. */ -sem_t *sem_open(const char *name, int oflag, ...); +#define sem_init(sem, pshared, value) sem_create(sem, value) /** - * @brief Close descriptor for named semaphore SEM. + * @brief Open a named semaphore @p name with open flags @p oflag. * - * @brief WARNING: named semaphore are currently not supported + * @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_open.html"> + * The Open Group Base Specifications Issue 7, sem_open() + * </a> * - * @param sem Semaphore to close - */ -int sem_close(sem_t *sem); - -/** - * @brief Remove named semaphore NAME. + * @todo named semaphore are currently not supported * - * @brief WARNING: named semaphore are currently not supported + * @param[in] name Name to set. + * @param[in] oflag Flags to set. * - * @param name Name to unlink + * @return Always @ref SEM_FAILED, since it is not implemented currently. */ -int sem_unlink(const char *name); +#define sem_open(name, oflag, ...) (SEM_FAILED) /** - * @brief Wait for SEM being posted. + * @brief Close descriptor for named semaphore @p sem. * - * @param sem Semaphore to wait + * @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_close.html"> + * The Open Group Base Specifications Issue 7, sem_close() + * </a> + * + * @todo named semaphore are currently not supported + * + * @param[in] sem Semaphore to close. + * + * @return Always -1, since it is not implemented currently. */ -int sem_wait(sem_t *sem); +#define sem_close(sem) (-1) /** - * @brief Similar to `sem_wait' but wait only until ABSTIME. + * @brief Remove named semaphore @p name. + * + * @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_unlink.html"> + * The Open Group Base Specifications Issue 7, sem_unlink() + * </a> * - * @brief WARNING: currently not supported + * @todo named semaphore are currently not supported * - * @param sem Semaphore to wait on - * @param abstime Max time to wait for a post + * @param[in] name Name to unlink. * + * @return Always -1, since it is not implemented currently. + */ +#define sem_unlink(name) (-1) + +/** + * @brief Similar to `sem_wait' but wait only until @p abstime. + * + * @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_timedwait.html"> + * The Open Group Base Specifications Issue 7, sem_timedwait() + * </a> + * + * The sem_timedwait() function shall lock the semaphore referenced by @p sem as in the sem_wait() + * function. However, if the semaphore cannot be locked without waiting for another process or + * thread to unlock the semaphore by performing a sem_post() function, this wait shall be + * terminated when the specified timeout expires. + * + * @param[in] sem Semaphore to wait on. + * @param[in] abstime Absolute time (that is when the clock on which temouts are based equals + * this value) the timeout for the wait shall expire. If the value specified + * has already passed the timeout expires immediately. + * + * @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 sem_timedwait(sem_t *sem, const struct timespec *abstime); /** * @brief Test whether SEM is posted. * - * @param sem Semaphore to trywait on + * @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_trywait.html"> + * The Open Group Base Specifications Issue 7, sem_trywait() + * </a> * - */ -int sem_trywait(sem_t *sem); - -/** - * @brief Post SEM. + * @param[in] sem Semaphore to try to wait on * - * @param sem Semaphore to post on + * @return 0 on success + * @return -EINVAL, if semaphore is invalid. + * @return -EAGAIN, if the semaphore was already locked. */ -int sem_post(sem_t *sem); +int sem_trywait(sem_t *sem); /** * @brief Get current value of SEM and store it in *SVAL. * - * @param sem Semaphore to get value from - * @param sval place whre value goes to + * @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_getvalue.html"> + * The Open Group Base Specifications Issue 7, sem_getvalue() + * </a> + * + * @param[in] sem Semaphore to get the value from. + * @param[out] sval Place where value goes to. + * + * @return 0 on success + * @return -EINVAL, if semaphore is invalid. */ -int sem_getvalue(sem_t *sem, int *sval); +static inline int sem_getvalue(sem_t *sem, int *sval) +{ + if (sem != NULL) { + *sval = (int)sem->value; + return 0; + } + return -EINVAL; +} #ifdef __cplusplus } #endif -#endif /* semaphore.h */ +#endif /* POSIX_SEMAPHORE_H_ */ +/** @} */ diff --git a/sys/posix/semaphore.c b/sys/posix/semaphore.c deleted file mode 100644 index 09a4c40c346586ea16a6218bed0b691d0d631e9c..0000000000000000000000000000000000000000 --- a/sys/posix/semaphore.c +++ /dev/null @@ -1,159 +0,0 @@ -/** - * Semaphore implemenation - * - * Copyright (C) 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 - * directory for more details. - * - * @ingroup posix - * - * @{ - * - * @file - * @brief Implementation of semaphores with priority queues - * - * @author Christian Mehlis <mehlis@inf.fu-berlin.de> - * @author René Kijewski <kijewski@inf.fu-berlin.de> - * - * @} - */ - -#include <inttypes.h> - -#include "irq.h" -#include "sched.h" -#include "tcb.h" -#include "thread.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -#include "semaphore.h" - -int sem_init(sem_t *sem, int pshared, unsigned int value) -{ - (void) pshared; /* nothing to do */ - - sem->value = value; - - /* waiters for the mutex */ - sem->queue.first = NULL; - - return 0; -} - -int sem_destroy(sem_t *sem) -{ - if (sem->queue.first) { - DEBUG("sem_destroy: %" PRIkernel_pid ": tried to destroy active semaphore.\n", - sched_active_thread->pid); - return -1; - } - return 0; -} - -sem_t *sem_open(const char *name, int oflag, ...) -{ - (void) name; /* named semaphore currently not supported */ - (void) oflag; - return SEM_FAILED; -} - -int sem_close(sem_t *sem) -{ - (void) sem; /* named semaphore currently not supported */ - return -1; -} - -int sem_unlink(const char *name) -{ - (void) name; /* named semaphore currently not supported */ - return -1; -} - -int sem_wait(sem_t *sem) -{ - while (1) { - unsigned old_state = disableIRQ(); - - unsigned value = sem->value; - if (value != 0) { - sem->value = value - 1; - restoreIRQ(old_state); - return 1; - } - - /* I'm going blocked */ - priority_queue_node_t n; - n.priority = (uint32_t) sched_active_thread->priority; - n.data = (uintptr_t) sched_active_thread; - n.next = NULL; - priority_queue_add(&sem->queue, &n); - - DEBUG("sem_wait: %" PRIkernel_pid ": Adding node to mutex queue: prio: %" PRIu32 "\n", - sched_active_thread->pid, sched_active_thread->priority); - - /* scheduler should schedule an other thread, that unlocks the - * mutex in the future, when this happens I get scheduled again - */ - sched_set_status((tcb_t*) sched_active_thread, STATUS_MUTEX_BLOCKED); - restoreIRQ(old_state); - thread_yield_higher(); - } -} - -int sem_timedwait(sem_t *sem, const struct timespec *abstime) -{ - (void) sem; /* timedwait currently not supported */ - (void) abstime; - return -1; /* signal problem */ -} - -int sem_trywait(sem_t *sem) -{ - unsigned old_state = disableIRQ(); - int result; - - unsigned value = sem->value; - if (value == 0) { - result = -1; - } - else { - result = 0; - sem->value = value - 1; - } - - restoreIRQ(old_state); - return result; -} - -int sem_post(sem_t *sem) -{ - unsigned old_state = disableIRQ(); - ++sem->value; - - priority_queue_node_t *next = priority_queue_remove_head(&sem->queue); - if (next) { - tcb_t *next_process = (tcb_t*) next->data; - DEBUG("sem_post: %" PRIkernel_pid ": waking up %" PRIkernel_pid "\n", - sched_active_thread->pid, next_process->pid); - sched_set_status(next_process, STATUS_PENDING); - - uint16_t prio = next_process->priority; - restoreIRQ(old_state); - sched_switch(prio); - } - else { - restoreIRQ(old_state); - } - - return 1; -} - -int sem_getvalue(sem_t *sem, int *sval) -{ - *sval = sem->value; - return 0; -} diff --git a/sys/posix/semaphore/Makefile b/sys/posix/semaphore/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..68d9a081b01f2d1923cfb9a18ebbfc41c8df6a28 --- /dev/null +++ b/sys/posix/semaphore/Makefile @@ -0,0 +1,3 @@ +MODULE = posix_semaphore + +include $(RIOTBASE)/Makefile.base diff --git a/sys/posix/semaphore/posix_semaphore.c b/sys/posix/semaphore/posix_semaphore.c new file mode 100644 index 0000000000000000000000000000000000000000..4f9756296fdc5494ceed9990937e42e9ee5e8726 --- /dev/null +++ b/sys/posix/semaphore/posix_semaphore.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 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 + * directory for more details. + */ + +/** + * @{ + * + * @file + * + * @author Christian Mehlis <mehlis@inf.fu-berlin.de> + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + * @author René Kijewski <kijewski@inf.fu-berlin.de> + */ + +#include <errno.h> +#include <inttypes.h> + +#include "irq.h" +#include "sched.h" +#include "sem.h" +#include "tcb.h" +#include "timex.h" +#include "thread.h" +#include "vtimer.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include "semaphore.h" + +#define USEC_IN_NS (1000) + +int sem_timedwait(sem_t *sem, const struct timespec *abstime) +{ + timex_t now, timeout = { abstime->tv_sec, abstime->tv_nsec / USEC_IN_NS }; + int res; + vtimer_now(&now); + if (timex_cmp(now, timeout) > 0) { + errno = ETIMEDOUT; + return -ETIMEDOUT; + } + timeout = timex_sub(timeout, now); + res = sem_wait_timed(sem, &timeout); + if (res < 0) { + errno = -res; + } + return res; +} + +int sem_trywait(sem_t *sem) +{ + unsigned int old_state, value; + int result; + if (sem == NULL) { + errno = EINVAL; + return -EINVAL; + } + old_state = disableIRQ(); + value = sem->value; + if (value == 0) { + errno = EAGAIN; + result = -EAGAIN; + } + else { + result = 0; + sem->value = value - 1; + } + + restoreIRQ(old_state); + return result; +} + +/** @} */ diff --git a/tests/posix_semaphore/Makefile b/tests/posix_semaphore/Makefile index edb55ba23da3947e13f8155b4f94ad3ea9afd86d..619d444f8ec78fc3f462a83401ee5c9eebfde232 100644 --- a/tests/posix_semaphore/Makefile +++ b/tests/posix_semaphore/Makefile @@ -4,7 +4,7 @@ include ../Makefile.tests_common BOARD_INSUFFICIENT_MEMORY := msb-430 msb-430h mbed_lpc1768 chronos stm32f0discovery \ pca10000 pca10005 weio yunjia-nrf51822 nrf6310 spark-core -USEMODULE += posix +USEMODULE += posix_semaphore DISABLE_MODULE += auto_init diff --git a/tests/posix_semaphore/main.c b/tests/posix_semaphore/main.c index c6258511a38585e987063515d8efa9bc93e6324f..55dc06f81b8b15465ba811964bbfde1d34d156e6 100644 --- a/tests/posix_semaphore/main.c +++ b/tests/posix_semaphore/main.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2013 Christian Mehlis <mehlis@inf.fu-berlin.de> * Copyright (C) 2013 René Kijewski <rene.kijewski@fu-berlin.de> + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> * * 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