Skip to content

Commit fd03c20

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

File tree

1 file changed

+74
-11
lines changed

1 file changed

+74
-11
lines changed

src/thread.c

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2006-2022, RT-Thread Development Team
2+
* Copyright (c) 2006-2025, RT-Thread Development Team
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*
@@ -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,18 @@ 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+
/* This check prevents other threads from concurrently executing _thread_detach
131+
* and duplicating the detach operations. Only proceed if close succeeds.
132+
*/
133+
if(error == RT_EOK)
134+
{
135+
_thread_detach_from_mutex(thread);
130136

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

134141
rt_exit_critical_safe(critical_level);
135142

@@ -423,9 +430,12 @@ RTM_EXPORT(rt_thread_startup);
423430
*/
424431
rt_err_t rt_thread_close(rt_thread_t thread)
425432
{
433+
rt_err_t error;
426434
rt_sched_lock_level_t slvl;
427435
rt_uint8_t thread_status;
428-
436+
437+
error = RT_EOK;
438+
429439
/* forbid scheduling on current core if closing current thread */
430440
RT_ASSERT(thread != rt_thread_self() || rt_critical_level());
431441

@@ -447,12 +457,56 @@ rt_err_t rt_thread_close(rt_thread_t thread)
447457

448458
/* change stat */
449459
rt_sched_thread_close(thread);
460+
461+
#ifdef RT_USING_SMP
462+
int cpu_id;
463+
rt_tick_t timeout = RT_TICK_PER_SECOND;
464+
rt_bool_t need_wait = RT_FALSE;
465+
466+
cpu_id = RT_SCHED_CTX(thread).oncpu;
467+
468+
if ((cpu_id != RT_CPU_DETACHED) && (cpu_id != rt_cpu_get_id()))
469+
{
470+
rt_hw_ipi_send(RT_SCHEDULE_IPI, RT_CPU_MASK ^ (1 << cpu_id));
471+
need_wait = RT_TRUE;
472+
}
473+
474+
rt_sched_unlock(slvl);
475+
476+
while (need_wait && timeout--)
477+
{
478+
rt_sched_lock(&slvl);
479+
480+
cpu_id = RT_SCHED_CTX(thread).oncpu;
481+
482+
rt_sched_unlock(slvl);
483+
484+
if (cpu_id == RT_CPU_DETACHED)
485+
{
486+
break;
487+
}
488+
}
489+
490+
if (need_wait && timeout == 0)
491+
{
492+
error = -RT_ETIMEOUT;
493+
}
494+
495+
return error;
496+
#endif
497+
}
498+
else
499+
{
500+
/* Avoid duplicate closing: If the thread is already closed, return an error.
501+
* This prevents race conditions when multiple threads call close/detach/delete concurrently.
502+
*/
503+
error = -RT_ERROR;
450504
}
451505

452506
/* scheduler works are done */
453507
rt_sched_unlock(slvl);
454508

455-
return RT_EOK;
509+
return error;
456510
}
457511
RTM_EXPORT(rt_thread_close);
458512

@@ -491,12 +545,20 @@ static rt_err_t _thread_detach(rt_thread_t thread)
491545

492546
error = rt_thread_close(thread);
493547

494-
_thread_detach_from_mutex(thread);
495-
496-
/* insert to defunct thread list */
497-
rt_thread_defunct_enqueue(thread);
548+
if (error == RT_EOK)
549+
{
550+
/* Only proceed if rt_thread_close() succeeded.
551+
* This ensures thread resources are safely released before detaching mutexes
552+
* and enqueueing to the defunct list.
553+
*/
554+
_thread_detach_from_mutex(thread);
555+
556+
/* insert to defunct thread list */
557+
rt_thread_defunct_enqueue(thread);
558+
}
498559

499560
rt_exit_critical_safe(critical_level);
561+
500562
return error;
501563
}
502564

@@ -1143,3 +1205,4 @@ rt_err_t rt_thread_get_name(rt_thread_t thread, char *name, rt_uint8_t name_size
11431205
RTM_EXPORT(rt_thread_get_name);
11441206

11451207
/**@}*/
1208+

0 commit comments

Comments
 (0)