Browse Source

[Kernel] Add prioceiling feature in mutex

Bernard Xiong 2 years ago
parent
commit
6823a5110b
3 changed files with 88 additions and 8 deletions
  1. 3 1
      include/rtdef.h
  2. 2 0
      include/rtthread.h
  3. 83 7
      src/ipc.c

+ 3 - 1
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 */

+ 2 - 0
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);

+ 83 - 7
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 <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 */
@@ -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;