Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2022-2023, The Puppy RTOS Authors | ||
3 | * | ||
4 | * SPDX-License-Identifier: Apache-2.0 | ||
5 | */ | ||
6 | |||
7 | #include <puppy.h> | ||
8 | #include <puppy/kobj.h> | ||
9 | #include <string.h> | ||
10 | |||
11 | #define KLOG_TAG "thread" | ||
12 | #define KLOG_LVL KLOG_WARNING | ||
13 | #include <puppy/klog.h> | ||
14 | |||
15 | #define P_THREAD_SLICE_DEFAULT 10 | ||
16 | |||
17 | static p_list_t thread_timeout_list = P_LIST_STATIC_INIT(&thread_timeout_list); | ||
18 | static void timeout_insert(struct timeout *timeout); | ||
19 | static int timeout_remove(struct timeout *timeout); | ||
20 | |||
21 | 8500 | void *p_thread_get_archdata(p_obj_t obj) | |
22 | { | ||
23 | 8500 | struct _thread_obj *thread = obj; | |
24 | 8500 | return thread->arch_data; | |
25 | } | ||
26 | 28 | void p_thread_entry(void (*entry)(void *parameter), void *param) | |
27 | { | ||
28 | KLOG_D("p_thread_entry enter..."); | ||
29 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | if (entry) |
30 | { | ||
31 | 28 | entry(param); | |
32 | } | ||
33 | |||
34 | KLOG_D("p_thread_entry exit..."); | ||
35 | 23 | p_thread_abort(p_thread_self()); | |
36 | ✗ | while (1); | |
37 | } | ||
38 | ✗ | static void _p_thread_cleanup(p_obj_t obj) | |
39 | { | ||
40 | ✗ | struct _thread_obj *thread = obj; | |
41 | ✗ | p_free(thread->stack_addr); | |
42 | ✗ | p_obj_deinit(thread); | |
43 | ✗ | } | |
44 | 28 | void p_thread_init(p_obj_t obj, const char *name, | |
45 | void (*entry)(void *param), | ||
46 | void *param, | ||
47 | void *stack_addr, | ||
48 | uint32_t stack_size, | ||
49 | uint8_t prio, | ||
50 | uint8_t bindcpu) | ||
51 | { | ||
52 | 28 | struct _thread_obj *thread = obj; | |
53 | |||
54 | 28 | p_obj_init(&thread->kobj, name, P_OBJ_TYPE_THREAD | P_OBJ_TYPE_STATIC, 0); | |
55 | |||
56 | 28 | thread->entry = entry; | |
57 | 28 | thread->param = param; | |
58 | 28 | thread->stack_addr = stack_addr; | |
59 | 28 | thread->stack_size = stack_size; | |
60 | 28 | thread->prio = prio; | |
61 | 28 | thread->slice_ticks = P_THREAD_SLICE_DEFAULT; | |
62 | 28 | thread->state = P_THREAD_STATE_INIT; | |
63 | 28 | thread->mode = 0; | |
64 | 28 | thread->cleanup = _p_thread_cleanup; | |
65 | 28 | thread->kernel_stack = 0; | |
66 | 28 | thread->bindcpu = bindcpu; | |
67 | 28 | thread->oncpu = CPU_NA; | |
68 | |||
69 | KLOG_D("thread_init -->[%s], entry:0x%x, stack_addr:0x%x, stack_size:%d ", | ||
70 | name, entry, stack_addr, stack_size); | ||
71 | |||
72 | 28 | memset(stack_addr,0x23, stack_size); | |
73 | |||
74 | 28 | thread->arch_data = arch_new_thread(p_thread_entry, entry, param, stack_addr, stack_size); | |
75 | 28 | } | |
76 | |||
77 | 17312 | p_obj_t p_thread_self(void) | |
78 | { | ||
79 | 17312 | return p_cpu_self()->curr_thread; | |
80 | } | ||
81 | |||
82 | 837 | p_obj_t p_thread_next(void) | |
83 | { | ||
84 | 837 | return p_cpu_self()->next_thread; | |
85 | } | ||
86 | |||
87 | 81 | const char *p_thread_self_name(void) | |
88 | { | ||
89 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 81 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
81 | KLOG_ASSERT(p_cpu_self()->curr_thread != NULL); |
90 |
1/6✗ Branch 2 not taken.
✓ Branch 3 taken 81 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
81 | KLOG_ASSERT(p_obj_get_type(p_cpu_self()->curr_thread) == P_OBJ_TYPE_THREAD); |
91 | 81 | return p_cpu_self()->curr_thread->kobj.name; | |
92 | } | ||
93 | |||
94 | 23 | int p_thread_abort(p_obj_t obj) | |
95 | { | ||
96 | 23 | struct _thread_obj *_thread = obj; | |
97 | 23 | p_base_t key = arch_irq_lock(); | |
98 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
23 | KLOG_ASSERT(p_obj_get_type(_thread) == P_OBJ_TYPE_THREAD); |
99 | |||
100 | 23 | _thread->state = P_THREAD_STATE_DEAD; | |
101 | 23 | timeout_remove(&_thread->timeout); | |
102 | 23 | p_thread_dead_add(_thread); | |
103 | 23 | p_sched(); | |
104 | |||
105 | ✗ | arch_irq_unlock(key); | |
106 | ✗ | return 0; | |
107 | } | ||
108 | |||
109 | ✗ | int p_thread_yield(void) | |
110 | { | ||
111 | ✗ | struct _thread_obj *_thread = p_cpu_self()->curr_thread; | |
112 | ✗ | p_base_t key = arch_irq_lock(); | |
113 | |||
114 | ✗ | KLOG_ASSERT(p_cpu_self()->curr_thread != NULL); | |
115 | ✗ | KLOG_ASSERT(p_obj_get_type(_thread) == P_OBJ_TYPE_THREAD); | |
116 | ✗ | KLOG_ASSERT(_thread->state == P_THREAD_STATE_RUN); | |
117 | |||
118 | ✗ | p_sched_ready_insert(_thread); | |
119 | ✗ | p_sched(); | |
120 | |||
121 | ✗ | arch_irq_unlock(key); | |
122 | ✗ | return 0; | |
123 | } | ||
124 | |||
125 | 33 | void sleep_timeout_fn(p_obj_t obj, void *param) | |
126 | { | ||
127 | 33 | struct _thread_obj *_thread = obj; | |
128 | 33 | _thread->errno = P_ETIMEOUT; | |
129 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
33 | KLOG_ASSERT(obj != NULL); |
130 | 33 | p_sched_ready_insert(_thread); | |
131 | 33 | p_sched(); | |
132 | 33 | } | |
133 | |||
134 | 33 | int p_thread_set_timeout(p_tick_t timeout, p_timeout_fn func, void *param) | |
135 | { | ||
136 | 33 | struct _thread_obj *_thread = p_cpu_self()->curr_thread; | |
137 | |||
138 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
33 | KLOG_ASSERT(p_obj_get_type(_thread) == P_OBJ_TYPE_THREAD); |
139 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
33 | KLOG_ASSERT(_thread->state == P_THREAD_STATE_RUN); |
140 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
33 | KLOG_ASSERT(p_node_is_linked(&_thread->timeout.node) == false); |
141 | |||
142 | /* check timeout node */ | ||
143 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
|
33 | if(p_node_is_linked(&_thread->timeout.node)) |
144 | { | ||
145 | ✗ | return -P_EINVAL; | |
146 | } | ||
147 | |||
148 | 33 | _thread->timeout.tick = p_tick_get() + timeout; | |
149 | 33 | _thread->timeout.func = func; | |
150 | 33 | _thread->timeout.param = param; | |
151 | 33 | timeout_insert(&_thread->timeout); | |
152 | 33 | return 0; | |
153 | } | ||
154 | |||
155 | 33 | int p_thread_sleep(p_tick_t tick) | |
156 | { | ||
157 | 33 | struct _thread_obj *_thread = p_cpu_self()->curr_thread; | |
158 | 33 | int err = P_EOK; | |
159 | 33 | p_base_t key = arch_irq_lock(); | |
160 | |||
161 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
33 | KLOG_ASSERT(p_obj_get_type(_thread) == P_OBJ_TYPE_THREAD); |
162 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
33 | KLOG_ASSERT(_thread->state == P_THREAD_STATE_RUN); |
163 | |||
164 | 33 | p_thread_set_timeout(tick, sleep_timeout_fn, NULL); | |
165 | |||
166 | 33 | _thread->state = P_THREAD_STATE_SLEEP; | |
167 | |||
168 | 33 | err = p_sched(); | |
169 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | if(err == -P_ETIMEOUT) |
170 | { | ||
171 | 33 | err = P_EOK; | |
172 | 33 | p_set_errno(err); | |
173 | } | ||
174 | |||
175 | 33 | arch_irq_unlock(key); | |
176 | 33 | return err; | |
177 | } | ||
178 | |||
179 | ✗ | int p_thread_wakeup(p_obj_t obj) | |
180 | { | ||
181 | ✗ | struct _thread_obj *_thread = obj; | |
182 | ✗ | int err = P_EOK; | |
183 | ✗ | p_base_t key = arch_irq_lock(); | |
184 | ✗ | KLOG_ASSERT(obj != NULL); | |
185 | ✗ | KLOG_ASSERT(p_obj_get_type(_thread) == P_OBJ_TYPE_THREAD); | |
186 | |||
187 | ✗ | p_sched_ready_insert(_thread); | |
188 | |||
189 | ✗ | arch_irq_unlock(key); | |
190 | ✗ | return err; | |
191 | } | ||
192 | |||
193 | 121 | int p_thread_block(p_obj_t obj) | |
194 | { | ||
195 | 121 | struct _thread_obj *_thread = obj; | |
196 | 121 | int err = P_EOK; | |
197 | 121 | p_base_t key = arch_irq_lock(); | |
198 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
121 | KLOG_ASSERT(p_obj_get_type(_thread) == P_OBJ_TYPE_THREAD); |
199 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
121 | KLOG_ASSERT(_thread->state == P_THREAD_STATE_RUN); |
200 | |||
201 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
|
121 | if (_thread->state != P_THREAD_STATE_RUN) |
202 | { | ||
203 | ✗ | err = -P_EINVAL; | |
204 | ✗ | goto _exit; | |
205 | } | ||
206 | 121 | _thread->state = P_THREAD_STATE_BLOCK; | |
207 | |||
208 | 121 | _exit: | |
209 | 121 | arch_irq_unlock(key); | |
210 | 121 | return err; | |
211 | } | ||
212 | |||
213 | 28 | int p_thread_start(p_obj_t obj) | |
214 | { | ||
215 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
28 | KLOG_ASSERT(obj != NULL); |
216 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
28 | KLOG_ASSERT(p_obj_get_type(obj) == P_OBJ_TYPE_THREAD); |
217 | |||
218 | 28 | p_sched_ready_insert(obj); | |
219 | 28 | p_sched(); | |
220 | 28 | return 0; | |
221 | } | ||
222 | |||
223 | |||
224 | /******** thread timeout ********/ | ||
225 | 2142 | static struct timeout *_next_timeout(void) | |
226 | { | ||
227 | struct timeout *timeout; | ||
228 | 2142 | p_base_t key = arch_irq_lock(); | |
229 | |||
230 |
2/2✓ Branch 1 taken 521 times.
✓ Branch 2 taken 1621 times.
|
2142 | if (!p_list_is_empty(&thread_timeout_list)) |
231 | { | ||
232 | 521 | timeout = p_list_entry(thread_timeout_list.head, | |
233 | struct timeout, node); | ||
234 | 521 | arch_irq_unlock(key); | |
235 | 521 | return timeout; | |
236 | } | ||
237 | |||
238 | 1621 | arch_irq_unlock(key); | |
239 | |||
240 | 1621 | return NULL; | |
241 | } | ||
242 | |||
243 | 33 | static void timeout_insert(struct timeout *timeout) | |
244 | { | ||
245 | 33 | struct timeout *_timeout = NULL, *temp_timeout; | |
246 | 33 | p_base_t key = arch_irq_lock(); | |
247 | p_node_t *node; | ||
248 | |||
249 |
2/2✓ Branch 0 taken 190 times.
✓ Branch 1 taken 33 times.
|
223 | p_list_for_each_node(&thread_timeout_list, node) |
250 | { | ||
251 | 190 | temp_timeout = p_list_entry(node, struct timeout, node); | |
252 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
|
190 | if (temp_timeout->tick > timeout->tick) |
253 | { | ||
254 | /* find out insert node */ | ||
255 | ✗ | _timeout = temp_timeout; | |
256 | ✗ | break; | |
257 | } | ||
258 | } | ||
259 | |||
260 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | if (_timeout) |
261 | { | ||
262 | ✗ | p_list_insert(&_timeout->node, &timeout->node); | |
263 | } | ||
264 | else | ||
265 | { | ||
266 | 33 | p_list_append(&thread_timeout_list, &timeout->node); | |
267 | } | ||
268 | |||
269 | 33 | arch_irq_unlock(key); | |
270 | 33 | } | |
271 | 23 | static int timeout_remove(struct timeout *timeout) | |
272 | { | ||
273 | 23 | p_base_t key = arch_irq_lock(); | |
274 | |||
275 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (timeout->node.next != NULL) |
276 | { | ||
277 | ✗ | p_list_remove(&timeout->node); | |
278 | } | ||
279 | |||
280 | 23 | arch_irq_unlock(key); | |
281 | 23 | return 0; | |
282 | } | ||
283 | |||
284 | 2142 | void thread_timeout_cb(p_base_t tick) | |
285 | { | ||
286 | struct timeout *timeout; | ||
287 | struct _thread_obj *_thread; | ||
288 | 2142 | _next: | |
289 | 2142 | timeout = _next_timeout(); | |
290 |
4/4✓ Branch 0 taken 521 times.
✓ Branch 1 taken 1621 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 488 times.
|
2142 | if(timeout && timeout->tick <= tick) |
291 | { | ||
292 | 33 | _thread = p_list_entry(timeout, | |
293 | struct _thread_obj, timeout); | ||
294 | |||
295 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
33 | KLOG_ASSERT(p_obj_get_type(_thread) == P_OBJ_TYPE_THREAD); |
296 | /* timeout ok */ | ||
297 | 33 | p_list_remove(&timeout->node); | |
298 | /* todo */ | ||
299 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | if (timeout->func) |
300 | { | ||
301 | 33 | timeout->func(_thread, timeout->param); | |
302 | } | ||
303 | 33 | goto _next; | |
304 | } | ||
305 | 2109 | } | |
306 | |||
307 | 23 | void p_thread_dead_add(p_obj_t tid) | |
308 | { | ||
309 | 23 | struct _thread_obj *th = tid; | |
310 | 23 | p_base_t key = arch_irq_lock(); | |
311 | 23 | p_list_append(&p_cpu_self()->dead_queue, &th->tnode); | |
312 | 23 | arch_irq_unlock(key); | |
313 | 23 | } | |
314 | |||
315 | 11 | void p_thread_dead_clean(void) | |
316 | { | ||
317 | p_node_t *node, *node_s; | ||
318 | 11 | p_base_t key = arch_irq_lock(); | |
319 |
2/2✓ Branch 2 taken 23 times.
✓ Branch 3 taken 11 times.
|
34 | p_list_for_each_node_safe(&p_cpu_self()->dead_queue, node, node_s) |
320 | { | ||
321 | 23 | struct _thread_obj *_thread = p_list_entry(node, struct _thread_obj, tnode); | |
322 | 23 | p_list_remove(node); | |
323 | 23 | arch_irq_unlock(key); | |
324 | |||
325 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (_thread->cleanup) |
326 | { | ||
327 | 23 | _thread->cleanup(_thread); /* todo: if other thread blocked in free func */ | |
328 | } | ||
329 | 23 | key = arch_irq_lock(); | |
330 | } | ||
331 | 11 | arch_irq_unlock(key); | |
332 | 11 | } | |
333 |