Skip to content

Commit cdaffef

Browse files
youvedeep-singhAnas Nashif
authored andcommitted
tests: kernel: posix: pthread: Add pthread test.
This test is POSIX based implementation of tests:kernel:pthread test. It used POSIX APIs instead of Zephyr APIs. Signed-off-by: Youvedeep Singh <[email protected]>
1 parent 2d37286 commit cdaffef

File tree

4 files changed

+256
-0
lines changed

4 files changed

+256
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
2+
project(NONE)
3+
4+
target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/include/posix)
5+
FILE(GLOB app_sources src/*.c)
6+
target_sources(app PRIVATE ${app_sources})
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
CONFIG_TEST=y
2+
CONFIG_PTHREAD_IPC=y
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/*
2+
* Copyright (c) 2017 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <tc_util.h>
8+
#include <kernel.h>
9+
#include <pthread.h>
10+
11+
#define N_THR 3
12+
13+
#define BOUNCES 64
14+
15+
#define STACKSZ 1024
16+
17+
K_THREAD_STACK_ARRAY_DEFINE(stacks, N_THR, STACKSZ);
18+
19+
void *thread_top(void *p1);
20+
21+
PTHREAD_MUTEX_DEFINE(lock);
22+
23+
PTHREAD_COND_DEFINE(cvar0);
24+
25+
PTHREAD_COND_DEFINE(cvar1);
26+
27+
PTHREAD_BARRIER_DEFINE(barrier, N_THR);
28+
29+
K_SEM_DEFINE(main_sem, 0, 2*N_THR);
30+
31+
static int bounce_failed;
32+
static int bounce_done[N_THR];
33+
34+
static int curr_bounce_thread;
35+
36+
static int barrier_failed;
37+
static int barrier_done[N_THR];
38+
39+
/* First phase bounces execution between two threads using a condition
40+
* variable, continuously testing that no other thread is mucking with
41+
* the protected state. This ends with all threads going back to
42+
* sleep on the condition variable and being woken by main() for the
43+
* second phase.
44+
*
45+
* Second phase simply lines up all the threads on a barrier, verifies
46+
* that none run until the last one enters, and that all run after the
47+
* exit.
48+
*
49+
* Test success is signaled to main() using a traditional semaphore.
50+
*/
51+
52+
void *thread_top(void *p1)
53+
{
54+
int i, j, id = (int) p1;
55+
int policy;
56+
struct sched_param schedparam;
57+
58+
pthread_getschedparam(pthread_self(), &policy, &schedparam);
59+
TC_PRINT("Thread %d starting with scheduling policy %d & priority %d\n",
60+
id, policy, schedparam.priority);
61+
/* Try a double-lock here to exercise the failing case of
62+
* trylock. We don't support RECURSIVE locks, so this is
63+
* guaranteed to fail.
64+
*/
65+
pthread_mutex_lock(&lock);
66+
67+
if (!pthread_mutex_trylock(&lock)) {
68+
TC_ERROR("pthread_mutex_trylock inexplicably succeeded\n");
69+
bounce_failed = 1;
70+
}
71+
72+
pthread_mutex_unlock(&lock);
73+
74+
for (i = 0; i < BOUNCES; i++) {
75+
76+
pthread_mutex_lock(&lock);
77+
78+
/* Wait for the current owner to signal us, unless we
79+
* are the very first thread, in which case we need to
80+
* wait a bit to be sure the other threads get
81+
* scheduled and wait on cvar0.
82+
*/
83+
if (!(id == 0 && i == 0)) {
84+
pthread_cond_wait(&cvar0, &lock);
85+
} else {
86+
pthread_mutex_unlock(&lock);
87+
usleep(500 * USEC_PER_MSEC);
88+
pthread_mutex_lock(&lock);
89+
}
90+
91+
/* Claim ownership, then try really hard to give someone
92+
* else a shot at hitting this if they are racing.
93+
*/
94+
curr_bounce_thread = id;
95+
for (j = 0; j < 1000; j++) {
96+
if (curr_bounce_thread != id) {
97+
TC_ERROR("Racing bounce threads\n");
98+
bounce_failed = 1;
99+
k_sem_give(&main_sem);
100+
pthread_mutex_unlock(&lock);
101+
return NULL;
102+
}
103+
sched_yield();
104+
}
105+
106+
/* Next one's turn, go back to the top and wait. */
107+
pthread_cond_signal(&cvar0);
108+
pthread_mutex_unlock(&lock);
109+
}
110+
111+
/* Signal we are complete to main(), then let it wake us up. Note
112+
* that we are using the same mutex with both cvar0 and cvar1,
113+
* which is non-standard but kosher per POSIX (and it works fine
114+
* in our implementation
115+
*/
116+
pthread_mutex_lock(&lock);
117+
bounce_done[id] = 1;
118+
k_sem_give(&main_sem);
119+
pthread_cond_wait(&cvar1, &lock);
120+
pthread_mutex_unlock(&lock);
121+
122+
/* Now just wait on the barrier. Make sure no one else finished
123+
* before we wait on it, then signal that we're done
124+
*/
125+
for (i = 0; i < N_THR; i++) {
126+
if (barrier_done[i]) {
127+
TC_ERROR("Barrier exited early\n");
128+
barrier_failed = 1;
129+
k_sem_give(&main_sem);
130+
}
131+
}
132+
pthread_barrier_wait(&barrier);
133+
barrier_done[id] = 1;
134+
k_sem_give(&main_sem);
135+
pthread_exit(p1);
136+
137+
return NULL;
138+
}
139+
140+
int bounce_test_done(void)
141+
{
142+
int i;
143+
144+
if (bounce_failed) {
145+
return 1;
146+
}
147+
148+
for (i = 0; i < N_THR; i++) {
149+
if (!bounce_done[i]) {
150+
return 0;
151+
}
152+
}
153+
154+
return 1;
155+
}
156+
157+
int barrier_test_done(void)
158+
{
159+
int i;
160+
161+
if (barrier_failed) {
162+
return 1;
163+
}
164+
165+
for (i = 0; i < N_THR; i++) {
166+
if (!barrier_done[i]) {
167+
return 0;
168+
}
169+
}
170+
171+
return 1;
172+
}
173+
174+
void main(void)
175+
{
176+
int i, ret, min_prio, max_prio, status = TC_FAIL;
177+
pthread_attr_t attr[N_THR];
178+
struct sched_param schedparam;
179+
pthread_t newthread[N_THR];
180+
int schedpolicy = SCHED_FIFO;
181+
void *retval;
182+
183+
TC_START("POSIX thread IPC APIs\n");
184+
schedparam.priority = CONFIG_NUM_COOP_PRIORITIES - 1;
185+
min_prio = sched_get_priority_min(schedpolicy);
186+
max_prio = sched_get_priority_max(schedpolicy);
187+
188+
if (min_prio < 0 || max_prio < 0 || schedparam.priority < min_prio ||
189+
schedparam.priority > max_prio) {
190+
TC_ERROR("Scheduling priority outside valid priority range\n");
191+
goto done;
192+
}
193+
194+
for (i = 0; i < N_THR; i++) {
195+
ret = pthread_attr_init(&attr[i]);
196+
if (ret != 0) {
197+
TC_ERROR("Thread attribute initialization failed\n");
198+
goto done;
199+
}
200+
pthread_attr_setstack(&attr[i], &stacks[i][0], STACKSZ);
201+
pthread_attr_setschedpolicy(&attr[i], schedpolicy);
202+
pthread_attr_setschedparam(&attr[i], &schedparam);
203+
ret = pthread_create(&newthread[i], &attr[i], thread_top,
204+
(void *)i);
205+
206+
if (ret != 0) {
207+
TC_ERROR("Number of threads exceeds maximum limit\n");
208+
goto done;
209+
}
210+
211+
}
212+
213+
while (!bounce_test_done()) {
214+
k_sem_take(&main_sem, K_FOREVER);
215+
}
216+
217+
if (bounce_failed) {
218+
goto done;
219+
}
220+
221+
TC_PRINT("Bounce test OK\n");
222+
223+
/* Wake up the worker threads */
224+
pthread_mutex_lock(&lock);
225+
pthread_cond_broadcast(&cvar1);
226+
pthread_mutex_unlock(&lock);
227+
228+
while (!barrier_test_done()) {
229+
k_sem_take(&main_sem, K_FOREVER);
230+
}
231+
232+
if (barrier_failed) {
233+
goto done;
234+
}
235+
236+
for (i = 0; i < N_THR; i++) {
237+
pthread_join(newthread[i], &retval);
238+
}
239+
240+
TC_PRINT("Barrier test OK\n");
241+
status = TC_PASS;
242+
243+
done:
244+
TC_END_REPORT(status);
245+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
tests:
2+
test:
3+
tags: core

0 commit comments

Comments
 (0)