Skip to content

Commit ad96b26

Browse files
committed
tests: posix: common: separate xsi_realtime_threads into standalone test
posix.common contains testsuites that can be separated into smaller groups of tests. This change moves tests in the xsi_realtime_threads option group into a singular testsuite tests/posix/xsi_realtime_threads app directory. Signed-off-by: Marvin Ouma <[email protected]>
1 parent 1903a8f commit ad96b26

File tree

4 files changed

+332
-0
lines changed

4 files changed

+332
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
5+
project(xsi_realtime_threads)
6+
7+
FILE(GLOB app_sources src/*.c)
8+
9+
target_sources(app PRIVATE ${app_sources})
10+
11+
target_compile_options(app PRIVATE -U_POSIX_C_SOURCE -D_POSIX_C_SOURCE=200809L)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CONFIG_ZTEST=y
2+
3+
CONFIG_POSIX_API=y
4+
5+
CONFIG_POSIX_AEP_CHOICE_BASE=y
6+
CONFIG_XSI_REALTIME_THREADS=y
7+
CONFIG_ASSERT_VERBOSE=y
8+
CONFIG_POSIX_THREAD_PRIORITY_SCHEDULING=y
9+
10+
CONFIG_DYNAMIC_THREAD=y
11+
CONFIG_DYNAMIC_THREAD_POOL_SIZE=6
12+
CONFIG_DYNAMIC_THREAD_STACK_SIZE=2048
13+
CONFIG_THREAD_STACK_INFO=y
14+
CONFIG_HEAP_MEM_POOL_SIZE=4096
15+
16+
CONFIG_LOG=y
17+
CONFIG_LOG_MODE_IMMEDIATE=y
18+
CONFIG_LOG_DEFAULT_LEVEL=4
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
/*
2+
* Copyright (c) 2025 Marvin Ouma
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <pthread.h>
8+
9+
#include <zephyr/ztest.h>
10+
#include <zephyr/sys/util.h>
11+
12+
#define BIOS_FOOD 0xB105F00D
13+
#define PRIO_INVALID -1
14+
#define PTHREAD_INVALID -1
15+
16+
static pthread_attr_t attr;
17+
static const pthread_attr_t uninit_attr;
18+
static bool detached_thread_has_finished;
19+
20+
static bool xsi_realtime_threads_predicate(const void *global_state)
21+
{
22+
pthread_attr_init(&attr);
23+
pthread_attr_setstacksize(&attr, 1024);
24+
return true;
25+
}
26+
27+
static void xsi_realtime_threads_teardown(void *fixture)
28+
{
29+
pthread_attr_destroy(&attr);
30+
}
31+
32+
static void *thread_entry(void *arg)
33+
{
34+
bool joinable = (bool)POINTER_TO_UINT(arg);
35+
36+
if (!joinable) {
37+
detached_thread_has_finished = true;
38+
}
39+
40+
return NULL;
41+
}
42+
43+
static void *inheritsched_entry(void *arg)
44+
{
45+
int prio;
46+
int inheritsched;
47+
int pprio = POINTER_TO_INT(arg);
48+
49+
zassert_ok(pthread_attr_getinheritsched(&attr, &inheritsched));
50+
51+
prio = k_thread_priority_get(k_current_get());
52+
53+
if (inheritsched == PTHREAD_INHERIT_SCHED) {
54+
/*
55+
* There will be numerical overlap between posix priorities in different scheduler
56+
* policies so only check the Zephyr priority here. The posix policy and posix
57+
* priority are derived from the Zephyr priority in any case.
58+
*/
59+
zassert_equal(prio, pprio, "actual priority: %d, expected priority: %d", prio,
60+
pprio);
61+
return NULL;
62+
}
63+
64+
/* inheritsched == PTHREAD_EXPLICIT_SCHED */
65+
int act_prio;
66+
int exp_prio;
67+
int act_policy;
68+
int exp_policy;
69+
struct sched_param param;
70+
71+
/* get the actual policy, param, etc */
72+
zassert_ok(pthread_getschedparam(pthread_self(), &act_policy, &param));
73+
act_prio = param.sched_priority;
74+
75+
/* get the expected policy, param, etc */
76+
zassert_ok(pthread_attr_getschedpolicy(&attr, &exp_policy));
77+
zassert_ok(pthread_attr_getschedparam(&attr, &param));
78+
exp_prio = param.sched_priority;
79+
80+
/* compare actual vs expected */
81+
zassert_equal(act_policy, exp_policy, "actual policy: %d, expected policy: %d", act_policy,
82+
exp_policy);
83+
zassert_equal(act_prio, exp_prio, "actual priority: %d, expected priority: %d", act_prio,
84+
exp_prio);
85+
86+
return NULL;
87+
}
88+
89+
static void create_thread_common_entry(const pthread_attr_t *attrp, bool expect_success,
90+
bool joinable, void *(*entry)(void *arg), void *arg)
91+
{
92+
pthread_t th;
93+
94+
if (!joinable) {
95+
detached_thread_has_finished = false;
96+
}
97+
98+
if (expect_success) {
99+
zassert_ok(pthread_create(&th, attrp, entry, arg));
100+
} else {
101+
zassert_not_ok(pthread_create(&th, attrp, entry, arg));
102+
return;
103+
}
104+
105+
if (joinable) {
106+
zassert_ok(pthread_join(th, NULL), "failed to join joinable thread");
107+
return;
108+
}
109+
110+
/* should not be able to join detached thread */
111+
zassert_not_ok(pthread_join(th, NULL));
112+
113+
for (size_t i = 0; i < 10; ++i) {
114+
k_msleep(2 * CONFIG_PTHREAD_RECYCLER_DELAY_MS);
115+
if (detached_thread_has_finished) {
116+
break;
117+
}
118+
}
119+
120+
zassert_true(detached_thread_has_finished, "detached thread did not seem to finish");
121+
}
122+
123+
static void create_thread_common(const pthread_attr_t *attrp, bool expect_success, bool joinable)
124+
{
125+
create_thread_common_entry(attrp, expect_success, joinable, thread_entry,
126+
UINT_TO_POINTER(joinable));
127+
}
128+
129+
static inline void can_create_thread(const pthread_attr_t *attrp)
130+
{
131+
create_thread_common(attrp, true, true);
132+
}
133+
134+
static void test_pthread_attr_setinheritsched_common(bool inheritsched)
135+
{
136+
int prio;
137+
int policy;
138+
struct sched_param param;
139+
140+
extern int zephyr_to_posix_priority(int priority, int *policy);
141+
142+
prio = k_thread_priority_get(k_current_get());
143+
zassert_not_equal(prio, K_LOWEST_APPLICATION_THREAD_PRIO);
144+
145+
/*
146+
* values affected by inheritsched are policy / priority / contentionscope
147+
*
148+
* we only support PTHREAD_SCOPE_SYSTEM, so no need to set contentionscope
149+
*/
150+
prio = K_LOWEST_APPLICATION_THREAD_PRIO;
151+
param.sched_priority = zephyr_to_posix_priority(prio, &policy);
152+
153+
zassert_ok(pthread_attr_setschedpolicy(&attr, policy));
154+
zassert_ok(pthread_attr_setschedparam(&attr, &param));
155+
zassert_ok(pthread_attr_setinheritsched(&attr, inheritsched));
156+
create_thread_common_entry(&attr, true, true, inheritsched_entry,
157+
UINT_TO_POINTER(k_thread_priority_get(k_current_get())));
158+
}
159+
160+
ZTEST(xsi_realtime_threads, test_pthread_attr_setinheritsched)
161+
{
162+
/* degenerate cases */
163+
{
164+
if (false) {
165+
/* undefined behaviour */
166+
zassert_equal(pthread_attr_setinheritsched(NULL, PTHREAD_EXPLICIT_SCHED),
167+
EINVAL);
168+
zassert_equal(pthread_attr_setinheritsched(NULL, PTHREAD_INHERIT_SCHED),
169+
EINVAL);
170+
zassert_equal(pthread_attr_setinheritsched((pthread_attr_t *)&uninit_attr,
171+
PTHREAD_INHERIT_SCHED),
172+
EINVAL);
173+
}
174+
zassert_equal(pthread_attr_setinheritsched(&attr, 3), EINVAL);
175+
}
176+
177+
/* valid cases */
178+
test_pthread_attr_setinheritsched_common(PTHREAD_INHERIT_SCHED);
179+
test_pthread_attr_setinheritsched_common(PTHREAD_EXPLICIT_SCHED);
180+
}
181+
182+
ZTEST(xsi_realtime_threads, test_pthread_attr_getinheritsched)
183+
{
184+
int inheritsched = BIOS_FOOD;
185+
186+
/* degenerate cases */
187+
{
188+
if (false) {
189+
/* undefined behaviour */
190+
zassert_equal(pthread_attr_getinheritsched(NULL, NULL), EINVAL);
191+
zassert_equal(pthread_attr_getinheritsched(NULL, &inheritsched), EINVAL);
192+
zassert_equal(pthread_attr_getinheritsched(&uninit_attr, &inheritsched),
193+
EINVAL);
194+
}
195+
zassert_equal(pthread_attr_getinheritsched(&attr, NULL), EINVAL);
196+
}
197+
198+
zassert_ok(pthread_attr_getinheritsched(&attr, &inheritsched));
199+
zassert_equal(inheritsched, PTHREAD_INHERIT_SCHED);
200+
}
201+
202+
ZTEST(xsi_realtime_threads, test_pthread_attr_getschedparam)
203+
{
204+
struct sched_param param = {
205+
.sched_priority = BIOS_FOOD,
206+
};
207+
208+
/* degenerate cases */
209+
{
210+
if (false) {
211+
/* undefined behaviour */
212+
zassert_equal(pthread_attr_getschedparam(NULL, NULL), EINVAL);
213+
zassert_equal(pthread_attr_getschedparam(NULL, &param), EINVAL);
214+
zassert_equal(pthread_attr_getschedparam(&uninit_attr, &param), EINVAL);
215+
}
216+
zassert_equal(pthread_attr_getschedparam(&attr, NULL), EINVAL);
217+
}
218+
219+
/* only check to see that the function succeeds and sets param */
220+
zassert_ok(pthread_attr_getschedparam(&attr, &param));
221+
zassert_not_equal(BIOS_FOOD, param.sched_priority);
222+
}
223+
224+
ZTEST(xsi_realtime_threads, test_pthread_attr_setschedparam)
225+
{
226+
struct sched_param param = {0};
227+
/* degenerate cases */
228+
{
229+
if (false) {
230+
/* undefined behaviour */
231+
zassert_equal(pthread_attr_setschedparam(NULL, NULL), EINVAL);
232+
zassert_equal(pthread_attr_setschedparam(NULL, &param), EINVAL);
233+
zassert_equal(
234+
pthread_attr_setschedparam((pthread_attr_t *)&uninit_attr, &param),
235+
EINVAL);
236+
}
237+
zassert_equal(pthread_attr_setschedparam(&attr, NULL), EINVAL);
238+
}
239+
240+
zassert_ok(pthread_attr_setschedparam(&attr, &param));
241+
242+
can_create_thread(&attr);
243+
}
244+
245+
static void *test_pthread_setschedprio_fn(void *arg)
246+
{
247+
int policy;
248+
int prio = 0;
249+
struct sched_param param;
250+
pthread_t self = pthread_self();
251+
252+
zassert_equal(pthread_setschedprio(self, PRIO_INVALID), EINVAL, "EINVAL was expected");
253+
zassert_equal(pthread_setschedprio(PTHREAD_INVALID, prio), ESRCH, "ESRCH was expected");
254+
255+
zassert_ok(pthread_setschedprio(self, prio));
256+
param.sched_priority = ~prio;
257+
zassert_ok(pthread_getschedparam(self, &policy, &param));
258+
zassert_equal(param.sched_priority, prio, "Priority unchanged");
259+
260+
return NULL;
261+
}
262+
263+
ZTEST(xsi_realtime_threads, test_pthread_setschedprio)
264+
{
265+
pthread_t th;
266+
267+
zassert_ok(pthread_create(&th, NULL, test_pthread_setschedprio_fn, NULL));
268+
zassert_ok(pthread_join(th, NULL));
269+
}
270+
271+
ZTEST_SUITE(xsi_realtime_threads, xsi_realtime_threads_predicate, NULL, NULL, NULL,
272+
xsi_realtime_threads_teardown);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
common:
2+
filter: not CONFIG_NATIVE_LIBC
3+
tags:
4+
- posix
5+
- xsi_realtime_threads
6+
# 1 tier0 platform per supported architecture
7+
platform_key:
8+
- arch
9+
- simulation
10+
min_flash: 64
11+
min_ram: 32
12+
timeout: 240
13+
platform_exclude:
14+
# linker_zephyr_pre0.cmd:140: syntax error (??)
15+
- qemu_xtensa/dc233c
16+
- native_sim
17+
- native_sim/native/64
18+
tests:
19+
portability.posix.xsi_realtime_threads: {}
20+
portability.posix.xsi_realtime_threads.minimal:
21+
extra_configs:
22+
- CONFIG_MINIMAL_LIBC=y
23+
portability.posix.xsi_realtime_threads.newlib:
24+
filter: TOOLCHAIN_HAS_NEWLIB == 1
25+
extra_configs:
26+
- CONFIG_NEWLIB_LIBC=y
27+
portability.posix.xsi_realtime_threads.picolibc:
28+
tags: picolibc
29+
filter: CONFIG_PICOLIBC_SUPPORTED
30+
extra_configs:
31+
- CONFIG_PICOLIBC=y

0 commit comments

Comments
 (0)