Просмотр исходного кода

futex对象链表转至lwp结构体内部,并实现其对象自动释放机制

shaojinchun 5 лет назад
Родитель
Сommit
fee4bf4b85
6 измененных файлов с 138 добавлено и 39 удалено
  1. 1 0
      components/lwp/lwp.h
  2. 60 38
      components/lwp/lwp_futex.c
  3. 4 0
      components/lwp/lwp_pid.c
  4. 2 1
      include/rtdef.h
  5. 6 0
      include/rtthread.h
  6. 65 0
      src/object.c

+ 1 - 0
components/lwp/lwp.h

@@ -92,6 +92,7 @@ struct rt_lwp
 
     struct rt_wqueue wait_queue; /*for console */
 
+    rt_list_t futex_list;
 #ifdef RT_USING_GDBSERVER
     int debug;
     uint32_t bak_first_ins;

+ 60 - 38
components/lwp/lwp_futex.c

@@ -18,35 +18,23 @@
 struct rt_futex
 {
     int *uaddr;
-
     rt_list_t list;
-    struct rt_lwp *lwp;
     rt_list_t waiting_thread;
 };
-static rt_list_t _futex_list = RT_LIST_OBJECT_INIT(_futex_list);
 
-struct rt_futex* futex_create(int *uaddr, struct rt_lwp *lwp)
-{
-    struct rt_futex *futex = RT_NULL;
+static struct rt_mutex _futex_lock;
 
-    futex = (struct rt_futex *)rt_malloc(sizeof(struct rt_futex));
-    if (futex)
-    {
-        futex->uaddr = uaddr;
-        futex->lwp = lwp;
-
-        rt_list_init(&(futex->list));
-        rt_list_init(&(futex->waiting_thread));
-
-        /* insert into futex list */
-        rt_list_insert_before(&_futex_list, &(futex->list));
-    }
-    return futex;
+static int futex_system_init(void)
+{
+    rt_mutex_init(&_futex_lock, "futexList", RT_IPC_FLAG_FIFO);
+    return 0;
 }
+INIT_PREV_EXPORT(futex_system_init);
 
-void futex_destory(struct rt_futex *futex)
+void futex_destory(void *data)
 {
     rt_base_t level = 0;
+    struct rt_futex *futex = (struct rt_futex *)data;
 
     if (futex)
     {
@@ -55,8 +43,6 @@ void futex_destory(struct rt_futex *futex)
         rt_list_remove(&(futex->list));
         rt_hw_interrupt_enable(level);
 
-        /* wakeup all threads in suspending list */
-
         /* release object */
         rt_free(futex);
     }
@@ -64,24 +50,50 @@ void futex_destory(struct rt_futex *futex)
     return ;
 }
 
+struct rt_futex* futex_create(int *uaddr, struct rt_lwp *lwp)
+{
+    struct rt_futex *futex = RT_NULL;
+    struct rt_object *obj = RT_NULL;
+
+    if (!lwp)
+    {
+        return RT_NULL;
+    }
+    futex = (struct rt_futex *)rt_malloc(sizeof(struct rt_futex));
+    if (!futex)
+    {
+        return RT_NULL;
+    }
+    obj = rt_custom_object_create("futex", (void *)futex, futex_destory);
+    if (!obj)
+    {
+        rt_free(futex);
+        return RT_NULL;
+    }
+
+    futex->uaddr = uaddr;
+    rt_list_init(&(futex->list));
+    rt_list_init(&(futex->waiting_thread));
+
+    /* insert into futex list */
+    rt_list_insert_before(&lwp->futex_list, &(futex->list));
+    return futex;
+}
+
 static struct rt_futex* futex_get(void *uaddr, struct rt_lwp *lwp)
 {
-    rt_base_t level = 0;
     struct rt_futex *futex = RT_NULL;
     rt_list_t *node = RT_NULL;
 
-    level = rt_hw_interrupt_disable();
-
-    rt_list_for_each(node, &_futex_list)
+    rt_list_for_each(node, &lwp->futex_list)
     {
         futex = rt_list_entry(node, struct rt_futex, list);
 
-        if (futex->uaddr == uaddr && futex->lwp == lwp) break;
+        if (futex->uaddr == uaddr) break;
     }
-    rt_hw_interrupt_enable(level);
 
     /* no this futex in the list */
-    if (node == &_futex_list) futex = RT_NULL;
+    if (node == &lwp->futex_list) futex = RT_NULL;
 
     return futex;
 }
@@ -91,15 +103,16 @@ int futex_wait(struct rt_futex *futex, int value, const struct timespec *timeout
     rt_base_t level = 0;
     rt_err_t ret = -RT_EINTR;
 
-    level = rt_hw_interrupt_disable();
     if (*(futex->uaddr) == value)
     {
         rt_thread_t thread = rt_thread_self();
 
+        level = rt_hw_interrupt_disable();
         ret = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE);
 
         if (ret < 0)
         {
+            rt_mutex_release(&_futex_lock);
             rt_hw_interrupt_enable(level);
             rt_set_errno(EINTR);
             return ret;
@@ -119,6 +132,7 @@ int futex_wait(struct rt_futex *futex, int value, const struct timespec *timeout
                     &time);
             rt_timer_start(&(thread->thread_timer));
         }
+        rt_mutex_release(&_futex_lock);
         rt_hw_interrupt_enable(level);
 
         /* do schedule */
@@ -129,7 +143,6 @@ int futex_wait(struct rt_futex *futex, int value, const struct timespec *timeout
     }
     else
     {
-        rt_hw_interrupt_enable(level);
         rt_set_errno(EAGAIN);
     }
 
@@ -138,9 +151,8 @@ int futex_wait(struct rt_futex *futex, int value, const struct timespec *timeout
 
 void futex_wake(struct rt_futex *futex, int number)
 {
-    rt_base_t level = 0;
+    rt_base_t level = rt_hw_interrupt_disable();
 
-    level = rt_hw_interrupt_disable();
     while (!rt_list_isempty(&(futex->waiting_thread)) && number)
     {
         rt_thread_t thread;
@@ -155,6 +167,7 @@ void futex_wake(struct rt_futex *futex, int number)
 
         number --;
     }
+    rt_mutex_release(&_futex_lock);
     rt_hw_interrupt_enable(level);
 
     /* do schedule */
@@ -164,10 +177,10 @@ void futex_wake(struct rt_futex *futex, int number)
 int sys_futex(int *uaddr, int op, int val, const struct timespec *timeout,
           int *uaddr2, int val3)
 {
-    rt_base_t level = 0;
+    struct rt_lwp *lwp = RT_NULL;
     struct rt_futex *futex = RT_NULL;
-    struct rt_lwp *lwp = lwp_self();
     int ret = 0;
+    rt_err_t lock_ret = 0;
 
     if (!lwp_user_accessable(uaddr, sizeof(int)))
     {
@@ -183,7 +196,14 @@ int sys_futex(int *uaddr, int op, int val, const struct timespec *timeout,
         }
     }
 
-    level = rt_hw_interrupt_disable();
+    lock_ret = rt_mutex_take_interruptible(&_futex_lock, RT_WAITING_FOREVER);
+    if (lock_ret != RT_EOK)
+    {
+        rt_set_errno(EAGAIN);
+        return -RT_EINTR;
+    }
+
+    lwp = lwp_self();
     futex = futex_get(uaddr, lwp);
     if (futex == RT_NULL)
     {
@@ -191,24 +211,26 @@ int sys_futex(int *uaddr, int op, int val, const struct timespec *timeout,
         futex = futex_create(uaddr, lwp);
         if (futex == RT_NULL)
         {
-            rt_hw_interrupt_enable(level);
+            rt_mutex_release(&_futex_lock);
             rt_set_errno(ENOMEM);
             return -RT_ENOMEM;
         }
     }
-    rt_hw_interrupt_enable(level);
 
     switch (op)
     {
         case FUTEX_WAIT:
             ret = futex_wait(futex, val, timeout);
+            /* _futex_lock is released by futex_wait */
             break;
 
         case FUTEX_WAKE:
             futex_wake(futex, val);
+            /* _futex_lock is released by futex_wake */
             break;
 
         default:
+            rt_mutex_release(&_futex_lock);
             rt_set_errno(ENOSYS);
             ret = -ENOSYS;
             break;

+ 4 - 0
components/lwp/lwp_pid.c

@@ -111,6 +111,7 @@ struct rt_lwp* lwp_new(void)
     pid_struct.pidmap[i] = lwp;
     rt_list_init(&lwp->t_grp);
     rt_list_init(&lwp->object_list);
+    rt_list_init(&lwp->futex_list);
     rt_wqueue_init(&lwp->wait_queue);
 
     lwp->ref = 1;
@@ -168,6 +169,9 @@ static void lwp_user_obj_free(struct rt_lwp *lwp)
             break;
         case RT_Object_Class_Channel:
             break;
+        case RT_Object_Class_Custom:
+            rt_custom_object_destroy(object);
+            break;
         default:
             LOG_E("input object type(%d) error", object->type);
             break;

+ 2 - 1
include/rtdef.h

@@ -404,7 +404,8 @@ enum rt_object_class_type
     RT_Object_Class_Timer         = 0x0a,      /**< The object is a timer. */
     RT_Object_Class_Module        = 0x0b,      /**< The object is a module. */
     RT_Object_Class_Channel       = 0x0c,      /**< The object is a channel */
-    RT_Object_Class_Unknown       = 0x0d,      /**< The object is unknown. */
+    RT_Object_Class_Custom        = 0x0d,      /**< The object is a custom object */
+    RT_Object_Class_Unknown       = 0x0e,      /**< The object is unknown. */
     RT_Object_Class_Static        = 0x80       /**< The object is a static object. */
 };
 

+ 6 - 0
include/rtthread.h

@@ -55,6 +55,12 @@ rt_bool_t rt_object_is_systemobject(rt_object_t object);
 rt_uint8_t rt_object_get_type(rt_object_t object);
 rt_object_t rt_object_find(const char *name, rt_uint8_t type);
 
+#ifdef RT_USING_HEAP
+/* custom object */
+rt_object_t rt_custom_object_create(const char *name, void *data, void (*data_destroy)(void *));
+void rt_custom_object_destroy(rt_object_t obj);
+#endif
+
 #ifdef RT_USING_HOOK
 void rt_object_attach_sethook(void (*hook)(struct rt_object *object));
 void rt_object_detach_sethook(void (*hook)(struct rt_object *object));

+ 65 - 0
src/object.c

@@ -26,6 +26,13 @@
 #include <lwp.h>
 #endif
 
+struct rt_custom_object
+{
+    struct rt_object parent;
+    void (*destroy)(void *);
+    void *data;
+};
+
 /*
  * define object_info for the number of rt_object_container items.
  */
@@ -62,6 +69,9 @@ enum rt_object_info_type
 #endif
 #ifdef RT_USING_LWP
     RT_Object_Info_Channel,                            /**< The object is a IPC channel */
+#endif
+#ifdef RT_USING_HEAP
+    RT_Object_Info_Custom,                             /**< The object is a custom object */
 #endif
     RT_Object_Info_Unknown,                            /**< The object is unknown. */
 };
@@ -113,6 +123,7 @@ static struct rt_object_information rt_object_container[RT_Object_Info_Unknown]
 #ifdef RT_USING_LWP
     /* initialize object container - module */
     {RT_Object_Class_Channel, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Channel), sizeof(struct rt_channel)},
+    {RT_Object_Class_Custom, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Custom), sizeof(struct rt_custom_object)},
 #endif
 };
 
@@ -616,4 +627,58 @@ rt_object_t rt_object_find(const char *name, rt_uint8_t type)
     return RT_NULL;
 }
 
+#ifdef RT_USING_HEAP
+/**
+ * This function will create a custom object
+ * container.
+ *
+ * @param name the specified name of object.
+ * @param type the type of object
+ * @param data the custom data
+ * @param data_destroy the custom object destroy callback
+ *
+ * @return the found object or RT_NULL if there is no this object
+ * in object container.
+ *
+ * @note this function shall not be invoked in interrupt status.
+ */
+
+rt_object_t rt_custom_object_create(const char *name, void *data, void (*data_destroy)(void *))
+{
+    struct rt_custom_object *cobj = RT_NULL;
+
+    cobj = (struct rt_custom_object *)rt_object_allocate(RT_Object_Class_Custom, name);
+    if (!cobj)
+    {
+        return RT_NULL;
+    }
+    cobj->destroy = data_destroy;
+    cobj->data = data;
+    return (struct rt_object *)cobj;
+}
+
+/**
+ * This function will destroy a custom object
+ * container.
+ *
+ * @param name the specified name of object.
+ *
+ * @note this function shall not be invoked in interrupt status.
+ */
+void rt_custom_object_destroy(rt_object_t obj)
+{
+    struct rt_custom_object *cobj = (struct rt_custom_object *)obj;
+
+    if (!obj || obj->type != RT_Object_Class_Custom)
+    {
+        return;
+    }
+    if (cobj->destroy)
+    {
+        cobj->destroy(cobj->data);
+    }
+    rt_object_delete(obj);
+}
+#endif
+
 /**@}*/