1 /*
2  * Copyright (c) 2019, 2020 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/irq_offload.h>
9 #include <zephyr/sys/mutex.h>
10 
11 
12 /**
13  * @brief Tests for Kernel Futex objects
14  * @defgroup kernel_futex_tests Futex
15  * @ingroup all_tests
16  * @{
17  * @}
18  */
19 
20 /* Macro declarations */
21 #define TOTAL_THREADS_WAITING (3)
22 #define PRIO_WAIT (CONFIG_ZTEST_THREAD_PRIORITY - 1)
23 #define PRIO_WAKE (CONFIG_ZTEST_THREAD_PRIORITY - 2)
24 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
25 #define PRIORITY 5
26 
27 /******************************************************************************/
28 /* declaration */
29 K_THREAD_STACK_DEFINE(stack_1, STACK_SIZE);
30 K_THREAD_STACK_DEFINE(futex_wake_stack, STACK_SIZE);
31 K_THREAD_STACK_ARRAY_DEFINE(multiple_stack,
32 		TOTAL_THREADS_WAITING, STACK_SIZE);
33 K_THREAD_STACK_ARRAY_DEFINE(multiple_wake_stack,
34 		TOTAL_THREADS_WAITING, STACK_SIZE);
35 
36 ZTEST_BMEM int woken;
37 ZTEST_BMEM int timeout;
38 ZTEST_BMEM int index[TOTAL_THREADS_WAITING];
39 ZTEST_BMEM struct k_futex simple_futex;
40 ZTEST_BMEM struct k_futex multiple_futex[TOTAL_THREADS_WAITING];
41 struct k_futex no_access_futex;
42 ZTEST_BMEM atomic_t not_a_futex;
43 ZTEST_BMEM struct sys_mutex also_not_a_futex;
44 
45 struct k_thread futex_tid;
46 struct k_thread futex_wake_tid;
47 struct k_thread multiple_tid[TOTAL_THREADS_WAITING];
48 struct k_thread multiple_wake_tid[TOTAL_THREADS_WAITING];
49 
50 /******************************************************************************/
51 /* Helper functions */
futex_isr_wake(const void * futex)52 static void futex_isr_wake(const void *futex)
53 {
54 	k_futex_wake((struct k_futex *)futex, false);
55 }
56 
futex_wake_from_isr(struct k_futex * futex)57 static void futex_wake_from_isr(struct k_futex *futex)
58 {
59 	irq_offload(futex_isr_wake, (const void *)futex);
60 }
61 
62 /* test futex wait, no futex wake */
futex_wait_task(void * p1,void * p2,void * p3)63 static void futex_wait_task(void *p1, void *p2, void *p3)
64 {
65 	int32_t ret_value;
66 	k_ticks_t time_val = *(int *)p1;
67 
68 	zassert_true(time_val >= (int)K_TICKS_FOREVER,
69 		     "invalid timeout parameter");
70 
71 	ret_value = k_futex_wait(&simple_futex,
72 			atomic_get(&simple_futex.val), K_TICKS(time_val));
73 
74 	switch (time_val) {
75 	case K_TICKS_FOREVER:
76 		zassert_true(ret_value == 0,
77 		     "k_futex_wait failed when it shouldn't have");
78 		zassert_false(ret_value == 0,
79 		     "futex wait task wakeup when it shouldn't have");
80 		break;
81 	case 0:
82 		zassert_true(ret_value == -ETIMEDOUT,
83 		     "k_futex_wait failed when it shouldn't have");
84 		atomic_sub(&simple_futex.val, 1);
85 		break;
86 	default:
87 		zassert_true(ret_value == -ETIMEDOUT,
88 		     "k_futex_wait failed when it shouldn't have");
89 		atomic_sub(&simple_futex.val, 1);
90 		break;
91 	}
92 }
93 
futex_wake_task(void * p1,void * p2,void * p3)94 static void futex_wake_task(void *p1, void *p2, void *p3)
95 {
96 	int32_t ret_value;
97 	int woken_num = *(int *)p1;
98 
99 	ret_value = k_futex_wake(&simple_futex,
100 				woken_num == 1 ? false : true);
101 	zassert_true(ret_value == woken_num,
102 		"k_futex_wake failed when it shouldn't have");
103 }
104 
futex_wait_wake_task(void * p1,void * p2,void * p3)105 static void futex_wait_wake_task(void *p1, void *p2, void *p3)
106 {
107 	int32_t ret_value;
108 	int time_val = *(int *)p1;
109 
110 	zassert_true(time_val >= (int)K_TICKS_FOREVER, "invalid timeout parameter");
111 
112 	ret_value = k_futex_wait(&simple_futex,
113 			atomic_get(&simple_futex.val), K_TICKS(time_val));
114 
115 	switch (time_val) {
116 	case K_TICKS_FOREVER:
117 		zassert_true(ret_value == 0,
118 		     "k_futex_wait failed when it shouldn't have");
119 		break;
120 	case 0:
121 		zassert_true(ret_value == -ETIMEDOUT,
122 		     "k_futex_wait failed when it shouldn't have");
123 		break;
124 	default:
125 		zassert_true(ret_value == 0,
126 		     "k_futex_wait failed when it shouldn't have");
127 		break;
128 	}
129 
130 	atomic_sub(&simple_futex.val, 1);
131 }
132 
futex_multiple_wake_task(void * p1,void * p2,void * p3)133 static void futex_multiple_wake_task(void *p1, void *p2, void *p3)
134 {
135 	int32_t ret_value;
136 	int woken_num = *(int *)p1;
137 	int idx = *(int *)p2;
138 
139 	zassert_true(woken_num > 0, "invalid woken number");
140 
141 	ret_value = k_futex_wake(&multiple_futex[idx],
142 			woken_num == 1 ? false : true);
143 	zassert_true(ret_value == woken_num,
144 		"k_futex_wake failed when it shouldn't have");
145 }
146 
futex_multiple_wait_wake_task(void * p1,void * p2,void * p3)147 static void futex_multiple_wait_wake_task(void *p1, void *p2, void *p3)
148 {
149 	int32_t ret_value;
150 	int time_val = *(int *)p1;
151 	int idx = *(int *)p2;
152 
153 	zassert_true(time_val == (int)K_TICKS_FOREVER, "invalid timeout parameter");
154 
155 	ret_value = k_futex_wait(&multiple_futex[idx],
156 		atomic_get(&(multiple_futex[idx].val)), K_TICKS(time_val));
157 	zassert_true(ret_value == 0,
158 	     "k_futex_wait failed when it shouldn't have");
159 
160 	atomic_sub(&(multiple_futex[idx].val), 1);
161 }
162 
163 /**
164  * @ingroup kernel_futex_tests
165  * @{
166  */
167 
168 /**
169  * @brief Test k_futex_wait() forever
170  */
ZTEST(futex,test_futex_wait_forever)171 ZTEST(futex, test_futex_wait_forever)
172 {
173 	timeout = K_TICKS_FOREVER;
174 
175 	atomic_set(&simple_futex.val, 1);
176 
177 	k_thread_create(&futex_tid, stack_1, STACK_SIZE,
178 			futex_wait_task, &timeout, NULL, NULL,
179 			PRIO_WAIT, K_USER | K_INHERIT_PERMS,
180 			K_NO_WAIT);
181 
182 	/* giving time for the futex_wait_task to execute */
183 	k_yield();
184 
185 	zassert_false(atomic_get(&simple_futex.val) == 0,
186 			"wait forever shouldn't wake");
187 
188 	k_thread_abort(&futex_tid);
189 }
190 
ZTEST(futex,test_futex_wait_timeout)191 ZTEST(futex, test_futex_wait_timeout)
192 {
193 	timeout = k_ms_to_ticks_ceil32(50);
194 
195 	atomic_set(&simple_futex.val, 1);
196 
197 	k_thread_create(&futex_tid, stack_1, STACK_SIZE,
198 			futex_wait_task, &timeout, NULL, NULL,
199 			PRIO_WAIT, K_USER | K_INHERIT_PERMS,
200 			K_NO_WAIT);
201 
202 	/* giving time for the futex_wait_task to execute */
203 	k_sleep(K_MSEC(100));
204 
205 	zassert_true(atomic_get(&simple_futex.val) == 0,
206 			"wait timeout doesn't timeout");
207 
208 	k_thread_abort(&futex_tid);
209 }
210 
ZTEST(futex,test_futex_wait_nowait)211 ZTEST(futex, test_futex_wait_nowait)
212 {
213 	timeout = 0;
214 
215 	atomic_set(&simple_futex.val, 1);
216 
217 	k_thread_create(&futex_tid, stack_1, STACK_SIZE,
218 			futex_wait_task, &timeout, NULL, NULL,
219 			PRIO_WAIT, K_USER | K_INHERIT_PERMS,
220 			K_NO_WAIT);
221 
222 	/* giving time for the futex_wait_task to execute */
223 	k_sleep(K_MSEC(100));
224 
225 	zassert_true(atomic_get(&simple_futex.val) == 0, "wait nowait fail");
226 
227 	k_thread_abort(&futex_tid);
228 }
229 
230 /**
231  * @brief Test k_futex_wait() and k_futex_wake()
232  */
ZTEST(futex,test_futex_wait_forever_wake)233 ZTEST(futex, test_futex_wait_forever_wake)
234 {
235 	woken = 1;
236 	timeout = K_TICKS_FOREVER;
237 
238 	atomic_set(&simple_futex.val, 1);
239 
240 	k_thread_create(&futex_tid, stack_1, STACK_SIZE,
241 			futex_wait_wake_task, &timeout, NULL, NULL,
242 			PRIO_WAIT, K_USER | K_INHERIT_PERMS,
243 			K_NO_WAIT);
244 
245 	/* giving time for the futex_wait_wake_task to execute */
246 	k_yield();
247 
248 	k_thread_create(&futex_wake_tid, futex_wake_stack, STACK_SIZE,
249 			futex_wake_task, &woken, NULL, NULL,
250 			PRIO_WAKE, K_USER | K_INHERIT_PERMS,
251 			K_NO_WAIT);
252 
253 	/* giving time for the futex_wake_task
254 	 * and futex_wait_wake_task to execute
255 	 */
256 	k_yield();
257 
258 	zassert_true(atomic_get(&simple_futex.val) == 0,
259 			"wait forever doesn't wake");
260 
261 	k_thread_abort(&futex_wake_tid);
262 	k_thread_abort(&futex_tid);
263 }
264 
ZTEST(futex,test_futex_wait_timeout_wake)265 ZTEST(futex, test_futex_wait_timeout_wake)
266 {
267 	woken = 1;
268 	timeout = k_ms_to_ticks_ceil32(100);
269 
270 	atomic_set(&simple_futex.val, 1);
271 
272 	k_thread_create(&futex_tid, stack_1, STACK_SIZE,
273 			futex_wait_wake_task, &timeout, NULL, NULL,
274 			PRIO_WAIT, K_USER | K_INHERIT_PERMS,
275 			K_NO_WAIT);
276 
277 	/* giving time for the futex_wait_wake_task to execute */
278 	k_yield();
279 
280 	k_thread_create(&futex_wake_tid, futex_wake_stack, STACK_SIZE,
281 			futex_wake_task, &woken, NULL, NULL,
282 			PRIO_WAKE, K_USER | K_INHERIT_PERMS,
283 			K_NO_WAIT);
284 
285 	/*
286 	 * giving time for the futex_wake_task
287 	 * and futex_wait_wake_task to execute
288 	 */
289 	k_yield();
290 
291 	zassert_true(atomic_get(&simple_futex.val) == 0,
292 			"wait timeout doesn't wake");
293 
294 	k_thread_abort(&futex_wake_tid);
295 	k_thread_abort(&futex_tid);
296 }
297 
ZTEST(futex,test_futex_wait_nowait_wake)298 ZTEST(futex, test_futex_wait_nowait_wake)
299 {
300 	woken = 0;
301 	timeout = 0;
302 
303 	atomic_set(&simple_futex.val, 1);
304 
305 	k_thread_create(&futex_tid, stack_1, STACK_SIZE,
306 			futex_wait_wake_task, &timeout, NULL, NULL,
307 			PRIO_WAIT, K_USER | K_INHERIT_PERMS,
308 			K_NO_WAIT);
309 
310 	/* giving time for the futex_wait_wake_task to execute */
311 	k_sleep(K_MSEC(100));
312 
313 	k_thread_create(&futex_wake_tid, futex_wake_stack, STACK_SIZE,
314 			futex_wake_task, &woken, NULL, NULL,
315 			PRIO_WAKE, K_USER | K_INHERIT_PERMS,
316 			K_NO_WAIT);
317 
318 	/* giving time for the futex_wake_task to execute */
319 	k_yield();
320 
321 	k_thread_abort(&futex_wake_tid);
322 	k_thread_abort(&futex_tid);
323 }
324 
ZTEST(futex,test_futex_wait_forever_wake_from_isr)325 ZTEST(futex, test_futex_wait_forever_wake_from_isr)
326 {
327 	timeout = K_TICKS_FOREVER;
328 
329 	atomic_set(&simple_futex.val, 1);
330 
331 	k_thread_create(&futex_tid, stack_1, STACK_SIZE,
332 			futex_wait_wake_task, &timeout, NULL, NULL,
333 			PRIO_WAIT, K_USER | K_INHERIT_PERMS,
334 			K_NO_WAIT);
335 
336 	/* giving time for the futex_wait_wake_task to execute */
337 	k_yield();
338 
339 	futex_wake_from_isr(&simple_futex);
340 
341 	/* giving time for the futex_wait_wake_task to execute */
342 	k_yield();
343 
344 	zassert_true(atomic_get(&simple_futex.val) == 0,
345 			"wait forever wake from isr doesn't wake");
346 
347 	k_thread_abort(&futex_tid);
348 }
349 
ZTEST(futex,test_futex_multiple_threads_wait_wake)350 ZTEST(futex, test_futex_multiple_threads_wait_wake)
351 {
352 	timeout = K_TICKS_FOREVER;
353 	woken = TOTAL_THREADS_WAITING;
354 
355 	atomic_clear(&simple_futex.val);
356 
357 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
358 		atomic_inc(&simple_futex.val);
359 		k_thread_create(&multiple_tid[i], multiple_stack[i],
360 				STACK_SIZE, futex_wait_wake_task,
361 				&timeout, NULL, NULL, PRIO_WAIT,
362 				K_USER | K_INHERIT_PERMS, K_NO_WAIT);
363 	}
364 
365 	/* giving time for the other threads to execute */
366 	k_yield();
367 
368 	k_thread_create(&futex_wake_tid, futex_wake_stack,
369 			STACK_SIZE, futex_wake_task, &woken,
370 			NULL, NULL, PRIO_WAKE,
371 			K_USER | K_INHERIT_PERMS, K_NO_WAIT);
372 
373 	/* giving time for the other threads to execute */
374 	k_yield();
375 
376 	zassert_true(atomic_get(&simple_futex.val) == 0,
377 			"wait forever wake doesn't wake all threads");
378 
379 	k_thread_abort(&futex_wake_tid);
380 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
381 		k_thread_abort(&multiple_tid[i]);
382 	}
383 }
384 
ZTEST(futex,test_multiple_futex_wait_wake)385 ZTEST(futex, test_multiple_futex_wait_wake)
386 {
387 	woken = 1;
388 	timeout = K_TICKS_FOREVER;
389 
390 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
391 		index[i] = i;
392 		atomic_set(&multiple_futex[i].val, 1);
393 		k_thread_create(&multiple_tid[i], multiple_stack[i],
394 				STACK_SIZE, futex_multiple_wait_wake_task,
395 				&timeout, &index[i], NULL, PRIO_WAIT,
396 				K_USER | K_INHERIT_PERMS, K_NO_WAIT);
397 	}
398 
399 	/* giving time for the other threads to execute */
400 	k_yield();
401 
402 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
403 		k_thread_create(&multiple_wake_tid[i], multiple_wake_stack[i],
404 				STACK_SIZE, futex_multiple_wake_task,
405 				&woken, &index[i], NULL, PRIO_WAKE,
406 				K_USER | K_INHERIT_PERMS, K_NO_WAIT);
407 	}
408 
409 	/* giving time for the other threads to execute */
410 	k_yield();
411 
412 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
413 		zassert_true(atomic_get(&multiple_futex[i].val) == 0,
414 			"wait forever wake doesn't wake %d thread", i);
415 	}
416 
417 	for (int i = 0; i < TOTAL_THREADS_WAITING; i++) {
418 		k_thread_abort(&multiple_tid[i]);
419 		k_thread_abort(&multiple_wake_tid[i]);
420 	}
421 }
422 
ZTEST_USER(futex,test_user_futex_bad)423 ZTEST_USER(futex, test_user_futex_bad)
424 {
425 	int ret;
426 
427 	/* Is a futex, but no access to its memory */
428 	ret = k_futex_wait(&no_access_futex, 0, K_NO_WAIT);
429 	zassert_equal(ret, -EACCES, "shouldn't have been able to access");
430 	ret = k_futex_wake(&no_access_futex, false);
431 	zassert_equal(ret, -EACCES, "shouldn't have been able to access");
432 
433 	/* Access to memory, but not a kernel object */
434 	ret = k_futex_wait((struct k_futex *)&not_a_futex, 0, K_NO_WAIT);
435 	zassert_equal(ret, -EINVAL, "waited on non-futex");
436 	ret = k_futex_wake((struct k_futex *)&not_a_futex, false);
437 	zassert_equal(ret, -EINVAL, "woke non-futex");
438 
439 	/* Access to memory, but wrong object type */
440 	ret = k_futex_wait((struct k_futex *)&also_not_a_futex, 0, K_NO_WAIT);
441 	zassert_equal(ret, -EINVAL, "waited on non-futex");
442 	ret = k_futex_wake((struct k_futex *)&also_not_a_futex, false);
443 	zassert_equal(ret, -EINVAL, "woke non-futex");
444 
445 	/* Wait with unexpected value */
446 	atomic_set(&simple_futex.val, 100);
447 	ret = k_futex_wait(&simple_futex, 0, K_NO_WAIT);
448 	zassert_equal(ret, -EAGAIN, "waited when values did not match");
449 
450 	/* Timeout case */
451 	ret = k_futex_wait(&simple_futex, 100, K_NO_WAIT);
452 	zassert_equal(ret, -ETIMEDOUT, "didn't time out");
453 }
454 
futex_wait_wake(void * p1,void * p2,void * p3)455 static void futex_wait_wake(void *p1, void *p2, void *p3)
456 {
457 	int32_t ret_value;
458 
459 	/* Test user thread can make wait without error
460 	 * Use assertion to verify k_futex_wait() returns 0
461 	 */
462 	ret_value = k_futex_wait(&simple_futex, 13, K_FOREVER);
463 	zassert_equal(ret_value, 0);
464 
465 	/* Test user thread can make wake without error
466 	 * Use assertion to verify k_futex_wake() returns 1,
467 	 * because only 1 thread wakes
468 	 */
469 	ret_value = k_futex_wake(&simple_futex, false);
470 	zassert_equal(ret_value, 1);
471 }
472 
futex_wake(void * p1,void * p2,void * p3)473 static void futex_wake(void *p1, void *p2, void *p3)
474 {
475 	int32_t atomic_ret_val;
476 	int32_t ret_value;
477 
478 	k_futex_wake(&simple_futex, false);
479 
480 	ret_value = k_futex_wait(&simple_futex, 13, K_FOREVER);
481 	zassert_equal(ret_value, 0);
482 
483 	/* Test user can write to the futex value
484 	 * Use assertion to verify subtraction correctness
485 	 * Initial value was 13, after atomic_sub() must be 12
486 	 */
487 	atomic_sub(&simple_futex.val, 1);
488 	atomic_ret_val = atomic_get(&simple_futex.val);
489 	zassert_equal(atomic_ret_val, 12);
490 }
491 
492 /**
493  * @brief Test kernel supports locating kernel objects without private kernel
494  * data anywhere in memory, control access with the memory domain configuration
495  *
496  * @details For that test kernel object which doesn't contain private kernel
497  * data will be used futex. Test performs handshaking between two user threads
498  * to test next requirements:
499  * - Place a futex simple_futex in user memory using ZTEST_BMEM
500  * - Show that user threads can write to futex value
501  * - Show that user threads can make wait/wake syscalls on it.
502  *
503  * @see atomic_set(), atomic_sub(), k_futex_wake(), k_futex_wait()
504  *
505  * @ingroup kernel_futex_tests
506  */
ZTEST_USER(futex,test_futex_locate_access)507 ZTEST_USER(futex, test_futex_locate_access)
508 {
509 
510 	atomic_set(&simple_futex.val, 13);
511 
512 	k_thread_create(&futex_tid, stack_1, STACK_SIZE,
513 			futex_wait_wake, NULL, NULL, NULL,
514 			PRIORITY, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
515 
516 	/* giving time for the futex_wait_wake_task to execute */
517 	k_yield();
518 
519 	k_thread_create(&futex_wake_tid, futex_wake_stack, STACK_SIZE,
520 			futex_wake, NULL, NULL, NULL,
521 			PRIORITY, K_USER | K_INHERIT_PERMS, K_NO_WAIT);
522 
523 	/*
524 	 * giving time for the futex_wake_task
525 	 * and futex_wait_wake_task to execute
526 	 */
527 	k_yield();
528 
529 	k_thread_abort(&futex_tid);
530 	k_thread_abort(&futex_wake_tid);
531 }
532 
533 /* ztest main entry*/
futex_setup(void)534 void *futex_setup(void)
535 {
536 	k_thread_access_grant(k_current_get(),
537 					&futex_tid, &stack_1, &futex_wake_tid, &futex_wake_stack,
538 					&simple_futex);
539 	return NULL;
540 }
541 
542 ZTEST_SUITE(futex, NULL, futex_setup, NULL, NULL, NULL);
543 /**
544  * @}
545  */
546