1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8
9 #include "tests_thread_apis.h"
10
11 static ZTEST_BMEM int execute_flag;
12
13 K_SEM_DEFINE(sync_sema, 0, 1);
14 #define BLOCK_SIZE 64
15
thread_entry(void * p1,void * p2,void * p3)16 static void thread_entry(void *p1, void *p2, void *p3)
17 {
18 execute_flag = 1;
19 k_msleep(100);
20 execute_flag = 2;
21 }
22
thread_entry_abort(void * p1,void * p2,void * p3)23 static void thread_entry_abort(void *p1, void *p2, void *p3)
24 {
25 /**TESTPOINT: abort current thread*/
26 execute_flag = 1;
27 k_thread_abort(k_current_get());
28 CODE_UNREACHABLE;
29 /*unreachable*/
30 execute_flag = 2;
31 zassert_true(1 == 0);
32 }
33 /**
34 * @ingroup kernel_thread_tests
35 * @brief Validate k_thread_abort() when called by current thread
36 *
37 * @details Create a user thread and let the thread execute.
38 * Then call k_thread_abort() and check if the thread is terminated.
39 * Here the main thread is also a user thread.
40 *
41 * @see k_thread_abort()
42 */
ZTEST_USER(threads_lifecycle,test_threads_abort_self)43 ZTEST_USER(threads_lifecycle, test_threads_abort_self)
44 {
45 execute_flag = 0;
46 k_thread_create(&tdata, tstack, STACK_SIZE, thread_entry_abort,
47 NULL, NULL, NULL, 0, K_USER, K_NO_WAIT);
48 k_msleep(100);
49 /**TESTPOINT: spawned thread executed but abort itself*/
50 zassert_true(execute_flag == 1);
51 }
52
53 /**
54 * @ingroup kernel_thread_tests
55 * @brief Validate k_thread_abort() when called by other thread
56 *
57 * @details Create a user thread and abort the thread before its
58 * execution. Create a another user thread and abort the thread
59 * after it has started.
60 *
61 * @see k_thread_abort()
62 */
ZTEST_USER(threads_lifecycle,test_threads_abort_others)63 ZTEST_USER(threads_lifecycle, test_threads_abort_others)
64 {
65 execute_flag = 0;
66 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
67 thread_entry, NULL, NULL, NULL,
68 0, K_USER, K_NO_WAIT);
69
70 k_thread_abort(tid);
71 k_msleep(100);
72 /**TESTPOINT: check not-started thread is aborted*/
73 zassert_true(execute_flag == 0);
74
75 tid = k_thread_create(&tdata, tstack, STACK_SIZE,
76 thread_entry, NULL, NULL, NULL,
77 0, K_USER, K_NO_WAIT);
78 k_msleep(50);
79 k_thread_abort(tid);
80 /**TESTPOINT: check running thread is aborted*/
81 zassert_true(execute_flag == 1);
82 k_msleep(1000);
83 zassert_true(execute_flag == 1);
84 }
85
86 /**
87 * @ingroup kernel_thread_tests
88 * @brief Test abort on a terminated thread
89 *
90 * @see k_thread_abort()
91 */
ZTEST(threads_lifecycle_1cpu,test_threads_abort_repeat)92 ZTEST(threads_lifecycle_1cpu, test_threads_abort_repeat)
93 {
94 execute_flag = 0;
95 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
96 thread_entry, NULL, NULL, NULL,
97 0, K_USER, K_NO_WAIT);
98
99 k_thread_abort(tid);
100 k_msleep(100);
101 k_thread_abort(tid);
102 k_msleep(100);
103 k_thread_abort(tid);
104 /* If no fault occurred till now. The test case passed. */
105 ztest_test_pass();
106 }
107
108 bool abort_called;
109 void *block;
110
delayed_thread_entry(void * p1,void * p2,void * p3)111 static void delayed_thread_entry(void *p1, void *p2, void *p3)
112 {
113 ARG_UNUSED(p1);
114 ARG_UNUSED(p2);
115 ARG_UNUSED(p3);
116
117 execute_flag = 1;
118
119 zassert_unreachable("Delayed thread shouldn't be executed");
120 }
121
122 /**
123 * @ingroup kernel_thread_tests
124 * @brief Test abort on delayed thread before it has started
125 * execution
126 *
127 * @see k_thread_abort()
128 */
ZTEST(threads_lifecycle_1cpu,test_delayed_thread_abort)129 ZTEST(threads_lifecycle_1cpu, test_delayed_thread_abort)
130 {
131 int current_prio = k_thread_priority_get(k_current_get());
132
133 execute_flag = 0;
134 /* Make current thread preemptive */
135 k_thread_priority_set(k_current_get(), K_PRIO_PREEMPT(2));
136
137 /* Create a preemptive thread of higher priority than
138 * current thread
139 */
140 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
141 delayed_thread_entry, NULL, NULL, NULL,
142 K_PRIO_PREEMPT(1), 0, K_MSEC(100));
143
144 /* Give up CPU */
145 k_msleep(50);
146
147 /* Test point: check if thread delayed for 100ms has not started*/
148 zassert_true(execute_flag == 0, "Delayed thread created is not"
149 " put to wait queue");
150
151 k_thread_abort(tid);
152
153 /* Test point: Test abort of thread before its execution*/
154 zassert_false(execute_flag == 1, "Delayed thread is has executed"
155 " before cancellation");
156
157 /* Restore the priority */
158 k_thread_priority_set(k_current_get(), current_prio);
159 }
160
161 static volatile bool isr_finished;
162
offload_func(const void * param)163 static void offload_func(const void *param)
164 {
165 struct k_thread *t = (struct k_thread *)param;
166
167 k_thread_abort(t);
168
169 /* Thread memory is unused now, validate that we can clobber it. */
170 if (!IS_ENABLED(CONFIG_ARCH_POSIX)) {
171 memset(t, 0, sizeof(*t));
172 }
173
174 /* k_thread_abort() in an isr shouldn't affect the ISR's execution */
175 isr_finished = true;
176 }
177
entry_abort_isr(void * p1,void * p2,void * p3)178 static void entry_abort_isr(void *p1, void *p2, void *p3)
179 {
180 /* Simulate taking an interrupt which kills this thread */
181 irq_offload(offload_func, k_current_get());
182
183 printk("shouldn't see this, thread should have been killed");
184 ztest_test_fail();
185 }
186
187 extern struct k_sem offload_sem;
188
189 /**
190 * @ingroup kernel_thread_tests
191 *
192 * @brief Show that threads can be aborted from interrupt context by itself
193 *
194 * @details Spwan a thread, then enter ISR context in child thread and abort
195 * the child thread. Check if ISR completed and target thread was aborted.
196 *
197 * @see k_thread_abort()
198 */
ZTEST(threads_lifecycle,test_abort_from_isr)199 ZTEST(threads_lifecycle, test_abort_from_isr)
200 {
201 isr_finished = false;
202 k_thread_create(&tdata, tstack, STACK_SIZE, entry_abort_isr,
203 NULL, NULL, NULL, 0, 0, K_NO_WAIT);
204
205
206 k_thread_join(&tdata, K_FOREVER);
207 zassert_true(isr_finished, "ISR did not complete");
208
209 /* Thread struct was cleared after the abort, make sure it is
210 * still clear (i.e. that the arch layer didn't write to it
211 * during interrupt exit). Doesn't work on posix, which needs
212 * the thread struct for its swap code.
213 */
214 uint8_t *p = (uint8_t *)&tdata;
215
216 if (!IS_ENABLED(CONFIG_ARCH_POSIX)) {
217 for (int i = 0; i < sizeof(tdata); i++) {
218 zassert_true(p[i] == 0, "Free memory write to aborted thread");
219 }
220 }
221
222 /* Notice: Recover back the offload_sem: This is use for releasing
223 * offload_sem which might be held when thread aborts itself in ISR
224 * context, it will cause irq_offload cannot be used again.
225 */
226 k_sem_give(&offload_sem);
227 }
228
229 /* use for sync thread start */
230 static struct k_sem sem_abort;
231
entry_aborted_thread(void * p1,void * p2,void * p3)232 static void entry_aborted_thread(void *p1, void *p2, void *p3)
233 {
234 k_sem_give(&sem_abort);
235
236 /* wait for being aborted */
237 while (1) {
238 k_sleep(K_MSEC(1));
239 }
240 zassert_unreachable("should not reach here");
241 }
242
243 /**
244 * @ingroup kernel_thread_tests
245 *
246 * @brief Show that threads can be aborted from interrupt context
247 *
248 * @details Spwan a thread, then enter ISR context in main thread and abort
249 * the child thread. Check if ISR completed and target thread was aborted.
250 *
251 * @see k_thread_abort()
252 */
ZTEST(threads_lifecycle,test_abort_from_isr_not_self)253 ZTEST(threads_lifecycle, test_abort_from_isr_not_self)
254 {
255 k_tid_t tid;
256
257 isr_finished = false;
258 k_sem_init(&sem_abort, 0, 1);
259
260 tid = k_thread_create(&tdata, tstack, STACK_SIZE, entry_aborted_thread,
261 NULL, NULL, NULL, 0, 0, K_NO_WAIT);
262
263 /* wait for thread started */
264 k_sem_take(&sem_abort, K_FOREVER);
265
266 /* Simulate taking an interrupt which kills spwan thread */
267 irq_offload(offload_func, (void *)tid);
268
269 zassert_true(isr_finished, "ISR did not complete");
270 }
271