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 ARG_UNUSED(p1);
397 ARG_UNUSED(p2);
398 ARG_UNUSED(p3);
399
400 ztest_set_fault_valid(true);
401 k_condvar_init(NULL);
402
403 /* should not go here*/
404 ztest_test_fail();
405 }
406
ZTEST_USER(condvar_tests,test_condvar_init_null)407 ZTEST_USER(condvar_tests, test_condvar_init_null)
408 {
409 k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
410 cond_init_null,
411 NULL, NULL, NULL,
412 K_PRIO_PREEMPT(0),
413 K_USER | K_INHERIT_PERMS, K_NO_WAIT);
414
415 k_thread_join(tid, K_FOREVER);
416 }
417 #else
ZTEST_USER(condvar_tests,test_condvar_init_null)418 ZTEST_USER(condvar_tests, test_condvar_init_null)
419 {
420 ztest_test_skip();
421 }
422 #endif
423
424 #ifdef CONFIG_USERSPACE
cond_signal_null(void * p1,void * p2,void * p3)425 static void cond_signal_null(void *p1, void *p2, void *p3)
426 {
427 ARG_UNUSED(p1);
428 ARG_UNUSED(p2);
429 ARG_UNUSED(p3);
430
431 ztest_set_fault_valid(true);
432 k_condvar_signal(NULL);
433
434 /* should not go here*/
435 ztest_test_fail();
436 }
437
cond_broadcast_null(void * p1,void * p2,void * p3)438 static void cond_broadcast_null(void *p1, void *p2, void *p3)
439 {
440 ARG_UNUSED(p1);
441 ARG_UNUSED(p2);
442 ARG_UNUSED(p3);
443
444 ztest_set_fault_valid(true);
445 k_condvar_broadcast(NULL);
446
447 /* should not go here*/
448 ztest_test_fail();
449 }
450
cond_wait_null(void * p1,void * p2,void * p3)451 static void cond_wait_null(void *p1, void *p2, void *p3)
452 {
453 ARG_UNUSED(p1);
454 ARG_UNUSED(p2);
455 ARG_UNUSED(p3);
456
457 ztest_set_fault_valid(true);
458 k_condvar_wait(NULL, NULL, K_FOREVER);
459
460 /* should not go here*/
461 ztest_test_fail();
462 }
463
ZTEST_USER(condvar_tests,test_condvar_signal_null)464 ZTEST_USER(condvar_tests, test_condvar_signal_null)
465 {
466 k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
467 cond_signal_null,
468 NULL, NULL, NULL,
469 K_PRIO_PREEMPT(0),
470 K_USER | K_INHERIT_PERMS, K_NO_WAIT);
471 k_thread_join(tid, K_FOREVER);
472 }
ZTEST_USER(condvar_tests,test_condvar_broadcast_null)473 ZTEST_USER(condvar_tests, test_condvar_broadcast_null)
474 {
475 k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
476 cond_broadcast_null,
477 NULL, NULL, NULL,
478 K_PRIO_PREEMPT(0),
479 K_USER | K_INHERIT_PERMS, K_NO_WAIT);
480
481 k_thread_join(tid, K_FOREVER);
482 }
ZTEST_USER(condvar_tests,test_condvar_wait_null)483 ZTEST_USER(condvar_tests, test_condvar_wait_null)
484 {
485 k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE,
486 cond_wait_null,
487 NULL, NULL, NULL,
488 K_PRIO_PREEMPT(0),
489 K_USER | K_INHERIT_PERMS, K_NO_WAIT);
490 k_thread_join(tid, K_FOREVER);
491 }
492
493 #else
ZTEST_USER(condvar_tests,test_condvar_signal_null)494 ZTEST_USER(condvar_tests, test_condvar_signal_null)
495 {
496 ztest_test_skip();
497 }
ZTEST_USER(condvar_tests,test_condvar_broadcast_null)498 ZTEST_USER(condvar_tests, test_condvar_broadcast_null)
499 {
500 ztest_test_skip();
501 }
ZTEST_USER(condvar_tests,test_condvar_wait_null)502 ZTEST_USER(condvar_tests, test_condvar_wait_null)
503 {
504 ztest_test_skip();
505 }
506 #endif
507
508
inc_count(void * p1,void * p2,void * p3)509 void inc_count(void *p1, void *p2, void *p3)
510 {
511 int i;
512 long multi = (long)p2;
513
514 for (i = 0; i < TCOUNT; i++) {
515 k_mutex_lock(&test_mutex, K_FOREVER);
516 count++;
517
518 if (count == COUNT_LIMIT) {
519 if (multi) {
520 k_condvar_broadcast(&simple_condvar);
521 } else {
522 k_condvar_signal(&simple_condvar);
523 }
524 }
525
526 k_mutex_unlock(&test_mutex);
527
528 /* Sleep so threads can alternate on mutex lock */
529 k_sleep(K_MSEC(50));
530 }
531 }
532
watch_count(void * p1,void * p2,void * p3)533 void watch_count(void *p1, void *p2, void *p3)
534 {
535 long my_id = (long)p1;
536
537 printk("Starting %s: thread %ld\n", __func__, my_id);
538
539 k_mutex_lock(&test_mutex, K_FOREVER);
540 while (count < COUNT_LIMIT) {
541 k_condvar_wait(&simple_condvar, &test_mutex, K_FOREVER);
542 }
543 count += 125;
544 k_mutex_unlock(&test_mutex);
545 }
546
_condvar_usecase(long multi)547 void _condvar_usecase(long multi)
548 {
549 long t1 = 1, t2 = 2, t3 = 3;
550 int i;
551
552 count = 0;
553
554 /* Reinit mutex to prevent affection from previous testcases */
555 k_mutex_init(&test_mutex);
556
557 k_thread_create(&multiple_tid[0], multiple_stack[0], STACK_SIZE, watch_count,
558 INT_TO_POINTER(t1), NULL, NULL, K_PRIO_PREEMPT(10),
559 K_USER | K_INHERIT_PERMS, K_NO_WAIT);
560
561 k_thread_create(&multiple_tid[1], multiple_stack[1], STACK_SIZE, inc_count,
562 INT_TO_POINTER(t2), INT_TO_POINTER(multi), NULL, K_PRIO_PREEMPT(10),
563 K_USER | K_INHERIT_PERMS, K_NO_WAIT);
564
565 k_thread_create(&multiple_tid[2], multiple_stack[2], STACK_SIZE, inc_count,
566 INT_TO_POINTER(t3), INT_TO_POINTER(multi), NULL, K_PRIO_PREEMPT(10),
567 K_USER | K_INHERIT_PERMS, K_NO_WAIT);
568
569 /* Wait for all threads to complete */
570 for (i = 0; i < 3; i++) {
571 k_thread_join(&multiple_tid[i], K_FOREVER);
572 }
573
574 zassert_equal(count, 145, "Count not equal to 145");
575
576 }
577
ZTEST_USER(condvar_tests,test_condvar_usecase_signal)578 ZTEST_USER(condvar_tests, test_condvar_usecase_signal)
579 {
580 _condvar_usecase(0);
581 }
582
ZTEST_USER(condvar_tests,test_condvar_usecase_broadcast)583 ZTEST_USER(condvar_tests, test_condvar_usecase_broadcast)
584 {
585 _condvar_usecase(1);
586 }
587
588 /*test case main entry*/
condvar_tests_setup(void)589 static void *condvar_tests_setup(void)
590 {
591 #ifdef CONFIG_USERSPACE
592 k_thread_access_grant(k_current_get(), &test_mutex, &condvar_tid, &condvar_wake_tid,
593 &simple_condvar, &stack_1, &condvar_wake_stack);
594
595 for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
596 k_thread_access_grant(k_current_get(),
597 &multiple_tid[i],
598 &multiple_wake_tid[i],
599 &multiple_stack[i],
600 &multiple_condvar[i],
601 &multiple_wake_stack[i]);
602 }
603 #endif
604 return NULL;
605 }
606
607 ZTEST_SUITE(condvar_tests, NULL, condvar_tests_setup, NULL, NULL, NULL);
608