1 /*
2  * Copyright (c) 2020 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 
8 #include <zephyr/ztest.h>
9 #include <zephyr/irq_offload.h>
10 #include <zephyr/ztest_error_hook.h>
11 
12 #define STACK_SIZE     (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
13 
14 #define PRIO_WAIT (CONFIG_ZTEST_THREAD_PRIORITY)
15 #define PRIO_WAKE (CONFIG_ZTEST_THREAD_PRIORITY)
16 
17 K_THREAD_STACK_DEFINE(stack_1, STACK_SIZE);
18 K_THREAD_STACK_DEFINE(condvar_wake_stack, STACK_SIZE);
19 
20 struct k_thread condvar_tid;
21 struct k_thread condvar_wake_tid;
22 
23 struct k_condvar simple_condvar;
24 K_MUTEX_DEFINE(test_mutex);
25 
26 #define TOTAL_THREADS_WAITING (3)
27 #define TCOUNT 10
28 #define COUNT_LIMIT 12
29 
30 ZTEST_BMEM int woken;
31 ZTEST_BMEM int timeout;
32 ZTEST_BMEM int index[TOTAL_THREADS_WAITING];
33 ZTEST_BMEM int count;
34 
35 struct k_condvar multiple_condvar[TOTAL_THREADS_WAITING];
36 
37 struct k_thread multiple_tid[TOTAL_THREADS_WAITING];
38 struct k_thread multiple_wake_tid[TOTAL_THREADS_WAITING];
39 K_THREAD_STACK_ARRAY_DEFINE(multiple_stack,
40 		TOTAL_THREADS_WAITING, STACK_SIZE);
41 K_THREAD_STACK_ARRAY_DEFINE(multiple_wake_stack,
42 		TOTAL_THREADS_WAITING, STACK_SIZE);
43 
44 
45 /******************************************************************************/
46 /* Helper functions */
condvar_isr_wake(const void * condvar)47 void condvar_isr_wake(const void *condvar)
48 {
49 	k_condvar_signal((struct k_condvar *)condvar);
50 }
51 
condvar_wake_from_isr(struct k_condvar * condvar)52 void condvar_wake_from_isr(struct k_condvar *condvar)
53 {
54 	irq_offload(condvar_isr_wake, (const void *)condvar);
55 }
56 
57 /* test condvar wait, no condvar wake */
condvar_wait_task(void * p1,void * p2,void * p3)58 void condvar_wait_task(void *p1, void *p2, void *p3)
59 {
60 	int32_t ret_value;
61 	k_ticks_t time_val = *(int *)p1;
62 
63 	k_condvar_init(&simple_condvar);
64 	zassert_true(time_val >= (int)K_TICKS_FOREVER,
65 		     "invalid timeout parameter");
66 
67 	k_mutex_lock(&test_mutex, K_FOREVER);
68 	ret_value = k_condvar_wait(&simple_condvar, &test_mutex, K_TICKS(time_val));
69 
70 	switch (time_val) {
71 	case K_TICKS_FOREVER:
72 		zassert_true(ret_value == 0,
73 		     "k_condvar_wait failed.");
74 		zassert_false(ret_value == 0,
75 		     "condvar wait task wakeup.");
76 		break;
77 	case 0:
78 		zassert_true(ret_value == -EAGAIN,
79 		     "k_condvar_wait failed.");
80 		break;
81 	default:
82 		zassert_true(ret_value == -EAGAIN,
83 		     "k_condvar_wait failed.: %d", ret_value);
84 		break;
85 	}
86 
87 	k_mutex_unlock(&test_mutex);
88 
89 }
90 
condvar_wake_task(void * p1,void * p2,void * p3)91 void condvar_wake_task(void *p1, void *p2, void *p3)
92 {
93 	int32_t ret_value;
94 
95 	ret_value = k_condvar_signal(&simple_condvar);
96 	zassert_equal(ret_value, 0,
97 		"k_condvar_wake failed. (%d!=%d)", ret_value, 0);
98 }
99 
condvar_wake_multiple(void * p1,void * p2,void * p3)100 void condvar_wake_multiple(void *p1, void *p2, void *p3)
101 {
102 	int32_t ret_value;
103 	int woken_num = *(int *)p1;
104 
105 	ret_value = k_condvar_broadcast(&simple_condvar);
106 	zassert_true(ret_value == woken_num,
107 		"k_condvar_wake failed. (%d!=%d)", ret_value, woken_num);
108 }
109 
condvar_wait_wake_task(void * p1,void * p2,void * p3)110 void condvar_wait_wake_task(void *p1, void *p2, void *p3)
111 {
112 	int32_t ret_value;
113 	int time_val = *(int *)p1;
114 
115 	zassert_true(time_val >= (int)K_TICKS_FOREVER, "invalid timeout parameter");
116 	k_mutex_lock(&test_mutex, K_FOREVER);
117 	ret_value = k_condvar_wait(&simple_condvar, &test_mutex, K_TICKS(time_val));
118 
119 	switch (time_val) {
120 	case K_TICKS_FOREVER:
121 		zassert_true(ret_value == 0,
122 		     "k_condvar_wait failed.");
123 		break;
124 	case 0:
125 		zassert_true(ret_value == -EAGAIN,
126 		     "k_condvar_wait failed.");
127 		break;
128 	default:
129 		zassert_true(ret_value == 0,
130 		     "k_condvar_wait failed.");
131 		break;
132 	}
133 
134 	k_mutex_unlock(&test_mutex);
135 }
136 
137 /**
138  * @brief Test k_condvar_wait() and k_condvar_wake()
139  */
ZTEST_USER(condvar_tests,test_condvar_wait_forever_wake)140 ZTEST_USER(condvar_tests, test_condvar_wait_forever_wake)
141 {
142 	woken = 1;
143 	timeout = K_TICKS_FOREVER;
144 
145 	k_condvar_init(&simple_condvar);
146 	k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
147 			condvar_wait_wake_task, &timeout, NULL, NULL,
148 			PRIO_WAIT, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
149 
150 	/* giving time for the condvar_wait_wake_task to execute */
151 	k_yield();
152 
153 	k_thread_create(&condvar_wake_tid, condvar_wake_stack, STACK_SIZE,
154 			condvar_wake_task, &woken, NULL, NULL,
155 			PRIO_WAKE, K_USER | K_INHERIT_PERMS, K_MSEC(1));
156 
157 	/* giving time for the condvar_wake_task
158 	 * and condvar_wait_wake_task to execute
159 	 */
160 	k_yield();
161 
162 	k_thread_abort(&condvar_wake_tid);
163 	k_thread_abort(&condvar_tid);
164 }
165 
166 
ZTEST_USER(condvar_tests,test_condvar_wait_timeout_wake)167 ZTEST_USER(condvar_tests, test_condvar_wait_timeout_wake)
168 {
169 	woken = 1;
170 	timeout = k_ms_to_ticks_ceil32(100);
171 
172 	k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
173 			condvar_wait_wake_task, &timeout, NULL, NULL,
174 			PRIO_WAIT, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
175 
176 	/* giving time for the condvar_wait_wake_task to execute */
177 	k_yield();
178 
179 	k_thread_create(&condvar_wake_tid, condvar_wake_stack, STACK_SIZE,
180 			condvar_wake_task, &woken, NULL, NULL,
181 			PRIO_WAKE, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
182 
183 	/*
184 	 * giving time for the condvar_wake_task
185 	 * and condvar_wait_wake_task to execute
186 	 */
187 	k_yield();
188 
189 
190 	k_thread_abort(&condvar_wake_tid);
191 	k_thread_abort(&condvar_tid);
192 }
193 
ZTEST_USER(condvar_tests,test_condvar_wait_timeout)194 ZTEST_USER(condvar_tests, test_condvar_wait_timeout)
195 {
196 	timeout = k_ms_to_ticks_ceil32(50);
197 
198 	k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
199 			condvar_wait_task, &timeout, NULL, NULL,
200 			PRIO_WAIT, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
201 
202 	/* giving time for the condvar_wait_task to execute */
203 	k_sleep(K_MSEC(100));
204 
205 	k_thread_abort(&condvar_tid);
206 }
207 
208 
209 /**
210  * @brief Test k_condvar_wait() forever
211  */
ZTEST_USER(condvar_tests,test_condvar_wait_forever)212 ZTEST_USER(condvar_tests, test_condvar_wait_forever)
213 {
214 	timeout = K_TICKS_FOREVER;
215 
216 
217 	k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
218 			condvar_wait_task, &timeout, NULL, NULL,
219 			PRIO_WAIT, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
220 
221 	/* giving time for the condvar_wait_task to execute */
222 	k_yield();
223 
224 	k_thread_abort(&condvar_tid);
225 }
226 
227 
ZTEST_USER(condvar_tests,test_condvar_wait_nowait)228 ZTEST_USER(condvar_tests, test_condvar_wait_nowait)
229 {
230 	timeout = 0;
231 
232 	k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
233 			condvar_wait_task, &timeout, NULL, NULL,
234 			PRIO_WAIT, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
235 
236 	/* giving time for the condvar_wait_task to execute */
237 	k_sleep(K_MSEC(100));
238 
239 	k_thread_abort(&condvar_tid);
240 }
241 
242 
ZTEST_USER(condvar_tests,test_condvar_wait_nowait_wake)243 ZTEST_USER(condvar_tests, test_condvar_wait_nowait_wake)
244 {
245 	woken = 0;
246 	timeout = 0;
247 
248 	k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
249 			condvar_wait_wake_task, &timeout, NULL, NULL,
250 			PRIO_WAIT, K_USER | K_INHERIT_PERMS,
251 			K_NO_WAIT);
252 
253 	/* giving time for the condvar_wait_wake_task to execute */
254 	k_sleep(K_MSEC(100));
255 
256 	k_thread_create(&condvar_wake_tid, condvar_wake_stack, STACK_SIZE,
257 			condvar_wake_task, &woken, NULL, NULL,
258 			PRIO_WAKE, K_USER | K_INHERIT_PERMS,
259 			K_NO_WAIT);
260 
261 	/* giving time for the condvar_wake_task to execute */
262 	k_yield();
263 
264 	k_thread_abort(&condvar_wake_tid);
265 	k_thread_abort(&condvar_tid);
266 }
267 
268 
ZTEST(condvar_tests,test_condvar_wait_forever_wake_from_isr)269 ZTEST(condvar_tests, test_condvar_wait_forever_wake_from_isr)
270 {
271 	timeout = K_TICKS_FOREVER;
272 
273 	k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
274 			condvar_wait_wake_task, &timeout, NULL, NULL,
275 			PRIO_WAIT, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
276 
277 	/* giving time for the condvar_wait_wake_task to execute */
278 	k_yield();
279 
280 	condvar_wake_from_isr(&simple_condvar);
281 
282 	/* giving time for the condvar_wait_wake_task to execute */
283 	k_yield();
284 
285 	k_thread_abort(&condvar_tid);
286 }
287 
ZTEST_USER(condvar_tests,test_condvar_multiple_threads_wait_wake)288 ZTEST_USER(condvar_tests, test_condvar_multiple_threads_wait_wake)
289 {
290 	timeout = K_TICKS_FOREVER;
291 	woken = TOTAL_THREADS_WAITING;
292 
293 	k_condvar_init(&simple_condvar);
294 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
295 
296 		k_thread_create(&multiple_tid[i], multiple_stack[i],
297 				STACK_SIZE, condvar_wait_wake_task,
298 				&timeout, NULL, NULL,
299 				PRIO_WAIT, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
300 	}
301 
302 	/* giving time for the other threads to execute */
303 	k_yield();
304 
305 	k_thread_create(&condvar_wake_tid, condvar_wake_stack,
306 			STACK_SIZE, condvar_wake_multiple, &woken,
307 			NULL, NULL, PRIO_WAKE,
308 			K_USER | K_INHERIT_PERMS, K_NO_WAIT);
309 
310 	/* giving time for the other threads to execute */
311 	k_yield();
312 
313 	k_thread_abort(&condvar_wake_tid);
314 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
315 		k_thread_abort(&multiple_tid[i]);
316 	}
317 }
318 
319 
condvar_multiple_wait_wake_task(void * p1,void * p2,void * p3)320 void condvar_multiple_wait_wake_task(void *p1, void *p2, void *p3)
321 {
322 	int32_t ret_value;
323 	int time_val = *(int *)p1;
324 	int idx = *(int *)p2;
325 
326 	k_condvar_init(&multiple_condvar[idx]);
327 
328 	zassert_true(time_val == (int)K_TICKS_FOREVER, "invalid timeout parameter");
329 	k_mutex_lock(&test_mutex, K_FOREVER);
330 
331 	ret_value = k_condvar_wait(&multiple_condvar[idx],
332 		&test_mutex, K_TICKS(time_val));
333 	zassert_true(ret_value == 0, "k_condvar_wait failed.");
334 
335 	k_mutex_unlock(&test_mutex);
336 }
337 
condvar_multiple_wake_task(void * p1,void * p2,void * p3)338 void condvar_multiple_wake_task(void *p1, void *p2, void *p3)
339 {
340 	int32_t ret_value;
341 	int woken_num = *(int *)p1;
342 	int idx = *(int *)p2;
343 
344 	zassert_true(woken_num > 0, "invalid woken number");
345 
346 	if (woken > 1) {
347 		ret_value = k_condvar_signal(&multiple_condvar[idx]);
348 	} else {
349 		ret_value = k_condvar_broadcast(&multiple_condvar[idx]);
350 	}
351 
352 	zassert_true(ret_value == woken_num, "k_condvar_wake failed. (%d!=%d)",
353 		     ret_value, woken_num);
354 }
355 
ZTEST_USER(condvar_tests,test_multiple_condvar_wait_wake)356 ZTEST_USER(condvar_tests, test_multiple_condvar_wait_wake)
357 {
358 	woken = 1;
359 	timeout = K_TICKS_FOREVER;
360 
361 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
362 		index[i] = i;
363 
364 		k_thread_create(&multiple_tid[i], multiple_stack[i],
365 				STACK_SIZE, condvar_multiple_wait_wake_task,
366 				&timeout, &index[i], NULL, PRIO_WAIT,
367 				K_USER | K_INHERIT_PERMS, K_NO_WAIT);
368 	}
369 
370 	/* giving time for the other threads to execute */
371 	k_msleep(10);
372 
373 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
374 		k_thread_create(&multiple_wake_tid[i], multiple_wake_stack[i],
375 				STACK_SIZE, condvar_multiple_wake_task,
376 				&woken, &index[i], NULL, PRIO_WAKE,
377 				K_USER | K_INHERIT_PERMS, K_NO_WAIT);
378 	}
379 
380 	/* giving time for the other threads to execute */
381 	k_yield();
382 
383 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
384 		;
385 	}
386 
387 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
388 		k_thread_abort(&multiple_tid[i]);
389 		k_thread_abort(&multiple_wake_tid[i]);
390 	}
391 }
392 
393 #ifdef CONFIG_USERSPACE
cond_init_null(void * p1,void * p2,void * p3)394 static void cond_init_null(void *p1, void *p2, void *p3)
395 {
396 	ztest_set_fault_valid(true);
397 	k_condvar_init(NULL);
398 
399 	/* should not go here*/
400 	ztest_test_fail();
401 }
402 
ZTEST_USER(condvar_tests,test_condvar_init_null)403 ZTEST_USER(condvar_tests, test_condvar_init_null)
404 {
405 	k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
406 			(k_thread_entry_t)cond_init_null,
407 			NULL, NULL, NULL,
408 			K_PRIO_PREEMPT(0),
409 			K_USER | K_INHERIT_PERMS, K_NO_WAIT);
410 
411 	k_thread_join(tid, K_FOREVER);
412 }
413 #else
ZTEST_USER(condvar_tests,test_condvar_init_null)414 ZTEST_USER(condvar_tests, test_condvar_init_null)
415 {
416 	ztest_test_skip();
417 }
418 #endif
419 
420 #ifdef CONFIG_USERSPACE
cond_signal_null(void * p1,void * p2,void * p3)421 static void cond_signal_null(void *p1, void *p2, void *p3)
422 {
423 	ztest_set_fault_valid(true);
424 	k_condvar_signal(NULL);
425 
426 	/* should not go here*/
427 	ztest_test_fail();
428 }
429 
cond_broadcast_null(void * p1,void * p2,void * p3)430 static void cond_broadcast_null(void *p1, void *p2, void *p3)
431 {
432 	ztest_set_fault_valid(true);
433 	k_condvar_broadcast(NULL);
434 
435 	/* should not go here*/
436 	ztest_test_fail();
437 }
438 
cond_wait_null(void * p1,void * p2,void * p3)439 static void cond_wait_null(void *p1, void *p2, void *p3)
440 {
441 	ztest_set_fault_valid(true);
442 	k_condvar_wait(NULL, NULL, K_FOREVER);
443 
444 	/* should not go here*/
445 	ztest_test_fail();
446 }
447 
ZTEST_USER(condvar_tests,test_condvar_signal_null)448 ZTEST_USER(condvar_tests, test_condvar_signal_null)
449 {
450 	k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
451 			(k_thread_entry_t)cond_signal_null,
452 			NULL, NULL, NULL,
453 			K_PRIO_PREEMPT(0),
454 			K_USER | K_INHERIT_PERMS, K_NO_WAIT);
455 	k_thread_join(tid, K_FOREVER);
456 }
ZTEST_USER(condvar_tests,test_condvar_broadcast_null)457 ZTEST_USER(condvar_tests, test_condvar_broadcast_null)
458 {
459 	k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
460 			(k_thread_entry_t)cond_broadcast_null,
461 			NULL, NULL, NULL,
462 			K_PRIO_PREEMPT(0),
463 			K_USER | K_INHERIT_PERMS, K_NO_WAIT);
464 
465 	k_thread_join(tid, K_FOREVER);
466 }
ZTEST_USER(condvar_tests,test_condvar_wait_null)467 ZTEST_USER(condvar_tests, test_condvar_wait_null)
468 {
469 	k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
470 			(k_thread_entry_t)cond_wait_null,
471 			NULL, NULL, NULL,
472 			K_PRIO_PREEMPT(0),
473 			K_USER | K_INHERIT_PERMS, K_NO_WAIT);
474 	k_thread_join(tid, K_FOREVER);
475 }
476 
477 #else
ZTEST_USER(condvar_tests,test_condvar_signal_null)478 ZTEST_USER(condvar_tests, test_condvar_signal_null)
479 {
480 	ztest_test_skip();
481 }
ZTEST_USER(condvar_tests,test_condvar_broadcast_null)482 ZTEST_USER(condvar_tests, test_condvar_broadcast_null)
483 {
484 	ztest_test_skip();
485 }
ZTEST_USER(condvar_tests,test_condvar_wait_null)486 ZTEST_USER(condvar_tests, test_condvar_wait_null)
487 {
488 	ztest_test_skip();
489 }
490 #endif
491 
492 
inc_count(void * p1,void * p2,void * p3)493 void inc_count(void *p1, void *p2, void *p3)
494 {
495 	int i;
496 	long multi = (long)p2;
497 
498 	for (i = 0; i < TCOUNT; i++) {
499 		k_mutex_lock(&test_mutex, K_FOREVER);
500 		count++;
501 
502 		if (count == COUNT_LIMIT) {
503 			if (multi) {
504 				k_condvar_broadcast(&simple_condvar);
505 			} else {
506 				k_condvar_signal(&simple_condvar);
507 			}
508 		}
509 
510 		k_mutex_unlock(&test_mutex);
511 
512 		/* Sleep so threads can alternate on mutex lock */
513 		k_sleep(K_MSEC(50));
514 	}
515 }
516 
watch_count(void * p1,void * p2,void * p3)517 void watch_count(void *p1, void *p2, void *p3)
518 {
519 	long my_id = (long)p1;
520 
521 	printk("Starting %s: thread %ld\n", __func__, my_id);
522 
523 	k_mutex_lock(&test_mutex, K_FOREVER);
524 	while (count < COUNT_LIMIT) {
525 		k_condvar_wait(&simple_condvar, &test_mutex, K_FOREVER);
526 	}
527 	count += 125;
528 	k_mutex_unlock(&test_mutex);
529 }
530 
_condvar_usecase(long multi)531 void _condvar_usecase(long multi)
532 {
533 	long t1 = 1, t2 = 2, t3 = 3;
534 	int i;
535 
536 	count = 0;
537 
538 	/* Reinit mutex to prevent affection from previous testcases */
539 	k_mutex_init(&test_mutex);
540 
541 	k_thread_create(&multiple_tid[0], multiple_stack[0], STACK_SIZE, watch_count,
542 			INT_TO_POINTER(t1), NULL, NULL, K_PRIO_PREEMPT(10),
543 			K_USER | K_INHERIT_PERMS, K_NO_WAIT);
544 
545 	k_thread_create(&multiple_tid[1], multiple_stack[1], STACK_SIZE, inc_count,
546 			INT_TO_POINTER(t2), INT_TO_POINTER(multi), NULL, K_PRIO_PREEMPT(10),
547 			K_USER | K_INHERIT_PERMS, K_NO_WAIT);
548 
549 	k_thread_create(&multiple_tid[2], multiple_stack[2], STACK_SIZE, inc_count,
550 			INT_TO_POINTER(t3), INT_TO_POINTER(multi), NULL, K_PRIO_PREEMPT(10),
551 			K_USER | K_INHERIT_PERMS, K_NO_WAIT);
552 
553 	/* Wait for all threads to complete */
554 	for (i = 0; i < 3; i++) {
555 		k_thread_join(&multiple_tid[i], K_FOREVER);
556 	}
557 
558 	zassert_equal(count, 145, "Count not equal to 145");
559 
560 }
561 
ZTEST_USER(condvar_tests,test_condvar_usecase_signal)562 ZTEST_USER(condvar_tests, test_condvar_usecase_signal)
563 {
564 	_condvar_usecase(0);
565 }
566 
ZTEST_USER(condvar_tests,test_condvar_usecase_broadcast)567 ZTEST_USER(condvar_tests, test_condvar_usecase_broadcast)
568 {
569 	_condvar_usecase(1);
570 }
571 
572 /*test case main entry*/
condvar_tests_setup(void)573 static void *condvar_tests_setup(void)
574 {
575 #ifdef CONFIG_USERSPACE
576 	k_thread_access_grant(k_current_get(), &test_mutex, &condvar_tid, &condvar_wake_tid,
577 				&simple_condvar, &stack_1, &condvar_wake_stack);
578 
579 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
580 		k_thread_access_grant(k_current_get(),
581 				      &multiple_tid[i],
582 				      &multiple_wake_tid[i],
583 				      &multiple_stack[i],
584 				      &multiple_condvar[i],
585 				      &multiple_wake_stack[i]);
586 	}
587 #endif
588 	return NULL;
589 }
590 
591 ZTEST_SUITE(condvar_tests, NULL, condvar_tests_setup, NULL, NULL, NULL);
592