| 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 |