From 34c77da153319da3225bd2064333b34942fee933 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Sat, 15 Oct 2022 16:19:13 +0800 Subject: [PATCH 1/6] [Kernel] Add nested mutex feature --- components/finsh/cmd.c | 9 +- include/rtdef.h | 12 +- include/rtthread.h | 1 + src/ipc.c | 324 +++++++++++++++++++++++++++++++---------- src/thread.c | 27 ++++ 5 files changed, 291 insertions(+), 82 deletions(-) diff --git a/components/finsh/cmd.c b/components/finsh/cmd.c index 799d7b3d51..137ca3acff 100644 --- a/components/finsh/cmd.c +++ b/components/finsh/cmd.c @@ -411,9 +411,9 @@ long list_mutex(void) maxlen = RT_NAME_MAX; - rt_kprintf("%-*.s owner hold suspend thread\n", maxlen, item_title); + rt_kprintf("%-*.s owner hold suspend thread priority\n", maxlen, item_title); object_split(maxlen); - rt_kprintf(" -------- ---- --------------\n"); + rt_kprintf(" -------- ---- -------------- --------\n"); do { @@ -436,13 +436,14 @@ long list_mutex(void) rt_hw_interrupt_enable(level); m = (struct rt_mutex *)obj; - rt_kprintf("%-*.*s %-8.*s %04d %d\n", + rt_kprintf("%-*.*s %-8.*s %04d %d %d\n", maxlen, RT_NAME_MAX, m->parent.parent.name, RT_NAME_MAX, m->owner->name, m->hold, - rt_list_len(&m->parent.suspend_thread)); + rt_list_len(&m->parent.suspend_thread), + m->priority); } } diff --git a/include/rtdef.h b/include/rtdef.h index 89ac9edf6e..12232c2d5c 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -665,12 +665,19 @@ struct rt_thread /* priority */ rt_uint8_t current_priority; /**< current priority */ + rt_uint8_t init_priority; /**< initialized priority */ #if RT_THREAD_PRIORITY_MAX > 32 rt_uint8_t number; rt_uint8_t high_mask; #endif /* RT_THREAD_PRIORITY_MAX > 32 */ rt_uint32_t number_mask; +#ifdef RT_USING_MUTEX + /* object for IPC */ + rt_list_t taken_object_list; + rt_object_t pending_object; +#endif + #ifdef RT_USING_EVENT /* thread event */ rt_uint32_t event_set; @@ -764,12 +771,11 @@ struct rt_mutex { struct rt_ipc_object parent; /**< inherit from ipc_object */ - rt_uint16_t value; /**< value of mutex */ - - rt_uint8_t original_priority; /**< priority of last thread hold the mutex */ + rt_uint8_t priority; /**< the maximal priority for pending thread */ rt_uint8_t hold; /**< numbers of thread hold the mutex */ struct rt_thread *owner; /**< current owner of mutex */ + rt_list_t taken_list; /**< the object list taken by thread */ }; typedef struct rt_mutex *rt_mutex_t; #endif /* RT_USING_MUTEX */ diff --git a/include/rtthread.h b/include/rtthread.h index c55720b7d1..893b24ea1b 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -368,6 +368,7 @@ rt_err_t rt_mutex_detach(rt_mutex_t mutex); rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag); rt_err_t rt_mutex_delete(rt_mutex_t mutex); #endif +void rt_mutex_drop_thread(rt_mutex_t mutex, rt_thread_t thread); rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout); rt_err_t rt_mutex_trytake(rt_mutex_t mutex); diff --git a/src/ipc.c b/src/ipc.c index 329fc7f4cf..67a998d5df 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -42,6 +42,7 @@ * 2022-01-07 Gabriel Moving __on_rt_xxxxx_hook to ipc.c * 2022-01-24 THEWON let rt_mutex_take return thread->error when using signal * 2022-04-08 Stanley Correct descriptions + * 2022-10-15 Bernard add nested mutex feature */ #include @@ -708,6 +709,80 @@ RTM_EXPORT(rt_sem_control); #endif /* RT_USING_SEMAPHORE */ #ifdef RT_USING_MUTEX +rt_inline rt_uint8_t _mutex_update_priority(struct rt_mutex *mutex) +{ + struct rt_thread *thread; + + if (!rt_list_isempty(&mutex->parent.suspend_thread)) + { + thread = rt_list_entry(mutex->parent.suspend_thread.next, struct rt_thread, tlist); + mutex->priority = thread->current_priority; + } + else + { + mutex->priority = 0xff; + } + + return mutex->priority; +} + +rt_inline rt_uint8_t _thread_get_mutex_priority(struct rt_thread* thread) +{ + struct rt_mutex *mutex; + rt_uint8_t priority = thread->init_priority; + + rt_list_for_each_entry(mutex, &(thread->taken_object_list), taken_list) + { + if (priority > mutex->priority) priority = mutex->priority; + } + + return priority; +} + +rt_inline void _thread_update_priority(struct rt_thread *thread, rt_uint8_t priority) +{ + RT_DEBUG_LOG(RT_DEBUG_IPC, + ("thread:%s priority -> %d\n", thread->name, priority)); + + /* change priority of the thread */ + rt_thread_control(thread, + RT_THREAD_CTRL_CHANGE_PRIORITY, + &priority); + + if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND) + { + /* whether change the priority of taken mutex */ + struct rt_object* pending_obj = thread->pending_object; + + if (pending_obj && rt_object_get_type(pending_obj) == RT_Object_Class_Mutex) + { + rt_uint8_t mutex_priority; + struct rt_mutex* pending_mutex = (struct rt_mutex *)pending_obj; + + /* re-insert thread to suspended thread list */ + rt_list_remove(&(thread->tlist)); + _ipc_list_suspend(&(pending_mutex->parent.suspend_thread), + thread, + pending_mutex->parent.parent.flag); + + /* update priority */ + _mutex_update_priority(pending_mutex); + /* change the priority of mutex owner thread */ + RT_DEBUG_LOG(RT_DEBUG_IPC, + ("mutex: %s priority -> %d\n", pending_mutex->parent.parent.name, + pending_mutex->priority)); + + mutex_priority = _thread_get_mutex_priority(pending_mutex->owner); + if (mutex_priority != pending_mutex->owner->current_priority) + { + _thread_update_priority(pending_mutex->owner, mutex_priority); + } + } + } + + return ; +} + /** * @addtogroup mutex */ @@ -752,10 +827,10 @@ rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag) /* initialize ipc object */ _ipc_object_init(&(mutex->parent)); - mutex->value = 1; - mutex->owner = RT_NULL; - mutex->original_priority = 0xFF; - mutex->hold = 0; + mutex->owner = RT_NULL; + mutex->priority = 0xFF; + mutex->hold = 0; + rt_list_init(&(mutex->taken_list)); /* flag can only be RT_IPC_FLAG_PRIO. RT_IPC_FLAG_FIFO cannot solve the unbounded priority inversion problem */ mutex->parent.parent.flag = RT_IPC_FLAG_PRIO; @@ -785,13 +860,19 @@ RTM_EXPORT(rt_mutex_init); */ rt_err_t rt_mutex_detach(rt_mutex_t mutex) { + rt_ubase_t level; + /* parameter check */ RT_ASSERT(mutex != RT_NULL); RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex); RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent)); + level = rt_hw_interrupt_disable(); /* wakeup all suspended threads */ _ipc_list_resume_all(&(mutex->parent.suspend_thread)); + /* remove mutex from thread's taken list */ + rt_list_remove(&mutex->taken_list); + rt_hw_interrupt_enable(level); /* detach mutex object */ rt_object_detach(&(mutex->parent.parent)); @@ -800,6 +881,48 @@ rt_err_t rt_mutex_detach(rt_mutex_t mutex) } RTM_EXPORT(rt_mutex_detach); +/* drop a thread from the suspend list of mutex */ +void rt_mutex_drop_thread(rt_mutex_t mutex, rt_thread_t thread) +{ + rt_uint8_t priority; + rt_bool_t need_update = RT_FALSE; + + rt_list_remove(&(thread->tlist)); + + /* should change the priority of mutex owner thread */ + if (mutex->owner->current_priority == thread->current_priority) + need_update = RT_TRUE; + + /* update the priority of mutex */ + if (!rt_list_isempty(&mutex->parent.suspend_thread)) + { + /* more thread suspended in the list */ + struct rt_thread *th; + + th = rt_list_entry(mutex->parent.suspend_thread.next, + struct rt_thread, + tlist); + /* update the priority of mutex */ + mutex->priority = th->current_priority; + } + else + { + /* set mutex priority to maximal priority */ + mutex->priority = 0xff; + } + + /* try to change the priority of mutex owner thread */ + if (need_update) + { + /* get the maximal priority of mutex in thread */ + priority = _thread_get_mutex_priority(mutex->owner); + if (priority != mutex->owner->current_priority) + { + _thread_update_priority(mutex->owner, priority); + } + } +} + #ifdef RT_USING_HEAP /** * @brief This function will create a mutex object. @@ -836,10 +959,10 @@ rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag) /* initialize ipc object */ _ipc_object_init(&(mutex->parent)); - mutex->value = 1; - mutex->owner = RT_NULL; - mutex->original_priority = 0xFF; - mutex->hold = 0; + mutex->owner = RT_NULL; + mutex->priority = 0xFF; + mutex->hold = 0; + rt_list_init(&(mutex->taken_list)); /* flag can only be RT_IPC_FLAG_PRIO. RT_IPC_FLAG_FIFO cannot solve the unbounded priority inversion problem */ mutex->parent.parent.flag = RT_IPC_FLAG_PRIO; @@ -869,6 +992,8 @@ RTM_EXPORT(rt_mutex_create); */ rt_err_t rt_mutex_delete(rt_mutex_t mutex) { + rt_ubase_t level; + /* parameter check */ RT_ASSERT(mutex != RT_NULL); RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex); @@ -876,8 +1001,12 @@ rt_err_t rt_mutex_delete(rt_mutex_t mutex) RT_DEBUG_NOT_IN_INTERRUPT; + level = rt_hw_interrupt_disable(); /* wakeup all suspended threads */ _ipc_list_resume_all(&(mutex->parent.suspend_thread)); + /* remove mutex from thread's taken list */ + rt_list_remove(&mutex->taken_list); + rt_hw_interrupt_enable(level); /* delete mutex object */ rt_object_delete(&(mutex->parent.parent)); @@ -933,8 +1062,8 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mutex->parent.parent))); RT_DEBUG_LOG(RT_DEBUG_IPC, - ("mutex_take: current thread %s, mutex value: %d, hold: %d\n", - thread->name, mutex->value, mutex->hold)); + ("mutex_take: current thread %s, hold: %d\n", + thread->name, mutex->hold)); /* reset thread error */ thread->error = RT_EOK; @@ -954,26 +1083,15 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) } else { - /* The value of mutex is 1 in initial status. Therefore, if the - * value is great than 0, it indicates the mutex is avaible. - */ - if (mutex->value > 0) + /* whether the mutex has owner thread. */ + if (mutex->owner == RT_NULL) { - /* mutex is available */ - mutex->value --; - /* set mutex owner and original priority */ - mutex->owner = thread; - mutex->original_priority = thread->current_priority; - if(mutex->hold < RT_MUTEX_HOLD_MAX) - { - mutex->hold ++; - } - else - { - rt_hw_interrupt_enable(level); /* enable interrupt */ - return -RT_EFULL; /* value overflowed */ - } + mutex->owner = thread; + mutex->priority = 0xff; + mutex->hold = 1; + /* insert mutex to thread's taken object list */ + rt_list_insert_after(&thread->taken_object_list, &mutex->taken_list); } else { @@ -990,23 +1108,28 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) } else { + rt_uint8_t priority = thread->current_priority; + /* mutex is unavailable, push to suspend list */ RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_take: suspend thread: %s\n", thread->name)); - /* change the owner thread priority of mutex */ - if (thread->current_priority < mutex->owner->current_priority) - { - /* change the owner thread priority */ - rt_thread_control(mutex->owner, - RT_THREAD_CTRL_CHANGE_PRIORITY, - &thread->current_priority); - } - /* suspend current thread */ _ipc_list_suspend(&(mutex->parent.suspend_thread), thread, mutex->parent.parent.flag); + /* set pending object in thread to this mutex */ + thread->pending_object = &(mutex->parent.parent); + + /* update the priority level of mutex */ + if (priority < mutex->priority) + { + mutex->priority = priority; + if (mutex->priority < mutex->owner->current_priority) + { + _thread_update_priority(mutex->owner, priority); + } + } /* has waiting time, start thread timer */ if (timeout > 0) @@ -1028,16 +1151,57 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) /* do schedule */ rt_schedule(); - if (thread->error != RT_EOK) + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + if (thread->error == RT_EOK) { - /* return error */ - return thread->error; + /* get mutex successfully */ } else { - /* the mutex is taken successfully. */ - /* disable interrupt */ - level = rt_hw_interrupt_disable(); + /* the mutex has not been taken and thread has detach from the pending list. */ + + rt_bool_t need_update = RT_FALSE; + + /* should change the priority of mutex owner thread */ + if (mutex->owner->current_priority == thread->current_priority) + need_update = RT_TRUE; + + /* update the priority of mutex */ + if (!rt_list_isempty(&mutex->parent.suspend_thread)) + { + /* more thread suspended in the list */ + struct rt_thread *th; + + th = rt_list_entry(mutex->parent.suspend_thread.next, + struct rt_thread, + tlist); + /* update the priority of mutex */ + mutex->priority = th->current_priority; + } + else + { + /* set mutex priority to maximal priority */ + mutex->priority = 0xff; + } + + /* try to change the priority of mutex owner thread */ + if (need_update) + { + /* get the maximal priority of mutex in thread */ + priority = _thread_get_mutex_priority(mutex->owner); + if (priority != mutex->owner->current_priority) + { + _thread_update_priority(mutex->owner, priority); + } + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* return error */ + return thread->error; } } } @@ -1109,8 +1273,8 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) level = rt_hw_interrupt_disable(); RT_DEBUG_LOG(RT_DEBUG_IPC, - ("mutex_release:current thread %s, mutex value: %d, hold: %d\n", - thread->name, mutex->value, mutex->hold)); + ("mutex_release:current thread %s, hold: %d\n", + thread->name, mutex->hold)); RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent))); @@ -1130,60 +1294,70 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) /* if no hold */ if (mutex->hold == 0) { - /* change the owner thread to original priority */ - if (mutex->original_priority != mutex->owner->current_priority) + /* remove mutex from thread's taken list */ + rt_list_remove(&mutex->taken_list); + + /* whether change the thread priority */ + if (thread->current_priority == mutex->priority) { - rt_thread_control(mutex->owner, + rt_uint8_t priority = 0xff; + + /* get the highest priority in the taken list of thread */ + priority = _thread_get_mutex_priority(thread); + + rt_thread_control(thread, RT_THREAD_CTRL_CHANGE_PRIORITY, - &(mutex->original_priority)); + &priority); + + need_schedule = RT_TRUE; } /* wakeup suspended thread */ if (!rt_list_isempty(&mutex->parent.suspend_thread)) { - /* get suspended thread */ - thread = rt_list_entry(mutex->parent.suspend_thread.next, + /* get the first suspended thread */ + struct rt_thread *next_thread = rt_list_entry(mutex->parent.suspend_thread.next, struct rt_thread, tlist); RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_release: resume thread: %s\n", - thread->name)); + next_thread->name)); - /* set new owner and priority */ - mutex->owner = thread; - mutex->original_priority = thread->current_priority; + /* remove the thread from the suspended list of mutex */ + rt_list_remove(&(next_thread->tlist)); - if(mutex->hold < RT_MUTEX_HOLD_MAX) + /* set new owner and put mutex into taken list of thread */ + mutex->owner = next_thread; + mutex->hold = 1; + rt_list_insert_after(&next_thread->taken_object_list, &mutex->taken_list); + /* cleanup pending object */ + next_thread->pending_object = RT_NULL; + + /* resume thread */ + rt_thread_resume(next_thread); + + /* update mutex priority */ + if (!rt_list_isempty(&(mutex->parent.suspend_thread))) { - mutex->hold ++; + struct rt_thread *th; + + th = rt_list_entry(mutex->parent.suspend_thread.next, + struct rt_thread, + tlist); + mutex->priority = th->current_priority; } else { - rt_hw_interrupt_enable(level); /* enable interrupt */ - return -RT_EFULL; /* value overflowed */ + mutex->priority = 0xff; } - /* resume thread */ - _ipc_list_resume(&(mutex->parent.suspend_thread)); - need_schedule = RT_TRUE; } else { - if(mutex->value < RT_MUTEX_VALUE_MAX) - { - /* increase value */ - mutex->value ++; - } - else - { - rt_hw_interrupt_enable(level); /* enable interrupt */ - return -RT_EFULL; /* value overflowed */ - } - /* clear owner */ - mutex->owner = RT_NULL; - mutex->original_priority = 0xff; + mutex->owner = RT_NULL; + mutex->priority = 0xff; } } diff --git a/src/thread.c b/src/thread.c index df6de24275..9d37861c5a 100644 --- a/src/thread.c +++ b/src/thread.c @@ -31,6 +31,7 @@ * 2021-12-27 Meco Man remove .init_priority * 2022-01-07 Gabriel Moving __on_rt_xxxxx_hook to thread.c * 2022-01-24 THEWON let rt_thread_sleep return thread->error when using signal + * 2022-10-15 Bernard add nested mutex feature */ #include @@ -187,10 +188,16 @@ static rt_err_t _thread_init(struct rt_thread *thread, /* priority init */ RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX); + thread->init_priority = priority; thread->current_priority = priority; thread->number_mask = 0; +#ifdef RT_USING_MUTEX + rt_list_init(&thread->taken_object_list); + thread->pending_object = RT_NULL; +#endif + #ifdef RT_USING_EVENT thread->event_set = 0; thread->event_info = 0; @@ -420,6 +427,16 @@ rt_err_t rt_thread_detach(rt_thread_t thread) /* change stat */ thread->stat = RT_THREAD_CLOSE; +#ifdef RT_USING_MUTEX + if ((thread->pending_object) && + (rt_object_get_type(thread->pending_object) == RT_Object_Class_Mutex)) + { + struct rt_mutex *mutex = (struct rt_mutex*)thread->pending_object; + rt_mutex_drop_thread(mutex, thread); + thread->pending_object = RT_NULL; + } +#endif + /* insert to defunct thread list */ rt_thread_defunct_enqueue(thread); @@ -523,6 +540,16 @@ rt_err_t rt_thread_delete(rt_thread_t thread) /* change stat */ thread->stat = RT_THREAD_CLOSE; +#ifdef RT_USING_MUTEX + if ((thread->pending_object) && + (rt_object_get_type(thread->pending_object) == RT_Object_Class_Mutex)) + { + struct rt_mutex *mutex = (struct rt_mutex*)thread->pending_object; + rt_mutex_drop_thread(mutex, thread); + thread->pending_object = RT_NULL; + } +#endif + /* insert to defunct thread list */ rt_thread_defunct_enqueue(thread); From 6823a5110b71d36caa21bab389656d463c863db7 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Sun, 16 Oct 2022 17:58:51 +0800 Subject: [PATCH 2/6] [Kernel] Add prioceiling feature in mutex --- include/rtdef.h | 4 ++- include/rtthread.h | 2 ++ src/ipc.c | 90 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/include/rtdef.h b/include/rtdef.h index 12232c2d5c..57401115d9 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -771,11 +771,13 @@ struct rt_mutex { struct rt_ipc_object parent; /**< inherit from ipc_object */ + rt_uint8_t ceiling_priority; /**< the priority ceiling of mutexe */ rt_uint8_t priority; /**< the maximal priority for pending thread */ rt_uint8_t hold; /**< numbers of thread hold the mutex */ + rt_uint8_t reserv; struct rt_thread *owner; /**< current owner of mutex */ - rt_list_t taken_list; /**< the object list taken by thread */ + rt_list_t taken_list; /**< the object list taken by thread */ }; typedef struct rt_mutex *rt_mutex_t; #endif /* RT_USING_MUTEX */ diff --git a/include/rtthread.h b/include/rtthread.h index 893b24ea1b..4b8f4c3aab 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -369,6 +369,8 @@ rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag); rt_err_t rt_mutex_delete(rt_mutex_t mutex); #endif void rt_mutex_drop_thread(rt_mutex_t mutex, rt_thread_t thread); +rt_uint8_t rt_mutex_setprioceiling(rt_mutex_t mutex, rt_uint8_t priority); +rt_uint8_t rt_mutex_getprioceiling(rt_mutex_t mutex); rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout); rt_err_t rt_mutex_trytake(rt_mutex_t mutex); diff --git a/src/ipc.c b/src/ipc.c index 67a998d5df..06a3b8e90b 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -43,6 +43,7 @@ * 2022-01-24 THEWON let rt_mutex_take return thread->error when using signal * 2022-04-08 Stanley Correct descriptions * 2022-10-15 Bernard add nested mutex feature + * 2022-10-16 Bernard add prioceiling feature in mutex */ #include @@ -708,6 +709,8 @@ RTM_EXPORT(rt_sem_control); /**@}*/ #endif /* RT_USING_SEMAPHORE */ +#define RT_USING_MUTEX + #ifdef RT_USING_MUTEX rt_inline rt_uint8_t _mutex_update_priority(struct rt_mutex *mutex) { @@ -728,12 +731,17 @@ rt_inline rt_uint8_t _mutex_update_priority(struct rt_mutex *mutex) rt_inline rt_uint8_t _thread_get_mutex_priority(struct rt_thread* thread) { - struct rt_mutex *mutex; + rt_list_t *node = RT_NULL; + struct rt_mutex *mutex = RT_NULL; rt_uint8_t priority = thread->init_priority; - rt_list_for_each_entry(mutex, &(thread->taken_object_list), taken_list) + rt_list_for_each(node, &(thread->taken_object_list)) { - if (priority > mutex->priority) priority = mutex->priority; + mutex = rt_list_entry(node, struct rt_mutex, taken_list); + if (priority > mutex->priority) + { + priority = mutex->priority; + } } return priority; @@ -830,6 +838,7 @@ rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag) mutex->owner = RT_NULL; mutex->priority = 0xFF; mutex->hold = 0; + mutex->ceiling_priority = 0xFF; rt_list_init(&(mutex->taken_list)); /* flag can only be RT_IPC_FLAG_PRIO. RT_IPC_FLAG_FIFO cannot solve the unbounded priority inversion problem */ @@ -882,6 +891,13 @@ rt_err_t rt_mutex_detach(rt_mutex_t mutex) RTM_EXPORT(rt_mutex_detach); /* drop a thread from the suspend list of mutex */ + +/** + * @brief drop a thread from the suspend list of mutex + * + * @param mutex is a pointer to a mutex object. + * @param thread is the thread should be dropped from mutex. + */ void rt_mutex_drop_thread(rt_mutex_t mutex, rt_thread_t thread) { rt_uint8_t priority; @@ -923,6 +939,55 @@ void rt_mutex_drop_thread(rt_mutex_t mutex, rt_thread_t thread) } } + +/** + * @brief set the prioceiling attribute of the mutex. + * + * @param mutex is a pointer to a mutex object. + * @param priority is the priority should be set to mutex. + * + * @return return the old priority ceiling + */ +rt_uint8_t rt_mutex_setprioceiling(rt_mutex_t mutex, rt_uint8_t priority) +{ + rt_uint8_t ret_priority = 0xFF; + + if ((mutex) && (priority < RT_THREAD_PRIORITY_MAX)) + { + ret_priority = mutex->ceiling_priority; + mutex->ceiling_priority = priority; + } + else + { + rt_set_errno(-RT_EINVAL); + } + + return ret_priority; +} +RTM_EXPORT(rt_mutex_setprioceiling); + + +/** + * @brief set the prioceiling attribute of the mutex. + * + * @param mutex is a pointer to a mutex object. + * + * @return return the current priority ceiling of the mutex. + */ +rt_uint8_t rt_mutex_getprioceiling(rt_mutex_t mutex) +{ + rt_uint8_t prio = 0xFF; + + if (mutex) + { + prio = mutex->ceiling_priority; + } + + return prio; +} +RTM_EXPORT(rt_mutex_getprioceiling); + + #ifdef RT_USING_HEAP /** * @brief This function will create a mutex object. @@ -962,6 +1027,7 @@ rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag) mutex->owner = RT_NULL; mutex->priority = 0xFF; mutex->hold = 0; + mutex->ceiling_priority = 0xFF; rt_list_init(&(mutex->taken_list)); /* flag can only be RT_IPC_FLAG_PRIO. RT_IPC_FLAG_FIFO cannot solve the unbounded priority inversion problem */ @@ -992,7 +1058,7 @@ RTM_EXPORT(rt_mutex_create); */ rt_err_t rt_mutex_delete(rt_mutex_t mutex) { - rt_ubase_t level; + rt_ubase_t level; /* parameter check */ RT_ASSERT(mutex != RT_NULL); @@ -1090,8 +1156,18 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) mutex->owner = thread; mutex->priority = 0xff; mutex->hold = 1; - /* insert mutex to thread's taken object list */ - rt_list_insert_after(&thread->taken_object_list, &mutex->taken_list); + + if (mutex->ceiling_priority != 0xFF) + { + /* set the priority of thread to the ceiling priority */ + if (mutex->ceiling_priority < mutex->owner->current_priority) + _thread_update_priority(mutex->owner, mutex->ceiling_priority); + } + else + { + /* insert mutex to thread's taken object list */ + rt_list_insert_after(&thread->taken_object_list, &mutex->taken_list); + } } else { @@ -1298,7 +1374,7 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) rt_list_remove(&mutex->taken_list); /* whether change the thread priority */ - if (thread->current_priority == mutex->priority) + if ((mutex->ceiling_priority != 0xFF) || (thread->current_priority == mutex->priority)) { rt_uint8_t priority = 0xff; From e645c95eb822153e592343d60c2a57acf23ad510 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Sun, 16 Oct 2022 18:23:26 +0800 Subject: [PATCH 3/6] [Kernel] Trim trailing spaces in ipc.c --- src/ipc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index 06a3b8e90b..95baef4422 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -894,7 +894,7 @@ RTM_EXPORT(rt_mutex_detach); /** * @brief drop a thread from the suspend list of mutex - * + * * @param mutex is a pointer to a mutex object. * @param thread is the thread should be dropped from mutex. */ @@ -942,7 +942,7 @@ void rt_mutex_drop_thread(rt_mutex_t mutex, rt_thread_t thread) /** * @brief set the prioceiling attribute of the mutex. - * + * * @param mutex is a pointer to a mutex object. * @param priority is the priority should be set to mutex. * @@ -969,9 +969,9 @@ RTM_EXPORT(rt_mutex_setprioceiling); /** * @brief set the prioceiling attribute of the mutex. - * + * * @param mutex is a pointer to a mutex object. - * + * * @return return the current priority ceiling of the mutex. */ rt_uint8_t rt_mutex_getprioceiling(rt_mutex_t mutex) From 63b97db64a89e258f93aca3876e48482fe0752a5 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Mon, 17 Oct 2022 08:01:48 +0800 Subject: [PATCH 4/6] [Kernel] Remove the debug definition for mutex --- src/ipc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index 95baef4422..314cb7a0eb 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -709,8 +709,6 @@ RTM_EXPORT(rt_sem_control); /**@}*/ #endif /* RT_USING_SEMAPHORE */ -#define RT_USING_MUTEX - #ifdef RT_USING_MUTEX rt_inline rt_uint8_t _mutex_update_priority(struct rt_mutex *mutex) { From e9a2dc0e022e8afb37a9a7088591230f488f91af Mon Sep 17 00:00:00 2001 From: "Man, Jianting (Meco)" <920369182@qq.com> Date: Tue, 25 Oct 2022 23:39:03 -0400 Subject: [PATCH 5/6] Update src/ipc.c --- src/ipc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index 314cb7a0eb..15853ff463 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -785,8 +785,6 @@ rt_inline void _thread_update_priority(struct rt_thread *thread, rt_uint8_t prio } } } - - return ; } /** From c06c4075f2e9462b67915029a9d6a074b301d13a Mon Sep 17 00:00:00 2001 From: "Man, Jianting (Meco)" <920369182@qq.com> Date: Tue, 25 Oct 2022 23:45:25 -0400 Subject: [PATCH 6/6] Update rtdef.h --- include/rtdef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rtdef.h b/include/rtdef.h index 57401115d9..a6af3dd2c3 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -774,7 +774,7 @@ struct rt_mutex rt_uint8_t ceiling_priority; /**< the priority ceiling of mutexe */ rt_uint8_t priority; /**< the maximal priority for pending thread */ rt_uint8_t hold; /**< numbers of thread hold the mutex */ - rt_uint8_t reserv; + rt_uint8_t reserved; /**< reserved field */ struct rt_thread *owner; /**< current owner of mutex */ rt_list_t taken_list; /**< the object list taken by thread */