From fe933a8e6a35764b4d51a31b8d744a6d442cec05 Mon Sep 17 00:00:00 2001 From: shaojinchun Date: Fri, 19 Mar 2021 18:18:22 +0800 Subject: [PATCH] =?UTF-8?q?smp=E5=8A=A0=E5=85=A5system=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E7=94=A8=E4=BB=A5=E4=BB=BB=E5=8A=A1tcb=E5=92=8C=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=A0=88=E5=9B=9E=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/rtthread.h | 5 +- src/Kconfig | 5 ++ src/idle.c | 189 +++++++++++++++++++++++++++++++-------------- src/scheduler.c | 5 -- src/thread.c | 8 +- 5 files changed, 141 insertions(+), 71 deletions(-) diff --git a/include/rtthread.h b/include/rtthread.h index a72d2d30c8..bf74108197 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -182,7 +182,6 @@ void rt_thread_idle_init(void); rt_err_t rt_thread_idle_sethook(void (*hook)(void)); rt_err_t rt_thread_idle_delhook(void (*hook)(void)); #endif -void rt_thread_idle_excute(void); rt_thread_t rt_thread_idle_gethandler(void); /* @@ -449,6 +448,10 @@ rt_err_t rt_mq_recv_killable(rt_mq_t mq, rt_err_t rt_mq_control(rt_mq_t mq, int cmd, void *arg); #endif +/* defunct */ +void rt_thread_defunct_enqueue(rt_thread_t thread); +rt_thread_t rt_thread_defunct_dequeue(void); + /* * spinlock */ diff --git a/src/Kconfig b/src/Kconfig index e96ff9b453..2508c2b550 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -105,6 +105,11 @@ config IDLE_THREAD_STACK_SIZE int "The stack size of idle thread" default 256 +config SYSTEM_THREAD_STACK_SIZE + int "The stack size of system thread (for defunct etc.)" + depends on RT_USING_SMP + default IDLE_THREAD_STACK_SIZE + config RT_USING_TIMER_SOFT bool "Enable software timer with a timer thread" default y diff --git a/src/idle.c b/src/idle.c index 42b2bb7ff0..b5bfcbe0de 100644 --- a/src/idle.c +++ b/src/idle.c @@ -44,12 +44,22 @@ #define _CPUS_NR 1 #endif -extern rt_list_t rt_thread_defunct; +static rt_list_t _rt_thread_defunct = RT_LIST_OBJECT_INIT(_rt_thread_defunct);; static struct rt_thread idle[_CPUS_NR]; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t rt_thread_stack[_CPUS_NR][IDLE_THREAD_STACK_SIZE]; +#ifdef RT_USING_SMP +#ifndef SYSTEM_THREAD_STACK_SIZE +#define SYSTEM_THREAD_STACK_SIZE IDLE_THREAD_STACK_SIZE +#endif +static struct rt_thread rt_system_thread; +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 @@ -127,33 +137,66 @@ rt_err_t rt_thread_idle_delhook(void (*hook)(void)) #endif +#ifdef RT_USING_MODULE /* Return whether there is defunctional thread to be deleted. */ rt_inline int _has_defunct_thread(void) { /* The rt_list_isempty has prototype of "int rt_list_isempty(const rt_list_t *l)". - * So the compiler has a good reason that the rt_thread_defunct list does - * not change within rt_thread_idle_excute thus optimize the "while" loop + * So the compiler has a good reason that the _rt_thread_defunct list does + * not change within rt_thread_defunct_exceute thus optimize the "while" loop * into a "if". * * So add the volatile qualifier here. */ - const volatile rt_list_t *l = (const volatile rt_list_t *)&rt_thread_defunct; + const volatile rt_list_t *l = (const volatile rt_list_t *)&_rt_thread_defunct; return l->next != l; } +#endif + +/* enqueue a thread to defunct queue + * it must be called between rt_hw_interrupt_disable and rt_hw_interrupt_enable + */ +void rt_thread_defunct_enqueue(rt_thread_t thread) +{ + rt_list_insert_after(&_rt_thread_defunct, &thread->tlist); +#ifdef RT_USING_SMP + rt_sem_release(&system_sem); +#endif +} + +/* dequeue a thread from defunct queue + * it must be called between rt_hw_interrupt_disable and rt_hw_interrupt_enable + */ +rt_thread_t rt_thread_defunct_dequeue(void) +{ + rt_thread_t thread = RT_NULL; + rt_list_t *l = &_rt_thread_defunct; + + if (l->next != l) + { + thread = rt_list_entry(l->next, + struct rt_thread, + tlist); + rt_list_remove(&(thread->tlist)); + } + return thread; +} /** * @ingroup Thread * * This function will perform system background job when system idle. */ -void rt_thread_idle_excute(void) +static void rt_defunct_execute(void) { - /* Loop until there is no dead thread. So one call to rt_thread_idle_excute + /* Loop until there is no dead thread. So one call to rt_defunct_execute * will do all the cleanups. */ - while (_has_defunct_thread()) + while (1) { rt_base_t lock; rt_thread_t thread; + void (*cleanup)(struct rt_thread *tid); + #ifdef RT_USING_MODULE struct rt_dlmodule *module = RT_NULL; #endif @@ -162,69 +205,63 @@ void rt_thread_idle_excute(void) /* disable interrupt */ lock = rt_hw_interrupt_disable(); - /* re-check whether list is empty */ - if (_has_defunct_thread()) - { - /* get defunct thread */ - thread = rt_list_entry(rt_thread_defunct.next, - struct rt_thread, - tlist); #ifdef RT_USING_MODULE - module = (struct rt_dlmodule*)thread->module_id; - if (module) - { - dlmodule_destroy(module); - } + /* check whether list is empty */ + if (!_has_defunct_thread()) + { + rt_hw_interrupt_enable(lock); + break; + } + /* get defunct thread */ + thread = rt_list_entry(_rt_thread_defunct.next, + struct rt_thread, + tlist); + module = (struct rt_dlmodule*)thread->module_id; + if (module) + { + dlmodule_destroy(module); + } + /* remove defunct thread */ + rt_list_remove(&(thread->tlist)); +#else + thread = rt_thread_defunct_dequeue(); + if (!thread) + { + rt_hw_interrupt_enable(lock); + break; + } #endif - /* remove defunct thread */ - rt_list_remove(&(thread->tlist)); - - /* lock scheduler to prevent scheduling in cleanup function. */ - rt_enter_critical(); - - /* invoke thread cleanup */ - if (thread->cleanup != RT_NULL) - thread->cleanup(thread); + /* invoke thread cleanup */ + cleanup = thread->cleanup; + if (cleanup != RT_NULL) + { + rt_hw_interrupt_enable(lock); + cleanup(thread); + lock = rt_hw_interrupt_disable(); + } #ifdef RT_USING_SIGNALS - rt_thread_free_sig(thread); + rt_thread_free_sig(thread); #endif - /* if it's a system object, not delete it */ - if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) - { - /* detach this object */ - rt_object_detach((rt_object_t)thread); - /* unlock scheduler */ - rt_exit_critical(); - - /* enable interrupt */ - rt_hw_interrupt_enable(lock); - - return; - } - - /* unlock scheduler */ - rt_exit_critical(); - } - else + /* if it's a system object, not delete it */ + if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) { + /* detach this object */ + rt_object_detach((rt_object_t)thread); /* enable interrupt */ rt_hw_interrupt_enable(lock); - - /* may the defunct thread list is removed by others, just return */ - return; } - - /* enable interrupt */ - rt_hw_interrupt_enable(lock); - + else + { + rt_hw_interrupt_enable(lock); #ifdef RT_USING_HEAP - /* release thread's stack */ - RT_KERNEL_FREE(thread->stack_addr); - /* delete thread object */ - rt_object_delete((rt_object_t)thread); + /* release thread's stack */ + RT_KERNEL_FREE(thread->stack_addr); + /* delete thread object */ + rt_object_delete((rt_object_t)thread); #endif + } } } @@ -255,13 +292,27 @@ static void rt_thread_idle_entry(void *parameter) } #endif - rt_thread_idle_excute(); -#ifdef RT_USING_PM +#ifndef RT_USING_SMP + rt_defunct_execute(); +#endif + +#ifdef RT_USING_PM rt_system_power_manager(); #endif } } +#ifdef RT_USING_SMP +static void rt_thread_system_entry(void *parameter) +{ + while (1) + { + rt_sem_take(&system_sem, RT_WAITING_FOREVER); + rt_defunct_execute(); + } +} +#endif + /** * @ingroup SystemInit * @@ -291,6 +342,24 @@ void rt_thread_idle_init(void) /* startup */ rt_thread_startup(&idle[i]); } + +#ifdef RT_USING_SMP + RT_ASSERT(RT_THREAD_PRIORITY_MAX > 2); + + rt_sem_init(&system_sem, "defunct", 1, 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 } /** diff --git a/src/scheduler.c b/src/scheduler.c index 385d800b48..41c1b167d0 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -47,8 +47,6 @@ struct rt_thread *rt_current_thread; rt_uint8_t rt_current_priority; #endif /*RT_USING_SMP*/ -rt_list_t rt_thread_defunct; - #ifdef RT_USING_HOOK static void (*rt_scheduler_hook)(struct rt_thread *from, struct rt_thread *to); @@ -229,9 +227,6 @@ void rt_system_scheduler_init(void) /* initialize ready table */ rt_memset(rt_thread_ready_table, 0, sizeof(rt_thread_ready_table)); #endif - - /* initialize thread defunct */ - rt_list_init(&rt_thread_defunct); } /** diff --git a/src/thread.c b/src/thread.c index dc497ee657..2027852e45 100644 --- a/src/thread.c +++ b/src/thread.c @@ -31,8 +31,6 @@ #include #include -extern rt_list_t rt_thread_defunct; - #ifdef RT_USING_HOOK static void (*rt_thread_suspend_hook)(rt_thread_t thread); static void (*rt_thread_resume_hook) (rt_thread_t thread); @@ -104,7 +102,7 @@ void rt_thread_exit(void) else { /* insert to defunct thread list */ - rt_list_insert_after(&rt_thread_defunct, &(thread->tlist)); + rt_thread_defunct_enqueue(thread); } /* switch to next task */ @@ -373,7 +371,7 @@ rt_err_t rt_thread_detach(rt_thread_t thread) /* disable interrupt */ lock = rt_hw_interrupt_disable(); /* insert to defunct thread list */ - rt_list_insert_after(&rt_thread_defunct, &(thread->tlist)); + rt_thread_defunct_enqueue(thread); /* enable interrupt */ rt_hw_interrupt_enable(lock); } @@ -469,7 +467,7 @@ rt_err_t rt_thread_delete(rt_thread_t thread) thread->stat = RT_THREAD_CLOSE; /* insert to defunct thread list */ - rt_list_insert_after(&rt_thread_defunct, &(thread->tlist)); + rt_thread_defunct_enqueue(thread); /* enable interrupt */ rt_hw_interrupt_enable(lock); -- Gitee