
5 changed files with 432 additions and 49 deletions
@ -1,54 +1,140 @@
|
||||
/* Functions for handling conditional variables. */ |
||||
|
||||
typedef unsigned long int pthread_cond_t; |
||||
typedef unsigned long int pthread_condattr_t; |
||||
|
||||
/* 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); |
||||
|
||||
/* Destroy condition variable COND. */ |
||||
int pthread_cond_destroy(pthread_cond_t *cond); |
||||
|
||||
/* Wake up one thread waiting for condition variable COND. */ |
||||
int pthread_cond_signal(pthread_cond_t *cond); |
||||
|
||||
/* Wake up all threads waiting for condition variables COND. */ |
||||
int pthread_cond_broadcast(pthread_cond_t *cond); |
||||
|
||||
/* Wait for condition variable COND to be signaled or broadcast.
|
||||
MUTEX is assumed to be locked before. |
||||
|
||||
This function is a cancellation point and therefore not marked with. */ |
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); |
||||
|
||||
/* 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). |
||||
|
||||
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. */ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup |
||||
* @brief |
||||
* @ingroup sys |
||||
* @{ |
||||
* |
||||
* @file condition_variable.h |
||||
* @brief RIOT POSIX condition variable API |
||||
* |
||||
* @author Martin Landsmann <martin.landsmann@haw-hamburg.de> |
||||
*/ |
||||
|
||||
#ifndef _CONDITION_VARIABLE_H |
||||
#define _CONDITION_VARIABLE_H |
||||
|
||||
#include <time.h> |
||||
#include "mutex.h" |
||||
|
||||
#if defined(CPU_CC430) || defined(CPU_MSP430X16X) |
||||
# include "msp430_types.h" |
||||
#endif |
||||
|
||||
/**
|
||||
* @note condition attributes are currently NOT USED in RIOT condition variables |
||||
*/ |
||||
typedef struct pthread_condattr_t { |
||||
int __dummy; |
||||
} pthread_condattr_t; |
||||
|
||||
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; |
||||
|
||||
/**
|
||||
* @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); |
||||
|
||||
/**
|
||||
* @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); |
||||
|
||||
/**
|
||||
* @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); |
||||
|
||||
/* Set the clock selected for the conditon variable attribute ATTR. */ |
||||
/**
|
||||
* @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); |
||||
|
||||
/**
|
||||
* @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 */ |
||||
|
@ -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; |
||||
} |
@ -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 |
@ -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