1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #3549 from authmillenon/sem/feat/initial

sem: initial import of a lightweight semaphore layer
This commit is contained in:
Martine Lenders 2015-10-19 14:45:34 +02:00
commit 3d4f373ba5
13 changed files with 754 additions and 239 deletions

View File

@ -301,6 +301,15 @@ ifneq (,$(filter posix,$(USEMODULE)))
USEMODULE += vtimer
endif
ifneq (,$(filter posix_semaphore,$(USEMODULE)))
USEMODULE += sem
USEMODULE += vtimer
endif
ifneq (,$(filter sem,$(USEMODULE)))
USEMODULE += vtimer
endif
ifneq (,$(filter vtimer,$(USEMODULE)))
USEMODULE += xtimer
USEMODULE += timex

View File

@ -1,3 +1,6 @@
ifneq (,$(filter posix_semaphore,$(USEMODULE)))
DIRS += posix/semaphore
endif
ifneq (,$(filter posix_sockets,$(USEMODULE)))
DIRS += posix/sockets
endif
@ -68,6 +71,9 @@ endif
ifneq (,$(filter netopt,$(USEMODULE)))
DIRS += net/crosslayer/netopt
endif
ifneq (,$(filter sem,$(USEMODULE)))
DIRS += sem
endif
DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))

View File

@ -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

145
sys/include/sem.h Normal file
View File

@ -0,0 +1,145 @@
/*
* 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
* directory for more details.
*/
/**
* @defgroup sys_sem Semaphores
* @ingroup sys
* @brief Lightweight semaphore implementation
* @{
*
* @file
* @brief Semaphore definitions
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Christian Mehlis <mehlis@inf.fu-berlin.de>
* @author René Kijewski <kijewski@inf.fu-berlin.de>
*/
#ifndef SEM_H_
#define SEM_H_
#include "priority_queue.h"
#include "timex.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief A Semaphore.
*/
typedef struct {
volatile unsigned int value; /**< value of the semaphore */
priority_queue_t queue; /**< list of threads waiting for the semaphore */
} sem_t;
/**
* @brief Creates semaphore.
*
* @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_init.html">
* The Open Group Base Specifications Issue 7, sem_init()
* </a> (without `pshared` parameter)
*
* @param[out] sem The created semaphore.
* @param[in] value Initial value for the semaphore.
*
* @return 0 on success.
* @return -EINVAL, if semaphore is invalid.
*/
int sem_create(sem_t *sem, unsigned int value);
/**
* @brief Destroys a semaphore.
*
* @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_destroy.html">
* The Open Group Base Specifications Issue 7, sem_destroy()
* </a>
*
* @param[in] sem The semaphore to destroy.
*
* @return 0 on success.
* @return -EINVAL, if semaphore is invalid.
*/
int sem_destroy(sem_t *sem);
/**
* @brief Wait for a semaphore being posted.
*
* @pre Message queue of active thread is initialized (see @ref msg_init_queue()).
*
* @param[in] sem A semaphore.
* @param[in] timeout Time until the semaphore times out. NULL 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 sem_wait_timed_msg(sem_t *sem, timex_t *timeout, msg_t *msg);
/**
* @brief Wait for a semaphore being posted (without timeout).
*
* @param[in] sem 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 sem_wait_msg(sem_t *sem, msg_t *msg)
{
return sem_wait_timed_msg(sem, NULL, msg);
}
/**
* @brief Wait for a semaphore being posted (dropping spurious messages).
* @details Any spurious messages received while waiting for the semaphore are silently dropped.
*
* @param[in] sem A semaphore.
* @param[in] timeout Time until the semaphore times out. NULL 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 sem_wait_timed(sem_t *sem, timex_t *timeout);
/**
* @brief Wait for a semaphore being posted (without timeout, dropping spurious messages).
*
* @param[in] sem A semaphore.
*
* @return 0 on success
* @return -EINVAL, if semaphore is invalid.
* @return -ECANCELED, if the semaphore was destroyed.
*/
static inline int sem_wait(sem_t *sem)
{
return sem_wait_timed(sem, NULL);
}
/**
* @brief Signal semaphore.
*
* @param[in] sem A semaphore.
*
* @return -EINVAL, if semaphore is invalid.
* @return -EOVERFLOW, if the semaphore's value would overflow.
*/
int sem_post(sem_t *sem);
#ifdef __cplusplus
}
#endif
#endif /* SEM_H_ */
/** @} */

