1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <ztest.h>
8 #include <irq_offload.h>
9 #include <debug/stack.h>
10
11 #define STACKSIZE (256 + CONFIG_TEST_EXTRA_STACKSIZE)
12
13 static K_THREAD_STACK_DEFINE(dyn_thread_stack, STACKSIZE);
14 static K_SEM_DEFINE(start_sem, 0, 1);
15 static K_SEM_DEFINE(end_sem, 0, 1);
16 static ZTEST_BMEM struct k_thread *dyn_thread;
17
k_sys_fatal_error_handler(unsigned int reason,const z_arch_esf_t * esf)18 void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf)
19 {
20 if (reason != K_ERR_KERNEL_OOPS) {
21 printk("wrong error reason\n");
22 k_fatal_halt(reason);
23 }
24 if (k_current_get() != dyn_thread) {
25 printk("wrong thread crashed\n");
26 k_fatal_halt(reason);
27 }
28 }
29
dyn_thread_entry(void * p1,void * p2,void * p3)30 static void dyn_thread_entry(void *p1, void *p2, void *p3)
31 {
32 k_sem_take(&start_sem, K_FOREVER);
33
34 k_sem_give(&end_sem);
35 }
36
prep(void)37 static void prep(void)
38 {
39 k_thread_access_grant(k_current_get(), dyn_thread_stack,
40 &start_sem, &end_sem);
41 }
42
create_dynamic_thread(void)43 static void create_dynamic_thread(void)
44 {
45 k_tid_t tid;
46
47 dyn_thread = k_object_alloc(K_OBJ_THREAD);
48
49 zassert_not_null(dyn_thread, "Cannot allocate thread k_object!");
50
51 tid = k_thread_create(dyn_thread, dyn_thread_stack, STACKSIZE,
52 dyn_thread_entry, NULL, NULL, NULL,
53 K_PRIO_PREEMPT(0), K_USER, K_FOREVER);
54
55 k_object_access_grant(&start_sem, tid);
56 k_object_access_grant(&end_sem, tid);
57
58 k_thread_start(tid);
59
60 k_sem_give(&start_sem);
61
62 zassert_true(k_sem_take(&end_sem, K_SECONDS(1)) == 0,
63 "k_sem_take(end_sem) failed");
64
65 k_thread_abort(tid);
66
67 k_object_release(dyn_thread);
68 }
69
permission_test(void)70 static void permission_test(void)
71 {
72 struct k_thread *dyn_thread;
73 k_tid_t tid;
74
75 dyn_thread = k_object_alloc(K_OBJ_THREAD);
76
77 zassert_not_null(dyn_thread, "Cannot allocate thread k_object!");
78
79 tid = k_thread_create(dyn_thread, dyn_thread_stack, STACKSIZE,
80 dyn_thread_entry, NULL, NULL, NULL,
81 K_PRIO_PREEMPT(0), K_USER, K_FOREVER);
82
83 k_object_access_grant(&start_sem, tid);
84
85 k_thread_start(tid);
86
87 /*
88 * Notice dyn_thread will not have permission to access
89 * end_sem, which will cause kernel oops.
90 */
91
92 k_sem_give(&start_sem);
93
94 /*
95 * If dyn_thread has permission to access end_sem,
96 * k_sem_take() would be able to take the semaphore.
97 */
98 zassert_true(k_sem_take(&end_sem, K_SECONDS(1)) != 0,
99 "Semaphore end_sem has incorrect permission");
100
101 k_thread_abort(tid);
102
103 k_object_release(dyn_thread);
104 }
105
106 /**
107 * @ingroup kernel_thread_tests
108 * @brief Test object permission on dynamic user thread when index is reused
109 *
110 * @details This creates one dynamic thread with permissions to both
111 * semaphores so there is no fault. Then a new thread is created and will be
112 * re-using the thread index in first pass. Except the second thread does
113 * not have permission to one of the semaphore. If permissions are cleared
114 * correctly when thread is destroyed, the second should raise kernel oops.
115 */
test_dyn_thread_perms(void)116 static void test_dyn_thread_perms(void)
117 {
118 permission_test();
119
120 TC_PRINT("===== must have access denied on k_sem %p\n", &end_sem);
121 }
122
123 static struct k_thread *dynamic_threads[CONFIG_MAX_THREAD_BYTES * 8];
124
test_thread_index_management(void)125 static void test_thread_index_management(void)
126 {
127 int i, ctr = 0;
128
129 /* Create thread objects until we run out of ids */
130 while (true) {
131 struct k_thread *t = k_object_alloc(K_OBJ_THREAD);
132
133 if (t == NULL) {
134 break;
135 }
136
137 dynamic_threads[ctr] = t;
138 ctr++;
139 }
140
141 zassert_true(ctr != 0, "unable to create any thread objects");
142
143 TC_PRINT("created %d thread objects\n", ctr);
144
145 /* Show that the above NULL return value wasn't because we ran out of
146 * heap space/
147 */
148 void *blob = k_malloc(256);
149 zassert_true(blob != NULL, "out of heap memory");
150
151 /* Free one of the threads... */
152 k_object_free(dynamic_threads[0]);
153
154 /* And show that we can now create another one, the freed thread's
155 * index should have been garbage collected.
156 */
157 dynamic_threads[0] = k_object_alloc(K_OBJ_THREAD);
158 zassert_true(dynamic_threads[0] != NULL,
159 "couldn't create thread object\n");
160
161 /* TODO: Implement a test that shows that thread IDs are properly
162 * recycled when a thread object is garbage collected due to references
163 * dropping to zero. For example, we ought to be able to exit here
164 * without calling k_object_free() on any of the threads we created
165 * here; their references would drop to zero and they would be
166 * automatically freed. However, it is known that the thread IDs are
167 * not properly recycled when this happens, see #17023.
168 */
169 for (i = 0; i < ctr; i++) {
170 k_object_free(dynamic_threads[i]);
171 }
172 }
173
174 /**
175 * @ingroup kernel_thread_tests
176 * @brief Test creation of dynamic user thread under kernel thread
177 *
178 * @details This is a simple test to create a user thread
179 * dynamically via k_object_alloc() under a kernel thread.
180 */
test_kernel_create_dyn_user_thread(void)181 static void test_kernel_create_dyn_user_thread(void)
182 {
183 create_dynamic_thread();
184 }
185
186 /**
187 * @ingroup kernel_thread_tests
188 * @brief Test creation of dynamic user thread under user thread
189 *
190 * @details This is a simple test to create a user thread
191 * dynamically via k_object_alloc() under a user thread.
192 */
test_user_create_dyn_user_thread(void)193 static void test_user_create_dyn_user_thread(void)
194 {
195 create_dynamic_thread();
196 }
197
198 /* test case main entry */
test_main(void)199 void test_main(void)
200 {
201 k_thread_system_pool_assign(k_current_get());
202
203 prep();
204
205 ztest_test_suite(thread_dynamic,
206 ztest_unit_test(test_kernel_create_dyn_user_thread),
207 ztest_user_unit_test(test_user_create_dyn_user_thread),
208 ztest_unit_test(test_dyn_thread_perms),
209 ztest_unit_test(test_thread_index_management)
210 );
211 ztest_run_test_suite(thread_dynamic);
212 }
213