@@ -922,6 +922,55 @@ rt_inline void _thread_update_priority(struct rt_thread *thread, rt_uint8_t prio
922922 }
923923}
924924
925+ /*
926+ * Detach a mutex waiter from mutex-specific state.
927+ *
928+ * The scheduler lock must be held. After this function returns true,
929+ * the waiter no longer needs to access the mutex object.
930+ */
931+ rt_bool_t rt_mutex_cleanup_waiter (rt_thread_t thread , rt_bool_t remove_from_list )
932+ {
933+ rt_mutex_t mutex ;
934+ rt_uint8_t priority ;
935+ rt_bool_t need_update = RT_FALSE ;
936+
937+ RT_SCHED_DEBUG_IS_LOCKED ;
938+
939+ if ((thread -> pending_object == RT_NULL ) ||
940+ (rt_object_get_type (thread -> pending_object ) != RT_Object_Class_Mutex ))
941+ {
942+ return RT_FALSE ;
943+ }
944+
945+ mutex = (rt_mutex_t )thread -> pending_object ;
946+
947+ if (mutex -> owner &&
948+ (rt_sched_thread_get_curr_prio (mutex -> owner ) ==
949+ rt_sched_thread_get_curr_prio (thread )))
950+ {
951+ need_update = RT_TRUE ;
952+ }
953+
954+ if (remove_from_list )
955+ {
956+ rt_list_remove (& RT_THREAD_LIST_NODE (thread ));
957+ }
958+ _mutex_update_priority (mutex );
959+
960+ if (need_update && mutex -> owner )
961+ {
962+ priority = _thread_get_mutex_priority (mutex -> owner );
963+ if (priority != rt_sched_thread_get_curr_prio (mutex -> owner ))
964+ {
965+ _thread_update_priority (mutex -> owner , priority , RT_UNINTERRUPTIBLE );
966+ }
967+ }
968+
969+ thread -> pending_object = RT_NULL ;
970+
971+ return RT_TRUE ;
972+ }
973+
925974static rt_bool_t _check_and_update_prio (rt_thread_t thread , rt_mutex_t mutex )
926975{
927976 RT_SCHED_DEBUG_IS_LOCKED ;
@@ -951,8 +1000,39 @@ static void _mutex_before_delete_detach(rt_mutex_t mutex)
9511000 rt_bool_t need_schedule = RT_FALSE ;
9521001
9531002 rt_spin_lock (& (mutex -> spinlock ));
954- /* wakeup all suspended threads */
955- rt_susp_list_resume_all (& (mutex -> parent .suspend_thread ), RT_ERROR );
1003+
1004+ /*
1005+ * Wake waiters and clear their mutex references under one scheduler lock.
1006+ * If timeout owns a waiter's timer, only clean the mutex state here; the
1007+ * timeout callback still owns making the thread ready.
1008+ */
1009+ for (;;)
1010+ {
1011+ rt_thread_t thread ;
1012+ rt_bool_t cleaned ;
1013+
1014+ rt_sched_lock (& slvl );
1015+ if (rt_list_isempty (& mutex -> parent .suspend_thread ))
1016+ {
1017+ rt_sched_unlock (slvl );
1018+ break ;
1019+ }
1020+
1021+ thread = RT_THREAD_LIST_NODE_ENTRY (mutex -> parent .suspend_thread .next );
1022+ if (rt_sched_thread_ready (thread ) == RT_EOK )
1023+ {
1024+ cleaned = rt_mutex_cleanup_waiter (thread , RT_FALSE );
1025+ RT_ASSERT (cleaned );
1026+ thread -> error = RT_ERROR ;
1027+ rt_sched_unlock (slvl );
1028+ }
1029+ else
1030+ {
1031+ cleaned = rt_mutex_cleanup_waiter (thread , RT_TRUE );
1032+ RT_ASSERT (cleaned );
1033+ rt_sched_unlock (slvl );
1034+ }
1035+ }
9561036
9571037 rt_sched_lock (& slvl );
9581038
@@ -1452,6 +1532,14 @@ static rt_err_t _rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout, int suspend
14521532 /* do schedule */
14531533 rt_schedule ();
14541534
1535+ /* Return the deletion error after the mutex was removed. */
1536+ if ((thread -> pending_object == RT_NULL ) &&
1537+ ((thread -> error == RT_ERROR ) ||
1538+ (thread -> error == - RT_ETIMEOUT )))
1539+ {
1540+ return thread -> error == RT_ERROR ? - RT_ERROR : thread -> error ;
1541+ }
1542+
14551543 rt_spin_lock (& (mutex -> spinlock ));
14561544
14571545 if (mutex -> owner == thread )
@@ -1657,32 +1745,27 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
16571745 /* whether change the thread priority */
16581746 need_schedule = _check_and_update_prio (owner , mutex );
16591747
1660- /* wakeup suspended thread */
1661- if (! rt_list_isempty ( & mutex -> parent . suspend_thread ) )
1748+ /* wakeup the first waiter that still owns its timer */
1749+ for (;; )
16621750 {
16631751 struct rt_thread * next_thread ;
1664- do
1665- {
1666- /* get the first suspended thread */
1667- next_thread = RT_THREAD_LIST_NODE_ENTRY (mutex -> parent .suspend_thread .next );
1668-
1669- RT_ASSERT (rt_sched_thread_is_suspended (next_thread ));
1752+ rt_bool_t cleaned ;
16701753
1671- /* remove the thread from the suspended list of mutex */
1672- rt_list_remove (& RT_THREAD_LIST_NODE (next_thread ));
1754+ if (rt_list_isempty (& mutex -> parent .suspend_thread ))
1755+ {
1756+ /* no waiting thread is woke up, clear owner */
1757+ mutex -> owner = RT_NULL ;
1758+ mutex -> priority = 0xff ;
1759+ rt_sched_unlock (slvl );
1760+ break ;
1761+ }
16731762
1674- /* resume thread to ready queue */
1675- if (rt_sched_thread_ready (next_thread ) != RT_EOK )
1676- {
1677- /**
1678- * a timeout timer had triggered while we try. So we skip
1679- * this thread and try again.
1680- */
1681- next_thread = RT_NULL ;
1682- }
1683- } while (!next_thread && !rt_list_isempty (& mutex -> parent .suspend_thread ));
1763+ /* get the first suspended thread */
1764+ next_thread = RT_THREAD_LIST_NODE_ENTRY (mutex -> parent .suspend_thread .next );
1765+ RT_ASSERT (rt_sched_thread_is_suspended (next_thread ));
16841766
1685- if (next_thread )
1767+ /* resume thread to ready queue */
1768+ if (rt_sched_thread_ready (next_thread ) == RT_EOK )
16861769 {
16871770 LOG_D ("mutex_release: resume thread: %s" ,
16881771 next_thread -> parent .name );
@@ -1709,23 +1792,17 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex)
17091792 }
17101793
17111794 need_schedule = RT_TRUE ;
1795+ rt_sched_unlock (slvl );
1796+ break ;
17121797 }
1713- else
1714- {
1715- /* no waiting thread is woke up, clear owner */
1716- mutex -> owner = RT_NULL ;
1717- mutex -> priority = 0xff ;
1718- }
1719-
1720- rt_sched_unlock (slvl );
1721- }
1722- else
1723- {
1724- rt_sched_unlock (slvl );
17251798
1726- /* clear owner */
1727- mutex -> owner = RT_NULL ;
1728- mutex -> priority = 0xff ;
1799+ /**
1800+ * A timeout callback owns this waiter. Remove only the mutex
1801+ * state and leave READY/error ownership to the callback, then
1802+ * retry the list head while the mutex remains locked.
1803+ */
1804+ cleaned = rt_mutex_cleanup_waiter (next_thread , RT_TRUE );
1805+ RT_ASSERT (cleaned );
17291806 }
17301807 }
17311808
0 commit comments