Преглед изворни кода

!121 增加clone和futex系统调用
Merge pull request !121 from jesven/add_clone_thread_support

bernard пре 5 година
родитељ
комит
328171c1df

+ 12 - 1
bsp/qemu-vexpress-a9/.config

@@ -172,6 +172,7 @@ CONFIG_RT_USING_PIN=y
 # CONFIG_RT_USING_ADC is not set
 # CONFIG_RT_USING_ADC is not set
 # CONFIG_RT_USING_DAC is not set
 # CONFIG_RT_USING_DAC is not set
 # CONFIG_RT_USING_NULL is not set
 # CONFIG_RT_USING_NULL is not set
+# CONFIG_RT_USING_ZERO is not set
 CONFIG_RT_USING_RANDOM=y
 CONFIG_RT_USING_RANDOM=y
 # CONFIG_RT_USING_PWM is not set
 # CONFIG_RT_USING_PWM is not set
 CONFIG_RT_USING_MTD_NOR=y
 CONFIG_RT_USING_MTD_NOR=y
@@ -337,6 +338,7 @@ CONFIG_RT_LWP_MAX_NR=30
 CONFIG_RT_CH_MSG_MAX_NR=1024
 CONFIG_RT_CH_MSG_MAX_NR=1024
 CONFIG_RT_LWP_SHM_MAX_NR=64
 CONFIG_RT_LWP_SHM_MAX_NR=64
 CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024
 CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024
+CONFIG_LWP_TID_MAX_NR=64
 
 
 #
 #
 # RT-Thread online packages
 # RT-Thread online packages
@@ -420,6 +422,7 @@ CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024
 # CONFIG_PKG_USING_PDULIB is not set
 # CONFIG_PKG_USING_PDULIB is not set
 # CONFIG_PKG_USING_BTSTACK is not set
 # CONFIG_PKG_USING_BTSTACK is not set
 # CONFIG_PKG_USING_LORAWAN_ED_STACK is not set
 # CONFIG_PKG_USING_LORAWAN_ED_STACK is not set
+# CONFIG_PKG_USING_WAYZ_IOTKIT is not set
 
 
 #
 #
 # security packages
 # security packages
@@ -472,6 +475,8 @@ CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024
 # CONFIG_PKG_USING_UMCN is not set
 # CONFIG_PKG_USING_UMCN is not set
 # CONFIG_PKG_USING_LWRB2RTT is not set
 # CONFIG_PKG_USING_LWRB2RTT is not set
 # CONFIG_PKG_USING_CPU_USAGE is not set
 # CONFIG_PKG_USING_CPU_USAGE is not set
+# CONFIG_PKG_USING_GBK2UTF8 is not set
+# CONFIG_PKG_USING_VCONSOLE is not set
 
 
 #
 #
 # system packages
 # system packages
@@ -510,6 +515,7 @@ CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024
 # CONFIG_PKG_USING_UC_COMMON is not set
 # CONFIG_PKG_USING_UC_COMMON is not set
 # CONFIG_PKG_USING_UC_MODBUS is not set
 # CONFIG_PKG_USING_UC_MODBUS is not set
 # CONFIG_PKG_USING_PPOOL is not set
 # CONFIG_PKG_USING_PPOOL is not set
+# CONFIG_PKG_USING_OPENAMP is not set
 
 
 #
 #
 # peripheral libraries and drivers
 # peripheral libraries and drivers
@@ -567,6 +573,9 @@ CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024
 # CONFIG_PKG_USING_SSD1306 is not set
 # CONFIG_PKG_USING_SSD1306 is not set
 # CONFIG_PKG_USING_QKEY is not set
 # CONFIG_PKG_USING_QKEY is not set
 # CONFIG_PKG_USING_RS485 is not set
 # CONFIG_PKG_USING_RS485 is not set
+# CONFIG_PKG_USING_NES is not set
+# CONFIG_PKG_USING_VIRTUAL_SENSOR is not set
+# CONFIG_PKG_USING_VDEVICE is not set
 
 
 #
 #
 # miscellaneous packages
 # miscellaneous packages
@@ -576,6 +585,7 @@ CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024
 # CONFIG_PKG_USING_FASTLZ is not set
 # CONFIG_PKG_USING_FASTLZ is not set
 # CONFIG_PKG_USING_MINILZO is not set
 # CONFIG_PKG_USING_MINILZO is not set
 # CONFIG_PKG_USING_QUICKLZ is not set
 # CONFIG_PKG_USING_QUICKLZ is not set
+# CONFIG_PKG_USING_LZMA is not set
 # CONFIG_PKG_USING_MULTIBUTTON is not set
 # CONFIG_PKG_USING_MULTIBUTTON is not set
 # CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set
 # CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set
 # CONFIG_PKG_USING_CANFESTIVAL is not set
 # CONFIG_PKG_USING_CANFESTIVAL is not set
@@ -654,9 +664,10 @@ CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024
 # CONFIG_PKG_USING_EMQ is not set
 # CONFIG_PKG_USING_EMQ is not set
 # CONFIG_PKG_USING_CFGM is not set
 # CONFIG_PKG_USING_CFGM is not set
 # CONFIG_PKG_USING_RT_CMSIS_DAP is not set
 # CONFIG_PKG_USING_RT_CMSIS_DAP is not set
-# CONFIG_PKG_USING_VIRTUAL_DEVICE is not set
 # CONFIG_PKG_USING_SMODULE is not set
 # CONFIG_PKG_USING_SMODULE is not set
 # CONFIG_PKG_USING_SNFD is not set
 # CONFIG_PKG_USING_SNFD is not set
