Skip to content

Commit 704de3d

Browse files
committed
fix(kernel): properly release mutexes in _thread_detach_from_mutex()
1 parent f9564d4 commit 704de3d

File tree

3 files changed

+40
-11
lines changed

3 files changed

+40
-11
lines changed

include/rtthread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ rt_err_t rt_mutex_trytake(rt_mutex_t mutex);
465465
rt_err_t rt_mutex_take_interruptible(rt_mutex_t mutex, rt_int32_t time);
466466
rt_err_t rt_mutex_take_killable(rt_mutex_t mutex, rt_int32_t time);
467467
rt_err_t rt_mutex_release(rt_mutex_t mutex);
468+
rt_err_t rt_mutex_force_release(rt_mutex_t mutex);
468469
rt_err_t rt_mutex_control(rt_mutex_t mutex, int cmd, void *arg);
469470

470471
rt_inline rt_thread_t rt_mutex_get_owner(rt_mutex_t mutex)

src/ipc.c

Lines changed: 37 additions & 8 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
*
@@ -1578,15 +1578,15 @@ RTM_EXPORT(rt_mutex_trytake);
15781578
* @brief This function will release a mutex. If there is thread suspended on the mutex, the thread will be resumed.
15791579
*
15801580
* @note If there are threads suspended on this mutex, the first thread in the list of this mutex object
1581-
* will be resumed, and a thread scheduling (rt_schedule) will be executed.
1581+
* will be resumed.
15821582
* If no threads are suspended on this mutex, the count value mutex->value of this mutex will increase by 1.
1583+
* This operation requires mutex->spinlock to be held.
15831584
*
15841585
* @param mutex is a pointer to a mutex object.
15851586
*
1586-
* @return Return the operation status. When the return value is RT_EOK, the operation is successful.
1587-
* If the return value is any other values, it means that the mutex release failed.
1587+
* @return Return RT_TRUE if scheduling is needed, RT_FALSE otherwise.
15881588
*/
1589-
rt_err_t rt_mutex_release(rt_mutex_t mutex)
1589+
static rt_err_t _rt_mutex_release(rt_mutex_t mutex, rt_bool_t is_force)
15901590
{
15911591
rt_sched_lock_level_t slvl;
15921592
struct rt_thread *thread;
@@ -1612,11 +1612,15 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
16121612
RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent)));
16131613

16141614
/* mutex only can be released by owner */
1615-
if (thread != mutex->owner)
1615+
if (is_force)
1616+
{
1617+
/* Force release by setting hold count to 1 */
1618+
mutex->hold = 1;
1619+
}
1620+
else if (thread != mutex->owner)
16161621
{
16171622
thread->error = -RT_ERROR;
16181623
rt_spin_unlock(&(mutex->spinlock));
1619-
16201624
return -RT_ERROR;
16211625
}
16221626

@@ -1713,9 +1717,31 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
17131717

17141718
return RT_EOK;
17151719
}
1716-
RTM_EXPORT(rt_mutex_release);
17171720

17181721

1722+
rt_err_t rt_mutex_force_release(rt_mutex_t mutex)
1723+
{
1724+
return _rt_mutex_release(mutex, RT_TRUE);
1725+
}
1726+
1727+
1728+
/**
1729+
* @brief Release a mutex owned by current thread.
1730+
*
1731+
* @note Resumes first suspended thread if any (requires scheduling).
1732+
* Increases mutex->value if no threads waiting.
1733+
* Must be called by mutex owner with spinlock held.
1734+
*
1735+
* @param mutex Pointer to the mutex object.
1736+
*
1737+
* @return RT_EOK on success, -RT_ERROR if not owner.
1738+
*/
1739+
rt_err_t rt_mutex_release(rt_mutex_t mutex)
1740+
{
1741+
return _rt_mutex_release(mutex, RT_FALSE);
1742+
}
1743+
RTM_EXPORT(rt_mutex_release);
1744+
17191745
/**
17201746
* @brief This function will set some extra attributions of a mutex object.
17211747
*
@@ -2043,6 +2069,7 @@ rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
20432069
need_schedule = RT_TRUE;
20442070
}
20452071
}
2072+
20462073
if (need_clear_set)
20472074
{
20482075
event->set &= ~need_clear_set;
@@ -3514,6 +3541,7 @@ static rt_err_t _rt_mq_send_wait(rt_mq_t mq,
35143541
msg->next = node;
35153542
break;
35163543
}
3544+
35173545
if (node->next == RT_NULL)
35183546
{
35193547
if (node != msg)
@@ -4031,3 +4059,4 @@ RTM_EXPORT(rt_mq_control);
40314059
/**@}*/
40324060
#endif /* RT_USING_MESSAGEQUEUE */
40334061
/**@}*/
4062+

src/thread.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ RT_OBJECT_HOOKLIST_DEFINE(rt_thread_inited);
7777
#endif /* defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR) */
7878

7979
#ifdef RT_USING_MUTEX
80+
8081
static void _thread_detach_from_mutex(rt_thread_t thread)
8182
{
8283
rt_list_t *node;
@@ -101,9 +102,7 @@ static void _thread_detach_from_mutex(rt_thread_t thread)
101102
{
102103
mutex = rt_list_entry(node, struct rt_mutex, taken_list);
103104
LOG_D("Thread [%s] exits while holding mutex [%s].\n", thread->parent.name, mutex->parent.parent.name);
104-
/* recursively take */
105-
mutex->hold = 1;
106-
rt_mutex_release(mutex);
105+
rt_mutex_force_release(mutex);
107106
}
108107

109108
rt_spin_unlock_irqrestore(&thread->spinlock, level);

0 commit comments

Comments
 (0)