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