blob: d03e36693468b583b47ed14724d309fba9a89762 [file] [log] [blame]
Christopher Friedt7b1b2572022-06-27 23:43:32 -04001/*
2 * Copyright (c) 2022, Meta
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include "kernel_internal.h"
8
9#include <zephyr/kernel.h>
Andrei Emeltchenko9d3a3e92023-12-13 13:30:18 +020010#include <ksched.h>
Christopher Friedt7b1b2572022-06-27 23:43:32 -040011#include <zephyr/kernel/thread_stack.h>
12#include <zephyr/logging/log.h>
13#include <zephyr/sys/bitarray.h>
Flavio Ceolinfc6d9ee2023-06-22 06:31:45 +000014#include <zephyr/sys/kobject.h>
Anas Nashif4e396172023-09-26 22:46:01 +000015#include <zephyr/internal/syscall_handler.h>
Christopher Friedt7b1b2572022-06-27 23:43:32 -040016
17LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
18
19#if CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0
20#define BA_SIZE CONFIG_DYNAMIC_THREAD_POOL_SIZE
21#else
22#define BA_SIZE 1
Simon Heinbcd1d192024-03-08 12:00:10 +010023#endif /* CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0 */
Christopher Friedt7b1b2572022-06-27 23:43:32 -040024
25struct dyn_cb_data {
26 k_tid_t tid;
27 k_thread_stack_t *stack;
28};
29
30static K_THREAD_STACK_ARRAY_DEFINE(dynamic_stack, CONFIG_DYNAMIC_THREAD_POOL_SIZE,
31 CONFIG_DYNAMIC_THREAD_STACK_SIZE);
32SYS_BITARRAY_DEFINE_STATIC(dynamic_ba, BA_SIZE);
33
34static k_thread_stack_t *z_thread_stack_alloc_dyn(size_t align, size_t size)
35{
36 return z_thread_aligned_alloc(align, size);
37}
38
39static k_thread_stack_t *z_thread_stack_alloc_pool(size_t size)
40{
41 int rv;
42 size_t offset;
43 k_thread_stack_t *stack;
44
45 if (size > CONFIG_DYNAMIC_THREAD_STACK_SIZE) {
46 LOG_DBG("stack size %zu is > pool stack size %d", size,
47 CONFIG_DYNAMIC_THREAD_STACK_SIZE);
48 return NULL;
49 }
50
51 rv = sys_bitarray_alloc(&dynamic_ba, 1, &offset);
52 if (rv < 0) {
53 LOG_DBG("unable to allocate stack from pool");
54 return NULL;
55 }
56
57 __ASSERT_NO_MSG(offset < CONFIG_DYNAMIC_THREAD_POOL_SIZE);
58
59 stack = (k_thread_stack_t *)&dynamic_stack[offset];
60
61 return stack;
62}
63
Flavio Ceolinfc6d9ee2023-06-22 06:31:45 +000064static k_thread_stack_t *stack_alloc_dyn(size_t size, int flags)
Christopher Friedt7b1b2572022-06-27 23:43:32 -040065{
Flavio Ceolinfc6d9ee2023-06-22 06:31:45 +000066 if ((flags & K_USER) == K_USER) {
67#ifdef CONFIG_DYNAMIC_OBJECTS
68 return k_object_alloc_size(K_OBJ_THREAD_STACK_ELEMENT, size);
69#else
70 /* Dynamic user stack needs a kobject, so if this option is not
71 * enabled we can't proceed.
72 */
73 return NULL;
Simon Heinbcd1d192024-03-08 12:00:10 +010074#endif /* CONFIG_DYNAMIC_OBJECTS */
Christopher Friedt7b1b2572022-06-27 23:43:32 -040075 }
76
Flavio Ceolinfc6d9ee2023-06-22 06:31:45 +000077 return z_thread_stack_alloc_dyn(Z_KERNEL_STACK_OBJ_ALIGN,
Daniel Leung6cd79362024-03-22 14:03:37 -070078 K_KERNEL_STACK_LEN(size));
Flavio Ceolinfc6d9ee2023-06-22 06:31:45 +000079}
80
81k_thread_stack_t *z_impl_k_thread_stack_alloc(size_t size, int flags)
82{
83 k_thread_stack_t *stack = NULL;
84
Christopher Friedt7b1b2572022-06-27 23:43:32 -040085 if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_ALLOC)) {
Flavio Ceolinfc6d9ee2023-06-22 06:31:45 +000086 stack = stack_alloc_dyn(size, flags);
Christopher Friedt7b1b2572022-06-27 23:43:32 -040087 if (stack == NULL && CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) {
88 stack = z_thread_stack_alloc_pool(size);
89 }
Flavio Ceolin4feb1822023-06-29 15:54:20 -070090 } else if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_POOL)) {
91 if (CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) {
92 stack = z_thread_stack_alloc_pool(size);
93 }
94
95 if ((stack == NULL) && IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) {
Flavio Ceolinfc6d9ee2023-06-22 06:31:45 +000096 stack = stack_alloc_dyn(size, flags);
Christopher Friedt7b1b2572022-06-27 23:43:32 -040097 }
Christopher Friedt7b1b2572022-06-27 23:43:32 -040098 }
99
100 return stack;
101}
102
103#ifdef CONFIG_USERSPACE
104static inline k_thread_stack_t *z_vrfy_k_thread_stack_alloc(size_t size, int flags)
105{
106 return z_impl_k_thread_stack_alloc(size, flags);
107}
108#include <syscalls/k_thread_stack_alloc_mrsh.c>
Simon Heinbcd1d192024-03-08 12:00:10 +0100109#endif /* CONFIG_USERSPACE */
Christopher Friedt7b1b2572022-06-27 23:43:32 -0400110
111static void dyn_cb(const struct k_thread *thread, void *user_data)
112{
113 struct dyn_cb_data *const data = (struct dyn_cb_data *)user_data;
114
115 if (data->stack == (k_thread_stack_t *)thread->stack_info.start) {
Fabio Baltieria477bdd2023-09-06 15:44:48 +0000116 __ASSERT(data->tid == NULL, "stack %p is associated with more than one thread!",
117 (void *)thread->stack_info.start);
Christopher Friedt7b1b2572022-06-27 23:43:32 -0400118 data->tid = (k_tid_t)thread;
119 }
120}
121
122int z_impl_k_thread_stack_free(k_thread_stack_t *stack)
123{
Christopher Friedt7b1b2572022-06-27 23:43:32 -0400124 struct dyn_cb_data data = {.stack = stack};
125
126 /* Get a possible tid associated with stack */
127 k_thread_foreach(dyn_cb, &data);
128
129 if (data.tid != NULL) {
Andrei Emeltchenko9d3a3e92023-12-13 13:30:18 +0200130 if (!(z_is_thread_state_set(data.tid, _THREAD_DUMMY) ||
131 z_is_thread_state_set(data.tid, _THREAD_DEAD))) {
Christopher Friedt7b1b2572022-06-27 23:43:32 -0400132 LOG_ERR("tid %p is in use!", data.tid);
133 return -EBUSY;
134 }
135 }
136
137 if (CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) {
138 if (IS_ARRAY_ELEMENT(dynamic_stack, stack)) {
139 if (sys_bitarray_free(&dynamic_ba, 1, ARRAY_INDEX(dynamic_stack, stack))) {
140 LOG_ERR("stack %p is not allocated!", stack);
141 return -EINVAL;
142 }
143
144 return 0;
145 }
146 }
147
148 if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) {
Flavio Ceolinfc6d9ee2023-06-22 06:31:45 +0000149#ifdef CONFIG_USERSPACE
Anas Nashifc25d0802023-09-27 10:49:28 +0000150 if (k_object_find(stack)) {
Flavio Ceolinfc6d9ee2023-06-22 06:31:45 +0000151 k_object_free(stack);
152 } else {
153 k_free(stack);
154 }
155#else
Christopher Friedt7b1b2572022-06-27 23:43:32 -0400156 k_free(stack);
Simon Heinbcd1d192024-03-08 12:00:10 +0100157#endif /* CONFIG_USERSPACE */
Christopher Friedt7b1b2572022-06-27 23:43:32 -0400158 } else {
Christopher Friedt9f3d7772024-01-01 13:01:35 -0500159 LOG_DBG("Invalid stack %p", stack);
Christopher Friedt7b1b2572022-06-27 23:43:32 -0400160 return -EINVAL;
161 }
162
163 return 0;
164}
165
166#ifdef CONFIG_USERSPACE
167static inline int z_vrfy_k_thread_stack_free(k_thread_stack_t *stack)
168{
169 return z_impl_k_thread_stack_free(stack);
170}
171#include <syscalls/k_thread_stack_free_mrsh.c>
Simon Heinbcd1d192024-03-08 12:00:10 +0100172#endif /* CONFIG_USERSPACE */