diff options
Diffstat (limited to 'src/defunct.c')
| -rw-r--r-- | src/defunct.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/defunct.c b/src/defunct.c new file mode 100644 index 0000000000..7fae3a876c --- /dev/null +++ b/src/defunct.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-08-30 heyuanjie87 the first version + * + */ + +#include <rthw.h> +#include <rtthread.h> + +#ifndef SYSTEM_THREAD_STACK_SIZE +#define SYSTEM_THREAD_STACK_SIZE IDLE_THREAD_STACK_SIZE +#endif +static rt_list_t _rt_thread_defunct = RT_LIST_OBJECT_INIT(_rt_thread_defunct); +static struct rt_spinlock _defunct_spinlock; +static struct rt_thread rt_system_thread; +rt_align(RT_ALIGN_SIZE) static rt_uint8_t rt_system_stack[SYSTEM_THREAD_STACK_SIZE]; +static struct rt_semaphore system_sem; + +/** + * @brief Enqueue a thread to defunct queue. + * + * @param thread the thread to be enqueued. + * + * @note It must be called between rt_hw_interrupt_disable and rt_hw_interrupt_enable + */ +void rt_thread_defunct_enqueue(rt_thread_t thread) +{ + rt_base_t level; + level = rt_spin_lock_irqsave(&_defunct_spinlock); + rt_list_insert_after(&_rt_thread_defunct, &RT_THREAD_LIST_NODE(thread)); + rt_spin_unlock_irqrestore(&_defunct_spinlock, level); + + rt_sem_release(&system_sem); +} + +/** + * @brief Dequeue a thread from defunct queue. + */ +rt_thread_t rt_thread_defunct_dequeue(void) +{ + rt_base_t level; + rt_thread_t thread = RT_NULL; + rt_list_t *l = &_rt_thread_defunct; + + level = rt_spin_lock_irqsave(&_defunct_spinlock); + if (l->next != l) + { + thread = RT_THREAD_LIST_NODE_ENTRY(l->next); + rt_list_remove(&RT_THREAD_LIST_NODE(thread)); + } + rt_spin_unlock_irqrestore(&_defunct_spinlock, level); + + return thread; +} + +/** + * @brief This function will perform system background job when system idle. + */ +static void rt_defunct_execute(void) +{ + /* Loop until there is no dead thread. So one call to rt_defunct_execute + * will do all the cleanups. */ + while (1) + { + rt_thread_t thread; + rt_bool_t object_is_systemobject; + void (*cleanup)(struct rt_thread *tid); + +#ifdef RT_USING_MODULE + struct rt_dlmodule *module = RT_NULL; +#endif + /* get defunct thread */ + thread = rt_thread_defunct_dequeue(); + if (thread == RT_NULL) + { + break; + } + +#ifdef RT_USING_MODULE + module = (struct rt_dlmodule *)thread->parent.module_id; + if (module) + { + dlmodule_destroy(module); + } +#endif + +#ifdef RT_USING_SIGNALS + rt_thread_free_sig(thread); +#endif + + /* store the point of "thread->cleanup" avoid to lose */ + cleanup = thread->cleanup; + + /* if it's a system object, detach it */ + object_is_systemobject = rt_object_is_systemobject((rt_object_t)thread); + if (object_is_systemobject == RT_TRUE) + { + /* detach this object */ + rt_object_detach((rt_object_t)thread); + } + + /* invoke thread cleanup */ + if (cleanup != RT_NULL) + { + cleanup(thread); + } + +#ifdef RT_USING_HEAP +#ifdef RT_USING_MEM_PROTECTION + if (thread->mem_regions != RT_NULL) + { + RT_KERNEL_FREE(thread->mem_regions); + } +#endif + /* if need free, delete it */ + if (object_is_systemobject == RT_FALSE) + { + /* release thread's stack */ +#ifdef RT_USING_HW_STACK_GUARD + RT_KERNEL_FREE(thread->stack_buf); +#else + RT_KERNEL_FREE(thread->stack_addr); +#endif + /* delete thread object */ + rt_object_delete((rt_object_t)thread); + } +#endif + } +} + +static void rt_thread_system_entry(void *parameter) +{ + RT_UNUSED(parameter); + + while (1) + { + int ret = rt_sem_take(&system_sem, RT_WAITING_FOREVER); + if (ret != RT_EOK) + { + rt_kprintf("failed to sem_take() error %d\n", ret); + RT_ASSERT(0); + } + rt_defunct_execute(); + } +} + +void rt_thread_defunct_init(void) +{ + RT_ASSERT(RT_THREAD_PRIORITY_MAX > 2); + + rt_spin_lock_init(&_defunct_spinlock); + + rt_sem_init(&system_sem, "defunct", 0, RT_IPC_FLAG_FIFO); + + /* create defunct thread */ + rt_thread_init(&rt_system_thread, + "tsystem", + rt_thread_system_entry, + RT_NULL, + rt_system_stack, + sizeof(rt_system_stack), + RT_THREAD_PRIORITY_MAX - 2, + 32); + /* startup */ + rt_thread_startup(&rt_system_thread); +} |
