GCC Code Coverage Report


Directory: kernel/
File: kernel/src/thread.c
Date: 2024-01-01 16:15:14
Exec Total Coverage
Lines: 141 175 80.6%
Functions: 18 21 85.7%
Branches: 33 142 23.2%

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