Skip to content

Commit 20b24a9

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 20b24a9

File tree

4 files changed

+307
-0
lines changed

4 files changed

+307
-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: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CONFIG_POSIX_API=y
2+
CONFIG_ZTEST=y
3+
4+
CONFIG_POSIX_AEP_CHOICE_BASE=y
5+
CONFIG_XSI_REALTIME_THREADS=y
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
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 void *thread_entry(void *arg)
21+
{
22+
bool joinable = (bool)POINTER_TO_UINT(arg);
23+
24+
if (!joinable) {
25+
detached_thread_has_finished = true;
26+
}
27+
28+
return NULL;
29+
}
30+
31+
static void *inheritsched_entry(void *arg)
32+
{
33+
int prio;
34+
int inheritsched;
35+
int pprio = POINTER_TO_INT(arg);
36+
37+
zassert_ok(pthread_attr_getinheritsched(&attr, &inheritsched));
38+
39+
prio = k_thread_priority_get(k_current_get());
40+
41+
if (inheritsched == PTHREAD_INHERIT_SCHED) {
42+
/*
43+
* There will be numerical overlap between posix priorities in different scheduler
44+
* policies so only check the Zephyr priority here. The posix policy and posix
45+
* priority are derived from the Zephyr priority in any case.
46+
*/
47+
zassert_equal(prio, pprio, "actual priority: %d, expected priority: %d", prio,
48+
pprio);
49+
return NULL;
50+
}
51+
52+
/* inheritsched == PTHREAD_EXPLICIT_SCHED */
53+
int act_prio;
54+
int exp_prio;
55+
int act_policy;
56+
int exp_policy;
57+
struct sched_param param;
58+
59+
/* get the actual policy, param, etc */
60+
zassert_ok(pthread_getschedparam(pthread_self(), &act_policy, &param));
61+
act_prio = param.sched_priority;
62+
63+
/* get the expected policy, param, etc */
64+
zassert_ok(pthread_attr_getschedpolicy(&attr, &exp_policy));
65+
zassert_ok(pthread_attr_getschedparam(&attr, &param));
66+
exp_prio = param.sched_priority;
67+
68+
/* compare actual vs expected */
69+
zassert_equal(act_policy, exp_policy, "actual policy: %d, expected policy: %d", act_policy,
70+
exp_policy);
71+
zassert_equal(act_prio, exp_prio, "actual priority: %d, expected priority: %d", act_prio,
72+
exp_prio);
73+
74+
return NULL;
75+
}
76+
77+
static void create_thread_common_entry(const pthread_attr_t *attrp, bool expect_success,
78+
bool joinable, void *(*entry)(void *arg), void *arg)
79+
{
80+
pthread_t th;
81+
82+
if (!joinable) {
83+
detached_thread_has_finished = false;
84+
}
85+
86+
if (expect_success) {
87+
zassert_ok(pthread_create(&th, attrp, entry, arg));
88+
} else {
89+
zassert_not_ok(pthread_create(&th, attrp, entry, arg));
90+
return;
91+
}
92+
93+
if (joinable) {
94+
zassert_ok(pthread_join(th, NULL), "failed to join joinable thread");
95+
return;
96+
}
97+
98+
/* should not be able to join detached thread */
99+
zassert_not_ok(pthread_join(th, NULL));
100+
101+
for (size_t i = 0; i < 10; ++i) {
102+
k_msleep(2 * CONFIG_PTHREAD_RECYCLER_DELAY_MS);
103+
if (detached_thread_has_finished) {
104+
break;
105+
}
106+
}
107+
108+
zassert_true(detached_thread_has_finished, "detached thread did not seem to finish");
109+
}
110+
111+
static void create_thread_common(const pthread_attr_t *attrp, bool expect_success, bool joinable)
112+
{
113+
create_thread_common_entry(attrp, expect_success, joinable, thread_entry,
114+
UINT_TO_POINTER(joinable));
115+
}
116+
117+
static inline void can_create_thread(const pthread_attr_t *attrp)
118+
{
119+
create_thread_common(attrp, true, true);
120+
}
121+
122+
static void test_pthread_attr_setinheritsched_common(bool inheritsched)
123+
{
124+
int prio;
125+
int policy;
126+
struct sched_param param;
127+
128+
extern int zephyr_to_posix_priority(int priority, int *policy);
129+
130+
prio = k_thread_priority_get(k_current_get());
131+
zassert_not_equal(prio, K_LOWEST_APPLICATION_THREAD_PRIO);
132+
133+
/*
134+
* values affected by inheritsched are policy / priority / contentionscope
135+
*
136+
* we only support PTHREAD_SCOPE_SYSTEM, so no need to set contentionscope
137+
*/
138+
prio = K_LOWEST_APPLICATION_THREAD_PRIO;
139+
param.sched_priority = zephyr_to_posix_priority(prio, &policy);
140+
141+
zassert_ok(pthread_attr_setschedpolicy(&attr, policy));
142+
zassert_ok(pthread_attr_setschedparam(&attr, &param));
143+
zassert_ok(pthread_attr_setinheritsched(&attr, inheritsched));
144+
create_thread_common_entry(&attr, true, true, inheritsched_entry,
145+
UINT_TO_POINTER(k_thread_priority_get(k_current_get())));
146+
}
147+
148+
ZTEST(xsi_realtime_threads, test_pthread_attr_setinheritsched)
149+
{
150+
/* degenerate cases */
151+
{
152+
if (false) {
153+
/* undefined behaviour */
154+
zassert_equal(pthread_attr_setinheritsched(NULL, PTHREAD_EXPLICIT_SCHED),
155+
EINVAL);
156+
zassert_equal(pthread_attr_setinheritsched(NULL, PTHREAD_INHERIT_SCHED),
157+
EINVAL);
158+
zassert_equal(pthread_attr_setinheritsched((pthread_attr_t *)&uninit_attr,
159+
PTHREAD_INHERIT_SCHED),
160+
EINVAL);
161+
}
162+
zassert_equal(pthread_attr_setinheritsched(&attr, 3), EINVAL);
163+
}
164+
165+
/* valid cases */
166+
test_pthread_attr_setinheritsched_common(PTHREAD_INHERIT_SCHED);
167+
test_pthread_attr_setinheritsched_common(PTHREAD_EXPLICIT_SCHED);
168+
}
169+
170+
ZTEST(xsi_realtime_threads, test_pthread_attr_getinheritsched)
171+
{
172+
int inheritsched = BIOS_FOOD;
173+
174+
/* degenerate cases */
175+
{
176+
if (false) {
177+
/* undefined behaviour */
178+
zassert_equal(pthread_attr_getinheritsched(NULL, NULL), EINVAL);
179+
zassert_equal(pthread_attr_getinheritsched(NULL, &inheritsched), EINVAL);
180+
zassert_equal(pthread_attr_getinheritsched(&uninit_attr, &inheritsched),
181+
EINVAL);
182+
}
183+
zassert_equal(pthread_attr_getinheritsched(&attr, NULL), EINVAL);
184+
}
185+
186+
zassert_ok(pthread_attr_getinheritsched(&attr, &inheritsched));
187+
zassert_equal(inheritsched, PTHREAD_INHERIT_SCHED);
188+
}
189+
190+
ZTEST(xsi_realtime_threads, test_pthread_attr_getschedparam)
191+
{
192+
struct sched_param param = {
193+
.sched_priority = BIOS_FOOD,
194+
};
195+
196+
/* degenerate cases */
197+
{
198+
if (false) {
199+
/* undefined behaviour */
200+
zassert_equal(pthread_attr_getschedparam(NULL, NULL), EINVAL);
201+
zassert_equal(pthread_attr_getschedparam(NULL, &param), EINVAL);
202+
zassert_equal(pthread_attr_getschedparam(&uninit_attr, &param), EINVAL);
203+
}
204+
zassert_equal(pthread_attr_getschedparam(&attr, NULL), EINVAL);
205+
}
206+
207+
/* only check to see that the function succeeds and sets param */
208+
zassert_ok(pthread_attr_getschedparam(&attr, &param));
209+
zassert_not_equal(BIOS_FOOD, param.sched_priority);
210+
}
211+
212+
ZTEST(xsi_realtime_threads, test_pthread_attr_setschedparam)
213+
{
214+
struct sched_param param = {0};
215+
216+
/* degenerate cases */
217+
{
218+
if (false) {
219+
/* undefined behaviour */
220+
zassert_equal(pthread_attr_setschedparam(NULL, NULL), EINVAL);
221+
zassert_equal(pthread_attr_setschedparam(NULL, &param), EINVAL);
222+
zassert_equal(
223+
pthread_attr_setschedparam((pthread_attr_t *)&uninit_attr, &param),
224+
EINVAL);
225+
}
226+
zassert_equal(pthread_attr_setschedparam(&attr, NULL), EINVAL);
227+
}
228+
229+
zassert_ok(pthread_attr_setschedparam(&attr, &param));
230+
231+
can_create_thread(&attr);
232+
}
233+
234+
static void *test_pthread_setschedprio_fn(void *arg)
235+
{
236+
int policy;
237+
int prio = 0;
238+
struct sched_param param;
239+
pthread_t self = pthread_self();
240+
241+
zassert_equal(pthread_setschedprio(self, PRIO_INVALID), EINVAL, "EINVAL was expected");
242+
zassert_equal(pthread_setschedprio(PTHREAD_INVALID, prio), ESRCH, "ESRCH was expected");
243+
244+
zassert_ok(pthread_setschedprio(self, prio));
245+
param.sched_priority = ~prio;
246+
zassert_ok(pthread_getschedparam(self, &policy, &param));
247+
zassert_equal(param.sched_priority, prio, "Priority unchanged");
248+
249+
return NULL;
250+
}
251+
252+
ZTEST(xsi_realtime_threads, test_pthread_setschedprio)
253+
{
254+
pthread_t th;
255+
256+
zassert_ok(pthread_create(&th, NULL, test_pthread_setschedprio_fn, NULL));
257+
zassert_ok(pthread_join(th, NULL));
258+
}
259+
260+
ZTEST_SUITE(xsi_realtime_threads, NULL, NULL, NULL, NULL, NULL);
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)