From 2f262aa3e8a64009522533f4bfbd0c6a03375cd9 Mon Sep 17 00:00:00 2001 From: eatvector <2302147681@qq.com> Date: Fri, 25 Jul 2025 11:39:15 +0000 Subject: [PATCH] fix(kernel): properly release mutexes in rt_thread_detach --- .github/workflows/.bsp_buildings.yml.swp | Bin 0 -> 16384 bytes include/rtthread.h | 1 + src/ipc.c | 123 +++++++++++++++++++---- src/thread.c | 4 +- 4 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/.bsp_buildings.yml.swp diff --git a/.github/workflows/.bsp_buildings.yml.swp b/.github/workflows/.bsp_buildings.yml.swp new file mode 100644 index 0000000000000000000000000000000000000000..49e758cf68da8850c42779489db61e163383019b GIT binary patch literal 16384 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 C`#RA8 literal 0 HcmV?d00001 diff --git a/include/rtthread.h b/include/rtthread.h index d9b582ab1e2..6a2901365d5 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -465,6 +465,7 @@ rt_err_t rt_mutex_trytake(rt_mutex_t mutex); rt_err_t rt_mutex_take_interruptible(rt_mutex_t mutex, rt_int32_t time); rt_err_t rt_mutex_take_killable(rt_mutex_t mutex, rt_int32_t time); rt_err_t rt_mutex_release(rt_mutex_t mutex); +rt_err_t rt_mutex_force_release(rt_mutex_t mutex); rt_err_t rt_mutex_control(rt_mutex_t mutex, int cmd, void *arg); rt_inline rt_thread_t rt_mutex_get_owner(rt_mutex_t mutex) diff --git a/src/ipc.c b/src/ipc.c index fdf33b2e330..313918f38b7 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -1578,15 +1578,15 @@ RTM_EXPORT(rt_mutex_trytake); * @brief This function will release a mutex. If there is thread suspended on the mutex, the thread will be resumed. * * @note If there are threads suspended on this mutex, the first thread in the list of this mutex object - * will be resumed, and a thread scheduling (rt_schedule) will be executed. + * will be resumed. * If no threads are suspended on this mutex, the count value mutex->value of this mutex will increase by 1. + * This operation requires mutex->spinlock to be held. * * @param mutex is a pointer to a mutex object. * - * @return Return the operation status. When the return value is RT_EOK, the operation is successful. - * If the return value is any other values, it means that the mutex release failed. + * @return Return RT_TRUE if scheduling is needed, RT_FALSE otherwise. */ -rt_err_t rt_mutex_release(rt_mutex_t mutex) +static rt_bool_t _rt_mutex_release(rt_mutex_t mutex) { rt_sched_lock_level_t slvl; struct rt_thread *thread; @@ -1601,25 +1601,14 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) /* only thread could release mutex because we need test the ownership */ RT_DEBUG_IN_THREAD_CONTEXT; - /* get current thread */ - thread = rt_thread_self(); + /* get the current owner thread of the mutex */ + thread = mutex->owner; - rt_spin_lock(&(mutex->spinlock)); - - LOG_D("mutex_release:current thread %s, hold: %d", - thread->parent.name, mutex->hold); + LOG_D("mutex_release: mutex owner thread %s, hold count: %d", + thread->parent.name, mutex->hold); RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent))); - /* mutex only can be released by owner */ - if (thread != mutex->owner) - { - thread->error = -RT_ERROR; - rt_spin_unlock(&(mutex->spinlock)); - - return -RT_ERROR; - } - /* decrease hold */ mutex->hold --; /* if no hold */ @@ -1705,17 +1694,113 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) } } + return need_schedule; +} + + +/** + * @brief Release a mutex owned by current thread. + * + * @note Resumes first suspended thread if any (requires scheduling). + * Increases mutex->value if no threads waiting. + * Must be called by mutex owner with spinlock held. + * + * @param mutex Pointer to the mutex object. + * + * @return RT_EOK on success, -RT_ERROR if not owner. + */ +rt_err_t rt_mutex_release(rt_mutex_t mutex) +{ + struct rt_thread *thread; + rt_bool_t need_schedule; + + /* parameter check */ + RT_ASSERT(mutex != RT_NULL); + RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex); + + need_schedule = RT_FALSE; + + /* only thread could release mutex because we need test the ownership */ + RT_DEBUG_IN_THREAD_CONTEXT; + + /* get current thread */ + thread = rt_thread_self(); + + rt_spin_lock(&(mutex->spinlock)); + + if (thread != mutex->owner) + { + thread->error = -RT_ERROR; + rt_spin_unlock(&(mutex->spinlock)); + + return -RT_ERROR; + } + + need_schedule= _rt_mutex_release(mutex); + rt_spin_unlock(&(mutex->spinlock)); /* perform a schedule */ if (need_schedule == RT_TRUE) + { rt_schedule(); + } return RT_EOK; } RTM_EXPORT(rt_mutex_release); +/** + * @brief Forcefully release a mutex (Internal API). + * + * @warning This is an internal function that bypasses normal ownership checks. + * When called by a thread different from the mutex owner: + * The owner thread MUST have been closed (rt_thread_close). + * The owner thread MUST be completely off CPU. + * Violating these conditions will cause undefined behavior. + * + * @note Key differences from rt_mutex_release(): + * Ownership check is skipped (caller can be non-owner). + * Forces hold count to 1 before release (handles recursive locks). + * Requires manual validation that owner thread is closed and off CPU + * when caller is not the owner. + * + * @param mutex Pointer to the mutex object to be force-released. + * + * @return Operation status (RT_EOK on success, -RT_ERROR on failure). + */ +rt_err_t rt_mutex_force_release(rt_mutex_t mutex) +{ + rt_bool_t need_schedule; + + /* parameter check */ + RT_ASSERT(mutex != RT_NULL); + RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex); + + need_schedule = RT_FALSE; + + /* only thread could release mutex because we need test the ownership */ + RT_DEBUG_IN_THREAD_CONTEXT; + + rt_spin_lock(&mutex->spinlock); + + /* Force set hold=1 to handle recursive mutex */ + mutex->hold=1; + need_schedule = _rt_mutex_release(mutex); + + rt_spin_unlock(&mutex->spinlock); + + /* perform a schedule */ + if (need_schedule == RT_TRUE) + { + rt_schedule(); + } + + return RT_EOK; +} + + /** * @brief This function will set some extra attributions of a mutex object. * diff --git a/src/thread.c b/src/thread.c index a520a323b16..5f332bf88b4 100644 --- a/src/thread.c +++ b/src/thread.c @@ -101,9 +101,7 @@ static void _thread_detach_from_mutex(rt_thread_t thread) { mutex = rt_list_entry(node, struct rt_mutex, taken_list); LOG_D("Thread [%s] exits while holding mutex [%s].\n", thread->parent.name, mutex->parent.parent.name); - /* recursively take */ - mutex->hold = 1; - rt_mutex_release(mutex); + rt_mutex_force_release(mutex); } rt_spin_unlock_irqrestore(&thread->spinlock, level);