Skip to content

Commit db1f8eb

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

File tree

1 file changed

+81
-9
lines changed

1 file changed

+81
-9
lines changed

src/thread.c

Lines changed: 81 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ static void _thread_detach_from_mutex(rt_thread_t thread) {}
116116

117117
static void _thread_exit(void)
118118
{
119+
rt_err_t error;
119120
struct rt_thread *thread;
120121
rt_base_t critical_level;
121122

@@ -124,12 +125,19 @@ static void _thread_exit(void)
124125

125126
critical_level = rt_enter_critical();
126127

127-
rt_thread_close(thread);
128+
error=rt_thread_close(thread);
128129

129-
_thread_detach_from_mutex(thread);
130+
/**
131+
* this check prevents concurrent _thread_detach operations by other threads.
132+
* proceeds only when the current thread has successfully closed the target thread.
133+
*/
134+
if(error == RT_EOK)
135+
{
136+
_thread_detach_from_mutex(thread);
130137

131-
/* insert to defunct thread list */
132-
rt_thread_defunct_enqueue(thread);
138+
/* insert to defunct thread list */
139+
rt_thread_defunct_enqueue(thread);
140+
}
133141

134142
rt_exit_critical_safe(critical_level);
135143

@@ -423,12 +431,15 @@ RTM_EXPORT(rt_thread_startup);
423431
*/
424432
rt_err_t rt_thread_close(rt_thread_t thread)
425433
{
434+
rt_err_t error;
426435
rt_sched_lock_level_t slvl;
427436
rt_uint8_t thread_status;
428437

429438
/* forbid scheduling on current core if closing current thread */
430439
RT_ASSERT(thread != rt_thread_self() || rt_critical_level());
431440

441+
error = RT_EOK;
442+
432443
/* before checking status of scheduler */
433444
rt_sched_lock(&slvl);
434445

@@ -447,12 +458,65 @@ rt_err_t rt_thread_close(rt_thread_t thread)
447458

448459
/* change stat */
449460
rt_sched_thread_close(thread);
461+
462+
#ifdef RT_USING_SMP
463+
int cpu_id;
464+
rt_tick_t timeout = RT_TICK_PER_SECOND;
465+
rt_bool_t need_wait = RT_FALSE;
466+
467+
/**
468+
* in SMP, the current thread and target thread may run on different CPUs.
469+
* although we set the target thread's state to closed, it may still execute
470+
* on another CPU until rescheduled. send IPI to force immediate rescheduling.
471+
*/
472+
cpu_id = RT_SCHED_CTX(thread).oncpu;
473+
rt_sched_unlock(slvl);
474+
if ((cpu_id != RT_CPU_DETACHED) && (cpu_id != rt_cpu_get_id()))
475+
{
476+
rt_hw_ipi_send(RT_SCHEDULE_IPI, RT_CPU_MASK ^ (1 << cpu_id));
477+
need_wait = RT_TRUE;
478+
}
479+
480+
/**
481+
* continuously check if target thread has detached from CPU core.
482+
* this loop ensures the thread fully stops before resource cleanup.
483+
* a timeout prevents deadlock if thread fails to detach promptly.
484+
*/
485+
while (need_wait && timeout--)
486+
{
487+
rt_sched_lock(&slvl);
488+
cpu_id = RT_SCHED_CTX(thread).oncpu;
489+
rt_sched_unlock(slvl);
490+
491+
if (cpu_id == RT_CPU_DETACHED)
492+
{
493+
break;
494+
}
495+
}
496+
497+
if (need_wait && timeout == 0)
498+
{
499+
LOG_D("Timeout waiting for thread %s (tid=%p) to detach from CPU%d",
500+
RT_NAME_MAX, thread->parent.name, thread, cpu_id);
501+
error = -RT_ETIMEOUT;
502+
}
503+
504+
return error;
505+
#endif
506+
}
507+
else
508+
{
509+
/**
510+
* avoid duplicate closing: if the thread is already closed, return an error.
511+
* this prevents race conditions when multiple threads call _thread_detach/_thread_exit concurrently.
512+
*/
513+
error = -RT_ERROR;
450514
}
451515

452516
/* scheduler works are done */
453517
rt_sched_unlock(slvl);
454518

455-
return RT_EOK;
519+
return error;
456520
}
457521
RTM_EXPORT(rt_thread_close);
458522

@@ -491,10 +555,18 @@ static rt_err_t _thread_detach(rt_thread_t thread)
491555

492556
error = rt_thread_close(thread);
493557

494-
_thread_detach_from_mutex(thread);
558+
/**
559+
* prevents concurrent thread cleanup operations by synchronizing between external
560+
* _thread_detach calls and the target thread's own _thread_exit path.
561+
* proceeds only when the current thread has successfully closed the target thread.
562+
*/
563+
if (error == RT_EOK)
564+
{
565+
_thread_detach_from_mutex(thread);
495566

496-
/* insert to defunct thread list */
497-
rt_thread_defunct_enqueue(thread);
567+
/* insert to defunct thread list */
568+
rt_thread_defunct_enqueue(thread);
569+
}
498570

499571
rt_exit_critical_safe(critical_level);
500572
return error;
@@ -1142,4 +1214,4 @@ rt_err_t rt_thread_get_name(rt_thread_t thread, char *name, rt_uint8_t name_size
11421214
}
11431215
RTM_EXPORT(rt_thread_get_name);
11441216

1145-
/**@}*/
1217+
/**@}*/

0 commit comments

Comments
 (0)