+# CONFIG_PKG_USING_UDBD is not set
+# CONFIG_PKG_USING_BENCHMARK is not set
 CONFIG_SOC_VEXPRESS_A9=y
 CONFIG_SOC_VEXPRESS_A9=y
 CONFIG_RT_USING_UART0=y
 CONFIG_RT_USING_UART0=y
 CONFIG_RT_USING_UART1=y
 CONFIG_RT_USING_UART1=y

+ 1 - 0
bsp/qemu-vexpress-a9/rtconfig.h

@@ -232,6 +232,7 @@
 #define RT_CH_MSG_MAX_NR 1024
 #define RT_CH_MSG_MAX_NR 1024
 #define RT_LWP_SHM_MAX_NR 64
 #define RT_LWP_SHM_MAX_NR 64
 #define LWP_CONSOLE_INPUT_BUFFER_SIZE 1024
 #define LWP_CONSOLE_INPUT_BUFFER_SIZE 1024
+#define LWP_TID_MAX_NR 64
 
 
 /* RT-Thread online packages */
 /* RT-Thread online packages */
 
 

+ 4 - 1
components/libc/time/SConscript

@@ -6,7 +6,10 @@ cwd = GetCurrentDir()
 src = Glob('*.c') + Glob('*.cpp')
 src = Glob('*.c') + Glob('*.cpp')
 CPPPATH = [cwd]
 CPPPATH = [cwd]
 
 
+#group = DefineGroup('pthreads', src, 
+#    depend = ['RT_USING_PTHREADS'], CPPPATH = CPPPATH)
+
 group = DefineGroup('pthreads', src, 
 group = DefineGroup('pthreads', src, 
-    depend = ['RT_USING_PTHREADS'], CPPPATH = CPPPATH)
+    depend = [''], CPPPATH = CPPPATH)
 
 
 Return('group')
 Return('group')

+ 2 - 0
components/libc/time/clock_time.h

@@ -45,6 +45,8 @@ int clock_getres  (clockid_t clockid, struct timespec *res);
 int clock_gettime (clockid_t clockid, struct timespec *tp);
 int clock_gettime (clockid_t clockid, struct timespec *tp);
 int clock_settime (clockid_t clockid, const struct timespec *tp);
 int clock_settime (clockid_t clockid, const struct timespec *tp);
 
 
+int clock_time_to_tick(const struct timespec *time);
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

+ 5 - 0
components/lwp/Kconfig

@@ -32,3 +32,8 @@ config LWP_CONSOLE_INPUT_BUFFER_SIZE
     int "The input buffer size of lwp console device"
     int "The input buffer size of lwp console device"
     default 1024
     default 1024
     depends on RT_USING_LWP
     depends on RT_USING_LWP
+
+config LWP_TID_MAX_NR
+    int "The maximum number of lwp thread id"
+    default 64
+    depends on RT_USING_LWP

+ 29 - 0
components/lwp/arch/arm/cortex-a/lwp_gcc.S

@@ -62,6 +62,35 @@ set_user_context:
     cps #Mode_SVC
     cps #Mode_SVC
     mov pc, lr
     mov pc, lr
 
 
+/*
+int lwp_set_thread_context(void *new_thread_stack, void *origin_thread_stack, void *user_stack, void **thread_sp, int tid);
+*/
+.global lwp_set_thread_context
+lwp_set_thread_context:
+    sub r12, r1, sp /* origin, r12 = origin sp offset */
+    sub r0, r0, r12 /* new sp */
+    stmfd r0!, {lr}
+    stmfd r0!, {lr}
+    stmfd r0!, {r12}
+    sub r12, sp, fp  /* new, r1 = origin fp offset */
+    sub r1, r0, r12
+    add r1, #12  /* new fp */
+    stmfd r0!, {r1} /* fp */
+    stmfd r0!, {r1 - r10}
+    mov r12, #0
+    stmfd r0!, {r12} /* new thread return value */
+    mrs r1, cpsr
+    stmfd r0!, {r1} /* spsr */
+    mov r1, #0
+    stmfd r0!, {r1} /* now user lr is 0 */
+    stmfd r0!, {r2} /* user sp */
+#ifdef RT_USING_FPU
+    stmfd r0!, {r1} /* not use fpu */
+#endif
+    str r0, [r3]
+    ldr r0, [sp]
+    mov pc, lr
+
 /*
 /*
  * void SVC_Handler(void);
  * void SVC_Handler(void);
  */
  */

+ 19 - 7
components/lwp/lwp.c

@@ -739,6 +739,7 @@ void lwp_cleanup(struct rt_thread *tid)
     level = rt_hw_interrupt_disable();
     level = rt_hw_interrupt_disable();
     lwp = (struct rt_lwp *)tid->lwp;
     lwp = (struct rt_lwp *)tid->lwp;
 
 
+    lwp_tid_put(tid->tid);
     rt_list_remove(&tid->sibling);
     rt_list_remove(&tid->sibling);
     lwp_ref_dec(lwp);
     lwp_ref_dec(lwp);
     rt_hw_interrupt_enable(level);
     rt_hw_interrupt_enable(level);
@@ -820,6 +821,7 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp)
     char *argv_last = argv[argc - 1];
     char *argv_last = argv[argc - 1];
     int bg = 0;
     int bg = 0;
     struct process_aux *aux;
     struct process_aux *aux;
+    int tid = 0;
 
 
     if (filename == RT_NULL)
     if (filename == RT_NULL)
         return -RT_ERROR;
         return -RT_ERROR;
