Skip to content

Commit 930789d

Browse files
committed
samples: kernel: add condition variable samples
Add a few samples for using condition variables.. Signed-off-by: Anas Nashif <[email protected]>
1 parent 6d53606 commit 930789d

File tree

8 files changed

+226
-0
lines changed

8 files changed

+226
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.13.1)
4+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
5+
project(condvar)
6+
7+
FILE(GLOB app_sources src/main.c)
8+
target_sources(app PRIVATE ${app_sources})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_TEST=y
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tests:
2+
sample.kernel.cond_var:
3+
tags: kernel condition_variables
4+
harness: console
5+
harness_config:
6+
type: one_line
7+
regex:
8+
- ".*Waited and joined with 3 threads"
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright (c) 2020 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <zephyr.h>
7+
#include <arch/cpu.h>
8+
#include <sys/arch_interface.h>
9+
10+
#define NUM_THREADS 3
11+
#define TCOUNT 10
12+
#define COUNT_LIMIT 12
13+
14+
static int count;
15+
16+
K_MUTEX_DEFINE(count_mutex);
17+
K_CONDVAR_DEFINE(count_threshold_cv);
18+
19+
#define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACKSIZE)
20+
21+
K_THREAD_STACK_EXTERN(tstack);
22+
K_THREAD_STACK_ARRAY_DEFINE(tstacks, NUM_THREADS, STACK_SIZE);
23+
24+
static struct k_thread t[NUM_THREADS];
25+
26+
void inc_count(void *p1, void *p2, void *p3)
27+
{
28+
int i;
29+
long my_id = (long)p1;
30+
31+
for (i = 0; i < TCOUNT; i++) {
32+
k_mutex_lock(&count_mutex, K_FOREVER);
33+
count++;
34+
35+
/*
36+
* Check the value of count and signal waiting thread when
37+
* condition is reached. Note that this occurs while mutex is
38+
* locked.
39+
*/
40+
41+
if (count == COUNT_LIMIT) {
42+
printk("%s: thread %ld, count = %d Threshold reached.",
43+
__func__, my_id, count);
44+
k_condvar_signal(&count_threshold_cv);
45+
printk("Just sent signal.\n");
46+
}
47+
printk("%s: thread %ld, count = %d, unlocking mutex\n",
48+
__func__, my_id, count);
49+
k_mutex_unlock(&count_mutex);
50+
51+
/* Sleep so threads can alternate on mutex lock */
52+
k_sleep(K_MSEC(500));
53+
}
54+
}
55+
56+
void watch_count(void *p1, void *p2, void *p3)
57+
{
58+
long my_id = (long)p1;
59+
60+
printk("Starting %s: thread %ld\n", __func__, my_id);
61+
62+
k_mutex_lock(&count_mutex, K_FOREVER);
63+
while (count < COUNT_LIMIT) {
64+
printk("%s: thread %ld Count= %d. Going into wait...\n",
65+
__func__, my_id, count);
66+
k_condvar_wait(&count_threshold_cv, &count_mutex, K_FOREVER);
67+
68+
printk("%s: thread %ld Condition signal received. Count= %d\n",
69+
__func__, my_id, count);
70+
}
71+
printk("%s: thread %ld Updating the value of count...\n",
72+
__func__, my_id);
73+
count += 125;
74+
printk("%s: thread %ld count now = %d.\n", __func__, my_id, count);
75+
printk("%s: thread %ld Unlocking mutex.\n", __func__, my_id);
76+
k_mutex_unlock(&count_mutex);
77+
}
78+
79+
void main(void)
80+
{
81+
long t1 = 1, t2 = 2, t3 = 3;
82+
int i;
83+
84+
count = 0;
85+
86+
k_thread_create(&t[0], tstacks[0], STACK_SIZE, watch_count,
87+
INT_TO_POINTER(t1), NULL, NULL, K_PRIO_PREEMPT(10), 0,
88+
K_NO_WAIT);
89+
90+
k_thread_create(&t[1], tstacks[1], STACK_SIZE, inc_count,
91+
INT_TO_POINTER(t2), NULL, NULL, K_PRIO_PREEMPT(10), 0,
92+
K_NO_WAIT);
93+
94+
k_thread_create(&t[2], tstacks[2], STACK_SIZE, inc_count,
95+
INT_TO_POINTER(t3), NULL, NULL, K_PRIO_PREEMPT(10), 0,
96+
K_NO_WAIT);
97+
98+
/* Wait for all threads to complete */
99+
for (i = 0; i < NUM_THREADS; i++) {
100+
k_thread_join(&t[i], K_FOREVER);
101+
}
102+
103+
printk("Main(): Waited and joined with %d threads. Final value of count = %d. Done.\n",
104+
NUM_THREADS, count);
105+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.13.1)
4+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
5+
project(condvar)
6+
7+
FILE(GLOB app_sources src/main.c)
8+
target_sources(app PRIVATE ${app_sources})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_TEST=y
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tests:
2+
sample.kernel.cond_var.simple:
3+
tags: kernel condition_variables
4+
harness: console
5+
harness_config:
6+
type: one_line
7+
regex:
8+
- ".*done == 20 so everyone is done"
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2020 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr.h>
8+
#include <arch/cpu.h>
9+
#include <sys/arch_interface.h>
10+
11+
#define NUM_THREADS 20
12+
#define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACKSIZE)
13+
14+
K_THREAD_STACK_EXTERN(tstack);
15+
K_THREAD_STACK_ARRAY_DEFINE(tstacks, NUM_THREADS, STACK_SIZE);
16+
17+
static struct k_thread t[NUM_THREADS];
18+
19+
K_MUTEX_DEFINE(mutex);
20+
K_CONDVAR_DEFINE(condvar);
21+
22+
static int done;
23+
24+
void worker_thread(void *p1, void *p2, void *p3)
25+
{
26+
const int myid = (long)p1;
27+
const int workloops = 5;
28+
29+
for (int i = 0; i < workloops; i++) {
30+
printk("[thread %d] working (%d/%d)\n", myid, i, workloops);
31+
k_sleep(K_MSEC(500));
32+
}
33+
34+
/*
35+
* we're going to manipulate done and use the cond, so we need the mutex
36+
*/
37+
k_mutex_lock(&mutex, K_FOREVER);
38+
39+
/*
40+
* increase the count of threads that have finished their work.
41+
*/
42+
done++;
43+
printk("[thread %d] done is now %d. Signalling cond.\n", myid, done);
44+
45+
k_condvar_signal(&condvar);
46+
k_mutex_unlock(&mutex);
47+
}
48+
49+
void main(void)
50+
{
51+
k_tid_t tid[NUM_THREADS];
52+
53+
done = 0;
54+
55+
for (int i = 0; i < NUM_THREADS; i++) {
56+
tid[i] =
57+
k_thread_create(&t[i], tstacks[i], STACK_SIZE,
58+
worker_thread, INT_TO_POINTER(i), NULL,
59+
NULL, K_PRIO_PREEMPT(10), 0, K_NO_WAIT);
60+
}
61+
k_sleep(K_MSEC(1000));
62+
63+
k_mutex_lock(&mutex, K_FOREVER);
64+
65+
/*
66+
* are the other threads still busy?
67+
*/
68+
while (done < NUM_THREADS) {
69+
printk("[thread %s] done is %d which is < %d so waiting on cond\n",
70+
__func__, done, (int)NUM_THREADS);
71+
72+
/* block this thread until another thread signals cond. While
73+
* blocked, the mutex is released, then re-acquired before this
74+
* thread is woken up and the call returns.
75+
*/
76+
k_condvar_wait(&condvar, &mutex, K_FOREVER);
77+
78+
printk("[thread %s] wake - cond was signalled.\n", __func__);
79+
80+
/* we go around the loop with the lock held */
81+
}
82+
83+
printk("[thread %s] done == %d so everyone is done\n",
84+
__func__, (int)NUM_THREADS);
85+
86+
k_mutex_unlock(&mutex);
87+
}

0 commit comments

Comments
 (0)