Skip to content

Commit a5e382d

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

File tree

1 file changed

+71
-10
lines changed

1 file changed

+71
-10
lines changed

src/thread.c

Lines changed: 71 additions & 10 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,6 +430,7 @@ 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;
428436

@@ -447,12 +455,56 @@ rt_err_t rt_thread_close(rt_thread_t thread)
447455

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

452504
/* scheduler works are done */
453505
rt_sched_unlock(slvl);
454506

455-
return RT_EOK;
507+
return error;
456508
}
457509
RTM_EXPORT(rt_thread_close);
458510

@@ -491,12 +543,20 @@ static rt_err_t _thread_detach(rt_thread_t thread)
491543

492544
error = rt_thread_close(thread);
493545

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

499558
rt_exit_critical_safe(critical_level);
559+
500560
return error;
501561
}
502562

@@ -1143,3 +1203,4 @@ rt_err_t rt_thread_get_name(rt_thread_t thread, char *name, rt_uint8_t name_size
11431203
RTM_EXPORT(rt_thread_get_name);
11441204

11451205
/**@}*/
1206+

0 commit comments

Comments
 (0)