@@ -833,9 +835,15 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp)
     }
     }
     LOG_D("lwp malloc : %p, size: %d!", lwp, sizeof(struct rt_lwp));
     LOG_D("lwp malloc : %p, size: %d!", lwp, sizeof(struct rt_lwp));
 
 
+    if ((tid = lwp_tid_get()) == 0)
+    {
+        lwp_ref_dec(lwp);
+        return -ENOMEM;
+    }
 #ifdef RT_USING_USERSPACE
 #ifdef RT_USING_USERSPACE
     if (lwp_user_space_init(lwp) != 0)
     if (lwp_user_space_init(lwp) != 0)
     {
     {
+        lwp_tid_put(tid);
         lwp_ref_dec(lwp);
         lwp_ref_dec(lwp);
         return -ENOMEM;
         return -ENOMEM;
     }
     }
@@ -849,6 +857,7 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp)
 
 
     if ((aux = lwp_argscopy(lwp, argc, argv, envp)) == RT_NULL)
     if ((aux = lwp_argscopy(lwp, argc, argv, envp)) == RT_NULL)
     {
     {
+        lwp_tid_put(tid);
         lwp_ref_dec(lwp);
         lwp_ref_dec(lwp);
         return -ENOMEM;
         return -ENOMEM;
     }
     }
@@ -856,7 +865,7 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp)
     result = lwp_load(filename, lwp, RT_NULL, 0, aux);
     result = lwp_load(filename, lwp, RT_NULL, 0, aux);
     if (result == RT_EOK)
     if (result == RT_EOK)
     {
     {
-        rt_thread_t tid;
+        rt_thread_t thread = RT_NULL;
 
 
         lwp_copy_stdio_fdt(lwp);
         lwp_copy_stdio_fdt(lwp);
 
 
@@ -864,13 +873,15 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp)
         thread_name = strrchr(filename, '/');
         thread_name = strrchr(filename, '/');
         thread_name = thread_name ? thread_name + 1 : filename;
         thread_name = thread_name ? thread_name + 1 : filename;
 
 
-        tid = rt_thread_create(thread_name, lwp_thread_entry, RT_NULL,
+        thread = rt_thread_create(thread_name, lwp_thread_entry, RT_NULL,
                                1024 * 4, 25, 200);
                                1024 * 4, 25, 200);
-        if (tid != RT_NULL)
+        if (thread != RT_NULL)
         {
         {
             struct rt_lwp *lwp_self;
             struct rt_lwp *lwp_self;
 
 
-            LOG_D("lwp kernel => (0x%08x, 0x%08x)\n", (rt_uint32_t)tid->stack_addr, (rt_uint32_t)tid->stack_addr + tid->stack_size);
+            thread->tid = tid;
+            lwp_tid_set_thread(tid, thread);
+            LOG_D("lwp kernel => (0x%08x, 0x%08x)\n", (rt_uint32_t)thread->stack_addr, (rt_uint32_t)thread->stack_addr + thread->stack_size);
             level = rt_hw_interrupt_disable();
             level = rt_hw_interrupt_disable();
             lwp_self = (struct rt_lwp *)rt_thread_self()->lwp;
             lwp_self = (struct rt_lwp *)rt_thread_self()->lwp;
             if (lwp_self)
             if (lwp_self)
@@ -880,8 +891,8 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp)
                 lwp_self->first_child = lwp;
                 lwp_self->first_child = lwp;
                 lwp->parent = lwp_self;
                 lwp->parent = lwp_self;
             }
             }
-            tid->lwp = lwp;
-            rt_list_insert_after(&lwp->t_grp, &tid->sibling);
+            thread->lwp = lwp;
+            rt_list_insert_after(&lwp->t_grp, &thread->sibling);
 
 
 #ifdef RT_USING_GDBSERVER
 #ifdef RT_USING_GDBSERVER
             if (debug)
             if (debug)
@@ -896,11 +907,12 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp)
             }
             }
             rt_hw_interrupt_enable(level);
             rt_hw_interrupt_enable(level);
 
 
-            rt_thread_startup(tid);
+            rt_thread_startup(thread);
             return lwp_to_pid(lwp);
             return lwp_to_pid(lwp);
         }
         }
     }
     }
 
 
+    lwp_tid_put(tid);
     lwp_ref_dec(lwp);
     lwp_ref_dec(lwp);
 
 
     return -RT_ERROR;
     return -RT_ERROR;

+ 10 - 0
components/lwp/lwp.h

@@ -92,6 +92,7 @@ struct rt_lwp
 
 
     struct rt_wqueue wait_queue; /*for console */
     struct rt_wqueue wait_queue; /*for console */
 
 
+    rt_list_t futex_list;
 #ifdef RT_USING_GDBSERVER
 #ifdef RT_USING_GDBSERVER
     int debug;
     int debug;
     uint32_t bak_first_ins;
     uint32_t bak_first_ins;
@@ -116,6 +117,11 @@ void lwp_set_thread_area(void *p);
 void* rt_cpu_get_thread_idr(void);
 void* rt_cpu_get_thread_idr(void);
 void rt_cpu_set_thread_idr(void *p);
 void rt_cpu_set_thread_idr(void *p);
 
 
+int lwp_tid_get(void);
+void lwp_tid_put(int tid);
+rt_thread_t lwp_tid_get_thread(int tid);
+void lwp_tid_set_thread(int tid, rt_thread_t thread);
+
 #ifdef RT_USING_USERSPACE
 #ifdef RT_USING_USERSPACE
 void lwp_mmu_switch(struct rt_thread *thread);
 void lwp_mmu_switch(struct rt_thread *thread);
 #endif
 #endif
@@ -164,6 +170,10 @@ struct __pthread {
 };
 };
 #endif
 #endif
 
 