View File

@ -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. */
/**
* @brief Value returned if `sem_open' failed.
*/
#define SEM_FAILED ((sem_t *) 0)
/**
* @brief Semaphore struct
* @brief Initialize semaphore.
*
* @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_init.html">
* The Open Group Base Specifications Issue 7, sem_init()
* </a>
*
* 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.
*
* @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.
*
* @return 0 on success.
* @return -EINVAL, if semaphore is invalid.
*/
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_init(sem, pshared, value) sem_create(sem, value)
/**
* @brief Initialize semaphore object SEM to VALUE.
* @brief Open a named semaphore @p name with open flags @p oflag.
*
* @param sem Semaphore to initialize
* @param pshared unused
* @param value Value to set
* @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_open.html">
* The Open Group Base Specifications Issue 7, sem_open()
* </a>
*
* @todo named semaphore are currently not supported
*
* @param[in] name Name to set.
* @param[in] oflag Flags to set.
*
* @return Always @ref SEM_FAILED, since it is not implemented currently.
*/
int sem_init(sem_t *sem, int pshared, unsigned int value);
#define sem_open(name, oflag, ...) (SEM_FAILED)
/**
* @brief Free resources associated with semaphore object SEM.
* @brief Close descriptor for named semaphore @p sem.
*
* @param sem Semaphore to destroy
* @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_destroy(sem_t *sem);
/*
* @brief Open a named semaphore NAME with open flags OFLAG.
*
* @brief WARNING: named semaphore are currently not supported
*
* @param name Name to set
* @param oflag Flags to set
*/
sem_t *sem_open(const char *name, int oflag, ...);
#define sem_close(sem) (-1)
/**
* @brief Close descriptor for named semaphore SEM.
* @brief Remove named semaphore @p name.
*
* @brief WARNING: named semaphore are currently not supported
* @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_unlink.html">
* The Open Group Base Specifications Issue 7, sem_unlink()
* </a>
*
* @param sem Semaphore to close
* @todo named semaphore are currently not supported
*
* @param[in] name Name to unlink.
*
* @return Always -1, since it is not implemented currently.
*/
int sem_close(sem_t *sem);
#define sem_unlink(name) (-1)
/**
* @brief Remove named semaphore NAME.
* @brief Similar to `sem_wait' but wait only until @p abstime.
*
* @brief WARNING: named semaphore are currently not supported
* @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_timedwait.html">
* The Open Group Base Specifications Issue 7, sem_timedwait()
* </a>
*
* @param name Name to unlink
*/
int sem_unlink(const char *name);
/**
* @brief Wait for SEM being posted.
* 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 sem Semaphore to wait
*/
int sem_wait(sem_t *sem);
/**
* @brief Similar to `sem_wait' but wait only until ABSTIME.
*
* @brief WARNING: currently not supported
*
* @param sem Semaphore to wait on
* @param abstime Max time to wait for a post
* @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>
*
* @param[in] sem Semaphore to try to wait on
*
* @return 0 on success
* @return -EINVAL, if semaphore is invalid.
* @return -EAGAIN, if the semaphore was already locked.
*/
int sem_trywait(sem_t *sem);
/**
* @brief Post SEM.
*
* @param sem Semaphore to post on
*/
int sem_post(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_ */
/** @} */

View File

@ -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;
}

View File

