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