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