@ -0,0 +1,3 @@
MODULE = posix_semaphore
include $(RIOTBASE)/Makefile.base

View File

@ -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;
}
/** @} */

1
sys/sem/Makefile Normal file
View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

173
sys/sem/sem.c Normal file
View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 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
* 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 <assert.h>
#include <errno.h>
#include <limits.h>
#include "irq.h"
#include "msg.h"
#include "vtimer.h"
#include "sem.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define MSG_SIGNAL (0x0501)
#define MSG_TIMEOUT (0x0502)
#define MSG_DESTROYED (0x0503)
int sem_create(sem_t *sem, unsigned int value)
{
if (sem == NULL) {
#ifdef MODULE_POSIX_SEMAPHORE
errno = EINVAL;
#endif
return -EINVAL;
}
sem->value = value;
/* waiters for the mutex */
sem->queue.first = NULL;
return 0;
}
int sem_destroy(sem_t *sem)
{
unsigned int old_state;
priority_queue_node_t *next;
if (sem == NULL) {
#ifdef MODULE_POSIX_SEMAPHORE
errno = EINVAL;
#endif
return -EINVAL;
}
old_state = disableIRQ();
while ((next = priority_queue_remove_head(&sem->queue)) != NULL) {
msg_t msg;
kernel_pid_t pid = (kernel_pid_t)next->data;
msg.type = MSG_DESTROYED;
msg.content.ptr = (void *) sem;
msg_send_int(&msg, pid);
}
restoreIRQ(old_state);
return 0;
}
int sem_wait_timed_msg(sem_t *sem, timex_t *timeout, msg_t *msg)
{
if (sem == NULL) {
return -EINVAL;
}
while (1) {
unsigned old_state = disableIRQ();
priority_queue_node_t n;
vtimer_t timeout_timer;
unsigned value = sem->value;
if (value != 0) {
sem->value = value - 1;
restoreIRQ(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(&sem->queue, &n);
DEBUG("sem_wait: %" PRIkernel_pid ": Adding node to semaphore queue: prio: %" PRIu32 "\n",
sched_active_thread->pid, sched_active_thread->priority);
if (timeout != NULL) {
vtimer_set_msg(&timeout_timer, *timeout, sched_active_pid,
MSG_TIMEOUT, sem);
}
restoreIRQ(old_state);
msg_receive(msg);
if (timeout != NULL) {
vtimer_remove(&timeout_timer); /* remove timer just to be sure */
}
if (msg->content.ptr != (void *) sem) {
return -EAGAIN;
}
switch (msg->type) {
case MSG_SIGNAL:
continue;
case MSG_TIMEOUT:
return -ETIMEDOUT;
case MSG_DESTROYED:
return -ECANCELED;
default:
return -EAGAIN;
}
}
}
int sem_wait_timed(sem_t *sem, timex_t *timeout)
{
int result;
do {
msg_t msg;
result = sem_wait_timed_msg(sem, timeout, &msg);
DEBUG("sem_wait: %" PRIkernel_pid ": Discarding message from %" PRIkernel_pid "\n",
sched_active_thread->pid, msg->sender_pid);
} while (result == -EAGAIN);
return result;
}
int sem_post(sem_t *sem)
{
unsigned int old_state, value;
priority_queue_node_t *next;
if (sem == NULL) {
return -EINVAL;
}
old_state = disableIRQ();
value = sem->value;
if (value == UINT_MAX) {
restoreIRQ(old_state);
return -EOVERFLOW;
}
++sem->value;
next = priority_queue_remove_head(&sem->queue);
if (next) {
uint16_t prio = (uint16_t)next->priority;
kernel_pid_t pid = (kernel_pid_t) next->data;
msg_t msg;
DEBUG("sem_post: %" PRIkernel_pid ": waking up %" PRIkernel_pid "\n",
sched_active_thread->pid, next_process->pid);
msg.type = MSG_SIGNAL;
msg.content.ptr = (void *) sem;
msg_send_int(&msg, pid);
restoreIRQ(old_state);
sched_switch(prio);
}
else {
restoreIRQ(old_state);
}
return 1;
}
/** @} */

View File

@ -2,10 +2,14 @@ APPLICATION = posix_semaphore
include ../Makefile.tests_common
BOARD_INSUFFICIENT_MEMORY := msb-430 msb-430h mbed_lpc1768 chronos stm32f0discovery \
pca10000 pca10005 weio yunjia-nrf51822 nrf6310 spark-core
pca10000 pca10005 weio yunjia-nrf51822 nrf6310 spark-core \
nucleo-f334
USEMODULE += posix
USEMODULE += posix_semaphore
DISABLE_MODULE += auto_init
include $(RIOTBASE)/Makefile.include
test:
python tests/01-run.py

View File

@ -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
@ -16,27 +17,36 @@
*
* @author Christian Mehlis <mehlis@inf.fu-berlin.de>
* @author René Kijewski <rene.kijewski@fu-berlin.de>
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*
* @}
*/
#include <stdio.h>
#include "msg.h"
#include "timex.h"
#include "thread.h"
#include "semaphore.h"
#include "vtimer.h"
#define SEMAPHORE_TEST_THREADS 5
char test1_thread_stack[THREAD_STACKSIZE_MAIN];
char test2_thread_stack[SEMAPHORE_TEST_THREADS][THREAD_STACKSIZE_MAIN];
#define SEMAPHORE_MSG_QUEUE_SIZE (8)
#define SEMAPHORE_TEST_THREADS (5)
static char test1_thread_stack[THREAD_STACKSIZE_MAIN];
static char test2_thread_stack[SEMAPHORE_TEST_THREADS][THREAD_STACKSIZE_MAIN];
static msg_t main_msg_queue[SEMAPHORE_MSG_QUEUE_SIZE];
static msg_t test1_msg_queue[SEMAPHORE_MSG_QUEUE_SIZE];
sem_t s;
static sem_t s1;
static sem_t s2;
static void *test1_second_thread(void *arg)
{
(void) arg;
msg_init_queue(test1_msg_queue, SEMAPHORE_MSG_QUEUE_SIZE);
puts("second: sem_trywait");
if (sem_trywait(&s) == 0) {
if (sem_trywait(&s1) == 0) {
puts("second: sem_trywait failed");
}
@ -44,7 +54,7 @@ static void *test1_second_thread(void *arg)
puts("second: wait for post");
if (sem_wait(&s) != 1) {
if (sem_wait(&s1) != 1) {
puts("second: sem_wait failed");
}
@ -58,7 +68,7 @@ static void test1(void)
{
puts("first: sem_init");
if (sem_init(&s, 0, 0) != 0) {
if (sem_init(&s1, 0, 0) != 0) {
puts("first: sem_init failed");
}
@ -78,7 +88,7 @@ static void test1(void)
puts("first: sem_getvalue");
int val;
if (sem_getvalue(&s, &val) != 0 || val != 0) {
if (sem_getvalue(&s1, &val) != 0 || val != 0) {
puts("first: sem_getvalue FAILED");
}
@ -92,7 +102,7 @@ static void test1(void)
puts("first: sem_trywait");
if (sem_trywait(&s) != -1) {
if (sem_trywait(&s1) != -1) {
puts("first: sem_trywait FAILED");
}
@ -100,7 +110,7 @@ static void test1(void)
puts("first: sem_post");
if (sem_post(&s) != 1) {
if (sem_post(&s1) != 1) {
puts("first: sem_post FAILED");
}
@ -110,7 +120,7 @@ static void test1(void)
puts("first: sem_destroy");
if (sem_destroy(&s) != 0) {
if (sem_destroy(&s1) != 0) {
puts("first: sem_destroy FAILED");
}
@ -119,7 +129,9 @@ static void test1(void)
static void *priority_sema_thread(void *name)
{
sem_wait(&s);
msg_t msg_queue[SEMAPHORE_MSG_QUEUE_SIZE];
msg_init_queue(msg_queue, SEMAPHORE_MSG_QUEUE_SIZE);
sem_wait(&s1);
printf("Thread '%s' woke up.\n", (const char *) name);
return NULL;
}
@ -129,7 +141,7 @@ void test2(void)
{
puts("first: sem_init");
if (sem_init(&s, 0, 0) != 0) {
if (sem_init(&s1, 0, 0) != 0) {
puts("first: sem_init FAILED");
}
@ -157,17 +169,105 @@ void test2(void)
for (int i = 0; i < SEMAPHORE_TEST_THREADS; i++) {
printf("post no. %d\n", i);
sem_post(&s);
sem_post(&s1);
puts("Back in main thread.");
}
}
static void *test3_one_two_thread(void *arg)
{
msg_t msg_queue[SEMAPHORE_MSG_QUEUE_SIZE];
(void)arg;
msg_init_queue(msg_queue, SEMAPHORE_MSG_QUEUE_SIZE);
sem_wait(&s1);
puts("Thread 1 woke up after waiting for s1.");
sem_wait(&s2);
puts("Thread 1 woke up after waiting for s2.");
return NULL;
}
static void *test3_two_one_thread(void *arg)
{
msg_t msg_queue[SEMAPHORE_MSG_QUEUE_SIZE];
(void)arg;
msg_init_queue(msg_queue, SEMAPHORE_MSG_QUEUE_SIZE);
sem_wait(&s2);
puts("Thread 2 woke up after waiting for s2.");
sem_wait(&s1);
puts("Thread 2 woke up after waiting for s1.");
return NULL;
}
void test3(void)
{
puts("first: sem_init s1");
if (sem_init(&s1, 0, 0) != 0) {
puts("first: sem_init FAILED");
}
puts("first: sem_init s2");
if (sem_init(&s2, 0, 0) != 0) {
puts("first: sem_init FAILED");
}
puts("first: create thread 1");
if (thread_create(test2_thread_stack[0], sizeof(test2_thread_stack[0]),
THREAD_PRIORITY_MAIN - 1, CREATE_STACKTEST,
test3_one_two_thread, NULL, "thread 1") < 0) {
puts("first: thread create FAILED");
return;
}
puts("first: create thread 2");
if (thread_create(test2_thread_stack[1], sizeof(test2_thread_stack[1]),
THREAD_PRIORITY_MAIN - 1, CREATE_STACKTEST,
test3_two_one_thread, NULL, "thread 2") < 0) {
puts("first: thread create FAILED");
return;
}
puts("------------------------------------------");
puts("post s1");
sem_post(&s1);
puts("post s2");
sem_post(&s2);
puts("post s2");
sem_post(&s2);
puts("post s1");
sem_post(&s1);
}
void test4(void)
{
struct timespec abs;
char timestamp[TIMEX_MAX_STR_LEN];
timex_t now, start, stop, exp = { 1, 0 };
vtimer_now(&now);
abs.tv_sec = now.seconds + 1;
abs.tv_nsec = now.microseconds * 1000;
puts("first: sem_init s1");
if (sem_init(&s1, 0, 0) != 0) {
puts("first: sem_init FAILED");
}
vtimer_now(&start);
puts("first: wait 1 sec for s1");
sem_timedwait(&s1, &abs);
vtimer_now(&stop);
stop = timex_sub(stop, start);
if (timex_cmp(stop, exp) < 0) {
printf("first: waited only %s => FAILED\n",
timex_to_str(stop, timestamp));
}
printf("first: waited %s\n", timex_to_str(stop, timestamp));
}
int main(void)
{
msg_init_queue(main_msg_queue, SEMAPHORE_MSG_QUEUE_SIZE);
puts("######################### TEST1:");
test1();
puts("######################### TEST2:");
test2();
puts("######################### TEST3:");
test3();
puts("######################### TEST4:");
test4();
puts("######################### DONE");
return 0;
}

View File

@ -0,0 +1,100 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# 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
# directory for more details.
import sys
import pexpect
def init():
term = pexpect.spawn("make term", timeout=1.1)
term.logfile = sys.stdout
return term
def test1(term):
term.expect_exact("######################### TEST1:")
term.expect_exact("first: sem_init")
term.expect_exact("first: thread create")
term.expect_exact("first: thread created")
term.expect_exact("first: sem_getvalue")
term.expect_exact("first: sem_getvalue != 0")
term.expect_exact("first: do yield")
term.expect_exact("second: sem_trywait")
term.expect_exact("second: sem_trywait done with == 0")
term.expect_exact("second: wait for post")
term.expect_exact("first: done yield")
term.expect_exact("first: sem_trywait")
term.expect_exact("first: sem_trywait FAILED")
term.expect_exact("first: sem_trywait done")
term.expect_exact("first: sem_post")
term.expect_exact("second: sem_wait failed")
term.expect_exact("second: sem was posted")
term.expect_exact("second: end")
term.expect_exact("first: sem_post done")
term.expect_exact("first: sem_destroy")
term.expect_exact("first: end")
def test2(term):
term.expect_exact("######################### TEST2:")
term.expect_exact("first: sem_init")
term.expect_exact("first: thread create: 5")
term.expect_exact("first: thread created: priority 5 (1/5)")
term.expect_exact("first: thread create: 4")
term.expect_exact("first: thread created: priority 4 (2/5)")
term.expect_exact("first: thread create: 3")
term.expect_exact("first: thread created: priority 3 (3/5)")
term.expect_exact("first: thread create: 2")
term.expect_exact("first: thread created: priority 2 (4/5)")
term.expect_exact("first: thread create: 1")
term.expect_exact("first: thread created: priority 1 (5/5)")
term.expect_exact("------------------------------------------")
term.expect_exact("post no. 0")
term.expect_exact("Thread 'priority 1' woke up.")
term.expect_exact("Back in main thread.")
term.expect_exact("post no. 1")
term.expect_exact("Thread 'priority 2' woke up.")
term.expect_exact("Back in main thread.")
term.expect_exact("post no. 2")
term.expect_exact("Thread 'priority 3' woke up.")
term.expect_exact("Back in main thread.")
term.expect_exact("post no. 3")
term.expect_exact("Thread 'priority 4' woke up.")
term.expect_exact("Back in main thread.")
term.expect_exact("post no. 4")
term.expect_exact("Thread 'priority 5' woke up.")
term.expect_exact("Back in main thread.")
def test3(term):
term.expect_exact("######################### TEST3:")
term.expect_exact("first: sem_init s1")
term.expect_exact("first: sem_init s2")
term.expect_exact("first: create thread 1")
term.expect_exact("first: create thread 2")
term.expect_exact("------------------------------------------")
term.expect_exact("post s1")
term.expect_exact("Thread 1 woke up after waiting for s1.")
term.expect_exact("post s2")
term.expect_exact("Thread 2 woke up after waiting for s2.")
term.expect_exact("post s2")
term.expect_exact("Thread 1 woke up after waiting for s2.")
term.expect_exact("post s1")
term.expect_exact("Thread 2 woke up after waiting for s1.")
def test4(term):
term.expect_exact("######################### TEST4:")
term.expect_exact("first: sem_init s1")
term.expect_exact("first: wait 1 sec for s1")
term.expect(r"first: waited 1\.\d{6} s")
if __name__ == "__main__":
TERM = init()
test1(TERM)
test2(TERM)
test3(TERM)
test4(TERM)
TERM.expect("######################### DONE")