From 5e7598b5779571d541af96cfd47a7c6011d7ede6 Mon Sep 17 00:00:00 2001 From: eatvector <2302147681@qq.com> Date: Sat, 26 Jul 2025 14:14:22 +0000 Subject: [PATCH] smp: ensure safe thread termination in rt_thread_close --- src/Kconfig | 9 +++++++ src/thread.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/Kconfig b/src/Kconfig index 099f95e9cfa..e5cfbb15ecc 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -83,6 +83,15 @@ config RT_CPUS_NR help Number of CPUs in the system +config RT_SMP_THREAD_DETACH_TIMEOUT + int "SMP thread detach timeout (ms)" + depends on RT_USING_SMP + default 2000 + range 100 5000 + help + Timeout value for waiting thread to detach from CPU in SMP mode. + Adjust based on hardware characteristics and system load. + config RT_ALIGN_SIZE int "Alignment size for CPU architecture data access" default 8 diff --git a/src/thread.c b/src/thread.c index a520a323b16..9f54025031b 100644 --- a/src/thread.c +++ b/src/thread.c @@ -423,12 +423,15 @@ RTM_EXPORT(rt_thread_startup); */ rt_err_t rt_thread_close(rt_thread_t thread) { + rt_err_t error; rt_sched_lock_level_t slvl; rt_uint8_t thread_status; /* forbid scheduling on current core if closing current thread */ RT_ASSERT(thread != rt_thread_self() || rt_critical_level()); + error = RT_EOK; + /* before checking status of scheduler */ rt_sched_lock(&slvl); @@ -447,12 +450,60 @@ rt_err_t rt_thread_close(rt_thread_t thread) /* change stat */ rt_sched_thread_close(thread); - } +#ifdef RT_USING_SMP + int cpu_id; + rt_tick_t start_tick; + rt_tick_t timeout = rt_tick_from_millisecond(RT_SMP_THREAD_DETACH_TIMEOUT); + rt_bool_t need_wait = RT_FALSE; + + /** + * in SMP, the current thread and target thread may run on different CPUs. + * although we set the target thread's state to closed, it may still execute + * on another CPU until rescheduled. send IPI to force immediate rescheduling. + */ + cpu_id = RT_SCHED_CTX(thread).oncpu; + rt_sched_unlock(slvl); + if ((cpu_id != RT_CPU_DETACHED) && (cpu_id != rt_cpu_get_id())) + { + rt_hw_ipi_send(RT_SCHEDULE_IPI, RT_CPU_MASK ^ (1 << cpu_id)); + need_wait = RT_TRUE; + } + + start_tick = rt_tick_get(); + + /** + * continuously check if target thread has detached from CPU core. + * this loop ensures the thread fully stops before resource cleanup. + * a timeout prevents deadlock if thread fails to detach promptly. + */ + while (need_wait) + { + if (rt_tick_get_delta(start_tick) >= timeout) + { + LOG_D("Timeout waiting for thread %s (tid=%p) to detach from CPU%d", + thread->parent.name, thread, cpu_id); + error = -RT_ETIMEOUT; + break; + } + + rt_sched_lock(&slvl); + cpu_id = RT_SCHED_CTX(thread).oncpu; + rt_sched_unlock(slvl); + + if (cpu_id == RT_CPU_DETACHED) + { + break; + } + } + + return error; +#endif + } /* scheduler works are done */ rt_sched_unlock(slvl); - return RT_EOK; + return error; } RTM_EXPORT(rt_thread_close); @@ -491,10 +542,14 @@ static rt_err_t _thread_detach(rt_thread_t thread) error = rt_thread_close(thread); - _thread_detach_from_mutex(thread); + /* only when the current thread has successfully closed the target thread. */ + if (error == RT_EOK) + { + _thread_detach_from_mutex(thread); - /* insert to defunct thread list */ - rt_thread_defunct_enqueue(thread); + /* insert to defunct thread list */ + rt_thread_defunct_enqueue(thread); + } rt_exit_critical_safe(critical_level); return error; @@ -1142,4 +1197,4 @@ rt_err_t rt_thread_get_name(rt_thread_t thread, char *name, rt_uint8_t name_size } RTM_EXPORT(rt_thread_get_name); -/**@}*/ +/**@}*/ \ No newline at end of file