mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
add pthread condition variable implementation
This commit is contained in:
parent
852618476c
commit
619039e0e2
@ -19,4 +19,7 @@ struct timeval {
|
||||
time_t tv_usec;
|
||||
};
|
||||
|
||||
/* TODO: remove once msp430 libc supports clockid_t */
|
||||
typedef int clockid_t;
|
||||
|
||||
#endif /* MSP430_TYPES_H */
|
||||
|
@ -1,54 +1,140 @@
|
||||
/* Functions for handling conditional variables. */
|
||||
/*
|
||||
* Copyright (C) 2014 Hamburg University of Applied Sciences (HAW)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
typedef unsigned long int pthread_cond_t;
|
||||
typedef unsigned long int pthread_condattr_t;
|
||||
/**
|
||||
* @defgroup
|
||||
* @brief
|
||||
* @ingroup sys
|
||||
* @{
|
||||
*
|
||||
* @file condition_variable.h
|
||||
* @brief RIOT POSIX condition variable API
|
||||
*
|
||||
* @author Martin Landsmann <martin.landsmann@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
/* Initialize condition variable COND using attributes ATTR, or use
|
||||
the default values if later is NULL. */
|
||||
int pthread_cond_init(pthread_cond_t *cond,
|
||||
const pthread_condattr_t *cond_attr);
|
||||
#ifndef _CONDITION_VARIABLE_H
|
||||
#define _CONDITION_VARIABLE_H
|
||||
|
||||
/* Destroy condition variable COND. */
|
||||
int pthread_cond_destroy(pthread_cond_t *cond);
|
||||
#include <time.h>
|
||||
#include "mutex.h"
|
||||
|
||||
/* Wake up one thread waiting for condition variable COND. */
|
||||
int pthread_cond_signal(pthread_cond_t *cond);
|
||||
#if defined(CPU_CC430) || defined(CPU_MSP430X16X)
|
||||
# include "msp430_types.h"
|
||||
#endif
|
||||
|
||||
/* Wake up all threads waiting for condition variables COND. */
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond);
|
||||
/**
|
||||
* @note condition attributes are currently NOT USED in RIOT condition variables
|
||||
*/
|
||||
typedef struct pthread_condattr_t {
|
||||
int __dummy;
|
||||
} pthread_condattr_t;
|
||||
|
||||
/* Wait for condition variable COND to be signaled or broadcast.
|
||||
MUTEX is assumed to be locked before.
|
||||
typedef struct pthread_cond_t {
|
||||
/* fields are managed by cv functions, don't touch */
|
||||
queue_node_t queue; /**< Threads currently waiting to be signaled. */
|
||||
} pthread_cond_t;
|
||||
|
||||
This function is a cancellation point and therefore not marked with. */
|
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
|
||||
/**
|
||||
* @brief Initializes a condition attribute variable object using default values
|
||||
* @param[in, out] attr pre-allocated condition attribute variable structure.
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_cond_condattr_init(struct pthread_condattr_t *attr);
|
||||
|
||||
/* Wait for condition variable COND to be signaled or broadcast until
|
||||
ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an
|
||||
absolute time specification; zero is the beginning of the epoch
|
||||
(00:00:00 GMT, January 1, 1970).
|
||||
/**
|
||||
* @brief Uninitializes a condition attribute variable object
|
||||
* @param[in, out] attr pre-allocated condition attribute variable structure.
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_cond_condattr_destroy(struct pthread_condattr_t *attr);
|
||||
|
||||
This function is a cancellation point and therefore not marked with. */
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
const struct timespec *abstime);
|
||||
|
||||
/* Functions for handling condition variable attributes. */
|
||||
|
||||
/* Initialize condition variable attribute ATTR. */
|
||||
int pthread_condattr_init(pthread_condattr_t *attr);
|
||||
|
||||
/* Destroy condition variable attribute ATTR. */
|
||||
int pthread_condattr_destroy(pthread_condattr_t *attr);
|
||||
|
||||
/* Get the process-shared flag of the condition variable attribute ATTR. */
|
||||
/**
|
||||
* @brief Get the process-shared attribute in an initialised attributes object referenced by attr
|
||||
* @note NOT USED since RIOT is a single process OS
|
||||
* @param[in] attr pre-allocated condition attribute variable structure.
|
||||
* @param[out] pshared the pre-allocated process-shared variable.
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared);
|
||||
|
||||
/* Set the process-shared flag of the condition variable attribute ATTR. */
|
||||
/**
|
||||
* @brief Set the process-shared attribute in an initialised attributes object referenced by attr
|
||||
* @note NOT USED since RIOT is a single process OS
|
||||
* @param[in, out] attr pre-allocated condition attribute variable structure.
|
||||
* @param[in] pshared pshared the pre-allocated process-shared variable.
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared);
|
||||
|
||||
/* Get the clock selected for the conditon variable attribute ATTR. */
|
||||
int pthread_condattr_getclock(const pthread_condattr_t *attr,
|
||||
clockid_t *clock_id);
|
||||
/**
|
||||
* @brief Get the clock selected for the conditon variable attribute attr.
|
||||
* @note currently NOT USED in RIOT.
|
||||
* @param[in] attr pre-allocated condition attribute variable structure.
|
||||
* @param[out] clock_id the clock ID that is used to measure the timeout service
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_condattr_getclock(const pthread_condattr_t *attr, clockid_t *clock_id);
|
||||
|
||||
/* Set the clock selected for the conditon variable attribute ATTR. */
|
||||
/**
|
||||
* @brief Set the clock selected for the conditon variable attribute ATTR.
|
||||
* @note currently NOT USED in RIOT.
|
||||
* @param[in, out] attr pre-allocated condition attribute variable structure.
|
||||
* @param[in] clock_id the clock ID that shall be used to measure the timeout service
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id);
|
||||
|
||||
/**
|
||||
* @brief Initializes a condition variable object
|
||||
* @param[in, out] cond pre-allocated condition variable structure.
|
||||
* @param[in] attr pre-allocated condition attribute variable structure.
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_cond_init(struct pthread_cond_t *cond, struct pthread_condattr_t *attr);
|
||||
|
||||
/**
|
||||
* @brief Destroy the condition variable cond
|
||||
* @param[in, out] cond pre-allocated condition variable structure.
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_cond_destroy(struct pthread_cond_t *cond);
|
||||
|
||||
/**
|
||||
* @brief blocks the calling thread until the specified condition cond is signalled
|
||||
* @param[in, out] cond pre-allocated condition variable structure.
|
||||
* @param[in, out] mutex pre-allocated mutex variable structure.
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_cond_wait(struct pthread_cond_t *cond, struct mutex_t *mutex);
|
||||
|
||||
/**
|
||||
* @brief blocks the calling thread until the specified condition cond is signalled
|
||||
* @param[in, out] cond pre-allocated condition variable structure.
|
||||
* @param[in, out] mutex pre-allocated mutex variable structure.
|
||||
* @param[in] abstime pre-allocated timeout.
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_cond_timedwait(struct pthread_cond_t *cond, struct mutex_t *mutex, const struct timespec *abstime);
|
||||
|
||||
/**
|
||||
* @brief unblock at least one of the threads that are blocked on the specified condition variable cond
|
||||
* @param[in, out] cond pre-allocated condition variable structure.
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_cond_signal(struct pthread_cond_t *cond);
|
||||
|
||||
/**
|
||||
* @brief unblock all threads that are currently blocked on the specified condition variable cond
|
||||
* @param[in, out] cond pre-allocated condition variable structure.
|
||||
* @return returns 0 on success, an errorcode otherwise.
|
||||
*/
|
||||
int pthread_cond_broadcast(struct pthread_cond_t *cond);
|
||||
|
||||
/** @} */
|
||||
#endif /* _CONDITION_VARIABLE_H */
|
||||
|
198
sys/posix/pthread/pthread_cond.c
Normal file
198
sys/posix/pthread/pthread_cond.c
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Hamburg University of Applied Sciences (HAW)
|
||||
*
|
||||
* This file is 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 sys
|
||||
* @{
|
||||
*
|
||||
* @file pthread_cond.c
|
||||
* @brief Condition variable implementation
|
||||
*
|
||||
* @author Martin Landsmann <martin.landsmann@haw-hamburg.de>
|
||||
* @author René Kijewski <rene.kijewski@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "pthread_cond.h"
|
||||
#include "thread.h"
|
||||
#include "vtimer.h"
|
||||
#include "sched.h"
|
||||
#include "irq.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct vtimer_t timer;
|
||||
|
||||
int pthread_cond_condattr_destroy(struct pthread_condattr_t *attr)
|
||||
{
|
||||
if (attr != NULL) {
|
||||
DEBUG("pthread_cond_condattr_destroy: currently attributes are not supported.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_condattr_init(struct pthread_condattr_t *attr)
|
||||
{
|
||||
if (attr != NULL) {
|
||||
DEBUG("pthread_cond_condattr_init: currently attributes are not supported.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared)
|
||||
{
|
||||
(void)attr;
|
||||
(void)pshared;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
|
||||
{
|
||||
(void)attr;
|
||||
(void)pshared;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_condattr_getclock(const pthread_condattr_t *attr, clockid_t *clock_id)
|
||||
{
|
||||
(void)attr;
|
||||
(void)clock_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id)
|
||||
{
|
||||
(void)attr;
|
||||
(void)clock_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_init(struct pthread_cond_t *cond, struct pthread_condattr_t *attr)
|
||||
{
|
||||
if (attr != NULL) {
|
||||
DEBUG("pthread_cond_init: currently attributes are not supported.\n");
|
||||
}
|
||||
|
||||
cond->queue.priority = 0;
|
||||
cond->queue.data = 0;
|
||||
cond->queue.next = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_destroy(struct pthread_cond_t *cond)
|
||||
{
|
||||
pthread_cond_init(cond, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_wait(struct pthread_cond_t *cond, struct mutex_t *mutex)
|
||||
{
|
||||
queue_node_t n;
|
||||
n.priority = active_thread->priority;
|
||||
n.data = active_thread->pid;
|
||||
n.next = NULL;
|
||||
|
||||
/* the signaling thread may not hold the mutex, the queue is not thread safe */
|
||||
unsigned old_state = disableIRQ();
|
||||
queue_priority_add(&(cond->queue), &n);
|
||||
restoreIRQ(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 = disableIRQ();
|
||||
queue_remove(&(cond->queue), &n);
|
||||
restoreIRQ(old_state);
|
||||
}
|
||||
|
||||
mutex_lock(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_timedwait(struct pthread_cond_t *cond, struct mutex_t *mutex, const struct timespec *abstime)
|
||||
{
|
||||
timex_t now, then, reltime;
|
||||
|
||||
vtimer_now(&now);
|
||||
then.seconds = abstime->tv_sec;
|
||||
then.microseconds = abstime->tv_nsec / 1000u;
|
||||
reltime = timex_sub(then, now);
|
||||
|
||||
vtimer_t timer;
|
||||
vtimer_set_wakeup(&timer, reltime, active_thread->pid);
|
||||
int result = pthread_cond_wait(cond, mutex);
|
||||
vtimer_remove(&timer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int pthread_cond_signal(struct pthread_cond_t *cond)
|
||||
{
|
||||
unsigned old_state = disableIRQ();
|
||||
|
||||
queue_node_t *head = queue_remove_head(&(cond->queue));
|
||||
int other_prio = -1;
|
||||
if (head != NULL) {
|
||||
tcb_t *other_thread = (tcb_t *) sched_threads[head->data];
|
||||
if (other_thread) {
|
||||
other_prio = other_thread->priority;
|
||||
sched_set_status(other_thread, STATUS_PENDING);
|
||||
}
|
||||
head->data = -1u;
|
||||
}
|
||||
|
||||
restoreIRQ(old_state);
|
||||
|
||||
if (other_prio >= 0) {
|
||||
sched_switch(active_thread->priority, other_prio);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max_prio(int a, int b)
|
||||
{
|
||||
return (a < 0) ? b : ((a < b) ? a : b);
|
||||
}
|
||||
|
||||
int pthread_cond_broadcast(struct pthread_cond_t *cond)
|
||||
{
|
||||
unsigned old_state = disableIRQ();
|
||||
|
||||
int other_prio = -1;
|
||||
|
||||
while (1) {
|
||||
queue_node_t *head = queue_remove_head(&(cond->queue));
|
||||
if (head == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
tcb_t *other_thread = (tcb_t *) sched_threads[head->data];
|
||||
if (other_thread) {
|
||||
other_prio = max_prio(other_prio, other_thread->priority);
|
||||
sched_set_status(other_thread, STATUS_PENDING);
|
||||
}
|
||||
head->data = -1u;
|
||||
}
|
||||
|
||||
restoreIRQ(old_state);
|
||||
|
||||
if (other_prio >= 0) {
|
||||
sched_switch(active_thread->priority, other_prio);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
10
tests/test_pthread_condition_variable/Makefile
Normal file
10
tests/test_pthread_condition_variable/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
export PROJECT = test_condition_variable
|
||||
include ../Makefile.tests_common
|
||||
|
||||
USEMODULE += posix
|
||||
USEMODULE += pthread
|
||||
USEMODULE += vtimer
|
||||
|
||||
CFLAGS += -DNATIVE_AUTO_EXIT
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
86
tests/test_pthread_condition_variable/main.c
Normal file
86
tests/test_pthread_condition_variable/main.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Hamburg University of Applied Sciences (HAW)
|
||||
*
|
||||
* This file is 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 tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief simple condition variable test application
|
||||
*
|
||||
* @author Martin Landsmann <martin.landsmann@haw-hamburg.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "pthread_cond.h"
|
||||
#include "thread.h"
|
||||
#include "mutex.h"
|
||||
|
||||
static mutex_t mutex;
|
||||
static struct pthread_cond_t cv;
|
||||
static volatile int is_finished;
|
||||
static volatile long count;
|
||||
static volatile long expected_value;
|
||||
static char stack[KERNEL_CONF_STACKSIZE_MAIN];
|
||||
|
||||
/**
|
||||
* @brief This thread tries to lock the mutex to enter the critical section.
|
||||
* Then it signals one waiting thread to check the condition and it goes to sleep again
|
||||
* If is_finished is set to 1 second_thread ends
|
||||
*/
|
||||
static void second_thread(void)
|
||||
{
|
||||
while (1) {
|
||||
mutex_lock(&mutex);
|
||||
|
||||
if (is_finished == 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_cond_signal(&cv);
|
||||
mutex_unlock_and_sleep(&mutex);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
count = 0;
|
||||
is_finished = 0;
|
||||
expected_value = 1000*1000;
|
||||
mutex_init(&mutex);
|
||||
pthread_cond_init(&cv, NULL);
|
||||
|
||||
int pid = thread_create(stack,
|
||||
KERNEL_CONF_STACKSIZE_MAIN,
|
||||
PRIORITY_MAIN - 1,
|
||||
CREATE_WOUT_YIELD | CREATE_STACKTEST,
|
||||
second_thread,
|
||||
"second_thread");
|
||||
|
||||
while (1) {
|
||||
mutex_lock(&mutex);
|
||||
thread_wakeup(pid);
|
||||
count++;
|
||||
|
||||
if ((count % 100000) == 0) {
|
||||
printf("Still alive alternated [count: %ldk] times.\n", count / 1000);
|
||||
}
|
||||
|
||||
if (count == expected_value) {
|
||||
puts("condition fulfilled.");
|
||||
is_finished = 1;
|
||||
mutex_unlock(&mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_cond_wait(&cv, &mutex);
|
||||
mutex_unlock(&mutex);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user