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