Skip to content

Commit 06eb489

Browse files
committed
kernel: add condition variables
Introduce condition variables similar to how they are done in POSIX with a mutex. Signed-off-by: Anas Nashif <[email protected]>
1 parent 6925877 commit 06eb489

File tree

4 files changed

+151
-0
lines changed

4 files changed

+151
-0
lines changed

include/kernel.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3168,6 +3168,84 @@ __syscall int k_mutex_unlock(struct k_mutex *mutex);
31683168
* @}
31693169
*/
31703170

3171+
3172+
struct k_condvar {
3173+
_wait_q_t wait_q;
3174+
};
3175+
3176+
#define Z_CONDVAR_INITIALIZER(obj) \
3177+
{ \
3178+
.wait_q = Z_WAIT_Q_INIT(&obj.wait_q), \
3179+
}
3180+
3181+
/**
3182+
* @defgroup condvar_apis Condition Variables APIs
3183+
* @ingroup kernel_apis
3184+
* @{
3185+
*/
3186+
3187+
/**
3188+
* @brief Initialize a condition variable
3189+
*
3190+
* @param condvar pointer to a @p k_condvar structure
3191+
* @retval 0 Condition variable created successfully
3192+
*/
3193+
__syscall int k_condvar_init(struct k_condvar *condvar);
3194+
3195+
/**
3196+
* @brief Signals one thread that is pending on the condition variable
3197+
*
3198+
* @param condvar pointer to a @p k_condvar structure
3199+
* @retval 0 On success
3200+
*/
3201+
__syscall int k_condvar_signal(struct k_condvar *condvar);
3202+
3203+
/**
3204+
* @brief Unblock all threads that are pending on the condition
3205+
* variable
3206+
*
3207+
* @param condvar pointer to a @p k_condvar structure
3208+
* @return An integer with number of woken threads on success
3209+
*/
3210+
__syscall int k_condvar_broadcast(struct k_condvar *condvar);
3211+
3212+
/**
3213+
* @brief Waits on the condition variable releasing the mutex lock
3214+
*
3215+
* Automically releases the currently owned mutex, blocks the current thread
3216+
* waiting on the condition variable specified by @a condvar,
3217+
* and finally acquires the mutex again.
3218+
*
3219+
* The waiting thread unblocks only after another thread calls
3220+
* k_condvar_signal, or k_condvar_broadcast with the same condition variable.
3221+
*
3222+
* @param condvar pointer to a @p k_condvar structure
3223+
* @param mutex Address of the mutex.
3224+
* @param timeout Waiting period for the condition variable
3225+
* or one of the special values K_NO_WAIT and K_FOREVER.
3226+
* @retval 0 On success
3227+
* @retval -EAGAIN Waiting period timed out.
3228+
*/
3229+
__syscall int k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex,
3230+
k_timeout_t timeout);
3231+
3232+
/**
3233+
* @brief Statically define and initialize a condition variable.
3234+
*
3235+
* The condition variable can be accessed outside the module where it is
3236+
* defined using:
3237+
*
3238+
* @code extern struct k_condvar <name>; @endcode
3239+
*
3240+
* @param name Name of the condition variable.
3241+
*/
3242+
#define K_CONDVAR_DEFINE(name) \
3243+
Z_STRUCT_SECTION_ITERABLE(k_condvar, name) = \
3244+
Z_CONDVAR_INITIALIZER(name)
3245+
/**
3246+
* @}
3247+
*/
3248+
31713249
/**
31723250
* @cond INTERNAL_HIDDEN
31733251
*/

include/linker/common-ram.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
Z_ITERABLE_SECTION_RAM_GC_ALLOWED(k_pipe, 4)
103103
Z_ITERABLE_SECTION_RAM_GC_ALLOWED(k_sem, 4)
104104
Z_ITERABLE_SECTION_RAM_GC_ALLOWED(k_queue, 4)
105+
Z_ITERABLE_SECTION_RAM_GC_ALLOWED(k_condvar, 4)
105106

106107
SECTION_DATA_PROLOGUE(_net_buf_pool_area,,SUBALIGN(4))
107108
{

kernel/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ list(APPEND kernel_files
2424
thread_abort.c
2525
version.c
2626
work_q.c
27+
condvar.c
2728
smp.c
2829
banner.c
2930
)

kernel/condvar.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2020 Intel Corporation.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <kernel.h>
8+
#include <kernel_structs.h>
9+
#include <toolchain.h>
10+
#include <ksched.h>
11+
#include <wait_q.h>
12+
13+
static struct k_spinlock lock;
14+
15+
int z_impl_k_condvar_init(struct k_condvar *condvar)
16+
{
17+
z_waitq_init(&condvar->wait_q);
18+
z_object_init(condvar);
19+
return 0;
20+
}
21+
22+
int z_impl_k_condvar_signal(struct k_condvar *condvar)
23+
{
24+
k_spinlock_key_t key = k_spin_lock(&lock);
25+
struct k_thread *thread = z_unpend_first_thread(&condvar->wait_q);
26+
27+
if (thread != NULL) {
28+
arch_thread_return_value_set(thread, 0);
29+
z_ready_thread(thread);
30+
z_reschedule(&lock, key);
31+
} else {
32+
k_spin_unlock(&lock, key);
33+
}
34+
return 0;
35+
}
36+
37+
int z_impl_k_condvar_broadcast(struct k_condvar *condvar)
38+
{
39+
struct k_thread *pending_thread;
40+
k_spinlock_key_t key;
41+
int woken = 0;
42+
43+
key = k_spin_lock(&lock);
44+
45+
/* wake up any threads that are waiting to write */
46+
while ((pending_thread = z_unpend_first_thread(&condvar->wait_q)) !=
47+
NULL) {
48+
arch_thread_return_value_set(pending_thread, 0);
49+
z_ready_thread(pending_thread);
50+
woken++;
51+
}
52+
53+
z_reschedule(&lock, key);
54+
55+
return woken;
56+
}
57+
58+
int z_impl_k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex,
59+
k_timeout_t timeout)
60+
{
61+
k_spinlock_key_t key;
62+
int ret;
63+
64+
key = k_spin_lock(&lock);
65+
k_mutex_unlock(mutex);
66+
67+
ret = z_pend_curr(&lock, key, &condvar->wait_q, timeout);
68+
k_mutex_lock(mutex, K_FOREVER);
69+
70+
return ret;
71+
}

0 commit comments

Comments
 (0)