Skip to content

Commit 5e7598b

Browse files
committed
smp: ensure safe thread termination in rt_thread_close
1 parent f9564d4 commit 5e7598b

File tree

2 files changed

+70
-6
lines changed

2 files changed

+70
-6
lines changed

src/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ config RT_CPUS_NR
8383
help
8484
Number of CPUs in the system
8585

86+
config RT_SMP_THREAD_DETACH_TIMEOUT
87+
int "SMP thread detach timeout (ms)"
88+
depends on RT_USING_SMP
89+
default 2000
90+
range 100 5000
91+
help
92+
Timeout value for waiting thread to detach from CPU in SMP mode.
93+
Adjust based on hardware characteristics and system load.
94+
8695
config RT_ALIGN_SIZE
8796
int "Alignment size for CPU architecture data access"
8897
default 8

src/thread.c

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -423,12 +423,15 @@ RTM_EXPORT(rt_thread_startup);
423423
*/
424424
rt_err_t rt_thread_close(rt_thread_t thread)
425425
{
426+
rt_err_t error;
426427
rt_sched_lock_level_t slvl;
427428
rt_uint8_t thread_status;
428429

429430
/* forbid scheduling on current core if closing current thread */
430431
RT_ASSERT(thread != rt_thread_self() || rt_critical_level());
431432

433+
error = RT_EOK;
434+
432435
/* before checking status of scheduler */
433436
rt_sched_lock(&slvl);
434437

@@ -447,12 +450,60 @@ rt_err_t rt_thread_close(rt_thread_t thread)
447450

448451
/* change stat */
449452
rt_sched_thread_close(thread);
450-
}
451453

454+
#ifdef RT_USING_SMP
455+
int cpu_id;
456+
rt_tick_t start_tick;
457+
rt_tick_t timeout = rt_tick_from_millisecond(RT_SMP_THREAD_DETACH_TIMEOUT);
458+
rt_bool_t need_wait = RT_FALSE;
459+
460+
/**
461+
* in SMP, the current thread and target thread may run on different CPUs.
462+
* although we set the target thread's state to closed, it may still execute
463+
* on another CPU until rescheduled. send IPI to force immediate rescheduling.
464+
*/
465+
cpu_id = RT_SCHED_CTX(thread).oncpu;
466+
rt_sched_unlock(slvl);
467+
if ((cpu_id != RT_CPU_DETACHED) && (cpu_id != rt_cpu_get_id()))
468+
{
469+
rt_hw_ipi_send(RT_SCHEDULE_IPI, RT_CPU_MASK ^ (1 << cpu_id));
470+
need_wait = RT_TRUE;
471+
}
472+
473+
start_tick = rt_tick_get();
474+
475+
/**
476+
* continuously check if target thread has detached from CPU core.
477+
* this loop ensures the thread fully stops before resource cleanup.
478+
* a timeout prevents deadlock if thread fails to detach promptly.
479+
*/
480+
while (need_wait)
481+
{
482+
if (rt_tick_get_delta(start_tick) >= timeout)
483+
{
484+
LOG_D("Timeout waiting for thread %s (tid=%p) to detach from CPU%d",
485+
thread->parent.name, thread, cpu_id);
486+
error = -RT_ETIMEOUT;
487+
break;
488+
}
489+
490+
rt_sched_lock(&slvl);
491+
cpu_id = RT_SCHED_CTX(thread).oncpu;
492+
rt_sched_unlock(slvl);
493+
494+
if (cpu_id == RT_CPU_DETACHED)
495+
{
496+
break;
497+
}
498+
}
499+
500+
return error;
501+
#endif
502+
}
452503
/* scheduler works are done */
453504
rt_sched_unlock(slvl);
454505

455-
return RT_EOK;
506+
return error;
456507
}
457508
RTM_EXPORT(rt_thread_close);
458509

@@ -491,10 +542,14 @@ static rt_err_t _thread_detach(rt_thread_t thread)
491542

492543
error = rt_thread_close(thread);
493544

494-
_thread_detach_from_mutex(thread);
545+
/* only when the current thread has successfully closed the target thread. */
546+
if (error == RT_EOK)
547+
{
548+
_thread_detach_from_mutex(thread);
495549

496-
/* insert to defunct thread list */
497-
rt_thread_defunct_enqueue(thread);
550+
/* insert to defunct thread list */
551+
rt_thread_defunct_enqueue(thread);
552+
}
498553

499554
rt_exit_critical_safe(critical_level);
500555
return error;
@@ -1142,4 +1197,4 @@ rt_err_t rt_thread_get_name(rt_thread_t thread, char *name, rt_uint8_t name_size
11421197
}
11431198
RTM_EXPORT(rt_thread_get_name);
11441199

1145-
/**@}*/
1200+
/**@}*/

0 commit comments

Comments
 (0)