[Kernel] Add prioceiling feature in mutex

This commit is contained in:
Bernard Xiong 2022-10-16 17:58:51 +08:00
parent 34c77da153
commit 6823a5110b
3 changed files with 88 additions and 8 deletions

View File

@ -771,8 +771,10 @@ 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 */

View File

@ -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);

View File

@ -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 <rtthread.h>
@ -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 */
@ -1090,9 +1156,19 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout)
mutex->owner = thread;
mutex->priority = 0xff;
mutex->hold = 1;
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
{
/* no waiting, return with timeout */
@ -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;