1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 #include <cmsis_os2.h>
10
11 #define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE
12
13 /* This is used to check the thread yield functionality between 2 threads */
14 static int thread_yield_check;
15 static int thread_yield_check_dynamic;
16
17 static K_THREAD_STACK_DEFINE(test_stack1, STACKSZ);
18 static osThreadAttr_t os_thread1_attr = {
19 .name = "Thread1",
20 .stack_mem = &test_stack1,
21 .stack_size = STACKSZ,
22 .priority = osPriorityHigh,
23 };
24
25 static K_THREAD_STACK_DEFINE(test_stack2, STACKSZ);
26 static osThreadAttr_t os_thread2_attr = {
27 .name = "Thread2",
28 .stack_mem = &test_stack2,
29 .stack_size = STACKSZ,
30 .priority = osPriorityHigh,
31 };
32
33 struct thread1_args {
34 int *yield_check;
35 const char *name;
36 };
37
thread1(void * argument)38 static void thread1(void *argument)
39 {
40 osStatus_t status;
41 osThreadId_t thread_id;
42 const char *name;
43 struct thread1_args *args = (struct thread1_args *)argument;
44
45 thread_id = osThreadGetId();
46 zassert_true(thread_id != NULL, "Failed getting Thread ID");
47
48 name = osThreadGetName(thread_id);
49 zassert_str_equal(args->name, name, "Failed getting Thread name");
50
51 /* This thread starts off at a high priority (same as thread2) */
52 (*args->yield_check)++;
53 zassert_equal(*args->yield_check, 1);
54
55 /* Yield to thread2 which is of same priority */
56 status = osThreadYield();
57 zassert_true(status == osOK, "Error doing thread yield");
58
59 /* thread_yield_check should now be 2 as it was incremented
60 * in thread2.
61 */
62 zassert_equal(*args->yield_check, 2);
63
64 osThreadExit();
65 }
66
thread2(void * argument)67 static void thread2(void *argument)
68 {
69 uint32_t i, num_threads, max_num_threads = 5U;
70 osThreadId_t *thread_array;
71 int *yield_check = (int *)argument;
72
73 /* By now thread1 would have set thread_yield_check to 1 and would
74 * have yielded the CPU. Incrementing it over here would essentially
75 * confirm that the yield was indeed executed.
76 */
77 (*yield_check)++;
78
79 thread_array = k_calloc(max_num_threads, sizeof(osThreadId_t));
80 num_threads = osThreadEnumerate(thread_array, max_num_threads);
81 zassert_equal(num_threads, 2,
82 "Incorrect number of cmsis rtos v2 threads");
83
84 for (i = 0U; i < num_threads; i++) {
85 uint32_t size = osThreadGetStackSize(thread_array[i]);
86 uint32_t space = osThreadGetStackSpace(thread_array[i]);
87
88 zassert_true(space < size,
89 "stack size remaining is not what is expected");
90 }
91
92 zassert_equal(osThreadGetState(thread_array[1]), osThreadReady,
93 "Thread not in ready state");
94 zassert_equal(osThreadGetState(thread_array[0]), osThreadRunning,
95 "Thread not in running state");
96
97 zassert_equal(osThreadSuspend(thread_array[1]), osOK, "");
98 zassert_equal(osThreadGetState(thread_array[1]), osThreadBlocked,
99 "Thread not in blocked state");
100
101 zassert_equal(osThreadResume(thread_array[1]), osOK, "");
102 zassert_equal(osThreadGetState(thread_array[1]), osThreadReady,
103 "Thread not in ready state");
104
105 k_free(thread_array);
106
107 /* Yield back to thread1 which is of same priority */
108 osThreadYield();
109 }
110
thread_apis_common(int * yield_check,const char * thread1_name,osThreadAttr_t * thread1_attr,osThreadAttr_t * thread2_attr)111 static void thread_apis_common(int *yield_check,
112 const char *thread1_name,
113 osThreadAttr_t *thread1_attr,
114 osThreadAttr_t *thread2_attr)
115 {
116 osThreadId_t id1;
117 osThreadId_t id2;
118
119 struct thread1_args args = {
120 .yield_check = yield_check,
121 .name = thread1_name
122 };
123
124 id1 = osThreadNew(thread1, &args, thread1_attr);
125 zassert_true(id1 != NULL, "Failed creating thread1");
126
127 id2 = osThreadNew(thread2, yield_check, thread2_attr);
128 zassert_true(id2 != NULL, "Failed creating thread2");
129
130 zassert_equal(osThreadGetCount(), 2,
131 "Incorrect number of cmsis rtos v2 threads");
132
133 do {
134 osDelay(100);
135 } while (*yield_check != 2);
136 }
137
ZTEST(cmsis_thread_apis,test_thread_apis_dynamic)138 ZTEST(cmsis_thread_apis, test_thread_apis_dynamic)
139 {
140 thread_apis_common(&thread_yield_check_dynamic, "ZephyrThread",
141 NULL, NULL);
142 }
143
ZTEST(cmsis_thread_apis,test_thread_apis)144 ZTEST(cmsis_thread_apis, test_thread_apis)
145 {
146 thread_apis_common(&thread_yield_check, os_thread1_attr.name,
147 &os_thread1_attr, &os_thread2_attr);
148 }
149
150 static osPriority_t OsPriorityInvalid = 60;
151
152 /* This is used to indicate the completion of processing for thread3 */
153 static int thread3_state;
154 static int thread3_state_dynamic;
155
156 static K_THREAD_STACK_DEFINE(test_stack3, STACKSZ);
157 static osThreadAttr_t thread3_attr = {
158 .name = "Thread3",
159 .stack_mem = &test_stack3,
160 .stack_size = STACKSZ,
161 .priority = osPriorityNormal,
162 };
163
thread3(void * argument)164 static void thread3(void *argument)
165 {
166 osStatus_t status;
167 osPriority_t rv;
168 osThreadId_t id = osThreadGetId();
169 osPriority_t prio = osThreadGetPriority(id);
170 int *state = (int *)argument;
171
172 /* Lower the priority of the current thread */
173 osThreadSetPriority(id, osPriorityBelowNormal);
174 rv = osThreadGetPriority(id);
175 zassert_equal(rv, osPriorityBelowNormal,
176 "Expected priority to be changed to %d, not %d",
177 (int)osPriorityBelowNormal, (int)rv);
178
179 /* Increase the priority of the current thread */
180 osThreadSetPriority(id, osPriorityAboveNormal);
181 rv = osThreadGetPriority(id);
182 zassert_equal(rv, osPriorityAboveNormal,
183 "Expected priority to be changed to %d, not %d",
184 (int)osPriorityAboveNormal, (int)rv);
185
186 /* Restore the priority of the current thread */
187 osThreadSetPriority(id, prio);
188 rv = osThreadGetPriority(id);
189 zassert_equal(rv, prio,
190 "Expected priority to be changed to %d, not %d",
191 (int)prio, (int)rv);
192
193 /* Try to set unsupported priority and assert failure */
194 status = osThreadSetPriority(id, OsPriorityInvalid);
195 zassert_true(status == osErrorParameter,
196 "Something's wrong with osThreadSetPriority!");
197
198 /* Indication that thread3 is done with its processing */
199 *state = 1;
200
201 /* Keep looping till it gets killed */
202 do {
203 osDelay(100);
204 } while (1);
205 }
206
thread_prior_common(int * state,osThreadAttr_t * attr)207 static void thread_prior_common(int *state, osThreadAttr_t *attr)
208 {
209 osStatus_t status;
210 osThreadId_t id3;
211
212 id3 = osThreadNew(thread3, state, attr);
213 zassert_true(id3 != NULL, "Failed creating thread3");
214
215 /* Keep delaying 10 milliseconds to ensure thread3 is done with
216 * its execution. It loops at the end and is terminated here.
217 */
218 do {
219 osDelay(10);
220 } while (*state == 0);
221
222 status = osThreadTerminate(id3);
223 zassert_true(status == osOK, "Error terminating thread3");
224
225 /* Try to set priority to inactive thread and assert failure */
226 status = osThreadSetPriority(id3, osPriorityNormal);
227 zassert_true(status == osErrorResource,
228 "Something's wrong with osThreadSetPriority!");
229
230 /* Try to terminate inactive thread and assert failure */
231 status = osThreadTerminate(id3);
232 zassert_true(status == osErrorResource,
233 "Something's wrong with osThreadTerminate!");
234
235 *state = 0;
236 }
237
ZTEST(cmsis_thread_apis,test_thread_prio_dynamic)238 ZTEST(cmsis_thread_apis, test_thread_prio_dynamic)
239 {
240 thread_prior_common(&thread3_state_dynamic, NULL);
241 }
242
ZTEST(cmsis_thread_apis,test_thread_prio)243 ZTEST(cmsis_thread_apis, test_thread_prio)
244 {
245 thread_prior_common(&thread3_state, &thread3_attr);
246 }
247
248 #define DELAY_MS 1000
249 #define DELTA_MS 500
250
thread5(void * argument)251 static void thread5(void *argument)
252 {
253 printk(" * Thread B started.\n");
254 osDelay(k_ms_to_ticks_ceil32(DELAY_MS));
255 printk(" * Thread B joining...\n");
256 }
257
thread4(void * argument)258 static void thread4(void *argument)
259 {
260 osThreadId_t tB = argument;
261 osStatus_t status;
262
263 printk(" + Thread A started.\n");
264 status = osThreadJoin(tB);
265 zassert_equal(status, osOK, "osThreadJoin thread B failed!");
266 printk(" + Thread A joining...\n");
267 }
268
ZTEST(cmsis_thread_apis,test_thread_join)269 ZTEST(cmsis_thread_apis, test_thread_join)
270 {
271 osThreadAttr_t attr = { 0 };
272 int64_t time_stamp;
273 int64_t milliseconds_spent;
274 osThreadId_t tA, tB;
275 osStatus_t status;
276
277 attr.attr_bits = osThreadJoinable;
278
279 time_stamp = k_uptime_get();
280
281 printk(" - Creating thread B...\n");
282 tB = osThreadNew(thread5, NULL, &attr);
283 zassert_not_null(tB, "Failed to create thread B with osThreadNew!");
284
285 printk(" - Creating thread A...\n");
286 attr.priority = osPriorityLow;
287 tA = osThreadNew(thread4, tB, &attr);
288 zassert_not_null(tA, "Failed to create thread A with osThreadNew!");
289
290 printk(" - Waiting for thread B to join...\n");
291 status = osThreadJoin(tB);
292 zassert_equal(status, osOK, "osThreadJoin thread B failed!");
293
294 if (status == osOK) {
295 printk(" - Thread B joined.\n");
296 }
297
298 milliseconds_spent = k_uptime_delta(&time_stamp);
299 zassert_true((milliseconds_spent >= DELAY_MS - DELTA_MS) &&
300 (milliseconds_spent <= DELAY_MS + DELTA_MS),
301 "Join completed but was too fast or too slow.");
302
303 printk(" - Waiting for thread A to join...\n");
304 status = osThreadJoin(tA);
305 zassert_equal(status, osOK, "osThreadJoin thread A failed!");
306
307 if (status == osOK) {
308 printk(" - Thread A joined.\n");
309 }
310 }
311
ZTEST(cmsis_thread_apis,test_thread_detached)312 ZTEST(cmsis_thread_apis, test_thread_detached)
313 {
314 osThreadId_t thread;
315 osStatus_t status;
316
317 thread = osThreadNew(thread5, NULL, NULL); /* osThreadDetached */
318 zassert_not_null(thread, "Failed to create thread with osThreadNew!");
319
320 osDelay(k_ms_to_ticks_ceil32(DELAY_MS - DELTA_MS));
321
322 status = osThreadJoin(thread);
323 zassert_equal(status, osErrorResource,
324 "Incorrect status returned from osThreadJoin!");
325
326 osDelay(k_ms_to_ticks_ceil32(DELTA_MS));
327 }
328
thread6(void * argument)329 void thread6(void *argument)
330 {
331 osThreadId_t thread = argument;
332 osStatus_t status;
333
334 status = osThreadJoin(thread);
335 zassert_equal(status, osErrorResource,
336 "Incorrect status returned from osThreadJoin!");
337 }
338
ZTEST(cmsis_thread_apis,test_thread_joinable_detach)339 ZTEST(cmsis_thread_apis, test_thread_joinable_detach)
340 {
341 osThreadAttr_t attr = { 0 };
342 osThreadId_t tA, tB;
343 osStatus_t status;
344
345 attr.attr_bits = osThreadJoinable;
346
347 tA = osThreadNew(thread5, NULL, &attr);
348 zassert_not_null(tA, "Failed to create thread with osThreadNew!");
349
350 tB = osThreadNew(thread6, tA, &attr);
351 zassert_not_null(tB, "Failed to create thread with osThreadNew!");
352
353 osDelay(k_ms_to_ticks_ceil32(DELAY_MS - DELTA_MS));
354
355 status = osThreadDetach(tA);
356 zassert_equal(status, osOK, "osThreadDetach failed.");
357
358 osDelay(k_ms_to_ticks_ceil32(DELTA_MS));
359 }
360
ZTEST(cmsis_thread_apis,test_thread_joinable_terminate)361 ZTEST(cmsis_thread_apis, test_thread_joinable_terminate)
362 {
363 osThreadAttr_t attr = { 0 };
364 osThreadId_t tA, tB;
365 osStatus_t status;
366
367 attr.attr_bits = osThreadJoinable;
368
369 tA = osThreadNew(thread5, NULL, &attr);
370 zassert_not_null(tA, "Failed to create thread with osThreadNew!");
371
372 tB = osThreadNew(thread6, tA, &attr);
373 zassert_not_null(tB, "Failed to create thread with osThreadNew!");
374
375 osDelay(k_ms_to_ticks_ceil32(DELAY_MS - DELTA_MS));
376
377 status = osThreadTerminate(tA);
378 zassert_equal(status, osOK, "osThreadTerminate failed.");
379
380 osDelay(k_ms_to_ticks_ceil32(DELTA_MS));
381 }
382 ZTEST_SUITE(cmsis_thread_apis, NULL, NULL, NULL, NULL, NULL);
383