Skip to content

Commit c5f73fb

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

File tree

3 files changed

+66
-23
lines changed

3 files changed

+66
-23
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_bool_t _rt_mutex_release_detach(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: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
rt_bool_t _rt_mutex_release(rt_mutex_t mutex)
15901590
{
15911591
rt_sched_lock_level_t slvl;
15921592
struct rt_thread *thread;
@@ -1601,25 +1601,14 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
16011601
/* only thread could release mutex because we need test the ownership */
16021602
RT_DEBUG_IN_THREAD_CONTEXT;
16031603

1604-
/* get current thread */
1605-
thread = rt_thread_self();
1606-
1607-
rt_spin_lock(&(mutex->spinlock));
1604+
/* get the current owner thread of the mutex */
1605+
thread = mutex->owner;
16081606

1609-
LOG_D("mutex_release:current thread %s, hold: %d",
1610-
thread->parent.name, mutex->hold);
1607+
LOG_D("mutex_release: mutex owner thread %s, hold count: %d",
1608+
thread->parent.name, mutex->hold);
16111609

16121610
RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent)));
16131611

1614-
/* mutex only can be released by owner */
1615-
if (thread != mutex->owner)
1616-
{
1617-
thread->error = -RT_ERROR;
1618-
rt_spin_unlock(&(mutex->spinlock));
1619-
1620-
return -RT_ERROR;
1621-
}
1622-
16231612
/* decrease hold */
16241613
mutex->hold --;
16251614
/* if no hold */
@@ -1705,17 +1694,68 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
17051694
}
17061695
}
17071696

1697+
return need_schedule;
1698+
}
1699+
1700+
1701+
rt_bool_t _rt_mutex_release_detach(rt_mutex_t mutex)
1702+
{
1703+
_rt_mutex_release(mutex);
1704+
}
1705+
1706+
1707+
/**
1708+
* @brief Release a mutex owned by current thread.
1709+
*
1710+
* @note Resumes first suspended thread if any (requires scheduling).
1711+
* Increases mutex->value if no threads waiting.
1712+
* Must be called by mutex owner with spinlock held.
1713+
*
1714+
* @param mutex Pointer to the mutex object.
1715+
*
1716+
* @return RT_EOK on success, -RT_ERROR if not owner.
1717+
*/
1718+
rt_err_t rt_mutex_release(rt_mutex_t mutex)
1719+
{
1720+
struct rt_thread *thread;
1721+
rt_bool_t need_schedule;
1722+
1723+
/* parameter check */
1724+
RT_ASSERT(mutex != RT_NULL);
1725+
RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
1726+
1727+
need_schedule = RT_FALSE;
1728+
1729+
/* only thread could release mutex because we need test the ownership */
1730+
RT_DEBUG_IN_THREAD_CONTEXT;
1731+
1732+
/* get current thread */
1733+
thread = rt_thread_self();
1734+
1735+
rt_spin_lock(&(mutex->spinlock));
1736+
1737+
if (thread != mutex->owner)
1738+
{
1739+
thread->error = -RT_ERROR;
1740+
rt_spin_unlock(&(mutex->spinlock));
1741+
1742+
return -RT_ERROR;
1743+
}
1744+
1745+
need_schedule= _rt_mutex_release(mutex);
1746+
17081747
rt_spin_unlock(&(mutex->spinlock));
17091748

17101749
/* perform a schedule */
17111750
if (need_schedule == RT_TRUE)
1751+
{
17121752
rt_schedule();
1753+
}
17131754

17141755
return RT_EOK;
17151756
}
17161757
RTM_EXPORT(rt_mutex_release);
17171758

1718-
17191759
/**
17201760
* @brief This function will set some extra attributions of a mutex object.
17211761
*

src/thread.c

Lines changed: 5 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,10 @@ 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_spin_lock(&(mutex->spinlock));
106+
mutex->hold=1;
107+
_rt_mutex_release(mutex);
108+
rt_spin_unlock(&(mutex->spinlock));
107109
}
108110

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

0 commit comments

Comments
 (0)