diff --git a/include/rtthread.h b/include/rtthread.h index f28db560d3..671f80d8e0 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -641,6 +641,7 @@ rt_ssize_t rt_mq_recv_prio(rt_mq_t mq, /**@}*/ /* defunct */ +void rt_thread_defunct_init(void); void rt_thread_defunct_enqueue(rt_thread_t thread); rt_thread_t rt_thread_defunct_dequeue(void); diff --git a/src/components.c b/src/components.c index d1adac181b..b561e227de 100644 --- a/src/components.c +++ b/src/components.c @@ -270,6 +270,9 @@ int rtthread_startup(void) /* idle thread initialization */ rt_thread_idle_init(); + /* defunct thread initialization */ + rt_thread_defunct_init(); + #ifdef RT_USING_SMP rt_hw_spin_lock(&_cpus_lock); #endif /* RT_USING_SMP */ 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 +#include + +#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); +} diff --git a/src/idle.c b/src/idle.c index 092b273783..9a805737eb 100644 --- a/src/idle.c +++ b/src/idle.c @@ -44,22 +44,10 @@ #define _CPUS_NR RT_CPUS_NR -static rt_list_t _rt_thread_defunct = RT_LIST_OBJECT_INIT(_rt_thread_defunct); -static struct rt_spinlock _defunct_spinlock; static struct rt_thread idle_thread[_CPUS_NR]; rt_align(RT_ALIGN_SIZE) static rt_uint8_t idle_thread_stack[_CPUS_NR][IDLE_THREAD_STACK_SIZE]; -#if defined(RT_USING_SMP) || defined(RT_USING_SMART) -#ifndef SYSTEM_THREAD_STACK_SIZE -#define SYSTEM_THREAD_STACK_SIZE IDLE_THREAD_STACK_SIZE -#endif -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; -#endif - #ifdef RT_USING_IDLE_HOOK #ifndef RT_IDLE_HOOK_LIST_SIZE #define RT_IDLE_HOOK_LIST_SIZE 4 @@ -135,128 +123,6 @@ rt_err_t rt_thread_idle_delhook(void (*hook)(void)) #endif /* RT_USING_IDLE_HOOK */ -/** - * @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); -#if defined(RT_USING_SMP) || defined(RT_USING_SMART) - rt_sem_release(&system_sem); -#endif -} - -/** - * @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; - -#ifdef RT_USING_SMP - 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); -#else - if (l->next != l) - { - thread = RT_THREAD_LIST_NODE_ENTRY(l->next); - level = rt_hw_interrupt_disable(); - rt_list_remove(&RT_THREAD_LIST_NODE(thread)); - rt_hw_interrupt_enable(level); - } -#endif - 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 idle_thread_entry(void *parameter) { RT_UNUSED(parameter); @@ -286,10 +152,6 @@ static void idle_thread_entry(void *parameter) } #endif /* RT_USING_IDLE_HOOK */ -#if !defined(RT_USING_SMP) && !defined(RT_USING_SMART) - rt_defunct_execute(); -#endif /* RT_USING_SMP */ - #ifdef RT_USING_PM void rt_system_power_manager(void); rt_system_power_manager(); @@ -297,24 +159,6 @@ static void idle_thread_entry(void *parameter) } } -#if defined(RT_USING_SMP) || defined(RT_USING_SMART) -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(); - } -} -#endif - /** * @brief This function will initialize idle thread, then start it. * @@ -327,6 +171,8 @@ void rt_thread_idle_init(void) char idle_thread_name[RT_NAME_MAX]; #endif /* RT_NAME_MAX > 0 */ + rt_spin_lock_init(&_hook_spinlock); + for (i = 0; i < _CPUS_NR; i++) { #if RT_NAME_MAX > 0 @@ -354,27 +200,6 @@ void rt_thread_idle_init(void) /* startup */ rt_thread_startup(&idle_thread[i]); } - -#if defined(RT_USING_SMP) || defined(RT_USING_SMART) - RT_ASSERT(RT_THREAD_PRIORITY_MAX > 2); - - rt_spin_lock_init(&_defunct_spinlock); - rt_spin_lock_init(&_hook_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); -#endif } /**