Procházet zdrojové kódy

add semaphore max value control. (#8390)

geniusgogo před 1 rokem
rodič
revize
3dfafcd1d9
2 změnil soubory, kde provedl 54 přidání a 20 odebrání
  1. 2 1
      include/rtdef.h
  2. 52 19
      src/ipc.c

+ 2 - 1
include/rtdef.h

@@ -1038,6 +1038,7 @@ typedef struct rt_thread *rt_thread_t;
 #define RT_IPC_CMD_UNKNOWN              0x00            /**< unknown IPC command */
 #define RT_IPC_CMD_RESET                0x01            /**< reset IPC object */
 #define RT_IPC_CMD_GET_STATE            0x02            /**< get the state of IPC object */
+#define RT_IPC_CMD_SET_VLIMIT           0x03            /**< set max limit value of IPC value */
 
 #define RT_WAITING_FOREVER              -1              /**< Block forever until get resource. */
 #define RT_WAITING_NO                   0               /**< Non-block. */
@@ -1061,7 +1062,7 @@ struct rt_semaphore
     struct rt_ipc_object parent;                        /**< inherit from ipc_object */
 
     rt_uint16_t          value;                         /**< value of semaphore. */
-    rt_uint16_t          reserved;                      /**< reserved field */
+    rt_uint16_t          max_value;
     struct rt_spinlock   spinlock;
 };
 typedef struct rt_semaphore *rt_sem_t;

+ 52 - 19
src/ipc.c

@@ -271,6 +271,23 @@ rt_inline rt_err_t _ipc_list_resume_all(rt_list_t *list)
  * @{
  */
 
+static void _sem_object_init(rt_sem_t       sem,
+                             rt_uint16_t    value,
+                             rt_uint8_t     flag,
+                             rt_uint16_t    max_value)
+{
+    /* initialize ipc object */
+    _ipc_object_init(&(sem->parent));
+
+    sem->max_value = max_value;
+    /* set initial value */
+    sem->value = value;
+
+    /* set parent */
+    sem->parent.parent.flag = flag;
+    rt_spin_lock_init(&(sem->spinlock));
+}
+
 /**
  * @brief    This function will initialize a static semaphore object.
  *
@@ -321,15 +338,7 @@ rt_err_t rt_sem_init(rt_sem_t    sem,
     /* initialize object */
     rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);
 
-    /* initialize ipc object */
-    _ipc_object_init(&(sem->parent));
-
-    /* set initial value */
-    sem->value = (rt_uint16_t)value;
-
-    /* set parent */
-    sem->parent.parent.flag = flag;
-    rt_spin_lock_init(&(sem->spinlock));
+    _sem_object_init(sem, value, flag, RT_SEM_VALUE_MAX);
 
     return RT_EOK;
 }
@@ -422,15 +431,7 @@ rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)
     if (sem == RT_NULL)
         return sem;
 
-    /* initialize ipc object */
-    _ipc_object_init(&(sem->parent));
-
-    /* set initial value */
-    sem->value = value;
-
-    /* set parent */
-    sem->parent.parent.flag = flag;
-    rt_spin_lock_init(&(sem->spinlock));
+    _sem_object_init(sem, value, flag, RT_SEM_VALUE_MAX);
 
     return sem;
 }
@@ -670,7 +671,7 @@ rt_err_t rt_sem_release(rt_sem_t sem)
     }
     else
     {
-        if(sem->value < RT_SEM_VALUE_MAX)
+        if(sem->value < sem->max_value)
         {
             sem->value ++; /* increase value */
         }
@@ -732,6 +733,38 @@ rt_err_t rt_sem_control(rt_sem_t sem, int cmd, void *arg)
 
         return RT_EOK;
     }
+    else if (cmd == RT_IPC_CMD_SET_VLIMIT)
+    {
+        rt_ubase_t max_value;
+        rt_bool_t need_schedule = RT_FALSE;
+
+        max_value = (rt_uint16_t)((rt_ubase_t)arg);
+        if (max_value > RT_SEM_VALUE_MAX || max_value < 1)
+        {
+            return -RT_EINVAL;
+        }
+
+        level = rt_spin_lock_irqsave(&(sem->spinlock));
+        if (max_value < sem->value)
+        {
+            if (!rt_list_isempty(&sem->parent.suspend_thread))
+            {
+                /* resume all waiting thread */
+                _ipc_list_resume_all(&sem->parent.suspend_thread);
+                need_schedule = RT_TRUE;
+            }
+        }
+        /* set new value */
+        sem->max_value = max_value;
+        rt_spin_unlock_irqrestore(&(sem->spinlock), level);
+
+        if (need_schedule)
+        {
+            rt_schedule();
+        }
+
+        return RT_EOK;
+    }
 
     return -RT_ERROR;
 }