kernel: add condition variables
Introduce condition variables similar to how they are done in POSIX with a mutex. Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
parent
69258775ec
commit
06eb489c45
4 changed files with 151 additions and 0 deletions
|
@ -3168,6 +3168,84 @@ __syscall int k_mutex_unlock(struct k_mutex *mutex);
|
|||
* @}
|
||||
*/
|
||||
|
||||
|
||||
struct k_condvar {
|
||||
_wait_q_t wait_q;
|
||||
};
|
||||
|
||||
#define Z_CONDVAR_INITIALIZER(obj) \
|
||||
{ \
|
||||
.wait_q = Z_WAIT_Q_INIT(&obj.wait_q), \
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup condvar_apis Condition Variables APIs
|
||||
* @ingroup kernel_apis
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initialize a condition variable
|
||||
*
|
||||
* @param condvar pointer to a @p k_condvar structure
|
||||
* @retval 0 Condition variable created successfully
|
||||
*/
|
||||
__syscall int k_condvar_init(struct k_condvar *condvar);
|
||||
|
||||
/**
|
||||
* @brief Signals one thread that is pending on the condition variable
|
||||
*
|
||||
* @param condvar pointer to a @p k_condvar structure
|
||||
* @retval 0 On success
|
||||
*/
|
||||
__syscall int k_condvar_signal(struct k_condvar *condvar);
|
||||
|
||||
/**
|
||||
* @brief Unblock all threads that are pending on the condition
|
||||
* variable
|
||||
*
|
||||
* @param condvar pointer to a @p k_condvar structure
|
||||
* @return An integer with number of woken threads on success
|
||||
*/
|
||||
__syscall int k_condvar_broadcast(struct k_condvar *condvar);
|
||||
|
||||
/**
|
||||
* @brief Waits on the condition variable releasing the mutex lock
|
||||
*
|
||||
* Automically releases the currently owned mutex, blocks the current thread
|
||||
* waiting on the condition variable specified by @a condvar,
|
||||
* and finally acquires the mutex again.
|
||||
*
|
||||
* The waiting thread unblocks only after another thread calls
|
||||
* k_condvar_signal, or k_condvar_broadcast with the same condition variable.
|
||||
*
|
||||
* @param condvar pointer to a @p k_condvar structure
|
||||
* @param mutex Address of the mutex.
|
||||
* @param timeout Waiting period for the condition variable
|
||||
* or one of the special values K_NO_WAIT and K_FOREVER.
|
||||
* @retval 0 On success
|
||||
* @retval -EAGAIN Waiting period timed out.
|
||||
*/
|
||||
__syscall int k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex,
|
||||
k_timeout_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Statically define and initialize a condition variable.
|
||||
*
|
||||
* The condition variable can be accessed outside the module where it is
|
||||
* defined using:
|
||||
*
|
||||
* @code extern struct k_condvar <name>; @endcode
|
||||
*
|
||||
* @param name Name of the condition variable.
|
||||
*/
|
||||
#define K_CONDVAR_DEFINE(name) \
|
||||
Z_STRUCT_SECTION_ITERABLE(k_condvar, name) = \
|
||||
Z_CONDVAR_INITIALIZER(name)
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cond INTERNAL_HIDDEN
|
||||
*/
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
Z_ITERABLE_SECTION_RAM_GC_ALLOWED(k_pipe, 4)
|
||||
Z_ITERABLE_SECTION_RAM_GC_ALLOWED(k_sem, 4)
|
||||
Z_ITERABLE_SECTION_RAM_GC_ALLOWED(k_queue, 4)
|
||||
Z_ITERABLE_SECTION_RAM_GC_ALLOWED(k_condvar, 4)
|
||||
|
||||
SECTION_DATA_PROLOGUE(_net_buf_pool_area,,SUBALIGN(4))
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ list(APPEND kernel_files
|
|||
thread_abort.c
|
||||
version.c
|
||||
work_q.c
|
||||
condvar.c
|
||||
smp.c
|
||||
banner.c
|
||||
)
|
||||
|
|
71
kernel/condvar.c
Normal file
71
kernel/condvar.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <kernel_structs.h>
|
||||
#include <toolchain.h>
|
||||
#include <ksched.h>
|
||||
#include <wait_q.h>
|
||||
|
||||
static struct k_spinlock lock;
|
||||
|
||||
int z_impl_k_condvar_init(struct k_condvar *condvar)
|
||||
{
|
||||
z_waitq_init(&condvar->wait_q);
|
||||
z_object_init(condvar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int z_impl_k_condvar_signal(struct k_condvar *condvar)
|
||||
{
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
struct k_thread *thread = z_unpend_first_thread(&condvar->wait_q);
|
||||
|
||||
if (thread != NULL) {
|
||||
arch_thread_return_value_set(thread, 0);
|
||||
z_ready_thread(thread);
|
||||
z_reschedule(&lock, key);
|
||||
} else {
|
||||
k_spin_unlock(&lock, key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int z_impl_k_condvar_broadcast(struct k_condvar *condvar)
|
||||
{
|
||||
struct k_thread *pending_thread;
|
||||
k_spinlock_key_t key;
|
||||
int woken = 0;
|
||||
|
||||
key = k_spin_lock(&lock);
|
||||
|
||||
/* wake up any threads that are waiting to write */
|
||||
while ((pending_thread = z_unpend_first_thread(&condvar->wait_q)) !=
|
||||
NULL) {
|
||||
arch_thread_return_value_set(pending_thread, 0);
|
||||
z_ready_thread(pending_thread);
|
||||
woken++;
|
||||
}
|
||||
|
||||
z_reschedule(&lock, key);
|
||||
|
||||
return woken;
|
||||
}
|
||||
|
||||
int z_impl_k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex,
|
||||
k_timeout_t timeout)
|
||||
{
|
||||
k_spinlock_key_t key;
|
||||
int ret;
|
||||
|
||||
key = k_spin_lock(&lock);
|
||||
k_mutex_unlock(mutex);
|
||||
|
||||
ret = z_pend_curr(&lock, key, &condvar->wait_q, timeout);
|
||||
k_mutex_lock(mutex, K_FOREVER);
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue