Skip to content

Commit 1b3ba57

Browse files
committed
tests: lib: cpp: add tests for std::condition_variable
Add tests for the ISO C++11 std::condition_variable. Signed-off-by: Christopher Friedt <[email protected]>
1 parent 17ec788 commit 1b3ba57

File tree

4 files changed

+235
-0
lines changed

4 files changed

+235
-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(condition_variable)
6+
7+
FILE(GLOB_RECURSE app_sources src/*.cpp)
8+
target_sources(app PRIVATE ${app_sources})
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CONFIG_ZTEST=y
2+
3+
CONFIG_CPP=y
4+
CONFIG_REQUIRES_FULL_LIBCPP=y
5+
CONFIG_CPP_EXCEPTIONS=y
6+
CONFIG_STD_CPP20=y
7+
8+
CONFIG_POSIX_API=y
9+
CONFIG_THREAD_STACK_INFO=y
10+
CONFIG_DYNAMIC_THREAD=y
11+
CONFIG_DYNAMIC_THREAD_STACK_SIZE=4096
12+
CONFIG_DYNAMIC_THREAD_POOL_SIZE=6
13+
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
14+
CONFIG_ZTEST_STACK_SIZE=4096
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* Copyright (c) 2020, Friedt Professional Engineering Services, Inc
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <array>
8+
#include <chrono>
9+
#include <condition_variable>
10+
#include <thread>
11+
12+
#include <zephyr/ztest.h>
13+
14+
constexpr auto N = CONFIG_DYNAMIC_THREAD_POOL_SIZE - 1;
15+
16+
using namespace std::chrono_literals;
17+
18+
using thread_pool = std::array<std::thread, N>;
19+
using scoped_lock = std::unique_lock<std::mutex>;
20+
using time_point = std::chrono::time_point<std::chrono::steady_clock>;
21+
22+
static std::mutex m;
23+
static std::condition_variable cv;
24+
25+
/* number of threads awoken before t1 */
26+
static size_t count;
27+
static time_point t0, t1, t2, t3;
28+
constexpr auto dt = 25ms;
29+
30+
static time_point now()
31+
{
32+
return std::chrono::steady_clock::now();
33+
}
34+
35+
static void time_init()
36+
{
37+
t0 = now();
38+
t1 = t0 + 2 * dt;
39+
t2 = t0 + 3 * dt;
40+
t3 = t0 + 4 * dt;
41+
}
42+
43+
static void notify_common(size_t n)
44+
{
45+
thread_pool tp;
46+
47+
count = 0;
48+
time_init();
49+
50+
for (auto &t : tp) {
51+
t = std::thread([] {
52+
scoped_lock lk(m);
53+
54+
do {
55+
cv.wait_until(lk, t3);
56+
auto nw = now();
57+
if (nw >= t1 && nw < t2) {
58+
++count;
59+
} else {
60+
break;
61+
}
62+
} while (true);
63+
});
64+
}
65+
66+
cv.notify_all();
67+
zassert_equal(count, 0, "expect: %zu actual: %zu", 0, count);
68+
69+
std::this_thread::sleep_until(t1);
70+
71+
if (n == 1) {
72+
cv.notify_one();
73+
} else {
74+
cv.notify_all();
75+
}
76+
77+
for (auto &t : tp) {
78+
t.join();
79+
}
80+
81+
zassert_equal(count, n, "expect: %zu actual: %zu", n, count);
82+
}
83+
84+
ZTEST(condition_variable, test_notify_one)
85+
{
86+
/*
87+
* Take the current time, t0. Several threads wait until time t2. If any thread wakes before
88+
* t2, increase count and exit. Notify one thread at time t1 = t2/2. Join all threads.
89+
* Verify that count == 1.
90+
*/
91+
92+
notify_common(1);
93+
}
94+
95+
ZTEST(condition_variable, test_notify_all)
96+
{
97+
/*
98+
* Take the current time, t0. Several threads wait until time t2. If any thread wakes before
99+
* t2, increase count and exit. Notify all threads at time t1 = t2/2. Join all threads.
100+
* Verify that count == N - 1.
101+
*/
102+
103+
notify_common(N);
104+
}
105+
106+
ZTEST(condition_variable, test_wait)
107+
{
108+
count = 0;
109+
time_init();
110+
111+
auto t = std::thread([] {
112+
scoped_lock lk(m);
113+
114+
cv.wait(lk);
115+
count++;
116+
});
117+
118+
std::this_thread::sleep_until(t1);
119+
cv.notify_one();
120+
121+
{
122+
scoped_lock lk(m);
123+
124+
cv.wait(lk, [] { return count == 1; });
125+
}
126+
127+
t.join();
128+
129+
zassert_equal(count, 1);
130+
}
131+
132+
ZTEST(condition_variable, test_wait_for)
133+
{
134+
count = 0;
135+
136+
auto t = std::thread([] {
137+
scoped_lock lk(m);
138+
139+
zassert_equal(cv.wait_for(lk, 0ms), std::cv_status::timeout);
140+
lk.lock();
141+
zassert_equal(cv.wait_for(lk, 3 * dt), std::cv_status::no_timeout);
142+
count++;
143+
});
144+
145+
std::this_thread::sleep_for(2 * dt);
146+
cv.notify_one();
147+
148+
{
149+
scoped_lock lk(m);
150+
151+
zassert_true(cv.wait_for(lk, dt, [] { return count == 1; }));
152+
}
153+
154+
t.join();
155+
156+
zassert_equal(count, 1);
157+
}
158+
159+
ZTEST(condition_variable, test_wait_until)
160+
{
161+
count = 0;
162+
time_init();
163+
164+
auto t = std::thread([] {
165+
scoped_lock lk(m);
166+
167+
zassert_equal(std::cv_status::timeout, cv.wait_until(lk, t0));
168+
std::this_thread::sleep_until(t1);
169+
count++;
170+
});
171+
172+
{
173+
scoped_lock lk(m);
174+
175+
zassert_true(cv.wait_until(lk, t2, [] { return count == 1; }));
176+
}
177+
178+
t.join();
179+
180+
zassert_equal(count, 1);
181+
}
182+
183+
ZTEST(condition_variable, test_native_handle)
184+
{
185+
zassert_not_null(cv.native_handle());
186+
}
187+
188+
ZTEST_SUITE(condition_variable, NULL, NULL, NULL, NULL, NULL);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
common:
2+
tags: cpp
3+
filter: CONFIG_FULL_LIBCPP_SUPPORTED
4+
integration_platforms:
5+
- qemu_cortex_a53
6+
- mps2/an385
7+
- qemu_riscv32
8+
- qemu_riscv64
9+
- qemu_x86
10+
- qemu_x86_64
11+
# llvm currently excluded due to 'inttypes.h' file not found
12+
toolchain_exclude:
13+
- llvm
14+
tests:
15+
cpp.condition_variable.newlib.except:
16+
tags: newlib
17+
filter: CONFIG_NEWLIB_LIBC_SUPPORTED
18+
extra_configs:
19+
- CONFIG_NEWLIB_LIBC=y
20+
- CONFIG_CPP_EXCEPTIONS=y
21+
cpp.condition_variable.newlib.noexcept:
22+
tags: newlib
23+
filter: CONFIG_NEWLIB_LIBC_SUPPORTED
24+
extra_configs:
25+
- CONFIG_NEWLIB_LIBC=y

0 commit comments

Comments
 (0)