Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2010-2014 Wind River Systems, Inc.
3 : : *
4 : : * SPDX-License-Identifier: Apache-2.0
5 : : */
6 : :
7 : : /**
8 : : * @file
9 : : * @brief Kernel thread support
10 : : *
11 : : * This module provides general purpose thread support.
12 : : */
13 : :
14 : : #include <zephyr/kernel.h>
15 : : #include <zephyr/spinlock.h>
16 : : #include <zephyr/sys/math_extras.h>
17 : : #include <zephyr/sys_clock.h>
18 : : #include <ksched.h>
19 : : #include <kthread.h>
20 : : #include <wait_q.h>
21 : : #include <zephyr/internal/syscall_handler.h>
22 : : #include <kernel_internal.h>
23 : : #include <kswap.h>
24 : : #include <zephyr/init.h>
25 : : #include <zephyr/tracing/tracing.h>
26 : : #include <string.h>
27 : : #include <stdbool.h>
28 : : #include <zephyr/sys/check.h>
29 : : #include <zephyr/random/random.h>
30 : : #include <zephyr/sys/atomic.h>
31 : : #include <zephyr/logging/log.h>
32 : : #include <zephyr/llext/symbol.h>
33 : : #include <zephyr/sys/iterable_sections.h>
34 : :
35 : : LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
36 : :
37 : : #ifdef CONFIG_OBJ_CORE_THREAD
38 : : static struct k_obj_type obj_type_thread;
39 : :
40 : : #ifdef CONFIG_OBJ_CORE_STATS_THREAD
41 : : static struct k_obj_core_stats_desc thread_stats_desc = {
42 : : .raw_size = sizeof(struct k_cycle_stats),
43 : : .query_size = sizeof(struct k_thread_runtime_stats),
44 : : .raw = z_thread_stats_raw,
45 : : .query = z_thread_stats_query,
46 : : .reset = z_thread_stats_reset,
47 : : .disable = z_thread_stats_disable,
48 : : .enable = z_thread_stats_enable,
49 : : };
50 : : #endif /* CONFIG_OBJ_CORE_STATS_THREAD */
51 : :
52 : : static int init_thread_obj_core_list(void)
53 : : {
54 : : /* Initialize mem_slab object type */
55 : :
56 : : #ifdef CONFIG_OBJ_CORE_THREAD
57 : : z_obj_type_init(&obj_type_thread, K_OBJ_TYPE_THREAD_ID,
58 : : offsetof(struct k_thread, obj_core));
59 : : #endif /* CONFIG_OBJ_CORE_THREAD */
60 : :
61 : : #ifdef CONFIG_OBJ_CORE_STATS_THREAD
62 : : k_obj_type_stats_init(&obj_type_thread, &thread_stats_desc);
63 : : #endif /* CONFIG_OBJ_CORE_STATS_THREAD */
64 : :
65 : : return 0;
66 : : }
67 : :
68 : : SYS_INIT(init_thread_obj_core_list, PRE_KERNEL_1,
69 : : CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
70 : : #endif /* CONFIG_OBJ_CORE_THREAD */
71 : :
72 : :
73 : : #define _FOREACH_STATIC_THREAD(thread_data) \
74 : : STRUCT_SECTION_FOREACH(_static_thread_data, thread_data)
75 : :
76 : 0 : bool k_is_in_isr(void)
77 : : {
78 : 0 : return arch_is_in_isr();
79 : : }
80 : : EXPORT_SYMBOL(k_is_in_isr);
81 : :
82 : : #ifdef CONFIG_THREAD_CUSTOM_DATA
83 : : void z_impl_k_thread_custom_data_set(void *value)
84 : : {
85 : : _current->custom_data = value;
86 : : }
87 : :
88 : : #ifdef CONFIG_USERSPACE
89 : : static inline void z_vrfy_k_thread_custom_data_set(void *data)
90 : : {
91 : : z_impl_k_thread_custom_data_set(data);
92 : : }
93 : : #include <zephyr/syscalls/k_thread_custom_data_set_mrsh.c>
94 : : #endif /* CONFIG_USERSPACE */
95 : :
96 : : void *z_impl_k_thread_custom_data_get(void)
97 : : {
98 : : return _current->custom_data;
99 : : }
100 : :
101 : : #ifdef CONFIG_USERSPACE
102 : : static inline void *z_vrfy_k_thread_custom_data_get(void)
103 : : {
104 : : return z_impl_k_thread_custom_data_get();
105 : : }
106 : : #include <zephyr/syscalls/k_thread_custom_data_get_mrsh.c>
107 : :
108 : : #endif /* CONFIG_USERSPACE */
109 : : #endif /* CONFIG_THREAD_CUSTOM_DATA */
110 : :
111 : 0 : int z_impl_k_is_preempt_thread(void)
112 : : {
113 [ # # # # ]: 0 : return !arch_is_in_isr() && thread_is_preemptible(_current);
114 : : }
115 : :
116 : : #ifdef CONFIG_USERSPACE
117 : : static inline int z_vrfy_k_is_preempt_thread(void)
118 : : {
119 : : return z_impl_k_is_preempt_thread();
120 : : }
121 : : #include <zephyr/syscalls/k_is_preempt_thread_mrsh.c>
122 : : #endif /* CONFIG_USERSPACE */
123 : :
124 : 0 : int z_impl_k_thread_priority_get(k_tid_t thread)
125 : : {
126 : 0 : return thread->base.prio;
127 : : }
128 : :
129 : : #ifdef CONFIG_USERSPACE
130 : : static inline int z_vrfy_k_thread_priority_get(k_tid_t thread)
131 : : {
132 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
133 : : return z_impl_k_thread_priority_get(thread);
134 : : }
135 : : #include <zephyr/syscalls/k_thread_priority_get_mrsh.c>
136 : : #endif /* CONFIG_USERSPACE */
137 : :
138 : 42 : int z_impl_k_thread_name_set(k_tid_t thread, const char *str)
139 : : {
140 : : #ifdef CONFIG_THREAD_NAME
141 [ - + ]: 42 : if (thread == NULL) {
142 : 0 : thread = _current;
143 : : }
144 : :
145 : 42 : strncpy(thread->name, str, CONFIG_THREAD_MAX_NAME_LEN - 1);
146 : 42 : thread->name[CONFIG_THREAD_MAX_NAME_LEN - 1] = '\0';
147 : :
148 : : #ifdef CONFIG_ARCH_HAS_THREAD_NAME_HOOK
149 : 42 : arch_thread_name_set(thread, str);
150 : : #endif /* CONFIG_ARCH_HAS_THREAD_NAME_HOOK */
151 : :
152 : 42 : SYS_PORT_TRACING_OBJ_FUNC(k_thread, name_set, thread, 0);
153 : :
154 : 42 : return 0;
155 : : #else
156 : : ARG_UNUSED(thread);
157 : : ARG_UNUSED(str);
158 : :
159 : : SYS_PORT_TRACING_OBJ_FUNC(k_thread, name_set, thread, -ENOSYS);
160 : :
161 : : return -ENOSYS;
162 : : #endif /* CONFIG_THREAD_NAME */
163 : : }
164 : :
165 : : #ifdef CONFIG_USERSPACE
166 : : static inline int z_vrfy_k_thread_name_set(k_tid_t thread, const char *str)
167 : : {
168 : : #ifdef CONFIG_THREAD_NAME
169 : : char name[CONFIG_THREAD_MAX_NAME_LEN];
170 : :
171 : : if (thread != NULL) {
172 : : if (K_SYSCALL_OBJ(thread, K_OBJ_THREAD) != 0) {
173 : : return -EINVAL;
174 : : }
175 : : }
176 : :
177 : : /* In theory we could copy directly into thread->name, but
178 : : * the current z_vrfy / z_impl split does not provide a
179 : : * means of doing so.
180 : : */
181 : : if (k_usermode_string_copy(name, str, sizeof(name)) != 0) {
182 : : return -EFAULT;
183 : : }
184 : :
185 : : return z_impl_k_thread_name_set(thread, name);
186 : : #else
187 : : return -ENOSYS;
188 : : #endif /* CONFIG_THREAD_NAME */
189 : : }
190 : : #include <zephyr/syscalls/k_thread_name_set_mrsh.c>
191 : : #endif /* CONFIG_USERSPACE */
192 : :
193 : 0 : const char *k_thread_name_get(k_tid_t thread)
194 : : {
195 : : #ifdef CONFIG_THREAD_NAME
196 : 0 : return (const char *)thread->name;
197 : : #else
198 : : ARG_UNUSED(thread);
199 : : return NULL;
200 : : #endif /* CONFIG_THREAD_NAME */
201 : : }
202 : :
203 : 0 : int z_impl_k_thread_name_copy(k_tid_t thread, char *buf, size_t size)
204 : : {
205 : : #ifdef CONFIG_THREAD_NAME
206 : 0 : strncpy(buf, thread->name, size);
207 : 0 : return 0;
208 : : #else
209 : : ARG_UNUSED(thread);
210 : : ARG_UNUSED(buf);
211 : : ARG_UNUSED(size);
212 : : return -ENOSYS;
213 : : #endif /* CONFIG_THREAD_NAME */
214 : : }
215 : :
216 : 0 : static size_t copy_bytes(char *dest, size_t dest_size, const char *src, size_t src_size)
217 : : {
218 : 0 : size_t bytes_to_copy;
219 : :
220 : 0 : bytes_to_copy = MIN(dest_size, src_size);
221 : 0 : memcpy(dest, src, bytes_to_copy);
222 : :
223 : 0 : return bytes_to_copy;
224 : : }
225 : :
226 : 0 : const char *k_thread_state_str(k_tid_t thread_id, char *buf, size_t buf_size)
227 : : {
228 : 0 : size_t off = 0;
229 : 0 : uint8_t bit;
230 : 0 : uint8_t thread_state = thread_id->base.thread_state;
231 : 0 : static const struct {
232 : : const char *str;
233 : : size_t len;
234 : : } state_string[] = {
235 : : { Z_STATE_STR_DUMMY, sizeof(Z_STATE_STR_DUMMY) - 1},
236 : : { Z_STATE_STR_PENDING, sizeof(Z_STATE_STR_PENDING) - 1},
237 : : { Z_STATE_STR_PRESTART, sizeof(Z_STATE_STR_PRESTART) - 1},
238 : : { Z_STATE_STR_DEAD, sizeof(Z_STATE_STR_DEAD) - 1},
239 : : { Z_STATE_STR_SUSPENDED, sizeof(Z_STATE_STR_SUSPENDED) - 1},
240 : : { Z_STATE_STR_ABORTING, sizeof(Z_STATE_STR_ABORTING) - 1},
241 : : { Z_STATE_STR_SUSPENDING, sizeof(Z_STATE_STR_SUSPENDING) - 1},
242 : : { Z_STATE_STR_QUEUED, sizeof(Z_STATE_STR_QUEUED) - 1},
243 : : };
244 : :
245 [ # # ]: 0 : if ((buf == NULL) || (buf_size == 0)) {
246 : : return "";
247 : : }
248 : :
249 : 0 : buf_size--; /* Reserve 1 byte for end-of-string character */
250 : :
251 : : /*
252 : : * Loop through each bit in the thread_state. Stop once all have
253 : : * been processed. If more than one thread_state bit is set, then
254 : : * separate the descriptive strings with a '+'.
255 : : */
256 : :
257 : :
258 [ # # ]: 0 : for (unsigned int index = 0; thread_state != 0; index++) {
259 : 0 : bit = BIT(index);
260 [ # # ]: 0 : if ((thread_state & bit) == 0) {
261 : 0 : continue;
262 : : }
263 : :
264 : 0 : off += copy_bytes(buf + off, buf_size - off,
265 : 0 : state_string[index].str,
266 : 0 : state_string[index].len);
267 : :
268 : 0 : thread_state &= ~bit;
269 : :
270 [ # # ]: 0 : if (thread_state != 0) {
271 : 0 : off += copy_bytes(buf + off, buf_size - off, "+", 1);
272 : : }
273 : : }
274 : :
275 : 0 : buf[off] = '\0';
276 : :
277 : 0 : return (const char *)buf;
278 : : }
279 : :
280 : : #ifdef CONFIG_USERSPACE
281 : : static inline int z_vrfy_k_thread_name_copy(k_tid_t thread,
282 : : char *buf, size_t size)
283 : : {
284 : : #ifdef CONFIG_THREAD_NAME
285 : : size_t len;
286 : : struct k_object *ko = k_object_find(thread);
287 : :
288 : : /* Special case: we allow reading the names of initialized threads
289 : : * even if we don't have permission on them
290 : : */
291 : : if ((thread == NULL) || (ko->type != K_OBJ_THREAD) ||
292 : : ((ko->flags & K_OBJ_FLAG_INITIALIZED) == 0)) {
293 : : return -EINVAL;
294 : : }
295 : : if (K_SYSCALL_MEMORY_WRITE(buf, size) != 0) {
296 : : return -EFAULT;
297 : : }
298 : : len = strlen(thread->name);
299 : : if ((len + 1) > size) {
300 : : return -ENOSPC;
301 : : }
302 : :
303 : : return k_usermode_to_copy((void *)buf, thread->name, len + 1);
304 : : #else
305 : : ARG_UNUSED(thread);
306 : : ARG_UNUSED(buf);
307 : : ARG_UNUSED(size);
308 : : return -ENOSYS;
309 : : #endif /* CONFIG_THREAD_NAME */
310 : : }
311 : : #include <zephyr/syscalls/k_thread_name_copy_mrsh.c>
312 : : #endif /* CONFIG_USERSPACE */
313 : :
314 : : #ifdef CONFIG_STACK_SENTINEL
315 : : /* Check that the stack sentinel is still present
316 : : *
317 : : * The stack sentinel feature writes a magic value to the lowest 4 bytes of
318 : : * the thread's stack when the thread is initialized. This value gets checked
319 : : * in a few places:
320 : : *
321 : : * 1) In k_yield() if the current thread is not swapped out
322 : : * 2) After servicing a non-nested interrupt
323 : : * 3) In z_swap(), check the sentinel in the outgoing thread
324 : : *
325 : : * Item 2 requires support in arch/ code.
326 : : *
327 : : * If the check fails, the thread will be terminated appropriately through
328 : : * the system fatal error handler.
329 : : */
330 : : void z_check_stack_sentinel(void)
331 : : {
332 : : uint32_t *stack;
333 : :
334 : : if ((_current->base.thread_state & _THREAD_DUMMY) != 0) {
335 : : return;
336 : : }
337 : :
338 : : stack = (uint32_t *)_current->stack_info.start;
339 : : if (*stack != STACK_SENTINEL) {
340 : : /* Restore it so further checks don't trigger this same error */
341 : : *stack = STACK_SENTINEL;
342 : : z_except_reason(K_ERR_STACK_CHK_FAIL);
343 : : }
344 : : }
345 : : #endif /* CONFIG_STACK_SENTINEL */
346 : :
347 : 50 : void z_impl_k_thread_start(k_tid_t thread)
348 : : {
349 : 50 : SYS_PORT_TRACING_OBJ_FUNC(k_thread, start, thread);
350 : :
351 : 50 : z_sched_start(thread);
352 : 50 : }
353 : :
354 : : #ifdef CONFIG_USERSPACE
355 : : static inline void z_vrfy_k_thread_start(k_tid_t thread)
356 : : {
357 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
358 : : return z_impl_k_thread_start(thread);
359 : : }
360 : : #include <zephyr/syscalls/k_thread_start_mrsh.c>
361 : : #endif /* CONFIG_USERSPACE */
362 : :
363 : : #if defined(CONFIG_STACK_POINTER_RANDOM) && (CONFIG_STACK_POINTER_RANDOM != 0)
364 : : int z_stack_adjust_initialized;
365 : :
366 : : static size_t random_offset(size_t stack_size)
367 : : {
368 : : size_t random_val;
369 : :
370 : : if (!z_stack_adjust_initialized) {
371 : : z_early_rand_get((uint8_t *)&random_val, sizeof(random_val));
372 : : } else {
373 : : sys_rand_get((uint8_t *)&random_val, sizeof(random_val));
374 : : }
375 : :
376 : : /* Don't need to worry about alignment of the size here,
377 : : * arch_new_thread() is required to do it.
378 : : *
379 : : * FIXME: Not the best way to get a random number in a range.
380 : : * See #6493
381 : : */
382 : : const size_t fuzz = random_val % CONFIG_STACK_POINTER_RANDOM;
383 : :
384 : : if (unlikely(fuzz * 2 > stack_size)) {
385 : : return 0;
386 : : }
387 : :
388 : : return fuzz;
389 : : }
390 : : #if defined(CONFIG_STACK_GROWS_UP)
391 : : /* This is so rare not bothering for now */
392 : : #error "Stack pointer randomization not implemented for upward growing stacks"
393 : : #endif /* CONFIG_STACK_GROWS_UP */
394 : : #endif /* CONFIG_STACK_POINTER_RANDOM */
395 : :
396 : 48 : static char *setup_thread_stack(struct k_thread *new_thread,
397 : : k_thread_stack_t *stack, size_t stack_size)
398 : : {
399 : 48 : size_t stack_obj_size, stack_buf_size;
400 : 48 : char *stack_ptr, *stack_buf_start;
401 : 48 : size_t delta = 0;
402 : :
403 : : #ifdef CONFIG_USERSPACE
404 : : if (z_stack_is_user_capable(stack)) {
405 : : stack_obj_size = K_THREAD_STACK_LEN(stack_size);
406 : : stack_buf_start = K_THREAD_STACK_BUFFER(stack);
407 : : stack_buf_size = stack_obj_size - K_THREAD_STACK_RESERVED;
408 : : } else
409 : : #endif /* CONFIG_USERSPACE */
410 : : {
411 : : /* Object cannot host a user mode thread */
412 : 48 : stack_obj_size = K_KERNEL_STACK_LEN(stack_size);
413 : 48 : stack_buf_start = K_KERNEL_STACK_BUFFER(stack);
414 : 48 : stack_buf_size = stack_obj_size - K_KERNEL_STACK_RESERVED;
415 : :
416 : : /* Zephyr treats stack overflow as an app bug. But
417 : : * this particular overflow can be seen by static
418 : : * analysis so needs to be handled somehow.
419 : : */
420 : 48 : if (K_KERNEL_STACK_RESERVED > stack_obj_size) {
421 : 48 : k_panic();
422 : : }
423 : :
424 : : }
425 : :
426 : : #ifdef CONFIG_THREAD_STACK_MEM_MAPPED
427 : : /* Map the stack into virtual memory and use that as the base to
428 : : * calculate the initial stack pointer at the high end of the stack
429 : : * object. The stack pointer may be reduced later in this function
430 : : * by TLS or random offset.
431 : : *
432 : : * K_MEM_MAP_UNINIT is used to mimic the behavior of non-mapped
433 : : * stack. If CONFIG_INIT_STACKS is enabled, the stack will be
434 : : * cleared below.
435 : : */
436 : : void *stack_mapped = k_mem_map_phys_guard((uintptr_t)stack, stack_obj_size,
437 : : K_MEM_PERM_RW | K_MEM_CACHE_WB | K_MEM_MAP_UNINIT,
438 : : false);
439 : :
440 : : __ASSERT_NO_MSG((uintptr_t)stack_mapped != 0);
441 : :
442 : : #ifdef CONFIG_USERSPACE
443 : : if (z_stack_is_user_capable(stack)) {
444 : : stack_buf_start = K_THREAD_STACK_BUFFER(stack_mapped);
445 : : } else
446 : : #endif /* CONFIG_USERSPACE */
447 : : {
448 : : stack_buf_start = K_KERNEL_STACK_BUFFER(stack_mapped);
449 : : }
450 : :
451 : : stack_ptr = (char *)stack_mapped + stack_obj_size;
452 : :
453 : : /* Need to store the info on mapped stack so we can remove the mappings
454 : : * when the thread ends.
455 : : */
456 : : new_thread->stack_info.mapped.addr = stack_mapped;
457 : : new_thread->stack_info.mapped.sz = stack_obj_size;
458 : :
459 : : #else /* CONFIG_THREAD_STACK_MEM_MAPPED */
460 : :
461 : : /* Initial stack pointer at the high end of the stack object, may
462 : : * be reduced later in this function by TLS or random offset
463 : : */
464 : 48 : stack_ptr = (char *)stack + stack_obj_size;
465 : :
466 : : #endif /* CONFIG_THREAD_STACK_MEM_MAPPED */
467 : :
468 : 48 : LOG_DBG("stack %p for thread %p: obj_size=%zu buf_start=%p "
469 : : " buf_size %zu stack_ptr=%p",
470 : : stack, new_thread, stack_obj_size, (void *)stack_buf_start,
471 : : stack_buf_size, (void *)stack_ptr);
472 : :
473 : : #ifdef CONFIG_INIT_STACKS
474 : 48 : memset(stack_buf_start, 0xaa, stack_buf_size);
475 : : #endif /* CONFIG_INIT_STACKS */
476 : : #ifdef CONFIG_STACK_SENTINEL
477 : : /* Put the stack sentinel at the lowest 4 bytes of the stack area.
478 : : * We periodically check that it's still present and kill the thread
479 : : * if it isn't.
480 : : */
481 : : *((uint32_t *)stack_buf_start) = STACK_SENTINEL;
482 : : #endif /* CONFIG_STACK_SENTINEL */
483 : : #ifdef CONFIG_THREAD_LOCAL_STORAGE
484 : : /* TLS is always last within the stack buffer */
485 : : delta += arch_tls_stack_setup(new_thread, stack_ptr);
486 : : #endif /* CONFIG_THREAD_LOCAL_STORAGE */
487 : : #ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA
488 : : size_t tls_size = sizeof(struct _thread_userspace_local_data);
489 : :
490 : : /* reserve space on highest memory of stack buffer for local data */
491 : : delta += tls_size;
492 : : new_thread->userspace_local_data =
493 : : (struct _thread_userspace_local_data *)(stack_ptr - delta);
494 : : #endif /* CONFIG_THREAD_USERSPACE_LOCAL_DATA */
495 : : #if defined(CONFIG_STACK_POINTER_RANDOM) && (CONFIG_STACK_POINTER_RANDOM != 0)
496 : : delta += random_offset(stack_buf_size);
497 : : #endif /* CONFIG_STACK_POINTER_RANDOM */
498 : 48 : delta = ROUND_UP(delta, ARCH_STACK_PTR_ALIGN);
499 : : #ifdef CONFIG_THREAD_STACK_INFO
500 : : /* Initial values. Arches which implement MPU guards that "borrow"
501 : : * memory from the stack buffer (not tracked in K_THREAD_STACK_RESERVED)
502 : : * will need to appropriately update this.
503 : : *
504 : : * The bounds tracked here correspond to the area of the stack object
505 : : * that the thread can access, which includes TLS.
506 : : */
507 : : new_thread->stack_info.start = (uintptr_t)stack_buf_start;
508 : : new_thread->stack_info.size = stack_buf_size;
509 : : new_thread->stack_info.delta = delta;
510 : : #endif /* CONFIG_THREAD_STACK_INFO */
511 : 48 : stack_ptr -= delta;
512 : :
513 : 48 : return stack_ptr;
514 : : }
515 : :
516 : : /*
517 : : * The provided stack_size value is presumed to be either the result of
518 : : * K_THREAD_STACK_SIZEOF(stack), or the size value passed to the instance
519 : : * of K_THREAD_STACK_DEFINE() which defined 'stack'.
520 : : */
521 : 48 : char *z_setup_new_thread(struct k_thread *new_thread,
522 : : k_thread_stack_t *stack, size_t stack_size,
523 : : k_thread_entry_t entry,
524 : : void *p1, void *p2, void *p3,
525 : : int prio, uint32_t options, const char *name)
526 : : {
527 : 48 : char *stack_ptr;
528 : :
529 [ + + - + : 48 : Z_ASSERT_VALID_PRIO(prio, entry);
- + ]
530 : :
531 : : #ifdef CONFIG_THREAD_ABORT_NEED_CLEANUP
532 : : k_thread_abort_cleanup_check_reuse(new_thread);
533 : : #endif /* CONFIG_THREAD_ABORT_NEED_CLEANUP */
534 : :
535 : : #ifdef CONFIG_OBJ_CORE_THREAD
536 : : k_obj_core_init_and_link(K_OBJ_CORE(new_thread), &obj_type_thread);
537 : : #ifdef CONFIG_OBJ_CORE_STATS_THREAD
538 : : k_obj_core_stats_register(K_OBJ_CORE(new_thread),
539 : : &new_thread->base.usage,
540 : : sizeof(new_thread->base.usage));
541 : : #endif /* CONFIG_OBJ_CORE_STATS_THREAD */
542 : : #endif /* CONFIG_OBJ_CORE_THREAD */
543 : :
544 : : #ifdef CONFIG_USERSPACE
545 : : __ASSERT((options & K_USER) == 0U || z_stack_is_user_capable(stack),
546 : : "user thread %p with kernel-only stack %p",
547 : : new_thread, stack);
548 : : k_object_init(new_thread);
549 : : k_object_init(stack);
550 : : new_thread->stack_obj = stack;
551 : : new_thread->syscall_frame = NULL;
552 : :
553 : : /* Any given thread has access to itself */
554 : : k_object_access_grant(new_thread, new_thread);
555 : : #endif /* CONFIG_USERSPACE */
556 : 48 : z_waitq_init(&new_thread->join_queue);
557 : :
558 : : /* Initialize various struct k_thread members */
559 : 48 : z_init_thread_base(&new_thread->base, prio, _THREAD_PRESTART, options);
560 : 48 : stack_ptr = setup_thread_stack(new_thread, stack, stack_size);
561 : :
562 : : #ifdef CONFIG_KERNEL_COHERENCE
563 : : /* Check that the thread object is safe, but that the stack is
564 : : * still cached!
565 : : */
566 : : __ASSERT_NO_MSG(arch_mem_coherent(new_thread));
567 : :
568 : : /* When dynamic thread stack is available, the stack may come from
569 : : * uncached area.
570 : : */
571 : : #ifndef CONFIG_DYNAMIC_THREAD
572 : : __ASSERT_NO_MSG(!arch_mem_coherent(stack));
573 : : #endif /* CONFIG_DYNAMIC_THREAD */
574 : :
575 : : #endif /* CONFIG_KERNEL_COHERENCE */
576 : :
577 : 48 : arch_new_thread(new_thread, stack, stack_ptr, entry, p1, p2, p3);
578 : :
579 : : /* static threads overwrite it afterwards with real value */
580 : 48 : new_thread->init_data = NULL;
581 : :
582 : : #ifdef CONFIG_USE_SWITCH
583 : : /* switch_handle must be non-null except when inside z_swap()
584 : : * for synchronization reasons. Historically some notional
585 : : * USE_SWITCH architectures have actually ignored the field
586 : : */
587 : : __ASSERT(new_thread->switch_handle != NULL,
588 : : "arch layer failed to initialize switch_handle");
589 : : #endif /* CONFIG_USE_SWITCH */
590 : : #ifdef CONFIG_THREAD_CUSTOM_DATA
591 : : /* Initialize custom data field (value is opaque to kernel) */
592 : : new_thread->custom_data = NULL;
593 : : #endif /* CONFIG_THREAD_CUSTOM_DATA */
594 : : #ifdef CONFIG_EVENTS
595 : : new_thread->no_wake_on_timeout = false;
596 : : #endif /* CONFIG_EVENTS */
597 : : #ifdef CONFIG_THREAD_MONITOR
598 : : new_thread->entry.pEntry = entry;
599 : : new_thread->entry.parameter1 = p1;
600 : : new_thread->entry.parameter2 = p2;
601 : : new_thread->entry.parameter3 = p3;
602 : :
603 : : k_spinlock_key_t key = k_spin_lock(&z_thread_monitor_lock);
604 : :
605 : : new_thread->next_thread = _kernel.threads;
606 : : _kernel.threads = new_thread;
607 : : k_spin_unlock(&z_thread_monitor_lock, key);
608 : : #endif /* CONFIG_THREAD_MONITOR */
609 : : #ifdef CONFIG_THREAD_NAME
610 [ + + ]: 48 : if (name != NULL) {
611 : 2 : strncpy(new_thread->name, name,
612 : : CONFIG_THREAD_MAX_NAME_LEN - 1);
613 : : /* Ensure NULL termination, truncate if longer */
614 : 2 : new_thread->name[CONFIG_THREAD_MAX_NAME_LEN - 1] = '\0';
615 : : #ifdef CONFIG_ARCH_HAS_THREAD_NAME_HOOK
616 : 2 : arch_thread_name_set(new_thread, name);
617 : : #endif /* CONFIG_ARCH_HAS_THREAD_NAME_HOOK */
618 : : } else {
619 : 46 : new_thread->name[0] = '\0';
620 : : }
621 : : #endif /* CONFIG_THREAD_NAME */
622 : : #ifdef CONFIG_SCHED_CPU_MASK
623 : 48 : if (IS_ENABLED(CONFIG_SCHED_CPU_MASK_PIN_ONLY)) {
624 : : new_thread->base.cpu_mask = 1; /* must specify only one cpu */
625 : : } else {
626 : 48 : new_thread->base.cpu_mask = -1; /* allow all cpus */
627 : : }
628 : : #endif /* CONFIG_SCHED_CPU_MASK */
629 : : #ifdef CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN
630 : : /* _current may be null if the dummy thread is not used */
631 [ - + ]: 48 : if (!_current) {
632 : 0 : new_thread->resource_pool = NULL;
633 : 0 : return stack_ptr;
634 : : }
635 : : #endif /* CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN */
636 : : #ifdef CONFIG_USERSPACE
637 : : z_mem_domain_init_thread(new_thread);
638 : :
639 : : if ((options & K_INHERIT_PERMS) != 0U) {
640 : : k_thread_perms_inherit(_current, new_thread);
641 : : }
642 : : #endif /* CONFIG_USERSPACE */
643 : : #ifdef CONFIG_SCHED_DEADLINE
644 : : new_thread->base.prio_deadline = 0;
645 : : #endif /* CONFIG_SCHED_DEADLINE */
646 : 48 : new_thread->resource_pool = _current->resource_pool;
647 : :
648 : : #ifdef CONFIG_SMP
649 : : z_waitq_init(&new_thread->halt_queue);
650 : : #endif /* CONFIG_SMP */
651 : :
652 : : #ifdef CONFIG_SCHED_THREAD_USAGE
653 : : new_thread->base.usage = (struct k_cycle_stats) {};
654 : : new_thread->base.usage.track_usage =
655 : : CONFIG_SCHED_THREAD_USAGE_AUTO_ENABLE;
656 : : #endif /* CONFIG_SCHED_THREAD_USAGE */
657 : :
658 : 48 : SYS_PORT_TRACING_OBJ_FUNC(k_thread, create, new_thread);
659 : :
660 : 48 : return stack_ptr;
661 : : }
662 : :
663 : :
664 : 46 : k_tid_t z_impl_k_thread_create(struct k_thread *new_thread,
665 : : k_thread_stack_t *stack,
666 : : size_t stack_size, k_thread_entry_t entry,
667 : : void *p1, void *p2, void *p3,
668 : : int prio, uint32_t options, k_timeout_t delay)
669 : : {
670 [ - + ]: 46 : __ASSERT(!arch_is_in_isr(), "Threads may not be created in ISRs");
671 : :
672 : 46 : z_setup_new_thread(new_thread, stack, stack_size, entry, p1, p2, p3,
673 : : prio, options, NULL);
674 : :
675 [ + + ]: 46 : if (!K_TIMEOUT_EQ(delay, K_FOREVER)) {
676 : 4 : thread_schedule_new(new_thread, delay);
677 : : }
678 : :
679 : 46 : return new_thread;
680 : : }
681 : :
682 : : #ifdef CONFIG_USERSPACE
683 : : bool z_stack_is_user_capable(k_thread_stack_t *stack)
684 : : {
685 : : return k_object_find(stack) != NULL;
686 : : }
687 : :
688 : : k_tid_t z_vrfy_k_thread_create(struct k_thread *new_thread,
689 : : k_thread_stack_t *stack,
690 : : size_t stack_size, k_thread_entry_t entry,
691 : : void *p1, void *p2, void *p3,
692 : : int prio, uint32_t options, k_timeout_t delay)
693 : : {
694 : : size_t total_size, stack_obj_size;
695 : : struct k_object *stack_object;
696 : :
697 : : /* The thread and stack objects *must* be in an uninitialized state */
698 : : K_OOPS(K_SYSCALL_OBJ_NEVER_INIT(new_thread, K_OBJ_THREAD));
699 : :
700 : : /* No need to check z_stack_is_user_capable(), it won't be in the
701 : : * object table if it isn't
702 : : */
703 : : stack_object = k_object_find(stack);
704 : : K_OOPS(K_SYSCALL_VERIFY_MSG(k_object_validation_check(stack_object, stack,
705 : : K_OBJ_THREAD_STACK_ELEMENT,
706 : : _OBJ_INIT_FALSE) == 0,
707 : : "bad stack object"));
708 : :
709 : : /* Verify that the stack size passed in is OK by computing the total
710 : : * size and comparing it with the size value in the object metadata
711 : : */
712 : : K_OOPS(K_SYSCALL_VERIFY_MSG(!size_add_overflow(K_THREAD_STACK_RESERVED,
713 : : stack_size, &total_size),
714 : : "stack size overflow (%zu+%zu)",
715 : : stack_size,
716 : : K_THREAD_STACK_RESERVED));
717 : :
718 : : /* Testing less-than-or-equal since additional room may have been
719 : : * allocated for alignment constraints
720 : : */
721 : : #ifdef CONFIG_GEN_PRIV_STACKS
722 : : stack_obj_size = stack_object->data.stack_data->size;
723 : : #else
724 : : stack_obj_size = stack_object->data.stack_size;
725 : : #endif /* CONFIG_GEN_PRIV_STACKS */
726 : : K_OOPS(K_SYSCALL_VERIFY_MSG(total_size <= stack_obj_size,
727 : : "stack size %zu is too big, max is %zu",
728 : : total_size, stack_obj_size));
729 : :
730 : : /* User threads may only create other user threads and they can't
731 : : * be marked as essential
732 : : */
733 : : K_OOPS(K_SYSCALL_VERIFY(options & K_USER));
734 : : K_OOPS(K_SYSCALL_VERIFY(!(options & K_ESSENTIAL)));
735 : :
736 : : /* Check validity of prio argument; must be the same or worse priority
737 : : * than the caller
738 : : */
739 : : K_OOPS(K_SYSCALL_VERIFY(_is_valid_prio(prio, NULL)));
740 : : K_OOPS(K_SYSCALL_VERIFY(z_is_prio_lower_or_equal(prio,
741 : : _current->base.prio)));
742 : :
743 : : z_setup_new_thread(new_thread, stack, stack_size,
744 : : entry, p1, p2, p3, prio, options, NULL);
745 : :
746 : : if (!K_TIMEOUT_EQ(delay, K_FOREVER)) {
747 : : thread_schedule_new(new_thread, delay);
748 : : }
749 : :
750 : : return new_thread;
751 : : }
752 : : #include <zephyr/syscalls/k_thread_create_mrsh.c>
753 : : #endif /* CONFIG_USERSPACE */
754 : :
755 : 48 : void z_init_thread_base(struct _thread_base *thread_base, int priority,
756 : : uint32_t initial_state, unsigned int options)
757 : : {
758 : : /* k_q_node is initialized upon first insertion in a list */
759 : 48 : thread_base->pended_on = NULL;
760 : 48 : thread_base->user_options = (uint8_t)options;
761 : 48 : thread_base->thread_state = (uint8_t)initial_state;
762 : :
763 : 48 : thread_base->prio = priority;
764 : :
765 : 48 : thread_base->sched_locked = 0U;
766 : :
767 : : #ifdef CONFIG_SMP
768 : : thread_base->is_idle = 0;
769 : : #endif /* CONFIG_SMP */
770 : :
771 : : #ifdef CONFIG_TIMESLICE_PER_THREAD
772 : : thread_base->slice_ticks = 0;
773 : : thread_base->slice_expired = NULL;
774 : : #endif /* CONFIG_TIMESLICE_PER_THREAD */
775 : :
776 : : /* swap_data does not need to be initialized */
777 : :
778 : 48 : z_init_thread_timeout(thread_base);
779 : 48 : }
780 : :
781 : 0 : FUNC_NORETURN void k_thread_user_mode_enter(k_thread_entry_t entry,
782 : : void *p1, void *p2, void *p3)
783 : : {
784 : 0 : SYS_PORT_TRACING_FUNC(k_thread, user_mode_enter);
785 : :
786 : 0 : _current->base.user_options |= K_USER;
787 : 0 : z_thread_essential_clear(_current);
788 : : #ifdef CONFIG_THREAD_MONITOR
789 : : _current->entry.pEntry = entry;
790 : : _current->entry.parameter1 = p1;
791 : : _current->entry.parameter2 = p2;
792 : : _current->entry.parameter3 = p3;
793 : : #endif /* CONFIG_THREAD_MONITOR */
794 : : #ifdef CONFIG_USERSPACE
795 : : __ASSERT(z_stack_is_user_capable(_current->stack_obj),
796 : : "dropping to user mode with kernel-only stack object");
797 : : #ifdef CONFIG_THREAD_USERSPACE_LOCAL_DATA
798 : : memset(_current->userspace_local_data, 0,
799 : : sizeof(struct _thread_userspace_local_data));
800 : : #endif /* CONFIG_THREAD_USERSPACE_LOCAL_DATA */
801 : : #ifdef CONFIG_THREAD_LOCAL_STORAGE
802 : : arch_tls_stack_setup(_current,
803 : : (char *)(_current->stack_info.start +
804 : : _current->stack_info.size));
805 : : #endif /* CONFIG_THREAD_LOCAL_STORAGE */
806 : : arch_user_mode_enter(entry, p1, p2, p3);
807 : : #else
808 : : /* XXX In this case we do not reset the stack */
809 : 0 : z_thread_entry(entry, p1, p2, p3);
810 : : #endif /* CONFIG_USERSPACE */
811 : : }
812 : :
813 : : #if defined(CONFIG_INIT_STACKS) && defined(CONFIG_THREAD_STACK_INFO)
814 : : #ifdef CONFIG_STACK_GROWS_UP
815 : : #error "Unsupported configuration for stack analysis"
816 : : #endif /* CONFIG_STACK_GROWS_UP */
817 : :
818 : : int z_stack_space_get(const uint8_t *stack_start, size_t size, size_t *unused_ptr)
819 : : {
820 : : size_t unused = 0;
821 : : const uint8_t *checked_stack = stack_start;
822 : : /* Take the address of any local variable as a shallow bound for the
823 : : * stack pointer. Addresses above it are guaranteed to be
824 : : * accessible.
825 : : */
826 : : const uint8_t *stack_pointer = (const uint8_t *)&stack_start;
827 : :
828 : : /* If we are currently running on the stack being analyzed, some
829 : : * memory management hardware will generate an exception if we
830 : : * read unused stack memory.
831 : : *
832 : : * This never happens when invoked from user mode, as user mode
833 : : * will always run this function on the privilege elevation stack.
834 : : */
835 : : if ((stack_pointer > stack_start) && (stack_pointer <= (stack_start + size)) &&
836 : : IS_ENABLED(CONFIG_NO_UNUSED_STACK_INSPECTION)) {
837 : : /* TODO: We could add an arch_ API call to temporarily
838 : : * disable the stack checking in the CPU, but this would
839 : : * need to be properly managed wrt context switches/interrupts
840 : : */
841 : : return -ENOTSUP;
842 : : }
843 : :
844 : : if (IS_ENABLED(CONFIG_STACK_SENTINEL)) {
845 : : /* First 4 bytes of the stack buffer reserved for the
846 : : * sentinel value, it won't be 0xAAAAAAAA for thread
847 : : * stacks.
848 : : *
849 : : * FIXME: thread->stack_info.start ought to reflect
850 : : * this!
851 : : */
852 : : checked_stack += 4;
853 : : size -= 4;
854 : : }
855 : :
856 : : for (size_t i = 0; i < size; i++) {
857 : : if ((checked_stack[i]) == 0xaaU) {
858 : : unused++;
859 : : } else {
860 : : break;
861 : : }
862 : : }
863 : :
864 : : *unused_ptr = unused;
865 : :
866 : : return 0;
867 : : }
868 : :
869 : : int z_impl_k_thread_stack_space_get(const struct k_thread *thread,
870 : : size_t *unused_ptr)
871 : : {
872 : : #ifdef CONFIG_THREAD_STACK_MEM_MAPPED
873 : : if (thread->stack_info.mapped.addr == NULL) {
874 : : return -EINVAL;
875 : : }
876 : : #endif /* CONFIG_THREAD_STACK_MEM_MAPPED */
877 : :
878 : : return z_stack_space_get((const uint8_t *)thread->stack_info.start,
879 : : thread->stack_info.size, unused_ptr);
880 : : }
881 : :
882 : : #ifdef CONFIG_USERSPACE
883 : : int z_vrfy_k_thread_stack_space_get(const struct k_thread *thread,
884 : : size_t *unused_ptr)
885 : : {
886 : : size_t unused;
887 : : int ret;
888 : :
889 : : ret = K_SYSCALL_OBJ(thread, K_OBJ_THREAD);
890 : : CHECKIF(ret != 0) {
891 : : return ret;
892 : : }
893 : :
894 : : ret = z_impl_k_thread_stack_space_get(thread, &unused);
895 : : CHECKIF(ret != 0) {
896 : : return ret;
897 : : }
898 : :
899 : : ret = k_usermode_to_copy(unused_ptr, &unused, sizeof(size_t));
900 : : CHECKIF(ret != 0) {
901 : : return ret;
902 : : }
903 : :
904 : : return 0;
905 : : }
906 : : #include <zephyr/syscalls/k_thread_stack_space_get_mrsh.c>
907 : : #endif /* CONFIG_USERSPACE */
908 : : #endif /* CONFIG_INIT_STACKS && CONFIG_THREAD_STACK_INFO */
909 : :
910 : : #ifdef CONFIG_USERSPACE
911 : : static inline k_ticks_t z_vrfy_k_thread_timeout_remaining_ticks(
912 : : const struct k_thread *thread)
913 : : {
914 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
915 : : return z_impl_k_thread_timeout_remaining_ticks(thread);
916 : : }
917 : : #include <zephyr/syscalls/k_thread_timeout_remaining_ticks_mrsh.c>
918 : :
919 : : static inline k_ticks_t z_vrfy_k_thread_timeout_expires_ticks(
920 : : const struct k_thread *thread)
921 : : {
922 : : K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
923 : : return z_impl_k_thread_timeout_expires_ticks(thread);
924 : : }
925 : : #include <zephyr/syscalls/k_thread_timeout_expires_ticks_mrsh.c>
926 : : #endif /* CONFIG_USERSPACE */
927 : :
928 : : #ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING
929 : : void z_thread_mark_switched_in(void)
930 : : {
931 : : #if defined(CONFIG_SCHED_THREAD_USAGE) && !defined(CONFIG_USE_SWITCH)
932 : : z_sched_usage_start(_current);
933 : : #endif /* CONFIG_SCHED_THREAD_USAGE && !CONFIG_USE_SWITCH */
934 : :
935 : : #ifdef CONFIG_TRACING
936 : : SYS_PORT_TRACING_FUNC(k_thread, switched_in);
937 : : #endif /* CONFIG_TRACING */
938 : : }
939 : :
940 : : void z_thread_mark_switched_out(void)
941 : : {
942 : : #if defined(CONFIG_SCHED_THREAD_USAGE) && !defined(CONFIG_USE_SWITCH)
943 : : z_sched_usage_stop();
944 : : #endif /*CONFIG_SCHED_THREAD_USAGE && !CONFIG_USE_SWITCH */
945 : :
946 : : #ifdef CONFIG_TRACING
947 : : #ifdef CONFIG_THREAD_LOCAL_STORAGE
948 : : /* Dummy thread won't have TLS set up to run arbitrary code */
949 : : if (!_current_cpu->current ||
950 : : (_current_cpu->current->base.thread_state & _THREAD_DUMMY) != 0)
951 : : return;
952 : : #endif /* CONFIG_THREAD_LOCAL_STORAGE */
953 : : SYS_PORT_TRACING_FUNC(k_thread, switched_out);
954 : : #endif /* CONFIG_TRACING */
955 : : }
956 : : #endif /* CONFIG_INSTRUMENT_THREAD_SWITCHING */
957 : :
958 : 0 : int k_thread_runtime_stats_get(k_tid_t thread,
959 : : k_thread_runtime_stats_t *stats)
960 : : {
961 [ # # ]: 0 : if ((thread == NULL) || (stats == NULL)) {
962 : : return -EINVAL;
963 : : }
964 : :
965 : : #ifdef CONFIG_SCHED_THREAD_USAGE
966 : : z_sched_thread_usage(thread, stats);
967 : : #else
968 : 0 : *stats = (k_thread_runtime_stats_t) {};
969 : : #endif /* CONFIG_SCHED_THREAD_USAGE */
970 : :
971 : 0 : return 0;
972 : : }
973 : :
974 : 0 : int k_thread_runtime_stats_all_get(k_thread_runtime_stats_t *stats)
975 : : {
976 : : #ifdef CONFIG_SCHED_THREAD_USAGE_ALL
977 : : k_thread_runtime_stats_t tmp_stats;
978 : : #endif /* CONFIG_SCHED_THREAD_USAGE_ALL */
979 : :
980 [ # # ]: 0 : if (stats == NULL) {
981 : : return -EINVAL;
982 : : }
983 : :
984 : 0 : *stats = (k_thread_runtime_stats_t) {};
985 : :
986 : : #ifdef CONFIG_SCHED_THREAD_USAGE_ALL
987 : : /* Retrieve the usage stats for each core and amalgamate them. */
988 : :
989 : : unsigned int num_cpus = arch_num_cpus();
990 : :
991 : : for (uint8_t i = 0; i < num_cpus; i++) {
992 : : z_sched_cpu_usage(i, &tmp_stats);
993 : :
994 : : stats->execution_cycles += tmp_stats.execution_cycles;
995 : : stats->total_cycles += tmp_stats.total_cycles;
996 : : #ifdef CONFIG_SCHED_THREAD_USAGE_ANALYSIS
997 : : stats->current_cycles += tmp_stats.current_cycles;
998 : : stats->peak_cycles += tmp_stats.peak_cycles;
999 : : stats->average_cycles += tmp_stats.average_cycles;
1000 : : #endif /* CONFIG_SCHED_THREAD_USAGE_ANALYSIS */
1001 : : stats->idle_cycles += tmp_stats.idle_cycles;
1002 : : }
1003 : : #endif /* CONFIG_SCHED_THREAD_USAGE_ALL */
1004 : :
1005 : 0 : return 0;
1006 : : }
1007 : :
1008 : 0 : int k_thread_runtime_stats_cpu_get(int cpu, k_thread_runtime_stats_t *stats)
1009 : : {
1010 [ # # ]: 0 : if (stats == NULL) {
1011 : : return -EINVAL;
1012 : : }
1013 : :
1014 : 0 : *stats = (k_thread_runtime_stats_t) {};
1015 : :
1016 : : #ifdef CONFIG_SCHED_THREAD_USAGE_ALL
1017 : : #ifdef CONFIG_SMP
1018 : : z_sched_cpu_usage(cpu, stats);
1019 : : #else
1020 : : __ASSERT(cpu == 0, "cpu filter out of bounds");
1021 : : ARG_UNUSED(cpu);
1022 : : z_sched_cpu_usage(0, stats);
1023 : : #endif
1024 : : #endif
1025 : :
1026 : 0 : return 0;
1027 : : }
1028 : :
1029 : : #ifdef CONFIG_THREAD_ABORT_NEED_CLEANUP
1030 : : /** Pointer to thread which needs to be cleaned up. */
1031 : : static struct k_thread *thread_to_cleanup;
1032 : :
1033 : : /** Spinlock for thread abort cleanup. */
1034 : : static struct k_spinlock thread_cleanup_lock;
1035 : :
1036 : : #ifdef CONFIG_THREAD_STACK_MEM_MAPPED
1037 : : static void *thread_cleanup_stack_addr;
1038 : : static size_t thread_cleanup_stack_sz;
1039 : : #endif /* CONFIG_THREAD_STACK_MEM_MAPPED */
1040 : :
1041 : : void defer_thread_cleanup(struct k_thread *thread)
1042 : : {
1043 : : /* Note when adding new deferred cleanup steps:
1044 : : * - The thread object may have been overwritten by the time
1045 : : * the actual cleanup is being done (e.g. thread object
1046 : : * allocated on a stack). So stash any necessary data here
1047 : : * that will be used in the actual cleanup steps.
1048 : : */
1049 : : thread_to_cleanup = thread;
1050 : :
1051 : : #ifdef CONFIG_THREAD_STACK_MEM_MAPPED
1052 : : /* Note that the permission of the stack should have been
1053 : : * stripped of user thread access due to the thread having
1054 : : * already exited from a memory domain. That is done via
1055 : : * k_thread_abort().
1056 : : */
1057 : :
1058 : : /* Stash the address and size so the region can be unmapped
1059 : : * later.
1060 : : */
1061 : : thread_cleanup_stack_addr = thread->stack_info.mapped.addr;
1062 : : thread_cleanup_stack_sz = thread->stack_info.mapped.sz;
1063 : :
1064 : : /* The stack is now considered un-usable. This should prevent any functions
1065 : : * from looking directly into the mapped stack if they are made to be aware
1066 : : * of memory mapped stacks, e.g., z_stack_space_get().
1067 : : */
1068 : : thread->stack_info.mapped.addr = NULL;
1069 : : thread->stack_info.mapped.sz = 0;
1070 : : #endif /* CONFIG_THREAD_STACK_MEM_MAPPED */
1071 : : }
1072 : :
1073 : : void do_thread_cleanup(struct k_thread *thread)
1074 : : {
1075 : : /* Note when adding new actual cleanup steps:
1076 : : * - The thread object may have been overwritten when this is
1077 : : * called. So avoid using any data from the thread object.
1078 : : */
1079 : : ARG_UNUSED(thread);
1080 : :
1081 : : #ifdef CONFIG_THREAD_STACK_MEM_MAPPED
1082 : : if (thread_cleanup_stack_addr != NULL) {
1083 : : k_mem_unmap_phys_guard(thread_cleanup_stack_addr,
1084 : : thread_cleanup_stack_sz, false);
1085 : :
1086 : : thread_cleanup_stack_addr = NULL;
1087 : : }
1088 : : #endif /* CONFIG_THREAD_STACK_MEM_MAPPED */
1089 : : }
1090 : :
1091 : : void k_thread_abort_cleanup(struct k_thread *thread)
1092 : : {
1093 : : K_SPINLOCK(&thread_cleanup_lock) {
1094 : : if (thread_to_cleanup != NULL) {
1095 : : /* Finish the pending one first. */
1096 : : do_thread_cleanup(thread_to_cleanup);
1097 : : thread_to_cleanup = NULL;
1098 : : }
1099 : :
1100 : : if (thread == _current) {
1101 : : /* Need to defer for current running thread as the cleanup
1102 : : * might result in exception. Actual cleanup will be done
1103 : : * at the next time k_thread_abort() is called, or at thread
1104 : : * creation if the same thread object is being reused. This
1105 : : * is to make sure the cleanup code no longer needs this
1106 : : * thread's stack. This is not exactly ideal as the stack
1107 : : * may still be memory mapped for a while. However, this is
1108 : : * a simple solution without a) the need to workaround
1109 : : * the schedule lock during k_thread_abort(), b) creating
1110 : : * another thread to perform the cleanup, and c) does not
1111 : : * require architecture code support (e.g. via exception).
1112 : : */
1113 : : defer_thread_cleanup(thread);
1114 : : } else {
1115 : : /* Not the current running thread, so we are safe to do
1116 : : * cleanups.
1117 : : */
1118 : : do_thread_cleanup(thread);
1119 : : }
1120 : : }
1121 : : }
1122 : :
1123 : : void k_thread_abort_cleanup_check_reuse(struct k_thread *thread)
1124 : : {
1125 : : K_SPINLOCK(&thread_cleanup_lock) {
1126 : : /* This is to guard reuse of the same thread object and make sure
1127 : : * any pending cleanups of it needs to be finished before the thread
1128 : : * object can be reused.
1129 : : */
1130 : : if (thread_to_cleanup == thread) {
1131 : : do_thread_cleanup(thread_to_cleanup);
1132 : : thread_to_cleanup = NULL;
1133 : : }
1134 : : }
1135 : : }
1136 : :
1137 : : #endif /* CONFIG_THREAD_ABORT_NEED_CLEANUP */
|