1 /*
2  * Copyright (c) 2018 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/debug/stack.h>
10 
11 #include "tests_thread_apis.h"
12 
13 #define SLEEP_MS 100
14 #define TEST_STRING "TEST"
15 #define TEST_STRING_UNLOCKED "TEST_UNLOCKED"
16 
17 static int tcount;
18 static bool thread_flag;
19 static bool create_thread;
20 static k_tid_t in_callback_tid;
21 
22 struct k_thread tdata1;
23 K_THREAD_STACK_DEFINE(tstack1, STACK_SIZE);
24 
thread_entry(void * p1,void * p2,void * p3)25 static void thread_entry(void *p1, void *p2, void *p3)
26 {
27 	ARG_UNUSED(p1);
28 	ARG_UNUSED(p2);
29 	ARG_UNUSED(p3);
30 
31 	k_msleep(SLEEP_MS);
32 }
33 
thread_callback(const struct k_thread * thread,void * user_data)34 static void thread_callback(const struct k_thread *thread, void *user_data)
35 {
36 	char *str = (char *)user_data;
37 
38 	if (thread == &tdata) {
39 		TC_PRINT("%s: Newly added thread found\n", str);
40 		TC_PRINT("%s: tid: %p, prio: %d\n",
41 				str, thread, thread->base.prio);
42 		thread_flag = true;
43 	}
44 	tcount++;
45 }
46 
47 static
thread_callback_unlocked(const struct k_thread * thread,void * user_data)48 void thread_callback_unlocked(const struct k_thread *thread, void *user_data)
49 {
50 	char *str = (char *)user_data;
51 
52 	if (create_thread) {
53 		in_callback_tid = k_thread_create(&tdata1, tstack1,
54 					STACK_SIZE,
55 					thread_entry,
56 					NULL, NULL, NULL, K_PRIO_PREEMPT(0),
57 					0, K_NO_WAIT);
58 		create_thread = false;
59 	}
60 
61 	if (thread == &tdata) {
62 		TC_PRINT("%s: Newly added thread found\n", str);
63 		TC_PRINT("%s: tid: %p, prio: %d\n",
64 				str, thread, thread->base.prio);
65 		thread_flag = true;
66 	}
67 
68 	if (thread == &tdata1) {
69 		TC_PRINT("%s: Newly added thread in callback found\n", str);
70 		TC_PRINT("%s: tid: %p, prio: %d\n",
71 				str, thread, thread->base.prio);
72 		thread_flag = true;
73 		k_thread_abort(in_callback_tid);
74 	}
75 	tcount++;
76 }
77 
78 /**
79  * @ingroup kernel_thread_tests
80  * @brief Test k_thread_foreach API
81  *
82  * @details Call k_thread_foreach() at the beginning of the test and
83  * call it again after creating a thread, See k_thread_foreach()
84  * iterates over the newly created thread and calls the user passed
85  * callback function.
86  *
87  * @see k_thread_foreach()
88  */
ZTEST(threads_lifecycle_1cpu,test_k_thread_foreach)89 ZTEST(threads_lifecycle_1cpu, test_k_thread_foreach)
90 {
91 	int count;
92 
93 	k_thread_foreach(thread_callback, TEST_STRING);
94 
95 	/* Check thread_count non-zero, thread_flag
96 	 * and stack_flag are not set.
97 	 */
98 	zassert_true(tcount && !thread_flag,
99 				"thread_callback() not getting called");
100 	/* Save the initial thread count */
101 	count = tcount;
102 
103 	/* Create new thread which should add a new entry to the thread list */
104 	k_tid_t tid = k_thread_create(&tdata, tstack,
105 			STACK_SIZE, thread_entry, NULL,
106 			NULL, NULL, K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
107 	k_msleep(1);
108 
109 	/* Call k_thread_foreach() and check
110 	 * thread_callback is getting called for
111 	 * the newly added thread.
112 	 */
113 	tcount = 0;
114 	k_thread_foreach(thread_callback, TEST_STRING);
115 
116 	/* Check thread_count > temp, thread_flag and stack_flag are set */
117 	zassert_true((tcount > count) && thread_flag,
118 					"thread_callback() not getting called");
119 	k_thread_abort(tid);
120 }
121 
122 /**
123  * @brief Test k_thread_foreach_unlock API
124  *
125  * @details Call k_thread_foreach_unlocked() at the beginning of the test and
126  * call it again after creating a thread, See k_thread_foreach_unlocked()
127  * iterates over the newly created thread and calls the user passed
128  * callback function.
129  * In contrast to k_thread_foreach(), k_thread_foreach_unlocked() allow
130  * callback function created or abort threads
131  *
132  * @see k_thread_foreach_unlocked()
133  * @ingroup kernel_thread_tests
134  */
ZTEST(threads_lifecycle_1cpu,test_k_thread_foreach_unlocked)135 ZTEST(threads_lifecycle_1cpu, test_k_thread_foreach_unlocked)
136 {
137 	int count;
138 
139 	thread_flag = false;
140 	tcount = 0;
141 	k_thread_foreach_unlocked(thread_callback_unlocked,
142 				  TEST_STRING_UNLOCKED);
143 
144 	/* Check thread_count non-zero, thread_flag
145 	 * and stack_flag are not set.
146 	 */
147 	zassert_true(tcount && !thread_flag,
148 				"thread_callback() not getting called");
149 	/* Save the initial thread count */
150 	count = tcount;
151 
152 	/* Create new thread which should add a new entry to the thread list */
153 	k_tid_t tid = k_thread_create(&tdata, tstack,
154 			STACK_SIZE, thread_entry, NULL,
155 			NULL, NULL, K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
156 	k_msleep(1);
157 
158 	/* Call k_thread_foreach() and check
159 	 * thread_callback is getting called for
160 	 * the newly added thread.
161 	 * meanwhile, a new thread is created in callback but
162 	 * it is not be counted in this iteration
163 	 */
164 	tcount = 0;
165 	create_thread = true;
166 	k_thread_foreach_unlocked(thread_callback_unlocked,
167 				  TEST_STRING_UNLOCKED);
168 
169 	/* Check thread_count > temp, thread_flag and stack_flag are set */
170 	zassert_true((tcount > count) && thread_flag,
171 					"thread_callback() not getting called");
172 
173 	/* thread_count increase again,
174 	 * as there is a thread is created in last iteration
175 	 */
176 	tcount = 0;
177 	k_thread_foreach_unlocked(thread_callback_unlocked,
178 				  TEST_STRING_UNLOCKED);
179 	zassert_true((tcount > count) && thread_flag,
180 					"thread_callback() not getting called");
181 	k_thread_abort(tid);
182 }
183 
184 /**
185  * @brief Test k_thread_foreach API with null callback
186  *
187  * @details Call k_thread_foreach() with null callback will trigger __ASSERT()
188  * and this test thread will be aborted by z_fatal_error()
189  * @see k_thread_foreach()
190  * @ingroup kernel_thread_tests
191  */
ZTEST(threads_lifecycle_1cpu,test_k_thread_foreach_null_cb)192 ZTEST(threads_lifecycle_1cpu, test_k_thread_foreach_null_cb)
193 {
194 	k_thread_foreach(NULL, TEST_STRING);
195 }
196 
197 /**
198  * @brief Test k_thread_foreach_unlocked API with null callback
199  *
200  * @details Call k_thread_foreach_unlocked() with null callback will trigger
201  * __ASSERT() and this test thread will be aborted by z_fatal_error()
202  *
203  * @see k_thread_foreach_unlocked()
204  * @ingroup kernel_thread_tests
205  */
206 
ZTEST(threads_lifecycle_1cpu,test_k_thread_foreach_unlocked_null_cb)207 ZTEST(threads_lifecycle_1cpu, test_k_thread_foreach_unlocked_null_cb)
208 {
209 	k_thread_foreach_unlocked(NULL, TEST_STRING_UNLOCKED);
210 }
211 
212 /**
213  * @brief Test k_thread_state_str API with null callback
214  *
215  * @details It's impossible to sched a thread step by step manually to
216  * experience each state from initialization to _THREAD_DEAD. To cover each
217  * line of function k_thread_state_str(), set thread_state of tdata1 and check
218  * the string this function returns
219  *
220  * @see k_thread_state_str()
221  * @ingroup kernel_thread_tests
222  */
ZTEST(threads_lifecycle_1cpu,test_k_thread_state_str)223 ZTEST(threads_lifecycle_1cpu, test_k_thread_state_str)
224 {
225 	char state_str[32];
226 	const char *str;
227 	k_tid_t tid = &tdata1;
228 
229 	tid->base.thread_state = 0;
230 	str = k_thread_state_str(tid, state_str, sizeof(state_str));
231 	zassert_str_equal(str, "");
232 
233 	tid->base.thread_state = _THREAD_DUMMY;
234 
235 	str = k_thread_state_str(tid, NULL, sizeof(state_str));
236 	zassert_str_equal(str, "");
237 
238 	str = k_thread_state_str(tid, state_str, 0);
239 	zassert_str_equal(str, "");
240 
241 	str = k_thread_state_str(tid, state_str, sizeof(state_str));
242 	zassert_str_equal(str, "dummy");
243 
244 	tid->base.thread_state = _THREAD_PENDING;
245 	str = k_thread_state_str(tid, state_str, sizeof(state_str));
246 	zassert_str_equal(str, "pending");
247 
248 	tid->base.thread_state = _THREAD_DEAD;
249 	str = k_thread_state_str(tid, state_str, sizeof(state_str));
250 	zassert_str_equal(str, "dead");
251 
252 	tid->base.thread_state = _THREAD_SLEEPING;
253 	str = k_thread_state_str(tid, state_str, sizeof(state_str));
254 	zassert_str_equal(str, "sleeping");
255 
256 	tid->base.thread_state = _THREAD_SUSPENDED;
257 	str = k_thread_state_str(tid, state_str, sizeof(state_str));
258 	zassert_str_equal(str, "suspended");
259 
260 	tid->base.thread_state = _THREAD_ABORTING;
261 	str = k_thread_state_str(tid, state_str, sizeof(state_str));
262 	zassert_str_equal(str, "aborting");
263 
264 	tid->base.thread_state = _THREAD_QUEUED;
265 	str = k_thread_state_str(tid, state_str, sizeof(state_str));
266 	zassert_str_equal(str, "queued");
267 
268 	tid->base.thread_state = _THREAD_PENDING | _THREAD_SUSPENDED;
269 	str = k_thread_state_str(tid, state_str, sizeof(state_str));
270 	zassert_str_equal(str, "pending+suspended");
271 }
272