diff --git a/bsp/qemu-vexpress-a9/.config b/bsp/qemu-vexpress-a9/.config index 3a3fa62497f8b53ed42431d1b316d5bbd1bc7622..aa5987defdc3e6595eeba29c7ae6e7f90c092dd2 100644 --- a/bsp/qemu-vexpress-a9/.config +++ b/bsp/qemu-vexpress-a9/.config @@ -172,6 +172,7 @@ CONFIG_RT_USING_PIN=y # CONFIG_RT_USING_ADC is not set # CONFIG_RT_USING_DAC 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_PWM is not set 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_LWP_SHM_MAX_NR=64 CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024 +CONFIG_LWP_TID_MAX_NR=64 # # 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_BTSTACK is not set # CONFIG_PKG_USING_LORAWAN_ED_STACK is not set +# CONFIG_PKG_USING_WAYZ_IOTKIT is not set # # security packages @@ -472,6 +475,8 @@ CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024 # CONFIG_PKG_USING_UMCN is not set # CONFIG_PKG_USING_LWRB2RTT 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 @@ -510,6 +515,7 @@ CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024 # CONFIG_PKG_USING_UC_COMMON is not set # CONFIG_PKG_USING_UC_MODBUS is not set # CONFIG_PKG_USING_PPOOL is not set +# CONFIG_PKG_USING_OPENAMP is not set # # 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_QKEY 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 @@ -576,6 +585,7 @@ CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024 # CONFIG_PKG_USING_FASTLZ is not set # CONFIG_PKG_USING_MINILZO 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_FLEXIBLE_BUTTON 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_CFGM 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_SNFD is not set +# CONFIG_PKG_USING_UDBD is not set +# CONFIG_PKG_USING_BENCHMARK is not set CONFIG_SOC_VEXPRESS_A9=y CONFIG_RT_USING_UART0=y CONFIG_RT_USING_UART1=y diff --git a/bsp/qemu-vexpress-a9/rtconfig.h b/bsp/qemu-vexpress-a9/rtconfig.h index c429182d6c0bde43de130bfd2466ddc3a3e3e2d7..00373d25e70316ddd28c3b3cb2bac48299765851 100644 --- a/bsp/qemu-vexpress-a9/rtconfig.h +++ b/bsp/qemu-vexpress-a9/rtconfig.h @@ -232,6 +232,7 @@ #define RT_CH_MSG_MAX_NR 1024 #define RT_LWP_SHM_MAX_NR 64 #define LWP_CONSOLE_INPUT_BUFFER_SIZE 1024 +#define LWP_TID_MAX_NR 64 /* RT-Thread online packages */ diff --git a/components/libc/time/SConscript b/components/libc/time/SConscript index 4ecd5d24bc7c784798e5e0bed1f4dbec17ad8044..a3b74c615834bc5d6f0263555cbdc7c4d55ce605 100644 --- a/components/libc/time/SConscript +++ b/components/libc/time/SConscript @@ -6,7 +6,10 @@ cwd = GetCurrentDir() src = Glob('*.c') + Glob('*.cpp') CPPPATH = [cwd] +#group = DefineGroup('pthreads', src, +# depend = ['RT_USING_PTHREADS'], CPPPATH = CPPPATH) + group = DefineGroup('pthreads', src, - depend = ['RT_USING_PTHREADS'], CPPPATH = CPPPATH) + depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/libc/time/clock_time.h b/components/libc/time/clock_time.h index 16b2306f4b2dad41879c9a4bfda0b3d192c2425f..0909d7961326bd7fa3aa2bd845ac72597b0395c9 100644 --- a/components/libc/time/clock_time.h +++ b/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_settime (clockid_t clockid, const struct timespec *tp); +int clock_time_to_tick(const struct timespec *time); + #ifdef __cplusplus } #endif diff --git a/components/lwp/Kconfig b/components/lwp/Kconfig index 609dabd37e429c285f499f1a198815b7ee4d35e5..1532a2202eb048e798454cd335a8a06de6bf7a7f 100644 --- a/components/lwp/Kconfig +++ b/components/lwp/Kconfig @@ -32,3 +32,8 @@ config LWP_CONSOLE_INPUT_BUFFER_SIZE int "The input buffer size of lwp console device" default 1024 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 diff --git a/components/lwp/arch/arm/cortex-a/lwp_gcc.S b/components/lwp/arch/arm/cortex-a/lwp_gcc.S index cad967fa04cd5dbdf6f3f22bfe3e3f5b3e88cfea..370c5b0d923a938326c2e98cad5f1292a7adba9f 100644 --- a/components/lwp/arch/arm/cortex-a/lwp_gcc.S +++ b/components/lwp/arch/arm/cortex-a/lwp_gcc.S @@ -62,6 +62,35 @@ set_user_context: cps #Mode_SVC 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); */ diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c index 7d7cd3db89f01945bdfacb189abb50f2e6dc3ecd..fc199e7ec89979f3ec5a92474aa6cb77c631c873 100644 --- a/components/lwp/lwp.c +++ b/components/lwp/lwp.c @@ -739,6 +739,7 @@ void lwp_cleanup(struct rt_thread *tid) level = rt_hw_interrupt_disable(); lwp = (struct rt_lwp *)tid->lwp; + lwp_tid_put(tid->tid); rt_list_remove(&tid->sibling); lwp_ref_dec(lwp); 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]; int bg = 0; struct process_aux *aux; + int tid = 0; if (filename == RT_NULL) 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)); + if ((tid = lwp_tid_get()) == 0) + { + lwp_ref_dec(lwp); + return -ENOMEM; + } #ifdef RT_USING_USERSPACE if (lwp_user_space_init(lwp) != 0) { + lwp_tid_put(tid); lwp_ref_dec(lwp); 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) { + lwp_tid_put(tid); lwp_ref_dec(lwp); 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); if (result == RT_EOK) { - rt_thread_t tid; + rt_thread_t thread = RT_NULL; 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 = 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); - if (tid != RT_NULL) + if (thread != RT_NULL) { 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(); lwp_self = (struct rt_lwp *)rt_thread_self()->lwp; 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->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 if (debug) @@ -896,11 +907,12 @@ pid_t lwp_execve(char *filename, int argc, char **argv, char **envp) } rt_hw_interrupt_enable(level); - rt_thread_startup(tid); + rt_thread_startup(thread); return lwp_to_pid(lwp); } } + lwp_tid_put(tid); lwp_ref_dec(lwp); return -RT_ERROR; diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h index 29a139b6589e3cfcf569e91bb6ad487068501c4b..5855e9286bde8ec01b6f62d99e4e00b2bbab5949 100644 --- a/components/lwp/lwp.h +++ b/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; @@ -116,6 +117,11 @@ void lwp_set_thread_area(void *p); void* rt_cpu_get_thread_idr(void); 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 void lwp_mmu_switch(struct rt_thread *thread); #endif @@ -164,6 +170,10 @@ struct __pthread { }; #endif +/* for futex op */ +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + #ifdef __cplusplus } #endif diff --git a/components/lwp/lwp_futex.c b/components/lwp/lwp_futex.c new file mode 100644 index 0000000000000000000000000000000000000000..97cd2ef152bbb5a91a0e0a9c65bf3426be98a3ec --- /dev/null +++ b/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 +#include +#ifdef RT_USING_USERSPACE +#include +#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; +} diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c index e13c6f33aa651ba0f013952b85eebb7b95eecfc3..71cc8b5c4aa6b557b1d1b970b87634f0edb43335 100644 --- a/components/lwp/lwp_pid.c +++ b/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; diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index 962525e87197d4b4ebd21cfdb505e1b73da27c09..2f361448d8f630093a9db27ce42dd7ddcab54206 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -76,6 +76,8 @@ static void kmem_put(void *kptr) } #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 * 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 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 */ @@ -359,6 +361,15 @@ void sys_exit(int value) lwp = (struct rt_lwp*)tid->lwp; 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); 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_base_t level; + rt_base_t level = 0; void *user_stack = 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_ref_inc(lwp); @@ -1147,32 +1159,40 @@ rt_thread_t sys_thread_create(void *arg[]) if (!user_stack) { 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, (void*)arg[2], ALLOC_KERNEL_STACK_SIZE, (rt_uint8_t)(size_t)arg[4], (rt_uint32_t)arg[5]); - if (!tid) + if (!thread) { 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(); - rt_list_insert_after(&lwp->t_grp, &tid->sibling); + rt_list_insert_after(&lwp->t_grp, &thread->sibling); rt_hw_interrupt_enable(level); - return tid; + return thread; fail: + lwp_tid_put(tid); #ifndef RT_USING_USERSPACE if (user_stack) { @@ -1186,6 +1206,154 @@ fail: 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) { return rt_thread_delete(thread); @@ -2204,9 +2372,12 @@ int sys_set_thread_area(void *p) 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) @@ -2342,6 +2513,8 @@ int sys_clock_getres(clockid_t clk, struct timespec *ts) return 0; } +int sys_futex(int *uaddr, int op, int val, void *timeout, void *uaddr2, int val3); + const static void* func_table[] = { (void*)sys_exit, /* 01 */ @@ -2400,47 +2573,47 @@ const static void* func_table[] = SYSCALL_USPACE(sys_mmap2), SYSCALL_USPACE(sys_munmap), - SYSCALL_USPACE(sys_shmget), + SYSCALL_USPACE(sys_shmget), /* 55 */ SYSCALL_USPACE(sys_shmrm), SYSCALL_USPACE(sys_shmat), SYSCALL_USPACE(sys_shmdt), (void *)sys_device_init, - (void *)sys_device_register, + (void *)sys_device_register, /* 60 */ (void *)sys_device_control, (void *)sys_device_find, (void *)sys_device_open, (void *)sys_device_close, - (void *)sys_device_read, + (void *)sys_device_read, /* 65 */ (void *)sys_device_write, (void *)sys_stat, (void *)sys_thread_find, SYSCALL_NET(sys_accept), - SYSCALL_NET(sys_bind), + SYSCALL_NET(sys_bind), /* 70 */ SYSCALL_NET(sys_shutdown), SYSCALL_NET(sys_getpeername), SYSCALL_NET(sys_getsockname), SYSCALL_NET(sys_getsockopt), - SYSCALL_NET(sys_setsockopt), + SYSCALL_NET(sys_setsockopt), /* 75 */ SYSCALL_NET(sys_connect), SYSCALL_NET(sys_listen), SYSCALL_NET(sys_recv), SYSCALL_NET(sys_recvfrom), - SYSCALL_NET(sys_send), + SYSCALL_NET(sys_send), /* 80 */ SYSCALL_NET(sys_sendto), SYSCALL_NET(sys_socket), SYSCALL_NET(sys_closesocket), 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, /* 90 */ (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, #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_tick_get, (void *)sys_exit_group, (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_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_delete, (void *)sys_timer_start, (void *)sys_timer_stop, - (void *)sys_timer_control, + (void *)sys_timer_control, /* 115 */ (void *)sys_getcwd, (void *)sys_chdir, (void *)sys_unlink, (void *)sys_mkdir, - (void *)sys_rmdir, + (void *)sys_rmdir, /* 120 */ (void *)sys_getdents, (void *)sys_get_errno, (void *)sys_set_thread_area, (void *)sys_set_tid_address, - (void *)sys_access, + (void *)sys_access, /* 125 */ (void *)sys_pipe, (void *)sys_clock_settime, (void *)sys_clock_gettime, (void *)sys_clock_getres, + (void *)sys_clone, /* 130 */ + (void *)sys_futex, }; const void *lwp_get_sys_api(rt_uint32_t number) diff --git a/components/lwp/lwp_tid.c b/components/lwp/lwp_tid.c new file mode 100644 index 0000000000000000000000000000000000000000..082c5dca3fb6d4024e4f027768388484c773dcf4 --- /dev/null +++ b/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 +#include + +#include "lwp.h" + +#ifdef RT_USING_USERSPACE +#include "lwp_user_mm.h" + +#ifdef RT_USING_GDBSERVER +#include +#include +#endif + +#endif + +#define DBG_TAG "LWP_TID" +#define DBG_LVL DBG_INFO +#include + +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; + } +} diff --git a/include/rtdef.h b/include/rtdef.h index 542a586ee1d322a212e332d30bec5dc21a090b7b..c7424b9700035303c97912ec76cc679821bf37ae 100644 --- a/include/rtdef.h +++ b/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. */ }; @@ -495,6 +496,13 @@ typedef void (*rt_sighandler_t)(int signo); typedef siginfo_t rt_siginfo_t; #define RT_SIG_MAX 32 + +#else + +#ifdef RT_USING_LWP +#include +#endif + #endif /**@}*/ @@ -734,6 +742,8 @@ struct rt_thread int debug_suspend; struct rt_hw_exp_stack *regs; void * thread_idr; /** lwp thread indicator */ + int tid; + int *clear_child_tid; #endif #endif diff --git a/include/rtthread.h b/include/rtthread.h index f6e08898897559e6d58d2ca17afbe8e5cb45f68d..a72d2d30c8a351dc348912de54c3c891f4c5fce3 100644 --- a/include/rtthread.h +++ b/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)); diff --git a/src/object.c b/src/object.c index 3929c7e17c67ed58bc80f7554046f385f3f88158..b3d3f18577461434f8b414e36fa77efbeb09b780 100644 --- a/src/object.c +++ b/src/object.c @@ -26,6 +26,13 @@ #include #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 + /**@}*/