1 /*
2  * Copyright (c) 2019 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr/ztest.h>
7 #include <zephyr/kernel.h>
8 
9 #include "tests_thread_apis.h"
10 
11 /* Very simple (and limited) test of the SMP cpu mask API.  Runs on
12  * just one CPU.  Creates a thread, sets the CPU mask, starts it,
13  * checks if it ran (or didn't run) as expected.
14  */
15 
16 struct k_thread child_thread;
17 
18 bool child_has_run;
19 
child_fn(void * a,void * b,void * c)20 void child_fn(void *a, void *b, void *c)
21 {
22 	child_has_run = true;
23 }
24 
25 
26 /**
27  * @brief Test the CPU mask APIs for thread lifecycle management
28  *
29  * This test verifies the behavior of the CPU mask APIs in the Zephyr kernel
30  * for thread lifecycle management. It ensures that the APIs behave as expected
31  * when operating on both running and non-running threads.
32  *
33  * @note This test is only executed if `CONFIG_SCHED_CPU_MASK` is enabled.
34  *       Otherwise, the test is skipped.
35  *
36  * @ingroup kernel_thread_tests
37  */
ZTEST(threads_lifecycle_1cpu,test_threads_cpu_mask)38 ZTEST(threads_lifecycle_1cpu, test_threads_cpu_mask)
39 {
40 #ifdef CONFIG_SCHED_CPU_MASK
41 	k_tid_t thread;
42 	int ret, pass, prio;
43 
44 	/* Shouldn't be able to operate on a running thread */
45 	ret = k_thread_cpu_mask_clear(k_current_get());
46 	zassert_true(ret == -EINVAL, "");
47 
48 	ret = k_thread_cpu_mask_enable_all(k_current_get());
49 	zassert_true(ret == -EINVAL, "");
50 
51 	ret = k_thread_cpu_mask_enable(k_current_get(), 0);
52 	zassert_true(ret == -EINVAL, "");
53 
54 	ret = k_thread_cpu_mask_disable(k_current_get(), 0);
55 	zassert_true(ret == -EINVAL, "");
56 
57 	ret = k_thread_cpu_pin(k_current_get(), 0);
58 	zassert_true(ret == -EINVAL, "");
59 
60 	for (pass = 0; pass < 4; pass++) {
61 		if (IS_ENABLED(CONFIG_SCHED_CPU_MASK_PIN_ONLY) && pass == 1) {
62 			/* Pass 1 enables more than one CPU in the
63 			 * mask, which is illegal when PIN_ONLY
64 			 */
65 			continue;
66 		}
67 
68 		child_has_run = false;
69 
70 		/* Create a thread at a higher priority, don't start
71 		 * it yet.
72 		 */
73 		prio = k_thread_priority_get(k_current_get());
74 		zassert_true(prio > K_HIGHEST_APPLICATION_THREAD_PRIO, "");
75 		thread = k_thread_create(&child_thread,
76 					 tstack, tstack_size,
77 					 child_fn, NULL, NULL, NULL,
78 					 K_HIGHEST_APPLICATION_THREAD_PRIO,
79 					 0, K_FOREVER);
80 
81 		/* Set up the CPU mask */
82 		if (pass == 0) {
83 			ret = k_thread_cpu_mask_clear(thread);
84 			zassert_true(ret == 0, "");
85 		} else if (pass == 1) {
86 			ret = k_thread_cpu_mask_enable_all(thread);
87 			zassert_true(ret == 0, "");
88 		} else if (pass == 2) {
89 			ret = k_thread_cpu_mask_disable(thread, 0);
90 			zassert_true(ret == 0, "");
91 		} else {
92 			ret = k_thread_cpu_mask_enable(thread, 0);
93 			zassert_true(ret == 0, "");
94 
95 			ret = k_thread_cpu_pin(thread, 0);
96 			zassert_true(ret == 0, "");
97 		}
98 
99 		/* Start it.  If it is runnable, it will do so
100 		 * immediately when we yield.  Check to see if it ran.
101 		 */
102 		zassert_false(child_has_run, "");
103 		k_thread_start(thread);
104 		k_yield();
105 
106 		if (pass == 1 || pass == 3) {
107 			zassert_true(child_has_run, "");
108 		} else {
109 			zassert_false(child_has_run, "");
110 		}
111 
112 		k_thread_abort(thread);
113 	}
114 #else
115 	ztest_test_skip();
116 #endif
117 }
118