forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdynamic.c
175 lines (145 loc) · 4.51 KB
/
dynamic.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
* Copyright (c) 2022, Meta
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "kernel_internal.h"
#include <zephyr/kernel.h>
#include <ksched.h>
#include <zephyr/kernel/thread_stack.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/bitarray.h>
#include <zephyr/sys/kobject.h>
#include <zephyr/internal/syscall_handler.h>
LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
#if CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0
#define BA_SIZE CONFIG_DYNAMIC_THREAD_POOL_SIZE
#else
#define BA_SIZE 1
#endif /* CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0 */
struct dyn_cb_data {
k_tid_t tid;
k_thread_stack_t *stack;
};
static K_THREAD_STACK_ARRAY_DEFINE(dynamic_stack, CONFIG_DYNAMIC_THREAD_POOL_SIZE,
CONFIG_DYNAMIC_THREAD_STACK_SIZE);
SYS_BITARRAY_DEFINE_STATIC(dynamic_ba, BA_SIZE);
static k_thread_stack_t *z_thread_stack_alloc_pool(size_t size)
{
int rv;
size_t offset;
k_thread_stack_t *stack;
if (size > CONFIG_DYNAMIC_THREAD_STACK_SIZE) {
LOG_DBG("stack size %zu is > pool stack size %d", size,
CONFIG_DYNAMIC_THREAD_STACK_SIZE);
return NULL;
}
rv = sys_bitarray_alloc(&dynamic_ba, 1, &offset);
if (rv < 0) {
LOG_DBG("unable to allocate stack from pool");
return NULL;
}
__ASSERT_NO_MSG(offset < CONFIG_DYNAMIC_THREAD_POOL_SIZE);
stack = (k_thread_stack_t *)&dynamic_stack[offset];
return stack;
}
static k_thread_stack_t *z_thread_stack_alloc_dyn(size_t size, int flags)
{
if ((flags & K_USER) == K_USER) {
#ifdef CONFIG_DYNAMIC_OBJECTS
return k_object_alloc_size(K_OBJ_THREAD_STACK_ELEMENT, size);
#else
/* Dynamic user stack needs a kobject, so if this option is not
* enabled we can't proceed.
*/
return NULL;
#endif /* CONFIG_DYNAMIC_OBJECTS */
}
return z_thread_aligned_alloc(Z_KERNEL_STACK_OBJ_ALIGN, K_KERNEL_STACK_LEN(size));
}
k_thread_stack_t *z_impl_k_thread_stack_alloc(size_t size, int flags)
{
k_thread_stack_t *stack = NULL;
if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_ALLOC)) {
stack = z_thread_stack_alloc_dyn(size, flags);
if (stack == NULL && CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) {
stack = z_thread_stack_alloc_pool(size);
}
} else if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_POOL)) {
if (CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) {
stack = z_thread_stack_alloc_pool(size);
}
if ((stack == NULL) && IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) {
stack = z_thread_stack_alloc_dyn(size, flags);
}
}
return stack;
}
#ifdef CONFIG_USERSPACE
static inline k_thread_stack_t *z_vrfy_k_thread_stack_alloc(size_t size, int flags)
{
return z_impl_k_thread_stack_alloc(size, flags);
}
#include <zephyr/syscalls/k_thread_stack_alloc_mrsh.c>
#endif /* CONFIG_USERSPACE */
static void dyn_cb(const struct k_thread *thread, void *user_data)
{
struct dyn_cb_data *const data = (struct dyn_cb_data *)user_data;
if (data->stack == (k_thread_stack_t *)thread->stack_info.start) {
__ASSERT(data->tid == NULL, "stack %p is associated with more than one thread!",
(void *)thread->stack_info.start);
data->tid = (k_tid_t)thread;
}
}
int z_impl_k_thread_stack_free(k_thread_stack_t *stack)
{
struct dyn_cb_data data = {.stack = stack};
/* Get a possible tid associated with stack */
k_thread_foreach(dyn_cb, &data);
if (data.tid != NULL) {
if (!(z_is_thread_state_set(data.tid, _THREAD_DUMMY) ||
z_is_thread_state_set(data.tid, _THREAD_DEAD))) {
LOG_ERR("tid %p is in use!", data.tid);
return -EBUSY;
}
}
if (CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) {
if (IS_ARRAY_ELEMENT(dynamic_stack, stack)) {
if (sys_bitarray_free(&dynamic_ba, 1, ARRAY_INDEX(dynamic_stack, stack))) {
LOG_ERR("stack %p is not allocated!", stack);
return -EINVAL;
}
return 0;
}
}
if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) {
#ifdef CONFIG_USERSPACE
if (k_object_find(stack)) {
k_object_free(stack);
} else {
k_free(stack);
}
#else
k_free(stack);
#endif /* CONFIG_USERSPACE */
} else {
LOG_DBG("Invalid stack %p", stack);
return -EINVAL;
}
return 0;
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_k_thread_stack_free(k_thread_stack_t *stack)
{
/* The thread stack object must not be in initialized state.
*
* Thread stack objects are initialized when the thread is created
* and de-initialized when the thread is destroyed. Since we can't
* free a stack that is in use, we have to check that the caller
* has access to the object but that it is not in use anymore.
*/
K_OOPS(K_SYSCALL_OBJ_NEVER_INIT(stack, K_OBJ_THREAD_STACK_ELEMENT));
return z_impl_k_thread_stack_free(stack);
}
#include <zephyr/syscalls/k_thread_stack_free_mrsh.c>
#endif /* CONFIG_USERSPACE */