+/* for futex op */
+#define FUTEX_WAIT  0
+#define FUTEX_WAKE  1
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

+ 240 - 0
components/lwp/lwp_futex.c

@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021/01/02     bernard      the first version
+ */
+
+#include <rtthread.h>
+#include <lwp.h>
+#ifdef RT_USING_USERSPACE
+#include <lwp_user_mm.h>
+#endif
+#include "clock_time.h"
+
+struct rt_futex
+{
+    int *uaddr;
+    rt_list_t list;
+    rt_list_t waiting_thread;
+};
+
+static struct rt_mutex _futex_lock;
+
+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(void *data)
+{
+    rt_base_t level = 0;
+    struct rt_futex *futex = (struct rt_futex *)data;
+
+    if (futex)
+    {
+        level = rt_hw_interrupt_disable();
+        /* remove futex from list */
+        rt_list_remove(&(futex->list));
+        rt_hw_interrupt_enable(level);
+
+        /* release object */
+        rt_free(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)
+{
+    struct rt_futex *futex = RT_NULL;
+    rt_list_t *node = RT_NULL;
+
+    rt_list_for_each(node, &lwp->futex_list)
+    {
+        futex = rt_list_entry(node, struct rt_futex, list);
+
+        if (futex->uaddr == uaddr) break;
+    }
+
+    /* no this futex in the list */
+    if (node == &lwp->futex_list) futex = RT_NULL;
+
+    return futex;
+}
+
+int futex_wait(struct rt_futex *futex, int value, const struct timespec *timeout)
+{
+    rt_base_t level = 0;
+    rt_err_t ret = -RT_EINTR;
+
+    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;
+        }
+
+        /* add into waiting thread list */
+        rt_list_insert_before(&(futex->waiting_thread), &(thread->tlist));
+
+        /* with timeout */
+        if (timeout)
+        {
+            rt_int32_t time = clock_time_to_tick(timeout);
+
+            /* start the timer of thread */
+            rt_timer_control(&(thread->thread_timer),
+                    RT_TIMER_CTRL_SET_TIME,
+                    &time);
+            rt_timer_start(&(thread->thread_timer));
+        }
+        rt_mutex_release(&_futex_lock);
+        rt_hw_interrupt_enable(level);
+
+        /* do schedule */
+        rt_schedule();
+
+        ret = thread->error;
+        /* check errno */
+    }
+    else
+    {
+        rt_set_errno(EAGAIN);
+    }
+
+    return ret;
+}
+
+void futex_wake(struct rt_futex *futex, int number)
+{
+    rt_base_t level = rt_hw_interrupt_disable();
+
+    while (!rt_list_isempty(&(futex->waiting_thread)) && number)
+    {
+        rt_thread_t thread;
+
+        thread = rt_list_entry(futex->waiting_thread.next, struct rt_thread, tlist);
+        /* remove from waiting list */
+        rt_list_remove(&(thread->list));
+
+        thread->error = RT_EOK;
+        /* resume the suspended thread */
+        rt_thread_resume(thread);
+
+        number --;
+    }
+    rt_mutex_release(&_futex_lock);
+    rt_hw_interrupt_enable(level);
+
+    /* do schedule */
+    rt_schedule();
+}
+
+int sys_futex(int *uaddr, int op, int val, const struct timespec *timeout,
+          int *uaddr2, int val3)
+{
+    struct rt_lwp *lwp = RT_NULL;
+    struct rt_futex *futex = RT_NULL;
+    int ret = 0;
+    rt_err_t lock_ret = 0;
+
+    if (!lwp_user_accessable(uaddr, sizeof(int)))
+    {
+        rt_set_errno(EINVAL);
+        return -RT_EINVAL;
+    }
+    if (timeout)
+    {
+        if (!lwp_user_accessable((void *)timeout, sizeof(struct timespec)))
+        {
+            rt_set_errno(EINVAL);
+            return -RT_EINVAL;
+        }
+    }
+
+    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)
+    {
+        /* create a futex according to this uaddr */
+        futex = futex_create(uaddr, lwp);
+        if (futex == RT_NULL)
+        {
+            rt_mutex_release(&_futex_lock);
+            rt_set_errno(ENOMEM);
+            return -RT_ENOMEM;
+        }
+    }
+
+    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;
+    }
+
+    return ret;
+}

+ 4 - 0
components/lwp/lwp_pid.c

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

+ 211 - 36
components/lwp/lwp_syscall.c

@@ -76,6 +76,8 @@ static void kmem_put(void *kptr)
 }
 }
 #endif
 #endif
 
 
+int sys_futex(int *uaddr, int op, int val, void *timeout, void *uaddr2, int val3);
+
 /* The same socket option is defined differently in the user interfaces and the
 /* The same socket option is defined differently in the user interfaces and the
  * implementation. The options should be converted in the kernel. */
  * implementation. The options should be converted in the kernel. */
 
 
@@ -343,7 +345,7 @@ static void lwp_user_thread(void *parameter)
     user_stack &= ~7; //align 8
     user_stack &= ~7; //align 8
     set_user_context((void*)user_stack);
     set_user_context((void*)user_stack);
 
 
-    lwp_user_entry(parameter, tid->user_entry, lwp->data_entry, (void*)user_stack);
+    lwp_user_entry(parameter, tid->user_entry, lwp->data_entry, RT_NULL);
 }
 }
 
 
 /* thread/process */
 /* thread/process */
@@ -359,6 +361,15 @@ void sys_exit(int value)
     lwp = (struct rt_lwp*)tid->lwp;
     lwp = (struct rt_lwp*)tid->lwp;
 
 
     level = rt_hw_interrupt_disable();
     level = rt_hw_interrupt_disable();
