Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/rtsched.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct rt_sched_thread_ctx
rt_uint8_t stat; /**< thread status */
rt_uint8_t sched_flag_locked:1; /**< calling thread have the scheduler locked */
rt_uint8_t sched_flag_ttmr_set:1; /**< thread timer is start */
rt_uint8_t sched_flag_defunct:1; /**< thread has been enqueued to defunct */

#ifdef ARCH_USING_HW_THREAD_SELF
rt_uint8_t critical_switch_flag:1; /**< critical switch pending */
Expand Down
1 change: 1 addition & 0 deletions src/scheduler_comm.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ void rt_sched_thread_init_ctx(struct rt_thread *thread, rt_uint32_t tick, rt_uin
{
/* setup thread status */
RT_SCHED_CTX(thread).stat = RT_THREAD_INIT;
RT_SCHED_CTX(thread).sched_flag_defunct = 0;

#ifdef RT_USING_SMP
/* not bind on any cpu */
Expand Down
38 changes: 32 additions & 6 deletions src/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,22 @@ static void _thread_detach_from_mutex(rt_thread_t thread)
static void _thread_detach_from_mutex(rt_thread_t thread) {}
#endif

static rt_err_t _thread_mark_defunct(rt_thread_t thread)
{
rt_err_t error = -RT_ERROR;
rt_base_t level;

level = rt_spin_lock_irqsave(&thread->spinlock);
if (!RT_SCHED_CTX(thread).sched_flag_defunct)
{
RT_SCHED_CTX(thread).sched_flag_defunct = 1;
error = RT_EOK;
}
rt_spin_unlock_irqrestore(&thread->spinlock, level);

return error;
}

static void _thread_exit(void)
{
struct rt_thread *thread;
Expand All @@ -126,10 +142,13 @@ static void _thread_exit(void)

rt_thread_close(thread);

_thread_detach_from_mutex(thread);
if (_thread_mark_defunct(thread) == 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);

Expand Down Expand Up @@ -513,10 +532,17 @@ static rt_err_t _thread_detach(rt_thread_t thread)

error = rt_thread_close(thread);

_thread_detach_from_mutex(thread);
if (error == RT_EOK)
{
error = _thread_mark_defunct(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;
Expand Down
71 changes: 71 additions & 0 deletions src/utest/thread_tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
*
* Test Scenarios:
* - Create, start, and delete a dynamic thread to verify dynamic thread lifecycle management
* - Let a dynamic thread exit normally, then call rt_thread_delete again in cleanup to verify duplicate delete handling
* - Initialize, start, and detach a static thread to verify static thread lifecycle management
* - Delay a thread for a specific tick count and check timing accuracy
* - Register and remove an idle hook, verifying it is called as expected
Expand All @@ -37,6 +38,7 @@
*
* Verification Metrics:
* - Threads are created, started, deleted, and detached successfully
* - Repeated deletion after normal thread exit returns an error without abnormal cleanup
* - The precision of both relative delay and absolute delay is correct.
* - Idle hook is invoked as expected during thread idle periods
* - Thread yield causes correct scheduling among threads of the same priority
Expand Down Expand Up @@ -71,13 +73,17 @@ static struct rt_thread thread2;
static rt_thread_t tid5 = RT_NULL;
static rt_thread_t tid6 = RT_NULL;
static rt_thread_t tid7 = RT_NULL;
static rt_thread_t tid9 = RT_NULL;
#endif /* RT_USING_HEAP */

static volatile rt_uint32_t tid3_delay_pass_flag = 0;
static volatile rt_uint32_t tid3_finish_flag = 0;
static volatile rt_uint32_t tid4_finish_flag = 0;
static volatile rt_uint32_t tid6_finish_flag = 0;
static volatile rt_uint32_t thread5_source = 0;
static rt_atomic_t thread9_exit_flag = 0;
static rt_atomic_t thread9_cleanup_flag = 0;
static rt_atomic_t thread9_delete_ret = -RT_ERROR;

#ifndef RT_USING_SMP
static volatile rt_uint32_t thread_yield_flag = 0;
Expand Down Expand Up @@ -452,6 +458,66 @@ static void test_thread_priority(void)
return;
}

#ifdef RT_USING_HEAP
static void thread9_entry(void *parameter)
{
RT_UNUSED(parameter);

while (rt_atomic_load(&thread9_exit_flag) == 0)
{
rt_thread_mdelay(1);
}
}

static void thread9_cleanup(struct rt_thread *thread)
{
rt_atomic_store(&thread9_delete_ret, rt_thread_delete(thread));
rt_atomic_store(&thread9_cleanup_flag, 1);
}

static void test_thread_exit_delete_again(void)
{
rt_err_t ret_startup = -RT_ERROR;

rt_atomic_store(&thread9_exit_flag, 0);
rt_atomic_store(&thread9_cleanup_flag, 0);
rt_atomic_store(&thread9_delete_ret, RT_EOK);

tid9 = rt_thread_create("thread9",
thread9_entry,
RT_NULL,
THREAD_STACK_SIZE,
UTEST_THR_PRIORITY - 1,
THREAD_TIMESLICE);
if (tid9 == RT_NULL)
{
LOG_E("rt_thread_create failed!");
uassert_false(tid9 == RT_NULL);
return;
}

tid9->cleanup = thread9_cleanup;

ret_startup = rt_thread_startup(tid9);
if (ret_startup != RT_EOK)
{
LOG_E("rt_thread_startup failed!");
uassert_false(ret_startup != RT_EOK);
rt_thread_delete(tid9);
return;
}

rt_atomic_store(&thread9_exit_flag, 1);

while (rt_atomic_load(&thread9_cleanup_flag) == 0)
{
rt_thread_mdelay(1);
}

uassert_int_equal(rt_atomic_load(&thread9_delete_ret), -RT_ERROR);
}
#endif /* RT_USING_HEAP */

static void test_delay_until(void)
{
rt_tick_t tick;
Expand Down Expand Up @@ -756,6 +822,9 @@ static rt_err_t utest_tc_init(void)
tid3_finish_flag = 0;
tid4_finish_flag = 0;
tid6_finish_flag = 0;
rt_atomic_store(&thread9_exit_flag, 0);
rt_atomic_store(&thread9_cleanup_flag, 0);
rt_atomic_store(&thread9_delete_ret, -RT_ERROR);
entry_idle_hook_times = 0;
count = 0;
return RT_EOK;
Expand All @@ -772,6 +841,8 @@ static void testcase(void)
UTEST_UNIT_RUN(test_static_thread);
/* create, delete */
UTEST_UNIT_RUN(test_dynamic_thread);
/* exit, duplicate delete */
UTEST_UNIT_RUN(test_thread_exit_delete_again);
/* delay */
UTEST_UNIT_RUN(test_thread_delay);
/* idle_sethook, idle_delhook */
Expand Down
Loading