diff --git a/include/rtthread.h b/include/rtthread.h index a72d2d30c8a351dc348912de54c3c891f4c5fce3..bf74108197b5bfef7494916e7c87012257a30baa 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 e96ff9b4535a935951b27b5f632e7097e3070512..2508c2b550d29a3a670507f6422583fdfe0f4cc3 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 42b2bb7ff06ab36e8efa83a31df70952e58d9cf2..b5bfcbe0de4a43824d45e9753411c124abf1f318 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 385d800b482c265627a906424fba6ae8052bd429..41c1b167d05f9df16f230d0fdd1e6ffbb860c284 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 dc497ee657769883e2c2ff13bd5da1b0e60c816f..2027852e45e584f032cf4219dd2f6f8141e9054d 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);