+    if (tid->clear_child_tid)
+    {
+        int t = 0;
+        int *clear_child_tid = tid->clear_child_tid;
+
+        tid->clear_child_tid = RT_NULL;
+        lwp_put_to_user(clear_child_tid, &t, sizeof t);
+        sys_futex(tid->clear_child_tid, FUTEX_WAKE, 1, RT_NULL, RT_NULL, 0);
+    }
     main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
     main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
     if (main_thread == tid)
     if (main_thread == tid)
     {
     {
@@ -1132,10 +1143,11 @@ void *lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size);
 
 
 rt_thread_t sys_thread_create(void *arg[])
 rt_thread_t sys_thread_create(void *arg[])
 {
 {
-    rt_base_t level;
+    rt_base_t level = 0;
     void *user_stack = 0;
     void *user_stack = 0;
     struct rt_lwp *lwp = 0;
     struct rt_lwp *lwp = 0;
-    rt_thread_t tid;
+    rt_thread_t thread = RT_NULL;
+    int tid = 0;
 
 
     lwp = rt_thread_self()->lwp;
     lwp = rt_thread_self()->lwp;
     lwp_ref_inc(lwp);
     lwp_ref_inc(lwp);
@@ -1147,32 +1159,40 @@ rt_thread_t sys_thread_create(void *arg[])
     if (!user_stack)
     if (!user_stack)
     {
     {
         rt_set_errno(EINVAL);
         rt_set_errno(EINVAL);
-        return RT_NULL;
+        goto fail;
     }
     }
-    tid = rt_thread_create((const char*)arg[0],
+    if ((tid = lwp_tid_get()) == 0)
+    {
+        rt_set_errno(ENOMEM);
+        goto fail;
+    }
+    thread = rt_thread_create((const char*)arg[0],
             lwp_user_thread,
             lwp_user_thread,
             (void*)arg[2],
             (void*)arg[2],
             ALLOC_KERNEL_STACK_SIZE,
             ALLOC_KERNEL_STACK_SIZE,
             (rt_uint8_t)(size_t)arg[4],
             (rt_uint8_t)(size_t)arg[4],
             (rt_uint32_t)arg[5]);
             (rt_uint32_t)arg[5]);
-    if (!tid)
+    if (!thread)
     {
     {
         goto fail;
         goto fail;
     }
     }
 
 
-    tid->cleanup = lwp_cleanup;
-    tid->user_entry = (void (*)(void *))arg[1];
-    tid->user_stack = (void *)user_stack;
-    tid->user_stack_size = (uint32_t)arg[3];
-    tid->lwp = (void*)lwp;
+    thread->cleanup = lwp_cleanup;
+    thread->user_entry = (void (*)(void *))arg[1];
+    thread->user_stack = (void *)user_stack;
+    thread->user_stack_size = (uint32_t)arg[3];
+    thread->lwp = (void*)lwp;
+    thread->tid = tid;
+    lwp_tid_set_thread(tid, thread);
 
 
     level = rt_hw_interrupt_disable();
     level = rt_hw_interrupt_disable();
-    rt_list_insert_after(&lwp->t_grp, &tid->sibling);
+    rt_list_insert_after(&lwp->t_grp, &thread->sibling);
     rt_hw_interrupt_enable(level);
     rt_hw_interrupt_enable(level);
 
 
-    return tid;
+    return thread;
 
 
 fail:
 fail:
+    lwp_tid_put(tid);
 #ifndef RT_USING_USERSPACE
 #ifndef RT_USING_USERSPACE
     if (user_stack)
     if (user_stack)
     {
     {
@@ -1186,6 +1206,154 @@ fail:
     return RT_NULL;
     return RT_NULL;
 }
 }
 
 
+#define CLONE_VM    0x00000100
+#define CLONE_FS    0x00000200
+#define CLONE_FILES 0x00000400
+#define CLONE_SIGHAND   0x00000800
+#define CLONE_PTRACE    0x00002000
+#define CLONE_VFORK 0x00004000
+#define CLONE_PARENT    0x00008000
+#define CLONE_THREAD    0x00010000
+#define CLONE_NEWNS 0x00020000
+#define CLONE_SYSVSEM   0x00040000
+#define CLONE_SETTLS    0x00080000
+#define CLONE_PARENT_SETTID 0x00100000
+#define CLONE_CHILD_CLEARTID    0x00200000
+#define CLONE_DETACHED  0x00400000
+#define CLONE_UNTRACED  0x00800000
+#define CLONE_CHILD_SETTID  0x01000000
+#define CLONE_NEWCGROUP 0x02000000
+#define CLONE_NEWUTS    0x04000000
+#define CLONE_NEWIPC    0x08000000
+#define CLONE_NEWUSER   0x10000000
+#define CLONE_NEWPID    0x20000000
+#define CLONE_NEWNET    0x40000000
+#define CLONE_IO    0x80000000
+
+/* arg[] -> flags
+ *          stack
+ *          new_tid
+ *          tls
+ *          set_clear_tid_address
+ *          quit_func
+ *          start_args
+ *          */
+#define SYS_CLONE_ARGS_NR 7
+int lwp_set_thread_context(void *new_thread_stack, void *origin_thread_stack, void *user_stack, void **thread_sp, int tid);
+long sys_clone(void *arg[])
+{
+    rt_base_t level = 0;
+    struct rt_lwp *lwp = 0;
+    rt_thread_t thread = RT_NULL;
+    rt_thread_t self = RT_NULL;
+    int tid = 0;
+
+    unsigned long flags = 0;
+    void *user_stack = RT_NULL;
+    int *new_tid = RT_NULL;
+    void *tls = RT_NULL;
+    /*
+       musl call flags (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
+       | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS
+       | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_DETACHED);
+       */
+
+    /* check args */
+    if (!lwp_user_accessable(arg, sizeof(void *[SYS_CLONE_ARGS_NR])))
+    {
+        rt_set_errno(EINVAL);
+        return -1;
+    }
+
+    flags = (unsigned long)(size_t)arg[0];
+    if ((flags & (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SYSVSEM))
+            != (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SYSVSEM))
+    {
+        rt_set_errno(EINVAL);
+        return -1;
+    }
+
+    user_stack = arg[1];
+    new_tid = (int *)arg[2];
+    tls = (void *)arg[3];
+
+    if ((flags & CLONE_PARENT_SETTID) == CLONE_PARENT_SETTID)
+    {
+        if (!lwp_user_accessable(new_tid, sizeof(int)))
+        {
+            rt_set_errno(EINVAL);
+            return -1;
+        }
+    }
+
+    self = rt_thread_self();
+    lwp = self->lwp;
+    lwp_ref_inc(lwp);
+    if (!user_stack)
+    {
+        rt_set_errno(EINVAL);
+        goto fail;
+    }
+    if ((tid = lwp_tid_get()) == 0)
+    {
+        rt_set_errno(ENOMEM);
+        goto fail;
+    }
+    thread = rt_thread_create((const char*)"pthread",
+            RT_NULL,
+            RT_NULL,
+            ALLOC_KERNEL_STACK_SIZE,
+            self->init_priority,
+            self->init_tick);
+    if (!thread)
+    {
+        goto fail;
+    }
+
+    thread->cleanup = lwp_cleanup;
+    thread->user_entry = RT_NULL;
+    thread->user_stack = RT_NULL;
+    thread->user_stack_size = 0;
+    thread->lwp = (void*)lwp;
+    thread->tid = tid;
+
+    if ((flags & CLONE_SETTLS) == CLONE_SETTLS)
+    {
+        thread->thread_idr = tls;
+    }
+    if ((flags & CLONE_PARENT_SETTID) == CLONE_PARENT_SETTID)
+    {
+        *new_tid = (int)(tid);
+    }
+    if ((flags & CLONE_CHILD_CLEARTID) == CLONE_CHILD_CLEARTID)
+    {
+        thread->clear_child_tid = (int*)arg[4];
+    }
+
+    level = rt_hw_interrupt_disable();
+    rt_list_insert_after(&lwp->t_grp, &thread->sibling);
+    rt_hw_interrupt_enable(level);
+
+    /* copy origin stack */
+    rt_memcpy(thread->stack_addr, self->stack_addr, ALLOC_KERNEL_STACK_SIZE);
+    lwp_tid_set_thread(tid, thread);
+    tid = lwp_set_thread_context((void*)((char*)thread->stack_addr + ALLOC_KERNEL_STACK_SIZE),
+            (void*)((char*)self->stack_addr + ALLOC_KERNEL_STACK_SIZE), user_stack, &thread->sp, tid);
+    if (tid)
+    {
+        rt_thread_startup(thread);
+    }
+    return (long)tid;
+
+fail:
+    lwp_tid_put(tid);
+    if (lwp)
+    {
+        lwp_ref_dec(lwp);
+    }
+    return -1;
+}
+
 rt_err_t sys_thread_delete(rt_thread_t thread)
 rt_err_t sys_thread_delete(rt_thread_t thread)
 {
 {
     return rt_thread_delete(thread);
     return rt_thread_delete(thread);
@@ -2204,9 +2372,12 @@ int sys_set_thread_area(void *p)
     return 0;
     return 0;
 }
 }
 
 
-long sys_set_tid_address(int *tidptr)
+int sys_set_tid_address(int *tidptr)
 {
 {
-    return 0;
+    rt_thread_t thread = rt_thread_self();
+
+    thread->clear_child_tid = tidptr;
+    return thread->tid;
 }
 }
 
 
 int sys_access(const char *filename, int mode)
 int sys_access(const char *filename, int mode)
@@ -2342,6 +2513,8 @@ int sys_clock_getres(clockid_t clk, struct timespec *ts)
     return 0;
     return 0;
 }
 }
 
 
+int sys_futex(int *uaddr, int op, int val, void *timeout, void *uaddr2, int val3);
+
 const static void* func_table[] =
 const static void* func_table[] =
 {
 {
     (void*)sys_exit,            /* 01 */
     (void*)sys_exit,            /* 01 */
@@ -2400,47 +2573,47 @@ const static void* func_table[] =
     SYSCALL_USPACE(sys_mmap2),
     SYSCALL_USPACE(sys_mmap2),
     SYSCALL_USPACE(sys_munmap),
     SYSCALL_USPACE(sys_munmap),
 
 
-    SYSCALL_USPACE(sys_shmget),
+    SYSCALL_USPACE(sys_shmget), /* 55 */
     SYSCALL_USPACE(sys_shmrm),
     SYSCALL_USPACE(sys_shmrm),
     SYSCALL_USPACE(sys_shmat),
     SYSCALL_USPACE(sys_shmat),
     SYSCALL_USPACE(sys_shmdt),
     SYSCALL_USPACE(sys_shmdt),
 
 
     (void *)sys_device_init,
     (void *)sys_device_init,
-    (void *)sys_device_register,
+    (void *)sys_device_register, /* 60 */
     (void *)sys_device_control,
     (void *)sys_device_control,
     (void *)sys_device_find,
     (void *)sys_device_find,
     (void *)sys_device_open,
     (void *)sys_device_open,
     (void *)sys_device_close,
     (void *)sys_device_close,
-    (void *)sys_device_read,
+    (void *)sys_device_read,    /* 65 */
     (void *)sys_device_write,
     (void *)sys_device_write,
 
 
     (void *)sys_stat,
     (void *)sys_stat,
     (void *)sys_thread_find,
     (void *)sys_thread_find,
 
 
     SYSCALL_NET(sys_accept),
     SYSCALL_NET(sys_accept),
-    SYSCALL_NET(sys_bind),
+    SYSCALL_NET(sys_bind),      /* 70 */
     SYSCALL_NET(sys_shutdown),
     SYSCALL_NET(sys_shutdown),
     SYSCALL_NET(sys_getpeername),
     SYSCALL_NET(sys_getpeername),
     SYSCALL_NET(sys_getsockname),
     SYSCALL_NET(sys_getsockname),
     SYSCALL_NET(sys_getsockopt),
     SYSCALL_NET(sys_getsockopt),
-    SYSCALL_NET(sys_setsockopt),
+    SYSCALL_NET(sys_setsockopt), /* 75 */
     SYSCALL_NET(sys_connect),
     SYSCALL_NET(sys_connect),
     SYSCALL_NET(sys_listen),
     SYSCALL_NET(sys_listen),
     SYSCALL_NET(sys_recv),
     SYSCALL_NET(sys_recv),
     SYSCALL_NET(sys_recvfrom),
     SYSCALL_NET(sys_recvfrom),
-    SYSCALL_NET(sys_send),
+    SYSCALL_NET(sys_send),      /* 80 */
     SYSCALL_NET(sys_sendto),
     SYSCALL_NET(sys_sendto),
     SYSCALL_NET(sys_socket),
     SYSCALL_NET(sys_socket),
 
 
     SYSCALL_NET(sys_closesocket),
     SYSCALL_NET(sys_closesocket),
     SYSCALL_NET(sys_getaddrinfo),
     SYSCALL_NET(sys_getaddrinfo),
-    SYSCALL_NET(sys_gethostbyname2_r),
+    SYSCALL_NET(sys_gethostbyname2_r), /* 85 */
 
 
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
-    (void *)sys_notimpl,    //(void *)network,
+    (void *)sys_notimpl,    //(void *)network, /* 90 */
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
     (void *)sys_notimpl,    //(void *)network,
@@ -2451,44 +2624,46 @@ const static void* func_table[] =
     (void *)sys_notimpl,
     (void *)sys_notimpl,
 #endif
 #endif
 
 
-    (void *)sys_notimpl,    //(void *)sys_hw_interrupt_disable,
+    (void *)sys_notimpl,    //(void *)sys_hw_interrupt_disable, /* 95 */
     (void *)sys_notimpl,    //(void *)sys_hw_interrupt_enable,
     (void *)sys_notimpl,    //(void *)sys_hw_interrupt_enable,
 
 
     (void *)sys_tick_get,
     (void *)sys_tick_get,
     (void *)sys_exit_group,
     (void *)sys_exit_group,
 
 
     (void *)sys_notimpl,    //(void *)rt_delayed_work_init,
     (void *)sys_notimpl,    //(void *)rt_delayed_work_init,
-    (void *)sys_notimpl,    //(void *)rt_work_submit,
+    (void *)sys_notimpl,    //(void *)rt_work_submit,           /* 100 */
     (void *)sys_notimpl,    //(void *)rt_wqueue_wakeup,
     (void *)sys_notimpl,    //(void *)rt_wqueue_wakeup,
     (void *)sys_thread_mdelay,
     (void *)sys_thread_mdelay,
-    (void*)sys_sigaction,
-    (void*)sys_sigprocmask,
-    (void*)sys_thread_kill,
-    (void*)sys_thread_sighandler_set,
-    (void*)sys_thread_sigprocmask,
-    (void*)sys_notimpl,
-    (void*)sys_notimpl,
-    (void*)sys_waitpid,
+    (void *)sys_sigaction,
+    (void *)sys_sigprocmask,
+    (void *)sys_thread_kill,      /* 105 */
+    (void *)sys_thread_sighandler_set,
+    (void *)sys_thread_sigprocmask,
+    (void *)sys_notimpl,
+    (void *)sys_notimpl,
+    (void *)sys_waitpid,          /* 110 */
 
 
     (void *)sys_timer_create,
     (void *)sys_timer_create,
     (void *)sys_timer_delete,
     (void *)sys_timer_delete,
     (void *)sys_timer_start,
     (void *)sys_timer_start,
     (void *)sys_timer_stop,
     (void *)sys_timer_stop,
-    (void *)sys_timer_control,
+    (void *)sys_timer_control,  /* 115 */
     (void *)sys_getcwd,
     (void *)sys_getcwd,
     (void *)sys_chdir,
     (void *)sys_chdir,
     (void *)sys_unlink,
     (void *)sys_unlink,
     (void *)sys_mkdir,
     (void *)sys_mkdir,
-    (void *)sys_rmdir,
+    (void *)sys_rmdir,          /* 120 */
     (void *)sys_getdents,
     (void *)sys_getdents,
     (void *)sys_get_errno,
     (void *)sys_get_errno,
     (void *)sys_set_thread_area,
     (void *)sys_set_thread_area,
     (void *)sys_set_tid_address,
     (void *)sys_set_tid_address,
-    (void *)sys_access,
+    (void *)sys_access,         /* 125 */
     (void *)sys_pipe,
     (void *)sys_pipe,
     (void *)sys_clock_settime,
     (void *)sys_clock_settime,
     (void *)sys_clock_gettime,
     (void *)sys_clock_gettime,
     (void *)sys_clock_getres,
     (void *)sys_clock_getres,
+    (void *)sys_clone,           /* 130 */
+    (void *)sys_futex,
 };
 };
 
 
 const void *lwp_get_sys_api(rt_uint32_t number)
 const void *lwp_get_sys_api(rt_uint32_t number)

+ 89 - 0
components/lwp/lwp_tid.c

@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-01-15     shaojinchun  first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "lwp.h"
+
+#ifdef RT_USING_USERSPACE
+#include "lwp_user_mm.h"
+
+#ifdef RT_USING_GDBSERVER
+#include <hw_breakpoint.h>
+#include <lwp_gdbserver.h>
+#endif
+
+#endif
+
+#define DBG_TAG    "LWP_TID"
+#define DBG_LVL    DBG_INFO
+#include <rtdbg.h>
+
+static rt_thread_t lwp_tid_ary[LWP_TID_MAX_NR + 1];
+static rt_thread_t *lwp_tid_free_head = RT_NULL;
+static int lwp_tid_ary_alloced = 1; /* 0 is reserved */
+
+int lwp_tid_get(void)
+{
+    int ret = 0;
+    rt_base_t level = rt_hw_interrupt_disable();
+    rt_thread_t *p = lwp_tid_free_head;
+
+    if (p)
+    {
+        lwp_tid_free_head = (rt_thread_t*)*p;
+    }
+    else if (lwp_tid_ary_alloced < LWP_TID_MAX_NR)
+    {
+        p = lwp_tid_ary + lwp_tid_ary_alloced;
+        lwp_tid_ary_alloced++;
+    }
+    if (p)
+    {
+        *p = RT_NULL;
+        ret = p - lwp_tid_ary;
+    }
+    rt_hw_interrupt_enable(level);
+    return ret;
+}
+
+void lwp_tid_put(int tid)
+{
+    rt_thread_t *p = RT_NULL;
+    rt_base_t level = rt_hw_interrupt_disable();
+
+    if (tid > 0 && tid < LWP_TID_MAX_NR)
+    {
+        p = lwp_tid_ary + tid;
+        *p = (rt_thread_t)lwp_tid_free_head;
+        lwp_tid_free_head = p;
+    }
+    rt_hw_interrupt_enable(level);
+}
+
+rt_thread_t lwp_tid_get_thread(int tid)
+{
+    rt_thread_t thread = RT_NULL;
+
+    if (tid > 0 && tid < LWP_TID_MAX_NR)
+    {
+        thread = lwp_tid_free_head[tid];
+    }
+    return thread;
+}
+
+void lwp_tid_set_thread(int tid, rt_thread_t thread)
+{
+    if (tid > 0 && tid < LWP_TID_MAX_NR)
+    {
+        lwp_tid_ary[tid] = thread;
+    }
+}

+ 11 - 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_Timer         = 0x0a,      /**< The object is a timer. */
     RT_Object_Class_Module        = 0x0b,      /**< The object is a module. */
     RT_Object_Class_Module        = 0x0b,      /**< The object is a module. */
     RT_Object_Class_Channel       = 0x0c,      /**< The object is a channel */
     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. */
     RT_Object_Class_Static        = 0x80       /**< The object is a static object. */
 };
 };
 
 
@@ -495,6 +496,13 @@ typedef void (*rt_sighandler_t)(int signo);
 typedef siginfo_t rt_siginfo_t;
 typedef siginfo_t rt_siginfo_t;
 
 
 #define RT_SIG_MAX          32
 #define RT_SIG_MAX          32
+
+#else
+
+#ifdef RT_USING_LWP
+#include <libc/libc_signal.h>
+#endif
+
 #endif
 #endif
 /**@}*/
 /**@}*/
 
 
@@ -734,6 +742,8 @@ struct rt_thread
     int debug_suspend;
     int debug_suspend;
     struct rt_hw_exp_stack *regs;
     struct rt_hw_exp_stack *regs;
     void * thread_idr;                                 /** lwp thread indicator */
     void * thread_idr;                                 /** lwp thread indicator */
+    int tid;
+    int *clear_child_tid;
 #endif
 #endif
 #endif
 #endif
 
 

+ 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_uint8_t rt_object_get_type(rt_object_t object);
 rt_object_t rt_object_find(const char *name, rt_uint8_t type);
 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
 #ifdef RT_USING_HOOK
 void rt_object_attach_sethook(void (*hook)(struct rt_object *object));
 void rt_object_attach_sethook(void (*hook)(struct rt_object *object));
 void rt_object_detach_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>
 #include <lwp.h>
 #endif
 #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.
  * define object_info for the number of rt_object_container items.
  */
  */
@@ -62,6 +69,9 @@ enum rt_object_info_type
 #endif
 #endif
 #ifdef RT_USING_LWP
 #ifdef RT_USING_LWP
     RT_Object_Info_Channel,                            /**< The object is a IPC channel */
     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
 #endif
     RT_Object_Info_Unknown,                            /**< The object is unknown. */
     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
 #ifdef RT_USING_LWP
     /* initialize object container - module */
     /* initialize object container - module */
     {RT_Object_Class_Channel, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Channel), sizeof(struct rt_channel)},
     {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
 #endif
 };
 };
 
 
@@ -616,4 +627,58 @@ rt_object_t rt_object_find(const char *name, rt_uint8_t type)
     return RT_NULL;
     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
+
 /**@}*/
 /**@}*/