diff --git a/components/drivers/tty/console.c b/components/drivers/tty/console.c index f9eb5ca510..ffc9ab71ec 100644 --- a/components/drivers/tty/console.c +++ b/components/drivers/tty/console.c @@ -20,7 +20,67 @@ #endif /* RT_TTY_DEBUG */ #include +#include +#include + static struct tty_struct console_dev; +static struct rt_ringbuffer console_rx_ringbuffer; +static struct rt_wqueue console_rx_wqueue; +static rt_thread_t console_rx_thread; +static const size_t rb_bufsz = 0x1000; + +static void console_rx_work(void *parameter) +{ + int len; + char ch; + int lens; + static char buf[0x1000]; + + struct tty_struct *console; + console = &console_dev; + + while (1) + { + rt_wqueue_wait(&console_rx_wqueue, 0, RT_WAITING_FOREVER); + lens = 0; + + while (lens < sizeof(buf)) + { + len = rt_ringbuffer_get(&console_rx_ringbuffer, (void *)&ch, sizeof(ch)); + if (len == 0) + { + break; + } + lens += len; + buf[lens-1] = ch; + } + + if (lens && console->ldisc->ops->receive_buf) + { + console->ldisc->ops->receive_buf((struct tty_struct *)console, buf, lens); + } + } +} + +static int rx_thread_init(void) +{ + void *rb_buffer; + rt_thread_t thread; + + rb_buffer = rt_malloc(rb_bufsz); + rt_ringbuffer_init(&console_rx_ringbuffer, rb_buffer, rb_bufsz); + rt_wqueue_init(&console_rx_wqueue); + + thread = rt_thread_create("console_rx", console_rx_work, &console_dev, rb_bufsz, 10, 10); + if (thread != RT_NULL) + { + rt_thread_startup(thread); + console_rx_thread = thread; + } + + return 0; +} +INIT_COMPONENT_EXPORT(rx_thread_init); static void console_rx_notify(struct rt_device *dev) { @@ -28,7 +88,6 @@ static void console_rx_notify(struct rt_device *dev) int len = 0; int lens = 0; char ch = 0; - char buf[1024] = {0}; console = (struct tty_struct *)dev; RT_ASSERT(console != RT_NULL); @@ -41,17 +100,14 @@ static void console_rx_notify(struct rt_device *dev) break; } lens += len; - buf[lens-1] = ch; - if (lens > 1024) + rt_ringbuffer_put(&console_rx_ringbuffer, (void *)&ch, sizeof(ch)); + if (lens > rb_bufsz) { break; } } - - if (console->ldisc->ops->receive_buf) - { - console->ldisc->ops->receive_buf((struct tty_struct *)console, buf, lens); - } + if (console_rx_thread) + rt_wqueue_wakeup(&console_rx_wqueue, 0); } struct tty_struct *console_tty_get(void) diff --git a/components/drivers/tty/n_tty.c b/components/drivers/tty/n_tty.c index 8b6d1d089f..1191f57696 100644 --- a/components/drivers/tty/n_tty.c +++ b/components/drivers/tty/n_tty.c @@ -50,7 +50,6 @@ #define ECHO_BLOCK 256 #define ECHO_DISCARD_WATERMARK RT_TTY_BUF - (ECHO_BLOCK + 32) - struct n_tty_data { /* producer-published */ @@ -136,6 +135,12 @@ rt_inline int test_and_clear_bit(int nr, volatile void *addr) return retval; } +#ifdef __GNUC__ +rt_inline unsigned long __ffs(unsigned long word) +{ + return __builtin_ffsl(word); +} +#else rt_inline unsigned long __ffs(unsigned long word) { int num = 0; @@ -174,6 +179,7 @@ rt_inline unsigned long __ffs(unsigned long word) return num; } +#endif #define BITS_PER_LONG 32 #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) @@ -703,13 +709,13 @@ static void __isig(int sig, struct tty_struct *tty) ld->ops->set_termios(tty, &old_termios); } } - tty_sigaddset(&lwp->signal_mask, SIGTTOU); + lwp_signal_kill(lwp, SIGTTOU, SI_USER, 0); old_lwp = tty_pop(&tty->head, RT_NULL); tty->foreground = old_lwp; } else { - lwp_kill(lwp_to_pid(lwp), sig); + lwp_signal_kill(lwp, sig, SI_USER, 0); } } } diff --git a/components/drivers/tty/tty.c b/components/drivers/tty/tty.c index 748be743cb..53f7ae1e59 100644 --- a/components/drivers/tty/tty.c +++ b/components/drivers/tty/tty.c @@ -126,26 +126,6 @@ struct rt_lwp *tty_pop(struct tty_node **head, struct rt_lwp *target_lwp) return lwp; } -rt_inline int tty_sigismember(lwp_sigset_t *set, int _sig) -{ - unsigned long sig = _sig - 1; - - if (_LWP_NSIG_WORDS == 1) - { - return 1 & (set->sig[0] >> sig); - } - else - { - return 1 & (set->sig[sig / _LWP_NSIG_BPW] >> (sig % _LWP_NSIG_BPW)); - } -} - -static int is_ignored(int sig) -{ - return (tty_sigismember(¤t->signal_mask, sig) || - current->signal_handler[sig-1] == SIG_IGN); -} - /** * tty_check_change - check for POSIX terminal changes * @tty: tty to check @@ -160,7 +140,6 @@ static int is_ignored(int sig) int __tty_check_change(struct tty_struct *tty, int sig) { pid_t pgrp = 0, tty_pgrp = 0; - struct rt_lwp *lwp = tty->foreground; int ret = 0; int level = 0; @@ -182,20 +161,7 @@ int __tty_check_change(struct tty_struct *tty, int sig) if (tty_pgrp && (pgrp != tty->pgrp)) { - if (is_ignored(sig)) - { - if (sig == SIGTTIN) - { - ret = -EIO; - } - } - else - { - if (lwp) - { - lwp_kill(lwp_to_pid(lwp), sig); - } - } + lwp_signal_kill(current, sig, SI_USER, 0); } rt_hw_interrupt_enable(level); diff --git a/components/libc/compilers/common/ctime.c b/components/libc/compilers/common/ctime.c index ea31cf753d..4f3e424f68 100644 --- a/components/libc/compilers/common/ctime.c +++ b/components/libc/compilers/common/ctime.c @@ -20,6 +20,8 @@ * 2021-05-01 Meco Man support fixed timezone * 2021-07-21 Meco Man implement that change/set timezone APIs * 2023-07-03 xqyjlj refactor posix time and timer + * 2023-07-16 Shell update signal generation routine for lwp + * adapt to new api and do the signal handling in thread context */ #include "sys/time.h" @@ -713,9 +715,56 @@ struct timer_obj clockid_t clockid; #ifdef RT_USING_SMART pid_t pid; + struct rt_work *work; #endif }; +#ifdef RT_USING_SMART +struct lwp_timer_event_param +{ + struct rt_work work; + + union + { + int tid; + pid_t pid; + }; + int signo; +}; + +static void _lwp_timer_event_from_tid(struct rt_work *work, void *param) +{ + rt_err_t ret; + struct lwp_timer_event_param *data = (void *)work; + rt_thread_t thread; + + RT_ASSERT(data->tid); + + thread = lwp_tid_get_thread(data->tid); + ret = lwp_thread_signal_kill(thread, data->signo, SI_TIMER, 0); + if (ret) + { + LOG_W("%s: Do kill failed(tid %d) returned %d", __func__, data->tid, ret); + } + + rt_free(work); +} + +static void _lwp_timer_event_from_pid(struct rt_work *work, void *param) +{ + rt_err_t ret; + struct lwp_timer_event_param *data = (void *)work; + + ret = lwp_signal_kill(lwp_from_pid(data->pid), data->signo, SI_TIMER, 0); + if (ret) + { + LOG_W("%s: Do kill failed(pid %d) returned %d", __func__, data->pid, ret); + } + + rt_free(work); +} +#endif /* RT_USING_SMART */ + static void rtthread_timer_wrapper(void *timerobj) { struct timer_obj *timer; @@ -735,7 +784,24 @@ static void rtthread_timer_wrapper(void *timerobj) rt_ktime_hrtimer_start(&timer->hrtimer); } #ifdef RT_USING_SMART - sys_kill(timer->pid, timer->sigev_signo); + /* this field is named as tid in musl */ + int tid = *(int *)&timer->sigev_notify_function; + struct lwp_timer_event_param *data = (void *)timer->work; + data->signo = timer->sigev_signo; + + if (!tid) + { + data->pid = timer->pid; + rt_work_init(timer->work, _lwp_timer_event_from_pid, 0); + } + else + { + data->tid = tid; + rt_work_init(timer->work, _lwp_timer_event_from_tid, 0); + } + + if (rt_work_submit(timer->work, 0)) + RT_ASSERT(0); #else if(timer->sigev_notify_function != RT_NULL) { @@ -802,7 +868,27 @@ int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) num %= 100; timer->sigev_signo = evp->sigev_signo; #ifdef RT_USING_SMART - timer->pid = lwp_self()->pid; + struct rt_work *work; + struct rt_lwp *lwp = lwp_self(); + + work = rt_malloc(sizeof(struct lwp_timer_event_param)); + if (!work) + { + rt_set_errno(ENOMEM); + return -1; + } + + if (lwp) + { + timer->pid = lwp_self()->pid; + } + else + { + timer->pid = 0; /* pid 0 is never used */ + } + + timer->work = work; + #endif timer->sigev_notify_function = evp->sigev_notify_function; timer->val = evp->sigev_value; diff --git a/components/lwp/arch/aarch64/cortex-a/lwp_arch.c b/components/lwp/arch/aarch64/cortex-a/lwp_arch.c index da9e5f94bd..f230251421 100644 --- a/components/lwp/arch/aarch64/cortex-a/lwp_arch.c +++ b/components/lwp/arch/aarch64/cortex-a/lwp_arch.c @@ -1,15 +1,20 @@ /* - * Copyright (c) 2006-2021, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-05-18 Jesven first version + * 2023-07-16 Shell Move part of the codes to C from asm in signal handling */ +#include #include #include +#include +#include +#include #ifdef ARCH_MM_MMU @@ -92,3 +97,75 @@ int arch_expand_user_stack(void *addr) } #endif +#define ALGIN_BYTES (16) + +struct signal_ucontext +{ + rt_int64_t sigreturn; + lwp_sigset_t save_sigmask; + + siginfo_t si; + + rt_align(16) + struct rt_hw_exp_stack frame; +}; + +void *arch_signal_ucontext_restore(rt_base_t user_sp) +{ + struct signal_ucontext *new_sp; + new_sp = (void *)user_sp; + + if (lwp_user_accessable(new_sp, sizeof(*new_sp))) + { + lwp_thread_signal_mask(rt_thread_self(), LWP_SIG_MASK_CMD_SET_MASK, &new_sp->save_sigmask, RT_NULL); + } + else + { + LOG_I("User frame corrupted during signal handling\nexiting..."); + sys_exit(EXIT_FAILURE); + } + + return (char *)&new_sp->frame + sizeof(struct rt_hw_exp_stack); +} + +void *arch_signal_ucontext_save(rt_base_t user_sp, siginfo_t *psiginfo, + struct rt_hw_exp_stack *exp_frame, + rt_base_t elr, rt_base_t spsr, + lwp_sigset_t *save_sig_mask) +{ + struct signal_ucontext *new_sp; + new_sp = (void *)(user_sp - sizeof(struct signal_ucontext)); + + if (lwp_user_accessable(new_sp, sizeof(*new_sp))) + { + /* push psiginfo */ + if (psiginfo) + { + memcpy(&new_sp->si, psiginfo, sizeof(*psiginfo)); + } + + /* exp frame is already aligned as AAPCS64 required */ + memcpy(&new_sp->frame, exp_frame, sizeof(*exp_frame)); + + /* fix the 3 fields in exception frame, so that memcpy will be fine */ + new_sp->frame.pc = elr; + new_sp->frame.cpsr = spsr; + new_sp->frame.sp_el0 = user_sp; + + /* copy the save_sig_mask */ + memcpy(&new_sp->save_sigmask, save_sig_mask, sizeof(lwp_sigset_t)); + + /* copy lwp_sigreturn */ + const size_t lwp_sigreturn_bytes = 8; + extern void lwp_sigreturn(void); + /* -> ensure that the sigreturn start at the outer most boundary */ + memcpy(&new_sp->sigreturn, &lwp_sigreturn, lwp_sigreturn_bytes); + } + else + { + LOG_I("%s: User stack overflow", __func__); + sys_exit(EXIT_FAILURE); + } + + return new_sp; +} diff --git a/components/lwp/arch/aarch64/cortex-a/lwp_arch.h b/components/lwp/arch/aarch64/cortex-a/lwp_arch.h index 33814163ff..46bbac5770 100644 --- a/components/lwp/arch/aarch64/cortex-a/lwp_arch.h +++ b/components/lwp/arch/aarch64/cortex-a/lwp_arch.h @@ -36,6 +36,28 @@ rt_inline void icache_invalid_all(void) asm volatile ("ic ialluis\n\tisb sy":::"memory"); } +/** + * @brief Save signal-related context to user stack + * + * @param user_sp the current sp of user + * @param exp_frame exception frame to resume former execution + * @param psiginfo pointer to the siginfo + * @param elr pc of former execution + * @param spsr program status of former execution + * @return void* the new user sp + */ +void *arch_signal_ucontext_save(rt_base_t user_sp, siginfo_t *psiginfo, + struct rt_hw_exp_stack *exp_frame, + rt_base_t elr, rt_base_t spsr, + lwp_sigset_t *save_sig_mask); + +/** + * @brief Restore the signal mask after return + * + * @param user_sp sp of user + * @return void* + */ +void *arch_signal_ucontext_restore(rt_base_t user_sp); #ifdef __cplusplus } #endif diff --git a/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S b/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S index a8f81ac248..cf75bd24b3 100644 --- a/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S +++ b/components/lwp/arch/aarch64/cortex-a/lwp_gcc.S @@ -1,11 +1,12 @@ /* - * Copyright (c) 2006-2021, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-05-18 Jesven first version + * 2023-07-16 Shell Move part of the codes to C from asm in signal handling */ #ifndef __ASSEMBLY__ @@ -192,8 +193,9 @@ arch_syscall_exit: add sp, sp, #0x40 RESTORE_FPU sp -.global arch_ret_to_user -arch_ret_to_user: +/* the sp is reset to the outer most level */ +START_POINT(arch_ret_to_user) + /* save exception frame */ SAVE_FPU sp stp x0, x1, [sp, #-0x10]! stp x2, x3, [sp, #-0x10]! @@ -216,12 +218,16 @@ arch_ret_to_user: stp x0, x1, [sp, #-0x10]! stp x29, x30, [sp, #-0x10]! + /* pre-action */ bl lwp_check_debug + bl lwp_check_exit_request cbz w0, 1f + /* exit on event */ mov x0, xzr b sys_exit 1: + /* check if dbg ops exist */ ldr x0, =rt_dbg_ops ldr x0, [x0] cbz x0, 3f @@ -236,9 +242,17 @@ arch_ret_to_user: bic x2, x2, x1 msr spsr_el1, x2 3: - bl lwp_signal_check - cmp x0, xzr + /** + * push 2 dummy words to simulate a exception frame of interrupt + */ + add sp, sp, #-0x10 + mov x0, sp + bl lwp_thread_signal_catch + add sp, sp, #0x10 + + /* check debug */ + /* restore exception frame */ ldp x29, x30, [sp], #0x10 ldp x0, x1, [sp], #0x10 msr fpcr, x0 @@ -261,14 +275,14 @@ arch_ret_to_user: ldp x0, x1, [sp], #0x10 RESTORE_FPU sp - bne user_do_signal - stp x0, x1, [sp, #-0x10]! ldr x0, =rt_dbg_ops ldr x0, [x0] cmp x0, xzr ldp x0, x1, [sp], #0x10 beq 1f + + /* save */ SAVE_FPU sp stp x0, x1, [sp, #-0x10]! stp x2, x3, [sp, #-0x10]! @@ -289,8 +303,11 @@ arch_ret_to_user: mrs x1, fpsr stp x0, x1, [sp, #-0x10]! stp x29, x30, [sp, #-0x10]! + mrs x0, elr_el1 bl dbg_attach_req + + /* restore */ ldp x29, x30, [sp], #0x10 ldp x0, x1, [sp], #0x10 msr fpcr, x0 @@ -313,6 +330,7 @@ arch_ret_to_user: RESTORE_FPU sp 1: eret +START_POINT_END(arch_ret_to_user) .global lwp_check_debug lwp_check_debug: @@ -371,26 +389,28 @@ lwp_check_debug_quit: arch_signal_quit: msr daifset, #3 -/* - drop stack data -*/ - add sp, sp, #CONTEXT_SIZE - bl lwp_signal_restore - /* x0 is user_ctx : ori sp, pc, cpsr */ - ldr x1, [x0] - ldr x2, [x0, #8] - ldr x3, [x0, #16] - msr spsr_el1, x3 - msr elr_el1, x2 - add x1, x1, #16 - msr sp_el0, x1 + /* drop current exception frame */ + add sp, sp, #CONTEXT_SIZE + mrs x0, sp_el0 + bl arch_signal_ucontext_restore + add x0, x0, #-CONTEXT_SIZE + msr sp_el0, x0 + + /* restore previous exception frame */ msr spsel, #0 + ldp x2, x3, [sp], #0x10 + msr elr_el1, x2 + msr spsr_el1, x3 + ldp x29, x30, [sp], #0x10 + // msr sp_el0, x29 + ldp x28, x29, [sp], #0x10 msr fpcr, x28 msr fpsr, x29 + ldp x28, x29, [sp], #0x10 ldp x26, x27, [sp], #0x10 ldp x24, x25, [sp], #0x10 @@ -412,65 +432,69 @@ arch_signal_quit: b arch_ret_to_user -user_do_signal: - msr spsel, #0 - SAVE_FPU sp - stp x0, x1, [sp, #-0x10]! - stp x2, x3, [sp, #-0x10]! - stp x4, x5, [sp, #-0x10]! - stp x6, x7, [sp, #-0x10]! - stp x8, x9, [sp, #-0x10]! - stp x10, x11, [sp, #-0x10]! - stp x12, x13, [sp, #-0x10]! - stp x14, x15, [sp, #-0x10]! - stp x16, x17, [sp, #-0x10]! - stp x18, x19, [sp, #-0x10]! - stp x20, x21, [sp, #-0x10]! - stp x22, x23, [sp, #-0x10]! - stp x24, x25, [sp, #-0x10]! - stp x26, x27, [sp, #-0x10]! - stp x28, x29, [sp, #-0x10]! - mrs x28, fpcr - mrs x29, fpsr - stp x28, x29, [sp, #-0x10]! - stp x29, x30, [sp, #-0x10]! +/** + * rt_noreturn + * void arch_thread_signal_enter( + * int signo, -> x0 + * siginfo_t *psiginfo, -> x1 + * void *exp_frame, -> x2 + * void *entry_uaddr, -> x3 + * lwp_sigset_t *save_sig_mask, -> x4 + * ) + */ +.global arch_thread_signal_enter +arch_thread_signal_enter: + mov x19, x0 + mov x20, x2 /* exp_frame */ + mov x21, x3 - sub sp, sp, #0x10 - adr x0, lwp_sigreturn - ldr w1, [x0] - str w1, [sp] - ldr w1, [x0, #4] - str w1, [sp, #4] + /** + * move exception frame to user stack + */ + mrs x0, sp_el0 + mrs x3, elr_el1 + mov x5, x4 + /** FIXME: spsr must restore from exception frame */ + mrs x4, spsr_el1 - mov x20, sp /* lwp_sigreturn */ - mov x0, sp + /* arch_signal_ucontext_save(user_sp, psiginfo, exp_frame, elr, spsr, save_sig_mask); */ + bl arch_signal_ucontext_save dc cvau, x0 dsb sy ic ialluis dsb sy - msr spsel, #1 + /** + * @brief Prepare the environment for signal handler + */ - mrs x1, elr_el1 - mrs x2, spsr_el1 - bl lwp_signal_backup - /* x0 is signal */ - mov x19, x0 - bl lwp_sighandler_get - adds x1, x0, xzr + /** drop exp frame on kernel stack, reset kernel sp */ + add sp, x20, #CONTEXT_SIZE + + /** reset user sp */ + msr sp_el0, x0 + /** set the return address to the sigreturn */ + mov x30, x0 + + /** set the entry address of signal handler */ + msr elr_el1, x21 + + /* siginfo is above the return address */ + add x2, x30, 16 + add x1, x2, #CONTEXT_SIZE mov x0, x19 - bne 1f - mov x1, x20 -1: - msr elr_el1, x1 - mov x30, x20 + + /** + * handler(signo, psi, ucontext); + */ eret lwp_debugreturn: mov x8, 0xf000 svc #0 +.global lwp_sigreturn lwp_sigreturn: mov x8, #0xe000 svc #0 diff --git a/components/lwp/arch/arm/cortex-a/lwp_arch.c b/components/lwp/arch/arm/cortex-a/lwp_arch.c index 5b786412e6..d10ac398a1 100644 --- a/components/lwp/arch/arm/cortex-a/lwp_arch.c +++ b/components/lwp/arch/arm/cortex-a/lwp_arch.c @@ -1,16 +1,18 @@ /* - * Copyright (c) 2006-2018, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-10-28 Jesven first version + * 2023-07-16 Shell Move part of the codes to C from asm in signal handling */ #include #include #include +#include #ifdef ARCH_MM_MMU @@ -54,7 +56,7 @@ void arch_kuser_init(rt_aspace_t aspace, void *vectors) { const size_t kuser_size = 0x1000; int err; - extern char __kuser_helper_start[], __kuser_helper_end[]; + extern char *__kuser_helper_start, *__kuser_helper_end; int kuser_sz = __kuser_helper_end - __kuser_helper_start; err = rt_aspace_map_static(aspace, &kuser_varea, &vectors, kuser_size, @@ -109,6 +111,88 @@ int arch_expand_user_stack(void *addr) } return ret; } +#define ALGIN_BYTES 8 +#define lwp_sigreturn_bytes 8 +struct signal_regs { + rt_base_t lr; + rt_base_t spsr; + rt_base_t r0_to_r12[13]; + rt_base_t ip; +}; + +struct signal_ucontext +{ + rt_base_t sigreturn[lwp_sigreturn_bytes / sizeof(rt_base_t)]; + lwp_sigset_t save_sigmask; + + siginfo_t si; + + rt_align(8) + struct signal_regs frame; +}; + +void *arch_signal_ucontext_restore(rt_base_t user_sp) +{ + struct signal_ucontext *new_sp; + rt_base_t ip; + new_sp = (void *)user_sp; + + if (lwp_user_accessable(new_sp, sizeof(*new_sp))) + { + lwp_thread_signal_mask(rt_thread_self(), LWP_SIG_MASK_CMD_SET_MASK, &new_sp->save_sigmask, RT_NULL); + ip = new_sp->frame.ip; + /* let user restore its lr from frame.ip */ + new_sp->frame.ip = new_sp->frame.lr; + /* kernel will pick eip from frame.lr */ + new_sp->frame.lr = ip; + } + else + { + LOG_I("User frame corrupted during signal handling\nexiting..."); + sys_exit(EXIT_FAILURE); + } + + return (void *)&new_sp->frame; +} + +void *arch_signal_ucontext_save(rt_base_t lr, siginfo_t *psiginfo, + struct signal_regs *exp_frame, rt_base_t user_sp, + lwp_sigset_t *save_sig_mask) +{ + rt_base_t spsr; + struct signal_ucontext *new_sp; + new_sp = (void *)(user_sp - sizeof(struct signal_ucontext)); + + if (lwp_user_accessable(new_sp, sizeof(*new_sp))) + { + /* push psiginfo */ + if (psiginfo) + { + memcpy(&new_sp->si, psiginfo, sizeof(*psiginfo)); + } + + memcpy(&new_sp->frame.r0_to_r12, exp_frame, sizeof(new_sp->frame.r0_to_r12) + sizeof(rt_base_t)); + new_sp->frame.lr = lr; + + __asm__ volatile("mrs %0, spsr":"=r"(spsr)); + new_sp->frame.spsr = spsr; + + /* copy the save_sig_mask */ + memcpy(&new_sp->save_sigmask, save_sig_mask, sizeof(lwp_sigset_t)); + + /* copy lwp_sigreturn */ + extern void lwp_sigreturn(void); + /* -> ensure that the sigreturn start at the outer most boundary */ + memcpy(&new_sp->sigreturn, &lwp_sigreturn, lwp_sigreturn_bytes); + } + else + { + LOG_I("%s: User stack overflow", __func__); + sys_exit(EXIT_FAILURE); + } + + return new_sp; +} #ifdef LWP_ENABLE_ASID #define MAX_ASID_BITS 8 diff --git a/components/lwp/arch/arm/cortex-a/lwp_arch.h b/components/lwp/arch/arm/cortex-a/lwp_arch.h index 71a1057224..def88bf3b2 100644 --- a/components/lwp/arch/arm/cortex-a/lwp_arch.h +++ b/components/lwp/arch/arm/cortex-a/lwp_arch.h @@ -40,6 +40,12 @@ rt_inline void icache_invalid_all(void) unsigned int arch_get_asid(struct rt_lwp *lwp); +struct signal_regs; +void *arch_signal_ucontext_restore(rt_base_t user_sp); +void *arch_signal_ucontext_save(rt_base_t lr, siginfo_t *psiginfo, + struct signal_regs *exp_frame, rt_base_t user_sp, + lwp_sigset_t *save_sig_mask); + #ifdef __cplusplus } #endif diff --git a/components/lwp/arch/arm/cortex-a/lwp_gcc.S b/components/lwp/arch/arm/cortex-a/lwp_gcc.S index 34f4d7e371..7e27592c6d 100644 --- a/components/lwp/arch/arm/cortex-a/lwp_gcc.S +++ b/components/lwp/arch/arm/cortex-a/lwp_gcc.S @@ -6,6 +6,7 @@ * Change Logs: * Date Author Notes * 2018-12-10 Jesven first version + * 2023-07-16 Shell Move part of the codes to C from asm in signal handling */ #include "rtconfig.h" @@ -191,7 +192,7 @@ arch_syscall_exit: .global arch_ret_to_user arch_ret_to_user: - push {r0-r3, r12, lr} + push {r0-r12, lr} bl lwp_check_debug bl lwp_check_exit_request cmp r0, #0 @@ -199,10 +200,10 @@ arch_ret_to_user: mov r0, #0 b sys_exit 1: - bl lwp_signal_check - cmp r0, #0 - pop {r0-r3, r12, lr} - bne user_do_signal + mov r0, sp + /* r0 -> exp frame */ + bl lwp_thread_signal_catch + pop {r0-r12, lr} push {r0} ldr r0, =rt_dbg_ops @@ -273,35 +274,65 @@ lwp_check_debug_quit: arch_signal_quit: cpsid i + /* drop context of signal handler */ pop {r0 - r3, r12} pop {r4, r5, lr} pop {lr} - bl lwp_signal_restore - /* r0 is user_ctx : ori sp, pc, cpsr*/ - ldr r1, [r0] - ldr r2, [r0, #4] - ldr r3, [r0, #8] - msr spsr_cxsf, r3 - mov lr, r2 + + /* restore context */ cps #Mode_SYS - mov sp, r1 + mov r0, sp + cps #Mode_SVC + bl arch_signal_ucontext_restore + + /* lr <- *(&frame.ip) */ + ldr lr, [r0] + cps #Mode_SYS + mov sp, r0 + + /* drop ip in the frame and restore cpsr */ + pop {r0} + pop {r0} + msr spsr_cxsf, r0 pop {r0-r12, lr} cps #Mode_SVC + b arch_ret_to_user -user_do_signal: - mov r0, r0 +/** + * rt_noreturn + * void arch_thread_signal_enter( + * int signo, -> r0 + * siginfo_t *psiginfo, -> r1 + * void *exp_frame, -> r2 + * void *entry_uaddr, -> r3 + * lwp_sigset_t *save_sig_mask, -> ?? + * ) + */ +.global arch_thread_signal_enter +arch_thread_signal_enter: + mov r4, r0 + mov r5, r3 + cps #Mode_SYS - push {r0-r12, lr} + mov r0, lr + mov r3, sp + cps #Mode_SVC + bl arch_signal_ucontext_save - sub sp, #8 - ldr r0, =lwp_sigreturn - ldr r1, [r0] - str r1, [sp] - ldr r1, [r0, #4] - str r1, [sp, #4] + /* reset user sp */ + cps #Mode_SYS + mov sp, r0 + mov lr, r0 + cps #Mode_SVC - mov r1, sp + /* r1,r2 <- new_user_sp */ + mov r1, r0 + mov r2, r0 + /* r0 <- signo */ + mov r0, r4 + + mov r1, r0 mcr p15, 0, r1, c7, c11, 1 ;//dc cmvau add r1, #4 mcr p15, 0, r1, c7, c11, 1 ;//dc cmvau @@ -311,27 +342,25 @@ user_do_signal: dsb isb - mov r5, sp ;//if func is 0 - mov lr, sp + /* r4 <- &sigreturn */ + mov r4, r2 - add r0, sp, #8 /* lwp_sigreturn */ - cps #Mode_SVC - mov r1, lr - mrs r2, spsr - bl lwp_signal_backup - /* r0 is signal */ - mov r4, r0 - bl lwp_sighandler_get - mov lr, r0 + /* lr <- user_handler() */ + mov lr, r5 cmp lr, #0 - moveq lr, r5 - mov r0, r4 + moveq lr, r4 + + /* r1 <- siginfo */ + mov r1, r2 + add r1, #8 + /* handler(signo, siginfo, ucontext) */ movs pc, lr lwp_debugreturn: mov r7, #0xf000 svc #0 +.global lwp_sigreturn lwp_sigreturn: mov r7, #0xe000 svc #0 diff --git a/components/lwp/arch/risc-v/rv64/lwp_arch.c b/components/lwp/arch/risc-v/rv64/lwp_arch.c index b2315a614f..217839a95a 100644 --- a/components/lwp/arch/risc-v/rv64/lwp_arch.c +++ b/components/lwp/arch/risc-v/rv64/lwp_arch.c @@ -14,6 +14,7 @@ * 2021-03-04 lizhirui modify for new version of rt-smart * 2021-11-22 JasonHu add lwp_set_thread_context * 2021-11-30 JasonHu add clone/fork support + * 2023-07-16 Shell Move part of the codes to C from asm in signal handling */ #include #include @@ -34,6 +35,7 @@ #include #include #include +#include extern rt_ubase_t MMUTable[]; @@ -245,6 +247,79 @@ int arch_set_thread_context(void (*exit)(void), void *new_thread_stack, */ } +#define ALGIN_BYTES (16) + +struct signal_ucontext +{ + rt_int64_t sigreturn; + lwp_sigset_t save_sigmask; + + siginfo_t si; + + rt_align(16) + struct rt_hw_stack_frame frame; +}; + +void *arch_signal_ucontext_restore(rt_base_t user_sp) +{ + struct signal_ucontext *new_sp; + new_sp = (void *)user_sp; + + if (lwp_user_accessable(new_sp, sizeof(*new_sp))) + { + lwp_thread_signal_mask(rt_thread_self(), LWP_SIG_MASK_CMD_SET_MASK, &new_sp->save_sigmask, RT_NULL); + } + else + { + LOG_I("User frame corrupted during signal handling\nexiting..."); + sys_exit(EXIT_FAILURE); + } + + return (void *)&new_sp->frame; +} + +void *arch_signal_ucontext_save(int signo, siginfo_t *psiginfo, + struct rt_hw_stack_frame *exp_frame, rt_base_t user_sp, + lwp_sigset_t *save_sig_mask) +{ + struct signal_ucontext *new_sp; + new_sp = (void *)(user_sp - sizeof(struct signal_ucontext)); + + if (lwp_user_accessable(new_sp, sizeof(*new_sp))) + { + /* push psiginfo */ + if (psiginfo) + { + memcpy(&new_sp->si, psiginfo, sizeof(*psiginfo)); + } + + memcpy(&new_sp->frame, exp_frame, sizeof(*exp_frame)); + + /* copy the save_sig_mask */ + memcpy(&new_sp->save_sigmask, save_sig_mask, sizeof(lwp_sigset_t)); + + /* copy lwp_sigreturn */ + const size_t lwp_sigreturn_bytes = 8; + extern void lwp_sigreturn(void); + /* -> ensure that the sigreturn start at the outer most boundary */ + memcpy(&new_sp->sigreturn, &lwp_sigreturn, lwp_sigreturn_bytes); + + /** + * synchronize dcache & icache if target is + * a Harvard Architecture machine, otherwise + * do nothing + */ + rt_hw_sync_cache_local(&new_sp->sigreturn, 8); + } + else + { + LOG_I("%s: User stack overflow", __func__); + sys_exit(EXIT_FAILURE); + } + + return new_sp; +} + /** * void lwp_exec_user(void *args, void *kernel_stack, void *user_entry) */ @@ -253,9 +328,4 @@ void lwp_exec_user(void *args, void *kernel_stack, void *user_entry) arch_start_umode(args, user_entry, (void *)USER_STACK_VEND, kernel_stack); } -void *arch_get_usp_from_uctx(struct rt_user_context *uctx) -{ - return uctx->sp; -} - #endif /* ARCH_MM_MMU */ diff --git a/components/lwp/arch/risc-v/rv64/lwp_arch.h b/components/lwp/arch/risc-v/rv64/lwp_arch.h index 604818ab5c..3b78f39355 100644 --- a/components/lwp/arch/risc-v/rv64/lwp_arch.h +++ b/components/lwp/arch/risc-v/rv64/lwp_arch.h @@ -59,6 +59,11 @@ rt_inline void icache_invalid_all(void) rt_hw_cpu_icache_invalidate_all(); } +struct rt_hw_stack_frame; +void *arch_signal_ucontext_restore(rt_base_t user_sp); +void *arch_signal_ucontext_save(int signo, siginfo_t *psiginfo, + struct rt_hw_stack_frame *exp_frame, rt_base_t user_sp, + lwp_sigset_t *save_sig_mask); #ifdef __cplusplus } #endif diff --git a/components/lwp/arch/risc-v/rv64/lwp_gcc.S b/components/lwp/arch/risc-v/rv64/lwp_gcc.S index de47b1e0ca..ab0f722bf1 100644 --- a/components/lwp/arch/risc-v/rv64/lwp_gcc.S +++ b/components/lwp/arch/risc-v/rv64/lwp_gcc.S @@ -10,6 +10,7 @@ * 2021-02-19 lizhirui port to new version of rt-smart * 2022-11-08 Wangxiaoyao Cleanup codes; * Support new context switch + * 2023-07-16 Shell Move part of the codes to C from asm in signal handling */ #include "rtconfig.h" @@ -89,9 +90,8 @@ arch_ret_to_user: call sys_exit 1: - call lwp_signal_check - beqz a0, ret_to_user_exit - J user_do_signal + mv a0, sp + call lwp_thread_signal_catch ret_to_user_exit: RESTORE_ALL @@ -103,129 +103,80 @@ ret_to_user_exit: * And handle pending signals; */ arch_signal_quit: - call lwp_signal_restore - call arch_get_usp_from_uctx - // return value is user sp + LOAD a0, FRAME_OFF_SP(sp) + call arch_signal_ucontext_restore + + /* reset kernel sp to the stack */ + STORE sp, FRAME_OFF_SP(a0) + /* return value is user sp */ mv sp, a0 - // restore user sp before enter trap + /* restore user sp before enter trap */ addi a0, sp, CTX_REG_NR * REGBYTES csrw sscratch, a0 + RESTORE_ALL SAVE_ALL j arch_ret_to_user /** - * Prepare and enter user signal handler - * Move user exception frame and setup signal return - * routine in user stack + * rt_noreturn + * void arch_thread_signal_enter( + * int signo, -> a0 + * siginfo_t *psiginfo, -> a1 + * void *exp_frame, -> a2 + * void *entry_uaddr, -> a3 + * lwp_sigset_t *save_sig_mask, -> a4 + * ) */ -user_do_signal: - /* prefetch ustack to avoid corrupted status in RESTORE/STORE pair below */ - LOAD t0, FRAME_OFF_SP(sp) - addi t1, t0, -CTX_REG_NR * REGBYTES - LOAD t2, (t0) - li t3, -0x1000 -1: - add t0, t0, t3 - LOAD t2, (t0) - bgt t0, t1, 1b - - /** restore and backup kernel sp carefully to avoid leaking */ - addi t0, sp, CTX_REG_NR * REGBYTES - csrw sscratch, t0 - - RESTORE_ALL - SAVE_ALL - - /** - * save lwp_sigreturn in user memory - */ - mv s0, sp - la t0, lwp_sigreturn - la t1, lwp_sigreturn_end - // t1 <- size - sub t1, t1, t0 - // s0 <- dst - sub s0, s0, t1 - mv s2, t1 -lwp_sigreturn_copy_loop: - addi t2, t1, -1 - add t3, t0, t2 - add t4, s0, t2 - lb t5, 0(t3) - sb t5, 0(t4) - mv t1, t2 - bnez t1, lwp_sigreturn_copy_loop - - /** - * 1. clear sscratch & restore kernel sp to - * enter kernel mode routine - * 2. storage exp frame address to restore context, - * by calling to lwp_signal_backup - * 3. storage lwp_sigreturn entry address - * 4. get signal id as param for signal handler - */ - mv s1, sp - csrrw sp, sscratch, x0 - - /** - * synchronize dcache & icache if target is - * a Harvard Architecture machine, otherwise - * do nothing - */ - mv a0, s0 - mv a1, s2 - call rt_hw_sync_cache_local - - /** - * backup user sp (point to saved exception frame, skip sigreturn routine) - * And get signal id - - * a0: user sp - * a1: user_pc (not used, marked as 0 to avoid abuse) - * a2: user_flag (not used, marked as 0 to avoid abuse) - */ - mv a0, s1 - mv a1, zero - mv a2, zero - call lwp_signal_backup - - /** - * backup signal id in s2, - * and get sighandler by signal id - */ +.global arch_thread_signal_enter +arch_thread_signal_enter: + mv s3, a2 mv s2, a0 - call lwp_sighandler_get + mv s1, a3 + + LOAD t0, FRAME_OFF_SP(a2) + mv a3, t0 + call arch_signal_ucontext_save + + /** restore kernel sp */ + addi sp, s3, CTX_REG_NR * REGBYTES /** * set regiter RA to user signal handler * set sp to user sp & save kernel sp in sscratch */ - mv ra, s0 + mv ra, a0 csrw sscratch, sp - mv sp, s0 + mv sp, a0 /** - * a0 is signal_handler, - * s1 = s0 == NULL ? lwp_sigreturn : s0; + * s1 is signal_handler, + * s1 = !s1 ? lwp_sigreturn : s1; */ - mv s1, s0 - beqz a0, skip_user_signal_handler - mv s1, a0 + bnez s1, 1f + mv s1, ra -skip_user_signal_handler: - // enter user mode and enable interrupt when return to user mode +1: + /* enter user mode and enable interrupt when return to user mode */ li t0, SSTATUS_SPP csrc sstatus, t0 li t0, SSTATUS_SPIE csrs sstatus, t0 - // sepc <- signal_handler + /* sepc <- signal_handler */ csrw sepc, s1 - // a0 <- signal id + /* a0 <- signal id */ mv a0, s2 + /* a1 <- siginfo */ + add a1, sp, 16 + /* dummy a2 */ + mv a2, a1 + + /** + * handler(signo, psi, ucontext); + */ sret .align 3 @@ -234,6 +185,7 @@ lwp_debugreturn: ecall .align 3 +.global lwp_sigreturn lwp_sigreturn: li a7, 0xfe ecall diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c index 62fa39e0e7..c27f4ca172 100644 --- a/components/lwp/lwp.c +++ b/components/lwp/lwp.c @@ -13,6 +13,10 @@ * 2023-02-20 wangxiaoyao fix bug on foreground app switch */ +#define DBG_TAG "LWP" +#define DBG_LVL DBG_WARNING +#include + #include #include @@ -32,12 +36,10 @@ #include "lwp.h" #include "lwp_arch.h" #include "lwp_arch_comm.h" +#include "lwp_signal.h" +#include "lwp_dbg.h" #include "console.h" -#define DBG_TAG "LWP" -#define DBG_LVL DBG_WARNING -#include - #ifdef ARCH_MM_MMU #include #endif /* end of ARCH_MM_MMU */ @@ -1025,37 +1027,32 @@ out: return ret; } +/* lwp thread clean up */ void lwp_cleanup(struct rt_thread *tid) { rt_base_t level; struct rt_lwp *lwp; - struct tty_node *tty_head = RT_NULL; if (tid == NULL) { + LOG_I("%s: invalid parameter tid == NULL", __func__); return; } - - LOG_I("cleanup thread: %s, stack_addr: %08X", tid->parent.name, tid->stack_addr); + else + LOG_D("cleanup thread: %s, stack_addr: 0x%x", tid->parent.name, tid->stack_addr); level = rt_hw_interrupt_disable(); lwp = (struct rt_lwp *)tid->lwp; + /* lwp thread cleanup */ lwp_tid_put(tid->tid); rt_list_remove(&tid->sibling); - rt_hw_interrupt_enable(level); - if (lwp->tty != RT_NULL) - { - tty_head = lwp->tty->head; - } - if (!lwp_ref_dec(lwp)) - { - if (tty_head) - { - tty_pop(&tty_head, lwp); - } - } + lwp_thread_signal_detach(&tid->signal); + rt_hw_interrupt_enable(level); + + /* tty will be release in lwp_ref_dec() if ref is cleared */ + lwp_ref_dec(lwp); return; } diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h index 46b1671463..b9cc9c7aae 100644 --- a/components/lwp/lwp.h +++ b/components/lwp/lwp.h @@ -88,8 +88,10 @@ struct rt_lwp struct rt_lwp *sibling; rt_list_t wait_list; - int32_t finish; - int lwp_ret; + rt_bool_t finish; + rt_bool_t terminated; + rt_bool_t background; + int lwp_ret; void *text_entry; uint32_t text_size; @@ -109,12 +111,8 @@ struct rt_lwp struct dfs_fdtable fdt; char cmd[RT_NAME_MAX]; - int sa_flags; - lwp_sigset_t signal; - lwp_sigset_t signal_mask; - int signal_mask_bak; - rt_uint32_t signal_in_process; - lwp_sighandler_t signal_handler[_LWP_NSIG]; + /* POSIX signal */ + struct lwp_signal signal; struct lwp_avl_struct *object_root; struct rt_mutex object_mutex; @@ -123,10 +121,9 @@ struct rt_lwp struct rt_wqueue wait_queue; /*for console */ struct tty_struct *tty; /* NULL if no tty */ - struct lwp_avl_struct *address_search_head; /* for addressed object fast rearch */ + struct lwp_avl_struct *address_search_head; /* for addressed object fast search */ char working_directory[DFS_PATH_MAX]; int debug; - int background; uint32_t bak_first_ins; #ifdef LWP_ENABLE_ASID diff --git a/components/lwp/lwp_arch_comm.h b/components/lwp/lwp_arch_comm.h index 22d881b078..bfd91ec189 100644 --- a/components/lwp/lwp_arch_comm.h +++ b/components/lwp/lwp_arch_comm.h @@ -1,10 +1,12 @@ /* - * Copyright (c) 2006-2021, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes + * 2022-09-30 RT-Thread the general porting API for lwp + * 2023-07-18 Shell New signal arch API arch_thread_signal_enter */ #ifndef __LWP_ARCH_COMM__ @@ -54,4 +56,9 @@ void arch_set_thread_area(void *p); void* arch_get_tidr(void); void arch_set_tidr(void *p); +/** entry point of architecture signal handling */ +rt_noreturn void arch_thread_signal_enter(int signo, siginfo_t *psiginfo, + void *exp_frame, void *entry_uaddr, + lwp_sigset_t *save_sig_mask); + #endif /* __LWP_ARCH_COMM__ */ diff --git a/components/lwp/lwp_clone.h b/components/lwp/lwp_clone.h new file mode 100644 index 0000000000..8623e5b1e1 --- /dev/null +++ b/components/lwp/lwp_clone.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-06 RT-Thread the first version + */ +#ifndef __LWP_CLONE_H__ +#define __LWP_CLONE_H__ + +#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 + +#endif /* __LWP_CLONE_H__ */ diff --git a/components/lwp/lwp_dbg.h b/components/lwp/lwp_dbg.h new file mode 100644 index 0000000000..84544759d9 --- /dev/null +++ b/components/lwp/lwp_dbg.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-07-11 RT-Thread first version + */ + +#ifndef __LWP_DBG_H__ +#define __LWP_DBG_H__ + +#include +#include +#include + +int dbg_thread_in_debug(void); +void dbg_register(struct dbg_ops_t *dbg_ops); +uint32_t dbg_get_ins(void); +void dbg_activate_step(void); +void dbg_deactivate_step(void); +int dbg_check_event(struct rt_hw_exp_stack *regs, unsigned long esr); +rt_channel_t gdb_server_channel(void); +int dbg_step_type(void); +void dbg_attach_req(void *pc); +int dbg_check_suspend(void); + +#endif /* __LWP_DBG_H__ */ diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c index d9710ad356..82d9c30570 100644 --- a/components/lwp/lwp_pid.c +++ b/components/lwp/lwp_pid.c @@ -22,6 +22,7 @@ #include "lwp.h" #include "lwp_pid.h" +#include "lwp_signal.h" #include "tty.h" #ifdef ARCH_MM_MMU @@ -319,7 +320,7 @@ struct rt_lwp* lwp_new(void) { return lwp; } - rt_memset(lwp, 0, sizeof(*lwp)); + memset(lwp, 0, sizeof(*lwp)); //lwp->tgroup_leader = RT_NULL; rt_list_init(&lwp->wait_list); lwp->leader = 0; @@ -331,6 +332,8 @@ struct rt_lwp* lwp_new(void) rt_wqueue_init(&lwp->wait_queue); lwp->ref = 1; + lwp_signal_init(&lwp->signal); + level = rt_hw_interrupt_disable(); pid = lwp_pid_get(); if (pid == 0) @@ -475,34 +478,33 @@ void lwp_free(struct rt_lwp* lwp) } /* for parent */ + if (lwp->parent) { - if (lwp->parent) + struct rt_thread *thread; + if (!rt_list_isempty(&lwp->wait_list)) { - struct rt_thread *thread; - if (!rt_list_isempty(&lwp->wait_list)) - { - thread = rt_list_entry(lwp->wait_list.next, struct rt_thread, tlist); - thread->error = RT_EOK; - thread->msg_ret = (void*)(rt_size_t)lwp->lwp_ret; - rt_thread_resume(thread); - rt_hw_interrupt_enable(level); - return; - } - else - { - struct rt_lwp **it = &lwp->parent->first_child; - - while (*it != lwp) - { - it = &(*it)->sibling; - } - *it = lwp->sibling; - } + thread = rt_list_entry(lwp->wait_list.next, struct rt_thread, tlist); + thread->error = RT_EOK; + thread->msg_ret = (void*)(rt_size_t)lwp->lwp_ret; + rt_thread_resume(thread); + rt_hw_interrupt_enable(level); + return; + } + else + { + struct rt_lwp **it = &lwp->parent->first_child; + + while (*it != lwp) + { + it = &(*it)->sibling; + } + *it = lwp->sibling; } - lwp_pid_put(lwp_to_pid(lwp)); - rt_hw_interrupt_enable(level); - rt_free(lwp); } + + lwp_pid_put(lwp_to_pid(lwp)); + rt_hw_interrupt_enable(level); + rt_free(lwp); } int lwp_ref_inc(struct rt_lwp *lwp) @@ -537,6 +539,7 @@ int lwp_ref_dec(struct rt_lwp *lwp) memset(&msg, 0, sizeof msg); rt_raw_channel_send(gdb_server_channel(), &msg); } + lwp_signal_detach(&lwp->signal); #ifndef ARCH_MM_MMU #ifdef RT_LWP_USING_SHM @@ -846,7 +849,7 @@ static void cmd_kill(int argc, char** argv) sig = atoi(argv[3]); } } - lwp_kill(pid, sig); + lwp_signal_kill(lwp_from_pid(pid), sig, SI_USER, 0); } MSH_CMD_EXPORT_ALIAS(cmd_kill, kill, send a signal to a process); @@ -861,7 +864,7 @@ static void cmd_killall(int argc, char** argv) while((pid = lwp_name2pid(argv[1])) > 0) { - lwp_kill(pid, SIGKILL); + lwp_signal_kill(lwp_from_pid(pid), SIGKILL, SI_USER, 0); rt_thread_mdelay(100); } } @@ -979,6 +982,11 @@ void lwp_terminate(struct rt_lwp *lwp) } level = rt_hw_interrupt_disable(); + + /* stop the receiving of signals */ + lwp->terminated = RT_TRUE; + + /* broadcast exit request for sibling threads */ for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next) { rt_thread_t thread; diff --git a/components/lwp/lwp_pid.h b/components/lwp/lwp_pid.h index 901c6f80b8..06855c9188 100644 --- a/components/lwp/lwp_pid.h +++ b/components/lwp/lwp_pid.h @@ -11,6 +11,8 @@ #ifndef LWP_PID_H__ #define LWP_PID_H__ +#include "lwp.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/components/lwp/lwp_signal.c b/components/lwp/lwp_signal.c index 44a1083c57..704c9f0a83 100644 --- a/components/lwp/lwp_signal.c +++ b/components/lwp/lwp_signal.c @@ -1,21 +1,115 @@ /* - * Copyright (c) 2006-2020, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-11-12 Jesven first version + * 2023-02-23 Shell Support sigtimedwait + * 2023-07-04 Shell Support siginfo, sigqueue + * remove lwp_signal_backup/restore() to reduce architecture codes + * update the generation, pending and delivery routines */ +#define DBG_TAG "LWP_SIGNAL" +#define DBG_LVL DBG_INFO +#include + #include #include +#include #include "lwp.h" #include "lwp_arch.h" +#include "lwp_signal.h" #include "sys/signal.h" +#include "syscall_generic.h" -rt_inline void lwp_sigaddset(lwp_sigset_t *set, int _sig) +static lwp_siginfo_t siginfo_create(int signo, int code, int value) +{ + lwp_siginfo_t siginfo; + struct rt_lwp *self_lwp; + rt_thread_t self_thr; + + siginfo = rt_malloc(sizeof(*siginfo)); + if (siginfo) + { + siginfo->ksiginfo.signo = signo; + siginfo->ksiginfo.code = code; + siginfo->ksiginfo.value = value; + + self_lwp = lwp_self(); + self_thr = rt_thread_self(); + if (self_lwp) + { + siginfo->ksiginfo.from_pid = self_lwp->pid; + siginfo->ksiginfo.from_tid = self_thr->tid; + } + else + { + siginfo->ksiginfo.from_pid = 0; + siginfo->ksiginfo.from_tid = 0; + } + } + + return siginfo; +} + +rt_inline void siginfo_delete(lwp_siginfo_t siginfo) +{ + rt_free(siginfo); +} + +rt_inline void _sigorsets(lwp_sigset_t *dset, const lwp_sigset_t *set0, const lwp_sigset_t *set1) +{ + switch (_LWP_NSIG_WORDS) + { + case 4: + dset->sig[3] = set0->sig[3] | set1->sig[3]; + dset->sig[2] = set0->sig[2] | set1->sig[2]; + case 2: + dset->sig[1] = set0->sig[1] | set1->sig[1]; + case 1: + dset->sig[0] = set0->sig[0] | set1->sig[0]; + default: + return; + } +} + +rt_inline void _sigandsets(lwp_sigset_t *dset, const lwp_sigset_t *set0, const lwp_sigset_t *set1) +{ + switch (_LWP_NSIG_WORDS) + { + case 4: + dset->sig[3] = set0->sig[3] & set1->sig[3]; + dset->sig[2] = set0->sig[2] & set1->sig[2]; + case 2: + dset->sig[1] = set0->sig[1] & set1->sig[1]; + case 1: + dset->sig[0] = set0->sig[0] & set1->sig[0]; + default: + return; + } +} + +rt_inline void _signotsets(lwp_sigset_t *dset, const lwp_sigset_t *set) +{ + switch (_LWP_NSIG_WORDS) + { + case 4: + dset->sig[3] = ~set->sig[3]; + dset->sig[2] = ~set->sig[2]; + case 2: + dset->sig[1] = ~set->sig[1]; + case 1: + dset->sig[0] = ~set->sig[0]; + default: + return; + } +} + +rt_inline void _sigaddset(lwp_sigset_t *set, int _sig) { unsigned long sig = _sig - 1; @@ -29,7 +123,7 @@ rt_inline void lwp_sigaddset(lwp_sigset_t *set, int _sig) } } -rt_inline void lwp_sigdelset(lwp_sigset_t *set, int _sig) +rt_inline void _sigdelset(lwp_sigset_t *set, int _sig) { unsigned long sig = _sig - 1; @@ -43,7 +137,7 @@ rt_inline void lwp_sigdelset(lwp_sigset_t *set, int _sig) } } -rt_inline int lwp_sigisemptyset(lwp_sigset_t *set) +rt_inline int _sigisemptyset(lwp_sigset_t *set) { switch (_LWP_NSIG_WORDS) { @@ -59,7 +153,7 @@ rt_inline int lwp_sigisemptyset(lwp_sigset_t *set) } } -rt_inline int lwp_sigismember(lwp_sigset_t *set, int _sig) +rt_inline int _sigismember(lwp_sigset_t *set, int _sig) { unsigned long sig = _sig - 1; @@ -73,7 +167,7 @@ rt_inline int lwp_sigismember(lwp_sigset_t *set, int _sig) } } -rt_inline int next_signal(lwp_sigset_t *pending, lwp_sigset_t *mask) +rt_inline int _next_signal(lwp_sigset_t *pending, lwp_sigset_t *mask) { unsigned long i, *s, *m, x; int sig = 0; @@ -116,7 +210,218 @@ rt_inline int next_signal(lwp_sigset_t *pending, lwp_sigset_t *mask) return sig; } -int lwp_suspend_sigcheck(rt_thread_t thread, int suspend_flag) +#define _SIGQ(tp) (&(tp)->signal.sig_queue) + +rt_inline int sigqueue_isempty(lwp_sigqueue_t sigqueue) +{ + return _sigisemptyset(&sigqueue->sigset_pending); +} + +rt_inline int sigqueue_ismember(lwp_sigqueue_t sigqueue, int signo) +{ + return _sigismember(&sigqueue->sigset_pending, signo); +} + +rt_inline int sigqueue_peek(lwp_sigqueue_t sigqueue, lwp_sigset_t *mask) +{ + return _next_signal(&sigqueue->sigset_pending, mask); +} + +rt_inline int sigqueue_examine(lwp_sigqueue_t sigqueue, lwp_sigset_t *pending) +{ + lwp_sigset_t not_mask; + int is_empty = sigqueue_isempty(sigqueue); + if (!is_empty) + { + _sigorsets(pending, &sigqueue->sigset_pending, ¬_mask); + } + return is_empty; +} + +static void sigqueue_enqueue(lwp_sigqueue_t sigqueue, lwp_siginfo_t siginfo) +{ + lwp_siginfo_t idx; + rt_bool_t inserted = RT_FALSE; + rt_list_for_each_entry(idx, &sigqueue->siginfo_list, node) + { + if (idx->ksiginfo.signo >= siginfo->ksiginfo.signo) + { + rt_list_insert_after(&idx->node, &siginfo->node); + inserted = RT_TRUE; + break; + } + } + + if (!inserted) + rt_list_insert_before(&sigqueue->siginfo_list, &siginfo->node); + + _sigaddset(&sigqueue->sigset_pending, siginfo->ksiginfo.signo); + return ; +} + +/** + * dequeue a siginfo matching the signo which is likely to be existed, and + * test if any other siblings remains + */ +static lwp_siginfo_t sigqueue_dequeue(lwp_sigqueue_t sigqueue, int signo) +{ + lwp_siginfo_t found; + lwp_siginfo_t candidate; + lwp_siginfo_t next; + rt_bool_t is_empty; + + found = RT_NULL; + is_empty = RT_TRUE; + rt_list_for_each_entry_safe(candidate, next, &sigqueue->siginfo_list, node) + { + if (candidate->ksiginfo.signo == signo) + { + if (found) + { + /* already found */ + is_empty = RT_FALSE; + break; + } + else + { + /* found first */ + found = candidate; + rt_list_remove(&found->node); + } + } + else if (candidate->ksiginfo.signo > signo) + break; + } + + if (found && is_empty) + _sigdelset(&sigqueue->sigset_pending, signo); + + return found; +} + +static void sigqueue_discard(lwp_sigqueue_t sigqueue, int signo) +{ + lwp_siginfo_t queuing_si; + while (!sigqueue_isempty(sigqueue)) + { + queuing_si = sigqueue_dequeue(sigqueue, signo); + siginfo_delete(queuing_si); + } +} + +/* assuming that (void *) is compatible to long at length */ +RT_CTASSERT(lp_width_same, sizeof(void *) == sizeof(long)); + +/** translate lwp siginfo to user siginfo_t */ +rt_inline void siginfo_k2u(lwp_siginfo_t ksigi, siginfo_t *usigi) +{ + usigi->si_code = ksigi->ksiginfo.code; + usigi->si_signo = ksigi->ksiginfo.signo; + usigi->si_value.sival_ptr = (void *)ksigi->ksiginfo.value; + usigi->si_pid = ksigi->ksiginfo.from_pid; + + /* deprecated field */ + usigi->si_errno = 0; +} + +/* must called in locked context */ +rt_inline lwp_sighandler_t _get_sighandler_locked(struct rt_lwp *lwp, int signo) +{ + return lwp->signal.sig_action[signo - 1]; +} + +static lwp_sigset_t *_mask_block_fn(rt_thread_t thread, const lwp_sigset_t *sigset, lwp_sigset_t *new_set) +{ + _sigorsets(new_set, &thread->signal.sigset_mask, sigset); + return new_set; +} + +static lwp_sigset_t *_mask_unblock_fn(rt_thread_t thread, const lwp_sigset_t *sigset, lwp_sigset_t *new_set) +{ + lwp_sigset_t complement; + _signotsets(&complement, sigset); + _sigandsets(new_set, &thread->signal.sigset_mask, &complement); + return new_set; +} + +static lwp_sigset_t *_mask_set_fn(rt_thread_t thread, const lwp_sigset_t *sigset, lwp_sigset_t *new_set) +{ + memcpy(new_set, sigset, sizeof(*sigset)); + return new_set; +} + +static lwp_sigset_t *(*_sig_mask_fn[__LWP_SIG_MASK_CMD_WATERMARK]) + (rt_thread_t thread, const lwp_sigset_t *sigset, lwp_sigset_t *new_set) = { + [LWP_SIG_MASK_CMD_BLOCK] = _mask_block_fn, + [LWP_SIG_MASK_CMD_UNBLOCK] = _mask_unblock_fn, + [LWP_SIG_MASK_CMD_SET_MASK] = _mask_set_fn, + }; + +static void _thread_signal_mask(rt_thread_t thread, lwp_sig_mask_cmd_t how, + const lwp_sigset_t *sigset, lwp_sigset_t *oset) +{ + lwp_sigset_t new_set; + + /** + * @note POSIX wants this API to be capable to query the current mask + * by passing NULL in `sigset` + */ + if (oset) + memcpy(oset, &thread->signal.sigset_mask, sizeof(lwp_sigset_t)); + + if (sigset) + { + _sig_mask_fn[how](thread, sigset, &new_set); + + /* remove un-maskable signal from set */ + _sigdelset(&new_set, SIGKILL); + _sigdelset(&new_set, SIGSTOP); + + memcpy(&thread->signal.sigset_mask, &new_set, sizeof(lwp_sigset_t)); + } +} + +void lwp_sigqueue_clear(lwp_sigqueue_t sigq) +{ + lwp_siginfo_t this, next; + if (!sigqueue_isempty(sigq)) + { + rt_list_for_each_entry_safe(this, next, &sigq->siginfo_list, node) + { + siginfo_delete(this); + } + } +} + +rt_err_t lwp_signal_init(struct lwp_signal *sig) +{ + rt_err_t rc; + rc = rt_mutex_init(&sig->sig_lock, "lwpsig", RT_IPC_FLAG_FIFO); + if (rc == RT_EOK) + { + memset(&sig->sig_dispatch_thr, 0, sizeof(sig->sig_dispatch_thr)); + + memset(&sig->sig_action, 0, sizeof(sig->sig_action)); + memset(&sig->sig_action_nodefer, 0, sizeof(sig->sig_action_nodefer)); + memset(&sig->sig_action_onstack, 0, sizeof(sig->sig_action_onstack)); + memset(&sig->sig_action_restart, 0, sizeof(sig->sig_action_restart)); + memset(&sig->sig_action_siginfo, 0, sizeof(sig->sig_action_siginfo)); + lwp_sigqueue_init(&sig->sig_queue); + } + return rc; +} + +rt_err_t lwp_signal_detach(struct lwp_signal *signal) +{ + rt_err_t ret; + + lwp_sigqueue_clear(&signal->sig_queue); + ret = rt_mutex_detach(&signal->sig_lock); + + return ret; +} + +int lwp_thread_signal_suspend_check(rt_thread_t thread, int suspend_flag) { struct rt_lwp *lwp = (struct rt_lwp*)thread->lwp; int ret = 0; @@ -124,22 +429,22 @@ int lwp_suspend_sigcheck(rt_thread_t thread, int suspend_flag) switch (suspend_flag) { case RT_INTERRUPTIBLE: - if (!lwp_sigisemptyset(&thread->signal)) + if (!sigqueue_isempty(_SIGQ(thread))) { break; } - if (thread->lwp && !lwp_sigisemptyset(&lwp->signal)) + if (thread->lwp && !sigqueue_isempty(_SIGQ(lwp))) { break; } ret = 1; break; case RT_KILLABLE: - if (lwp_sigismember(&thread->signal, SIGKILL)) + if (sigqueue_ismember(_SIGQ(thread), SIGKILL)) { break; } - if (thread->lwp && lwp_sigismember(&lwp->signal, SIGKILL)) + if (thread->lwp && sigqueue_ismember(_SIGQ(lwp), SIGKILL)) { break; } @@ -155,180 +460,411 @@ int lwp_suspend_sigcheck(rt_thread_t thread, int suspend_flag) return ret; } -int lwp_signal_check(void) +void lwp_thread_signal_catch(void *exp_frame) { rt_base_t level; + int signo; struct rt_thread *thread; struct rt_lwp *lwp; - uint32_t have_signal = 0; - - level = rt_hw_interrupt_disable(); + lwp_siginfo_t siginfo; + lwp_sigqueue_t pending; + lwp_sigset_t *sig_mask; + lwp_sigset_t save_sig_mask; + lwp_sigset_t new_sig_mask; + lwp_sighandler_t handler; + siginfo_t usiginfo; + siginfo_t *p_usi; thread = rt_thread_self(); - - if (thread->signal_in_process) - { - goto out; - } - lwp = (struct rt_lwp*)thread->lwp; - if (lwp->signal_in_process) - { - goto out; - } - - have_signal = !lwp_sigisemptyset(&thread->signal); - if (have_signal) - { - thread->signal_in_process = 1; - goto out; - } - have_signal = !lwp_sigisemptyset(&lwp->signal); - if (have_signal) - { - lwp->signal_in_process = 1; - } -out: - rt_hw_interrupt_enable(level); - return have_signal; -} - -int lwp_signal_backup(void *user_sp, void *user_pc, void* user_flag) -{ - rt_base_t level; - struct rt_thread *thread; - struct rt_lwp *lwp; - int signal; - + RT_ASSERT(!!lwp); level = rt_hw_interrupt_disable(); - thread = rt_thread_self(); - if (thread->signal_in_process) - { - thread->user_ctx.sp = user_sp; - thread->user_ctx.pc = user_pc; - thread->user_ctx.flag = user_flag; - signal = next_signal(&thread->signal, &thread->signal_mask); - RT_ASSERT(signal != 0); - lwp_sigaddset(&thread->signal_mask, signal); - thread->signal_mask_bak = signal; - lwp_sigdelset(&thread->signal, signal); + /* check if signal exist */ + if (!sigqueue_isempty(_SIGQ(thread))) + { + pending = _SIGQ(thread); + sig_mask = &thread->signal.sigset_mask; + } + else if (!sigqueue_isempty(_SIGQ(lwp))) + { + pending = _SIGQ(lwp); + sig_mask = &thread->signal.sigset_mask; } else { - lwp = (struct rt_lwp*)thread->lwp; - lwp->user_ctx.sp = user_sp; - lwp->user_ctx.pc = user_pc; - lwp->user_ctx.flag = user_flag; + pending = RT_NULL; + } - signal = next_signal(&lwp->signal, &lwp->signal_mask); - RT_ASSERT(signal != 0); - lwp_sigaddset(&lwp->signal_mask, signal); - lwp->signal_mask_bak = signal; - lwp_sigdelset(&lwp->signal, signal); + if (pending) + { + /* peek the pending signal */ + signo = sigqueue_peek(pending, sig_mask); + if (signo) + { + siginfo = sigqueue_dequeue(pending, signo); + RT_ASSERT(siginfo != RT_NULL); + handler = _get_sighandler_locked(lwp, signo); + + /* IGN signal will never be queued */ + RT_ASSERT(handler != LWP_SIG_ACT_IGN); + + /* copy the blocked signal mask from the registered signal action */ + memcpy(&new_sig_mask, &lwp->signal.sig_action_mask[signo - 1], sizeof(new_sig_mask)); + + if (!_sigismember(&lwp->signal.sig_action_nodefer, signo)) + _sigaddset(&new_sig_mask, signo); + + _thread_signal_mask(thread, LWP_SIG_MASK_CMD_BLOCK, &new_sig_mask, &save_sig_mask); + + /* siginfo is need for signal action */ + if (_sigismember(&lwp->signal.sig_action_siginfo, signo)) + { + siginfo_k2u(siginfo, &usiginfo); + p_usi = &usiginfo; + } + else + p_usi = RT_NULL; + } } rt_hw_interrupt_enable(level); - return signal; + + if (pending && signo) + { + siginfo_delete(siginfo); + + /* signal default handler */ + if (handler == LWP_SIG_ACT_DFL) + { + LOG_D("%s: default handler; and exit", __func__); + sys_exit(0); + } + + /** + * enter signal action of user + * @note that the p_usi is release before entering signal action by + * reseting the kernel sp. + */ + arch_thread_signal_enter(signo, p_usi, exp_frame, handler, &save_sig_mask); + /* the arch_thread_signal_enter() never return */ + RT_ASSERT(0); + } } -struct rt_user_context *lwp_signal_restore(void) +static int _do_signal_wakeup(rt_thread_t thread, int sig) { - rt_base_t level; - struct rt_thread *thread; - struct rt_lwp *lwp; - struct rt_user_context *ctx; - - level = rt_hw_interrupt_disable(); - thread = rt_thread_self(); - if (thread->signal_in_process) + int need_schedule; + if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) { - ctx = &thread->user_ctx; - thread->signal_in_process = 0; - lwp_sigdelset(&thread->signal_mask, thread->signal_mask_bak); - thread->signal_mask_bak = 0; + if ((thread->stat & RT_SIGNAL_COMMON_WAKEUP_MASK) != RT_SIGNAL_COMMON_WAKEUP_MASK) + { + rt_thread_wakeup(thread); + need_schedule = 1; + } + else if ((sig == SIGKILL) && ((thread->stat & RT_SIGNAL_KILL_WAKEUP_MASK) != RT_SIGNAL_KILL_WAKEUP_MASK)) + { + rt_thread_wakeup(thread); + need_schedule = 1; + } + else + { + need_schedule = 0; + } + } + else + need_schedule = 0; + + return need_schedule; +} + +/** find a candidate to be notified of the arrival */ +static rt_thread_t _signal_find_catcher(struct rt_lwp *lwp, int signo) +{ + rt_thread_t catcher = RT_NULL; + rt_thread_t candidate; + + candidate = lwp->signal.sig_dispatch_thr[signo - 1]; + if (candidate != RT_NULL && !_sigismember(&candidate->signal.sigset_mask, signo)) + { + catcher = candidate; } else { - lwp = (struct rt_lwp*)thread->lwp; - ctx = &lwp->user_ctx; - RT_ASSERT(lwp->signal_in_process != 0); - lwp->signal_in_process = 0; + candidate = rt_thread_self(); - lwp_sigdelset(&lwp->signal_mask, lwp->signal_mask_bak); - lwp->signal_mask_bak = 0; + /** @note: lwp of current is a const value that can be safely read */ + if (candidate->lwp == lwp && + !_sigismember(&candidate->signal.sigset_mask, signo)) + { + catcher = candidate; + } + else + { + rt_list_for_each_entry(candidate, &lwp->t_grp, sibling) + { + if (!_sigismember(&candidate->signal.sigset_mask, signo)) + { + catcher = candidate; + break; + } + } + + /* fall back to main thread */ + if (catcher == RT_NULL) + catcher = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling); + } + + /* reset the cache thread to catcher (even if catcher is main thread) */ + lwp->signal.sig_dispatch_thr[signo - 1] = catcher; } - rt_hw_interrupt_enable(level); - return ctx; + + return catcher; } -rt_inline int _lwp_check_ignore(int sig) +static int _siginfo_deliver_to_lwp(struct rt_lwp *lwp, lwp_siginfo_t siginfo) { - if (sig == SIGCHLD || sig == SIGCONT) + rt_thread_t catcher; + + catcher = _signal_find_catcher(lwp, siginfo->ksiginfo.signo); + + sigqueue_enqueue(&lwp->signal.sig_queue, siginfo); + return _do_signal_wakeup(catcher, siginfo->ksiginfo.signo); +} + +static int _siginfo_deliver_to_thread(struct rt_lwp *lwp, rt_thread_t thread, lwp_siginfo_t siginfo) +{ + sigqueue_enqueue(_SIGQ(thread), siginfo); + return _do_signal_wakeup(thread, siginfo->ksiginfo.signo); +} + +rt_inline rt_bool_t _sighandler_is_ignored(struct rt_lwp *lwp, int signo) +{ + rt_bool_t is_ignored; + lwp_sighandler_t action; + lwp_sigset_t ign_set = lwp_sigset_init(LWP_SIG_IGNORE_SET); + + action = _get_sighandler_locked(lwp, signo); + + if (action == LWP_SIG_ACT_IGN) + is_ignored = RT_TRUE; + else if (action == LWP_SIG_ACT_DFL && _sigismember(&ign_set, signo)) + is_ignored = RT_TRUE; + else + is_ignored = RT_FALSE; + + return is_ignored; +} + +rt_inline rt_bool_t _sighandler_cannot_caught(struct rt_lwp *lwp, int signo) +{ + return signo == SIGKILL || signo == SIGSTOP; +} + +rt_err_t lwp_signal_kill(struct rt_lwp *lwp, long signo, long code, long value) +{ + rt_err_t ret = -1; + rt_base_t level; + lwp_siginfo_t siginfo; + rt_bool_t terminated; + rt_bool_t need_schedule; + + /** must be able to be suspended */ + RT_DEBUG_SCHEDULER_AVAILABLE(RT_TRUE); + + if (!lwp || signo < 0 || signo >= _LWP_NSIG) { - return 1; + ret = -RT_EINVAL; } - return 0; + else + { + need_schedule = RT_FALSE; + + /* FIXME: acquire READ lock to lwp */ + level = rt_hw_interrupt_disable(); + terminated = lwp->terminated; + + /* short-circuit code for inactive task, ignored signals */ + if (terminated || _sighandler_is_ignored(lwp, signo)) + { + ret = 0; + } + else + { + siginfo = siginfo_create(signo, code, value); + + if (siginfo) + { + need_schedule = _siginfo_deliver_to_lwp(lwp, siginfo); + ret = 0; + } + else + { + LOG_I("%s: siginfo malloc failed", __func__); + ret = -RT_ENOMEM; + } + } + + rt_hw_interrupt_enable(level); + + if (need_schedule) + rt_schedule(); + } + return ret; } -void sys_exit(int value); -lwp_sighandler_t lwp_sighandler_get(int sig) +static void _signal_action_flag_k2u(int signo, struct lwp_signal *signal, struct lwp_sigaction *act) { - lwp_sighandler_t func = RT_NULL; + long flags = 0; + if (_sigismember(&signal->sig_action_nodefer, signo)) + flags |= SA_NODEFER; + if (_sigismember(&signal->sig_action_onstack, signo)) + flags |= SA_ONSTACK; + if (_sigismember(&signal->sig_action_restart, signo)) + flags |= SA_RESTART; + if (_sigismember(&signal->sig_action_siginfo, signo)) + flags |= SA_SIGINFO; + + act->sa_flags = flags; +} + +static void _signal_action_flag_u2k(int signo, struct lwp_signal *signal, const struct lwp_sigaction *act) +{ + long flags = act->sa_flags; + if (flags & SA_NODEFER) + _sigaddset(&signal->sig_action_nodefer, signo); + if (flags & SA_ONSTACK) + _sigaddset(&signal->sig_action_onstack, signo); + if (flags & SA_RESTART) + _sigaddset(&signal->sig_action_restart, signo); + if (flags & SA_SIGINFO) + _sigaddset(&signal->sig_action_siginfo, signo); +} + +rt_err_t lwp_signal_action(struct rt_lwp *lwp, int signo, + const struct lwp_sigaction *restrict act, + struct lwp_sigaction *restrict oact) +{ + lwp_sighandler_t prev_handler; + lwp_sigqueue_t thread_sigq; + rt_list_t *thread_list; + rt_err_t ret = RT_EOK; + rt_base_t level; + + if (lwp) + { + /** acquire READ access to lwp */ + level = rt_hw_interrupt_disable(); + + if (oact) + { + oact->sa_mask = lwp->signal.sig_action_mask[signo - 1]; + oact->__sa_handler._sa_handler = lwp->signal.sig_action[signo - 1]; + oact->sa_restorer = RT_NULL; + _signal_action_flag_k2u(signo, &lwp->signal, oact); + } + if (act) + { + /** + * @note POSIX.1-2017 requires calls to sigaction() that supply a NULL act + * argument succeed, even in the case of signals that cannot be caught or ignored + */ + if (_sighandler_cannot_caught(lwp, signo)) + ret = -RT_EINVAL; + else + { + prev_handler = _get_sighandler_locked(lwp, signo); + lwp->signal.sig_action_mask[signo - 1] = act->sa_mask; + if (act->__sa_handler._sa_handler == SIG_IGN) + lwp->signal.sig_action[signo - 1] = LWP_SIG_ACT_IGN; + else + lwp->signal.sig_action[signo - 1] = act->__sa_handler._sa_handler; + + _signal_action_flag_u2k(signo, &lwp->signal, act); + + /** + * @brief Discard the pending signal if signal action is set to SIG_IGN + * + * @note POSIX.1-2017: Setting a signal action to SIG_IGN for a signal + * that is pending shall cause the pending signal to be discarded, + * whether or not it is blocked. + */ + if (prev_handler != LWP_SIG_ACT_IGN && + _get_sighandler_locked(lwp, signo) == LWP_SIG_ACT_IGN) + { + sigqueue_discard(_SIGQ(lwp), signo); + for (thread_list = lwp->t_grp.next; + thread_list != &lwp->t_grp; + thread_list = thread_list->next) + { + thread_sigq = _SIGQ(rt_list_entry(thread_list, struct rt_thread, sibling)); + sigqueue_discard(thread_sigq, signo); + } + } + } + } + + rt_hw_interrupt_enable(level); + } + else + ret = -RT_EINVAL; + + return ret; +} + +rt_err_t lwp_thread_signal_kill(rt_thread_t thread, long signo, long code, long value) +{ + rt_err_t ret = -1; + rt_base_t level; struct rt_lwp *lwp; - rt_thread_t thread; - rt_base_t level; + lwp_siginfo_t siginfo; + rt_bool_t need_schedule; - if (sig == 0 || sig > _LWP_NSIG) - { - return func; - } - level = rt_hw_interrupt_disable(); - thread = rt_thread_self(); -#ifndef ARCH_MM_MMU - if (thread->signal_in_process) - { - func = thread->signal_handler[sig - 1]; - goto out; - } -#endif - lwp = (struct rt_lwp*)thread->lwp; + /** must be able to be suspended */ + RT_DEBUG_SCHEDULER_AVAILABLE(RT_TRUE); - func = lwp->signal_handler[sig - 1]; - if (!func) + if (!thread || signo < 0 || signo >= _LWP_NSIG) { - if (_lwp_check_ignore(sig)) + ret = -RT_EINVAL; + } + else + { + lwp = thread->lwp; + need_schedule = RT_FALSE; + + RT_ASSERT(lwp); + + /* FIXME: acquire READ lock to lwp */ + level = rt_hw_interrupt_disable(); + + if (!lwp) + ret = -RT_EPERM; + else if (lwp->terminated || _sighandler_is_ignored(lwp, signo)) + ret = 0; + else { - goto out; + siginfo = siginfo_create(signo, code, value); + + if (siginfo) + { + need_schedule = _siginfo_deliver_to_thread(lwp, thread, siginfo); + ret = 0; + } + else + { + LOG_I("%s: siginfo malloc failed", __func__); + ret = -RT_ENOMEM; + } } - if (lwp->signal_in_process) - { - lwp_terminate(lwp); - } - sys_exit(0); + + rt_hw_interrupt_enable(level); + + if (need_schedule) + rt_schedule(); } -out: - rt_hw_interrupt_enable(level); - if (func == (lwp_sighandler_t)SIG_IGN) - { - func = RT_NULL; - } - return func; -} - -void lwp_sighandler_set(int sig, lwp_sighandler_t func) -{ - rt_base_t level; - - if (sig == 0 || sig > _LWP_NSIG) - return; - if (sig == SIGKILL || sig == SIGSTOP) - return; - level = rt_hw_interrupt_disable(); - ((struct rt_lwp*)rt_thread_self()->lwp)->signal_handler[sig - 1] = func; - rt_hw_interrupt_enable(level); + return ret; } #ifndef ARCH_MM_MMU @@ -344,263 +880,153 @@ void lwp_thread_sighandler_set(int sig, lwp_sighandler_t func) } #endif -int lwp_sigaction(int sig, const struct lwp_sigaction *act, - struct lwp_sigaction *oact, size_t sigsetsize) +rt_err_t lwp_thread_signal_mask(rt_thread_t thread, lwp_sig_mask_cmd_t how, + const lwp_sigset_t *sigset, lwp_sigset_t *oset) { + rt_err_t ret = -1; rt_base_t level; struct rt_lwp *lwp; - int ret = -RT_EINVAL; - lwp_sigset_t newset; - level = rt_hw_interrupt_disable(); - lwp = (struct rt_lwp*)rt_thread_self()->lwp; - if (!lwp) + if (thread) { - goto out; - } - if (sigsetsize != sizeof(lwp_sigset_t)) - { - goto out; - } - if (!act && !oact) - { - goto out; - } - if (oact) - { - oact->sa_flags = lwp->sa_flags; - oact->sa_mask = lwp->signal_mask; - oact->sa_restorer = RT_NULL; - oact->__sa_handler._sa_handler = lwp->signal_handler[sig - 1]; - } - if (act) - { - lwp->sa_flags = act->sa_flags; - newset = act->sa_mask; - lwp_sigdelset(&newset, SIGKILL); - lwp_sigdelset(&newset, SIGSTOP); - lwp->signal_mask = newset; - lwp_sighandler_set(sig, act->__sa_handler._sa_handler); - } - ret = 0; -out: - rt_hw_interrupt_enable(level); - return ret; -} + /** FIXME: acquire READ access to rt_thread */ + level = rt_hw_interrupt_disable(); -rt_inline void sigorsets(lwp_sigset_t *dset, const lwp_sigset_t *set0, const lwp_sigset_t *set1) -{ - switch (_LWP_NSIG_WORDS) - { - case 4: - dset->sig[3] = set0->sig[3] | set1->sig[3]; - dset->sig[2] = set0->sig[2] | set1->sig[2]; - case 2: - dset->sig[1] = set0->sig[1] | set1->sig[1]; - case 1: - dset->sig[0] = set0->sig[0] | set1->sig[0]; - default: - return; - } -} - -rt_inline void sigandsets(lwp_sigset_t *dset, const lwp_sigset_t *set0, const lwp_sigset_t *set1) -{ - switch (_LWP_NSIG_WORDS) - { - case 4: - dset->sig[3] = set0->sig[3] & set1->sig[3]; - dset->sig[2] = set0->sig[2] & set1->sig[2]; - case 2: - dset->sig[1] = set0->sig[1] & set1->sig[1]; - case 1: - dset->sig[0] = set0->sig[0] & set1->sig[0]; - default: - return; - } -} - -int lwp_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset) -{ - int ret = -1; - rt_base_t level; - struct rt_lwp *lwp; - struct rt_thread *thread; - lwp_sigset_t newset; - - level = rt_hw_interrupt_disable(); - - thread = rt_thread_self(); - lwp = (struct rt_lwp*)thread->lwp; - if (!lwp) - { - goto out; - } - if (oset) - { - rt_memcpy(oset, &lwp->signal_mask, sizeof(lwp_sigset_t)); - } - - if (sigset) - { - switch (how) + lwp = (struct rt_lwp*)thread->lwp; + if (!lwp) { - case SIG_BLOCK: - sigorsets(&newset, &lwp->signal_mask, sigset); - break; - case SIG_UNBLOCK: - sigandsets(&newset, &lwp->signal_mask, sigset); - break; - case SIG_SETMASK: - newset = *sigset; - break; - default: - ret = -RT_EINVAL; - goto out; - } - - lwp_sigdelset(&newset, SIGKILL); - lwp_sigdelset(&newset, SIGSTOP); - - lwp->signal_mask = newset; - } - ret = 0; -out: - rt_hw_interrupt_enable(level); - return ret; -} - -int lwp_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset) -{ - rt_base_t level; - struct rt_thread *thread; - lwp_sigset_t newset; - - level = rt_hw_interrupt_disable(); - thread = rt_thread_self(); - - if (oset) - { - rt_memcpy(oset, &thread->signal_mask, sizeof(lwp_sigset_t)); - } - - if (sigset) - { - switch (how) - { - case SIG_BLOCK: - sigorsets(&newset, &thread->signal_mask, sigset); - break; - case SIG_UNBLOCK: - sigandsets(&newset, &thread->signal_mask, sigset); - break; - case SIG_SETMASK: - newset = *sigset; - break; - default: - goto out; - } - - lwp_sigdelset(&newset, SIGKILL); - lwp_sigdelset(&newset, SIGSTOP); - - thread->signal_mask = newset; - } -out: - rt_hw_interrupt_enable(level); - return 0; -} - -static void _do_signal_wakeup(rt_thread_t thread, int sig) -{ - if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) - { - int need_schedule = 1; - - if ((thread->stat & RT_SIGNAL_COMMON_WAKEUP_MASK) != RT_SIGNAL_COMMON_WAKEUP_MASK) - { - rt_thread_wakeup(thread); - } - else if ((sig == SIGKILL) && ((thread->stat & RT_SIGNAL_KILL_WAKEUP_MASK) != RT_SIGNAL_KILL_WAKEUP_MASK)) - { - rt_thread_wakeup(thread); + ret = -RT_EPERM; } else { - need_schedule = 0; + ret = 0; + _thread_signal_mask(thread, how, sigset, oset); } - /* do schedule */ - if (need_schedule) - { - rt_schedule(); - } + rt_hw_interrupt_enable(level); } + else + ret = -RT_EINVAL; + + return ret; } -int lwp_kill(pid_t pid, int sig) +static int _dequeue_signal(rt_thread_t thread, lwp_sigset_t *mask, siginfo_t *usi) { - rt_base_t level; + int signo; + lwp_siginfo_t si; struct rt_lwp *lwp; - int ret = -1; - rt_thread_t thread; + lwp_sigset_t *pending; - if (sig < 0 || sig >= _LWP_NSIG) + pending = &_SIGQ(thread)->sigset_pending; + signo = _next_signal(pending, mask); + if (!signo) { - rt_set_errno(EINVAL); - return ret; + lwp = thread->lwp; + RT_ASSERT(lwp); + pending = &_SIGQ(lwp)->sigset_pending; + signo = _next_signal(pending, mask); } - level = rt_hw_interrupt_disable(); - lwp = lwp_from_pid(pid); - if (!lwp || lwp->finish) - { - rt_set_errno(ESRCH); - goto out; - } - if (sig) - { - /* check main thread */ - thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling); - if (!lwp_sigismember(&lwp->signal_mask, sig)) /* if signal masked */ - { - lwp_sigaddset(&lwp->signal, sig); - _do_signal_wakeup(thread, sig); - } - } - ret = 0; -out: - rt_hw_interrupt_enable(level); - return ret; + + if (!signo) + return signo; + + si = sigqueue_dequeue(_SIGQ(thread), signo); + RT_ASSERT(!!si); + + siginfo_k2u(si, usi); + siginfo_delete(si); + + return signo; } -int lwp_thread_kill(rt_thread_t thread, int sig) +rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset, + siginfo_t *usi, struct timespec *timeout) { - rt_base_t level; - int ret = -RT_EINVAL; + LOG_D("%s", __func__); - if (!thread) - { - rt_set_errno(ESRCH); - return ret; - } - if (sig < 0 || sig >= _LWP_NSIG) - { - rt_set_errno(EINVAL); - return ret; - } + rt_base_t level; + rt_err_t ret; + int sig; + + /** + * @brief POSIX + * If one of the signals in set is already pending for the calling thread, + * sigwaitinfo() will return immediately + */ + + /* Create a mask of signals user dont want or cannot catch */ + _sigdelset(sigset, SIGKILL); + _sigdelset(sigset, SIGSTOP); + _signotsets(sigset, sigset); + + /* FIXME: acquire READ lock to lwp */ level = rt_hw_interrupt_disable(); - if (!thread->lwp) - { - rt_set_errno(EPERM); - goto out; - } - if (!lwp_sigismember(&thread->signal_mask, sig)) /* if signal masked */ - { - lwp_sigaddset(&thread->signal, sig); - _do_signal_wakeup(thread, sig); - } - ret = 0; -out: + sig = _dequeue_signal(thread, sigset, usi); rt_hw_interrupt_enable(level); - return ret; + if (sig) + return sig; + + /* WARNING atomic problem, what if pending signal arrives before we sleep */ + + /** + * @brief POSIX + * if none of the signals specified by set are pending, sigtimedwait() shall + * wait for the time interval specified in the timespec structure referenced + * by timeout. + */ + if (timeout) + { + /* TODO: verify timeout valid ? not overflow 32bits, nanosec valid, ... */ + rt_uint32_t time; + time = rt_timespec_to_tick(timeout); + + /** + * @brief POSIX + * If the timespec structure pointed to by timeout is zero-valued and + * if none of the signals specified by set are pending, then + * sigtimedwait() shall return immediately with an error + */ + if (time == 0) + return -EAGAIN; + + ret = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE); + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + + } + else + { + /* suspend kernel forever until signal was received */ + ret = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE); + } + + if (ret == RT_EOK) + { + rt_schedule(); + ret = -EAGAIN; + } + /* else ret == -EINTR */ + + /* FIXME: acquire READ lock to lwp */ + level = rt_hw_interrupt_disable(); + sig = _dequeue_signal(thread, sigset, usi); + rt_hw_interrupt_enable(level); + + return sig ? sig : ret; +} + +void lwp_thread_signal_pending(rt_thread_t thread, lwp_sigset_t *pending) +{ + struct rt_lwp *lwp; + lwp = thread->lwp; + + if (lwp) + { + memset(pending, 0, sizeof(*pending)); + sigqueue_examine(_SIGQ(thread), pending); + sigqueue_examine(_SIGQ(lwp), pending); + } } diff --git a/components/lwp/lwp_signal.h b/components/lwp/lwp_signal.h index 6d393f0098..3d6bc311f7 100644 --- a/components/lwp/lwp_signal.h +++ b/components/lwp/lwp_signal.h @@ -1,39 +1,176 @@ /* - * Copyright (c) 2006-2020, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes - * 2020-02-23 Jesven first version. + * 2020-02-23 Jesven first version. + * 2023-07-06 Shell update the generation, pending and delivery API */ -#ifndef LWP_SIGNAL_H__ -#define LWP_SIGNAL_H__ +#ifndef __LWP_SIGNAL_H__ +#define __LWP_SIGNAL_H__ + +#include "syscall_generic.h" #include +#include #ifdef __cplusplus extern "C" { #endif -int lwp_signal_check(void); -int lwp_signal_backup(void *user_sp, void *user_pc, void* user_flag); -struct rt_user_context *lwp_signal_restore(void); -lwp_sighandler_t lwp_sighandler_get(int sig); -void lwp_sighandler_set(int sig, lwp_sighandler_t func); +#define _USIGNAL_SIGMASK(signo) (1u << ((signo)-1)) +#define LWP_SIG_IGNORE_SET (_USIGNAL_SIGMASK(SIGCHLD) | _USIGNAL_SIGMASK(SIGURG)) +#define LWP_SIG_ACT_DFL ((lwp_sighandler_t)0) +#define LWP_SIG_ACT_IGN ((lwp_sighandler_t)1) +#define LWP_SIG_USER_SA_FLAGS \ + (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ + SA_NODEFER | SA_RESETHAND | SA_EXPOSE_TAGBITS) + +typedef enum { + LWP_SIG_MASK_CMD_BLOCK, + LWP_SIG_MASK_CMD_UNBLOCK, + LWP_SIG_MASK_CMD_SET_MASK, + __LWP_SIG_MASK_CMD_WATERMARK +} lwp_sig_mask_cmd_t; + +/** + * LwP implementation of POSIX signal + */ +struct lwp_signal { + struct rt_mutex sig_lock; + + struct lwp_sigqueue sig_queue; + rt_thread_t sig_dispatch_thr[_LWP_NSIG]; + + lwp_sighandler_t sig_action[_LWP_NSIG]; + lwp_sigset_t sig_action_mask[_LWP_NSIG]; + + lwp_sigset_t sig_action_nodefer; + lwp_sigset_t sig_action_onstack; + lwp_sigset_t sig_action_restart; + lwp_sigset_t sig_action_siginfo; +}; + +struct rt_lwp; + #ifndef ARCH_MM_MMU +void lwp_sighandler_set(int sig, lwp_sighandler_t func); void lwp_thread_sighandler_set(int sig, lwp_sighandler_t func); #endif -int lwp_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset); -int lwp_sigaction(int sig, const struct lwp_sigaction *act, struct lwp_sigaction * oact, size_t sigsetsize); -int lwp_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset); -int lwp_kill(pid_t pid, int sig); -int lwp_thread_kill(rt_thread_t thread, int sig); +rt_inline void lwp_sigqueue_init(lwp_sigqueue_t sigq) +{ + rt_memset(&sigq->sigset_pending, 0, sizeof(lwp_sigset_t)); + rt_list_init(&sigq->siginfo_list); +} + +/** + * @brief release the signal queue + * + * @param sigq target signal queue + */ +void lwp_sigqueue_clear(lwp_sigqueue_t sigq); + +rt_err_t lwp_signal_init(struct lwp_signal *sig); + +rt_err_t lwp_signal_detach(struct lwp_signal *signal); + +rt_inline void lwp_thread_signal_detach(struct lwp_thread_signal *tsig) +{ + lwp_sigqueue_clear(&tsig->sig_queue); +} + +/** + * @brief send a signal to the process + * + * @param lwp the process to be killed + * @param signo the signal number + * @param code as in siginfo + * @param value as in siginfo + * @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as successful + * + * @note the *signal_kill have the same definition of a successful return as + * kill() in IEEE Std 1003.1-2017 + */ +rt_err_t lwp_signal_kill(struct rt_lwp *lwp, long signo, long code, long value); + +/** + * @brief set or examine the signal action of signo + * + * @param signo signal number + * @param act the signal action + * @param oact the old signal action + * @return rt_err_t + */ +rt_err_t lwp_signal_action(struct rt_lwp *lwp, int signo, + const struct lwp_sigaction *restrict act, + struct lwp_sigaction *restrict oact); + +/** + * @brief send a signal to the thread + * + * @param thread target thread + * @param signo the signal number + * @param code as in siginfo + * @param value as in siginfo + * @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as successful + */ +rt_err_t lwp_thread_signal_kill(rt_thread_t thread, long signo, long code, long value); + +/** + * @brief set signal mask of target thread + * + * @param thread the target thread + * @param how command + * @param sigset operand + * @param oset the address to old set + * @return rt_err_t + */ +rt_err_t lwp_thread_signal_mask(rt_thread_t thread, lwp_sig_mask_cmd_t how, + const lwp_sigset_t *sigset, lwp_sigset_t *oset); + +/** + * @brief Catch signal if exists and no return, otherwise return with no side effect + * + * @param exp_frame the exception frame on kernel stack + */ +void lwp_thread_signal_catch(void *exp_frame); + +/** + * @brief Check if it's okay to suspend for current lwp thread + * + * @param thread target thread + * @param suspend_flag suspend flag of target thread + * @return int 1 if can be suspended, otherwise not + */ +int lwp_thread_signal_suspend_check(rt_thread_t thread, int suspend_flag); + +/** + * @brief Asynchronously wait for signal + * + * @param thread target thread + * @param sigset the signals to be waited + * @param info address of user siginfo + * @param timeout timeout of waiting + * @return rt_err_t + */ +rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset, + siginfo_t *usi, struct timespec *timeout); + +/** + * @brief Examine the set of signals that are blocked from delivery to the + * calling thread and that are pending on the process or the calling thread + * + * @param thread target thread + * @param sigset where mask of pending signals is returned + */ +void lwp_thread_signal_pending(rt_thread_t thread, lwp_sigset_t *sigset); #ifdef __cplusplus } #endif -#endif +#endif /* __LWP_SIGNAL_H__ */ diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index e89b2db1c0..fa25423523 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -11,8 +11,11 @@ * 2021-02-12 lizhirui add 64-bit support for sys_brk * 2021-02-20 lizhirui fix some warnings * 2023-03-13 WangXiaoyao Format & fix syscall return value + * 2023-07-06 Shell adapt the signal API, and clone, fork to new implementation of lwp signal */ + #define _GNU_SOURCE + /* RT-Thread System call */ #include #include @@ -28,6 +31,7 @@ #include "syscall_generic.h" #include +#include "lwp_signal.h" #ifdef ARCH_MM_MMU #include #include @@ -1007,11 +1011,80 @@ sysret_t sys_exec(char *filename, int argc, char **argv, char **envp) return lwp_execve(filename, 0, argc, argv, envp); } -sysret_t sys_kill(int pid, int sig) +sysret_t sys_kill(int pid, int signo) { - int ret = 0; - ret = lwp_kill(pid, sig); - return (ret < 0 ? GET_ERRNO() : ret); + rt_err_t kret; + sysret_t sysret; + rt_base_t level; + struct rt_lwp *lwp; + + /* handling the semantics of sys_kill */ + if (pid > 0) + { + /* TODO: lock the lwp strcut */ + level = rt_hw_interrupt_disable(); + lwp = lwp_from_pid(pid); + + /* lwp_signal_kill() can handle NULL lwp */ + if (lwp) + kret = lwp_signal_kill(lwp, signo, SI_USER, 0); + else + kret = -RT_ENOENT; + + rt_hw_interrupt_enable(level); + } + else if (pid == 0) + { + /** + * sig shall be sent to all processes (excluding an unspecified set + * of system processes) whose process group ID is equal to the process + * group ID of the sender, and for which the process has permission to + * send a signal. + */ + kret = -RT_ENOSYS; + } + else if (pid == -1) + { + /** + * sig shall be sent to all processes (excluding an unspecified set + * of system processes) for which the process has permission to send + * that signal. + */ + kret = -RT_ENOSYS; + } + else /* pid < -1 */ + { + /** + * sig shall be sent to all processes (excluding an unspecified set + * of system processes) whose process group ID is equal to the absolute + * value of pid, and for which the process has permission to send a signal. + */ + kret = -RT_ENOSYS; + } + + switch (kret) + { + case -RT_ENOENT: + sysret = -ESRCH; + break; + case -RT_EINVAL: + sysret = -EINVAL; + break; + case -RT_ENOSYS: + sysret = -ENOSYS; + break; + + /** + * kill() never returns ENOMEM, so return normally to caller. + * IEEE Std 1003.1-2017 says the kill() function is successful + * if the process has permission to send sig to any of the + * processes specified by pid. + */ + case -RT_ENOMEM: + default: + sysret = 0; + } + return sysret; } sysret_t sys_getpid(void) @@ -1500,40 +1573,9 @@ fail: } return RT_NULL; } -#ifdef ARCH_MM_MMU -#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 +#ifdef ARCH_MM_MMU +#include "lwp_clone.h" long _sys_clone(void *arg[]) { @@ -1687,9 +1729,12 @@ static void lwp_struct_copy(struct rt_lwp *dst, struct rt_lwp *src) dst->tty = src->tty; rt_memcpy(dst->cmd, src->cmd, RT_NAME_MAX); - dst->sa_flags = src->sa_flags; - dst->signal_mask = src->signal_mask; - rt_memcpy(dst->signal_handler, src->signal_handler, sizeof dst->signal_handler); + rt_memcpy(&dst->signal.sig_action, &src->signal.sig_action, sizeof(dst->signal.sig_action)); + rt_memcpy(&dst->signal.sig_action_mask, &src->signal.sig_action_mask, sizeof(dst->signal.sig_action_mask)); + rt_memcpy(&dst->signal.sig_action_nodefer, &src->signal.sig_action_nodefer, sizeof(dst->signal.sig_action_nodefer)); + rt_memcpy(&dst->signal.sig_action_onstack, &src->signal.sig_action_onstack, sizeof(dst->signal.sig_action_onstack)); + rt_memcpy(&dst->signal.sig_action_restart, &dst->signal.sig_action_restart, sizeof(dst->signal.sig_action_restart)); + rt_memcpy(&dst->signal.sig_action_siginfo, &dst->signal.sig_action_siginfo, sizeof(dst->signal.sig_action_siginfo)); rt_strcpy(dst->working_directory, src->working_directory); } @@ -1797,7 +1842,7 @@ sysret_t _sys_fork(void) thread->user_entry = self_thread->user_entry; thread->user_stack = self_thread->user_stack; thread->user_stack_size = self_thread->user_stack_size; - thread->signal_mask = self_thread->signal_mask; + thread->signal.sigset_mask = self_thread->signal.sigset_mask; thread->thread_idr = self_thread->thread_idr; thread->lwp = (void *)lwp; thread->tid = tid; @@ -2457,12 +2502,11 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[]) _swap_lwp_data(lwp, new_lwp, void *, args); - rt_memset(&thread->signal_mask, 0, sizeof(thread->signal_mask)); - rt_memset(&thread->signal_mask_bak, 0, sizeof(thread->signal_mask_bak)); - lwp->sa_flags = 0; - rt_memset(&lwp->signal_mask, 0, sizeof(lwp->signal_mask)); - rt_memset(&lwp->signal_mask_bak, 0, sizeof(lwp->signal_mask_bak)); - rt_memset(lwp->signal_handler, 0, sizeof(lwp->signal_handler)); + lwp_thread_signal_detach(&thread->signal); + rt_memset(&thread->signal.sigset_mask, 0, sizeof(thread->signal.sigset_mask)); + + lwp_signal_detach(&lwp->signal); + lwp_signal_init(&lwp->signal); /* to do: clsoe files with flag CLOEXEC */ @@ -2470,6 +2514,9 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[]) rt_hw_interrupt_enable(level); + /* setup the signal for the dummy lwp, so that is can be smoothly recycled */ + lwp_signal_init(&new_lwp->signal); + lwp_ref_dec(new_lwp); arch_start_umode(lwp->args, lwp->text_entry, @@ -3267,9 +3314,10 @@ struct k_sigaction { }; sysret_t sys_sigaction(int sig, const struct k_sigaction *act, - struct k_sigaction *oact, size_t sigsetsize) + struct k_sigaction *oact, size_t sigsetsize) { int ret = -RT_EINVAL; + struct rt_lwp *lwp; struct lwp_sigaction kact, *pkact = RT_NULL; struct lwp_sigaction koact, *pkoact = RT_NULL; @@ -3310,7 +3358,9 @@ sysret_t sys_sigaction(int sig, const struct k_sigaction *act, pkact = &kact; } - ret = lwp_sigaction(sig, pkact, pkoact, sigsetsize); + lwp = lwp_self(); + RT_ASSERT(lwp); + ret = lwp_signal_action(lwp, sig, pkact, pkoact); #ifdef ARCH_MM_MMU if (ret == 0 && oact) { @@ -3324,6 +3374,12 @@ out: return (ret < 0 ? GET_ERRNO() : ret); } +static int mask_command_u2k[] = { + [SIG_BLOCK] = LWP_SIG_MASK_CMD_BLOCK, + [SIG_UNBLOCK] = LWP_SIG_MASK_CMD_UNBLOCK, + [SIG_SETMASK] = LWP_SIG_MASK_CMD_SET_MASK, +}; + sysret_t sys_sigprocmask(int how, const sigset_t *sigset, sigset_t *oset, size_t size) { int ret = -1; @@ -3377,7 +3433,7 @@ sysret_t sys_sigprocmask(int how, const sigset_t *sigset, sigset_t *oset, size_t pnewset = (lwp_sigset_t *)sigset; #endif /* ARCH_MM_MMU */ } - ret = lwp_sigprocmask(how, pnewset, poldset); + ret = lwp_thread_signal_mask(rt_thread_self(), mask_command_u2k[how], pnewset, poldset); #ifdef ARCH_MM_MMU if (ret < 0) { @@ -3391,6 +3447,97 @@ sysret_t sys_sigprocmask(int how, const sigset_t *sigset, sigset_t *oset, size_t return (ret < 0 ? -EFAULT: ret); } +sysret_t sys_sigpending(sigset_t *sigset, size_t sigsize) +{ + sysret_t ret = 0; + lwp_sigset_t lwpset; + + /* Verify and Get sigset, timeout */ + if (!sigset || !lwp_user_accessable((void *)sigset, sigsize)) + { + ret = -EFAULT; + } + else + { + /* Fit sigset size to lwp set */ + if (sizeof(lwpset) < sigsize) + { + LOG_I("%s: sigsize (%lx) extends lwp sigset chunk\n", __func__, sigsize); + sigsize = sizeof(lwpset); + } + + lwp_thread_signal_pending(rt_thread_self(), &lwpset); + + if (!lwp_put_to_user(sigset, &lwpset, sigsize)) + RT_ASSERT(0); /* should never happened */ + } + + return ret; +} + +sysret_t sys_sigtimedwait(const sigset_t *sigset, siginfo_t *info, const struct timespec *timeout, size_t sigsize) +{ + int sig; + size_t ret; + lwp_sigset_t lwpset; + siginfo_t kinfo; + struct timespec ktimeout; + struct timespec *ptimeout; + + /* Fit sigset size to lwp set */ + if (sizeof(lwpset) < sigsize) + { + LOG_I("%s: sigsize (%lx) extends lwp sigset chunk\n", __func__, sigsize); + sigsize = sizeof(lwpset); + } + else + { + memset(&lwpset, 0, sizeof(lwpset)); + } + + /* Verify and Get sigset, timeout */ + if (!sigset || !lwp_user_accessable((void *)sigset, sigsize)) + { + return -EFAULT; + } + else + { + ret = lwp_get_from_user(&lwpset, (void *)sigset, sigsize); + RT_ASSERT(ret == sigsize); + } + + if (timeout) + { + if (!lwp_user_accessable((void *)timeout, sizeof(*timeout))) + return -EFAULT; + else + { + ret = lwp_get_from_user(&ktimeout, (void *)timeout, sizeof(*timeout)); + ptimeout = &ktimeout; + RT_ASSERT(ret == sizeof(*timeout)); + } + } + else + { + ptimeout = RT_NULL; + } + + sig = lwp_thread_signal_timedwait(rt_thread_self(), &lwpset, &kinfo, ptimeout); + + if (info) + { + if (!lwp_user_accessable((void *)info, sizeof(*info))) + return -EFAULT; + else + { + ret = lwp_put_to_user(info, &kinfo, sizeof(*info)); + RT_ASSERT(ret == sizeof(*info)); + } + } + + return sig; +} + sysret_t sys_tkill(int tid, int sig) { #ifdef ARCH_MM_MMU @@ -3400,7 +3547,7 @@ sysret_t sys_tkill(int tid, int sig) level = rt_hw_interrupt_disable(); thread = lwp_tid_get_thread(tid); - ret = lwp_thread_kill(thread, sig); + ret = lwp_thread_signal_kill(thread, sig, SI_USER, 0); rt_hw_interrupt_enable(level); return ret; #else @@ -3461,7 +3608,7 @@ sysret_t sys_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_ pnewset = (lwp_sigset_t *)sigset; #endif } - ret = lwp_thread_sigprocmask(how, pnewset, poldset); + ret = lwp_thread_signal_mask(rt_thread_self(), mask_command_u2k[how], pnewset, poldset); if (ret < 0) { return ret; @@ -5169,7 +5316,7 @@ sysret_t sys_symlink(const char *existing, const char *new) return (ret < 0 ? GET_ERRNO() : ret); } -const static struct rt_syscall_def func_table[] = +static const struct rt_syscall_def func_table[] = { SYSCALL_SIGN(sys_exit), /* 01 */ SYSCALL_SIGN(sys_read), @@ -5391,6 +5538,15 @@ const static struct rt_syscall_def func_table[] = SYSCALL_SIGN(sys_symlink), SYSCALL_SIGN(sys_getaffinity), /* 180 */ SYSCALL_SIGN(sys_sysinfo), + SYSCALL_SIGN(sys_notimpl), + SYSCALL_SIGN(sys_notimpl), + SYSCALL_SIGN(sys_notimpl), + SYSCALL_SIGN(sys_notimpl), /* 185 */ + SYSCALL_SIGN(sys_notimpl), + SYSCALL_SIGN(sys_sigpending), + SYSCALL_SIGN(sys_sigtimedwait), + SYSCALL_SIGN(sys_notimpl), + SYSCALL_SIGN(sys_notimpl), /* 190 */ }; const void *lwp_get_sys_api(rt_uint32_t number) @@ -5408,6 +5564,10 @@ const void *lwp_get_sys_api(rt_uint32_t number) { func = func_table[number].func; } + else + { + LOG_I("Unimplement syscall %d", number); + } } return func; @@ -5428,6 +5588,10 @@ const char *lwp_get_syscall_name(rt_uint32_t number) { name = (char*)func_table[number].name; } + else + { + LOG_I("Unimplement syscall %d", number); + } } // skip sys_ diff --git a/include/rtdef.h b/include/rtdef.h index d12c929d9a..9562c410f5 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -218,6 +218,7 @@ typedef __gnuc_va_list va_list; #define rt_used __attribute__((used)) #define rt_align(n) __attribute__((aligned(n))) #define rt_weak __attribute__((weak)) +#define rt_noreturn __attribute__ ((noreturn)) #define rt_inline static __inline #define RTT_API #elif defined (__ADSPBLACKFIN__) /* for VisualDSP++ Compiler */ @@ -399,6 +400,7 @@ typedef int (*init_fn_t)(void); #define RT_ETRAP 11 /**< Trap event */ #define RT_ENOENT 12 /**< No entry */ #define RT_ENOSPC 13 /**< No space left */ +#define RT_EPERM 14 /**< Operation not permitted */ /**@}*/ @@ -753,14 +755,20 @@ struct rt_wakeup #define _LWP_NSIG_BPW 32 #endif -#define _LWP_NSIG_WORDS (_LWP_NSIG / _LWP_NSIG_BPW) +#define _LWP_NSIG_WORDS (RT_ALIGN(_LWP_NSIG, _LWP_NSIG_BPW) / _LWP_NSIG_BPW) typedef void (*lwp_sighandler_t)(int); +typedef void (*lwp_sigaction_t)(int signo, siginfo_t *info, void *context); typedef struct { unsigned long sig[_LWP_NSIG_WORDS]; } lwp_sigset_t; +#if _LWP_NSIG <= 64 +#define lwp_sigmask(signo) ((lwp_sigset_t){.sig = {[0] = ((long)(1u << ((signo)-1)))}}) +#define lwp_sigset_init(mask) ((lwp_sigset_t){.sig = {[0] = (long)(mask)}}) +#endif + struct lwp_sigaction { union { void (*_sa_handler)(int); @@ -771,6 +779,29 @@ struct lwp_sigaction { void (*sa_restorer)(void); }; +typedef struct lwp_siginfo { + rt_list_t node; + + struct { + int signo; + int code; + long value; + + int from_tid; + pid_t from_pid; + } ksiginfo; +} *lwp_siginfo_t; + +typedef struct lwp_sigqueue { + rt_list_t siginfo_list; + lwp_sigset_t sigset_pending; +} *lwp_sigqueue_t; + +struct lwp_thread_signal { + lwp_sigset_t sigset_mask; + struct lwp_sigqueue sig_queue; +}; + struct rt_user_context { void *sp; @@ -779,120 +810,116 @@ struct rt_user_context }; #endif +typedef void (*rt_thread_cleanup_t)(struct rt_thread *tid); + /** * Thread structure */ struct rt_thread { - struct rt_object parent; - rt_list_t tlist; /**< the thread list */ + struct rt_object parent; + rt_list_t tlist; /**< the thread list */ /* stack point and entry */ - void *sp; /**< stack point */ - void *entry; /**< entry */ - void *parameter; /**< parameter */ - void *stack_addr; /**< stack address */ - rt_uint32_t stack_size; /**< stack size */ + void *sp; /**< stack point */ + void *entry; /**< entry */ + void *parameter; /**< parameter */ + void *stack_addr; /**< stack address */ + rt_uint32_t stack_size; /**< stack size */ /* error code */ - rt_err_t error; /**< error code */ + rt_err_t error; /**< error code */ - rt_uint8_t stat; /**< thread status */ + rt_uint8_t stat; /**< thread status */ #ifdef RT_USING_SMP - rt_uint8_t bind_cpu; /**< thread is bind to cpu */ - rt_uint8_t oncpu; /**< process on cpu */ + rt_uint8_t bind_cpu; /**< thread is bind to cpu */ + rt_uint8_t oncpu; /**< process on cpu */ - rt_uint16_t scheduler_lock_nest; /**< scheduler lock count */ - rt_uint16_t cpus_lock_nest; /**< cpus lock count */ - rt_uint16_t critical_lock_nest; /**< critical lock count */ + rt_uint16_t scheduler_lock_nest; /**< scheduler lock count */ + rt_int16_t cpus_lock_nest; /**< cpus lock count */ + rt_uint16_t critical_lock_nest; /**< critical lock count */ #endif /*RT_USING_SMP*/ /* priority */ - rt_uint8_t current_priority; /**< current priority */ - rt_uint8_t init_priority; /**< initialized priority */ + rt_uint8_t current_priority; /**< current priority */ + rt_uint8_t init_priority; /**< initialized priority */ #if RT_THREAD_PRIORITY_MAX > 32 - rt_uint8_t number; - rt_uint8_t high_mask; + rt_uint8_t number; + rt_uint8_t high_mask; #endif /* RT_THREAD_PRIORITY_MAX > 32 */ - rt_uint32_t number_mask; /**< priority number mask */ + rt_uint32_t number_mask; /**< priority number mask */ #ifdef RT_USING_MUTEX /* object for IPC */ - rt_list_t taken_object_list; - rt_object_t pending_object; + rt_list_t taken_object_list; + rt_object_t pending_object; #endif #ifdef RT_USING_EVENT /* thread event */ - rt_uint32_t event_set; - rt_uint8_t event_info; + rt_uint32_t event_set; + rt_uint8_t event_info; #endif /* RT_USING_EVENT */ #ifdef RT_USING_SIGNALS - rt_sigset_t sig_pending; /**< the pending signals */ - rt_sigset_t sig_mask; /**< the mask bits of signal */ + rt_sigset_t sig_pending; /**< the pending signals */ + rt_sigset_t sig_mask; /**< the mask bits of signal */ #ifndef RT_USING_SMP - void *sig_ret; /**< the return stack pointer from signal */ + void *sig_ret; /**< the return stack pointer from signal */ #endif /* RT_USING_SMP */ - rt_sighandler_t *sig_vectors; /**< vectors of signal handler */ - void *si_list; /**< the signal infor list */ + rt_sighandler_t *sig_vectors; /**< vectors of signal handler */ + void *si_list; /**< the signal infor list */ #endif /* RT_USING_SIGNALS */ -#ifdef RT_USING_SMART - void *msg_ret; /**< the return msg */ -#endif - - rt_ubase_t init_tick; /**< thread's initialized tick */ - rt_ubase_t remaining_tick; /**< remaining tick */ + rt_ubase_t init_tick; /**< thread's initialized tick */ + rt_ubase_t remaining_tick; /**< remaining tick */ #ifdef RT_USING_CPU_USAGE - rt_uint64_t duration_tick; /**< cpu usage tick */ + rt_uint64_t duration_tick; /**< cpu usage tick */ #endif /* RT_USING_CPU_USAGE */ #ifdef RT_USING_PTHREADS - void *pthread_data; /**< the handle of pthread data, adapt 32/64bit */ + void *pthread_data; /**< the handle of pthread data, adapt 32/64bit */ #endif /* RT_USING_PTHREADS */ - struct rt_timer thread_timer; /**< built-in thread timer */ + struct rt_timer thread_timer; /**< built-in thread timer */ - void (*cleanup)(struct rt_thread *tid); /**< cleanup function when thread exit */ + rt_thread_cleanup_t cleanup; /**< cleanup function when thread exit */ /* light weight process if present */ #ifdef RT_USING_SMART - void *lwp; + void *msg_ret; /**< the return msg */ + + void *lwp; /**< the lwp reference */ /* for user create */ - void *user_entry; - void *user_stack; - rt_uint32_t user_stack_size; - rt_uint32_t *kernel_sp; /**< kernel stack point */ - rt_list_t sibling; /**< next thread of same process */ + void *user_entry; + void *user_stack; + rt_uint32_t user_stack_size; + rt_uint32_t *kernel_sp; /**< kernel stack point */ + rt_list_t sibling; /**< next thread of same process */ + + struct lwp_thread_signal signal; /**< lwp signal for user-space thread */ + struct rt_user_context user_ctx; /**< user space context */ + struct rt_wakeup wakeup; /**< wakeup data */ + int exit_request; + int tid; - lwp_sigset_t signal; - lwp_sigset_t signal_mask; - int signal_mask_bak; - rt_uint32_t signal_in_process; #ifndef ARCH_MM_MMU - lwp_sighandler_t signal_handler[32]; -#endif - struct rt_user_context user_ctx; + lwp_sighandler_t signal_handler[32]; +#else + int step_exec; + int debug_attach_req; + int debug_ret_user; + int debug_suspend; + struct rt_hw_exp_stack *regs; + void *thread_idr; /** lwp thread indicator */ + int *clear_child_tid; +#endif /* ARCH_MM_MMU */ +#endif /* RT_USING_SMART */ - struct rt_wakeup wakeup; /**< wakeup data */ - int exit_request; -#if defined(ARCH_MM_MMU) - int step_exec; - int debug_attach_req; - int debug_ret_user; - int debug_suspend; - struct rt_hw_exp_stack *regs; - void * thread_idr; /** lwp thread indicator */ - int *clear_child_tid; -#endif - int tid; -#endif - - rt_ubase_t user_data; /**< private user data beyond this thread */ + rt_ubase_t user_data; /**< private user data beyond this thread */ }; typedef struct rt_thread *rt_thread_t; diff --git a/src/thread.c b/src/thread.c index 61f3e289f9..ad8712c899 100644 --- a/src/thread.c +++ b/src/thread.c @@ -262,10 +262,12 @@ static rt_err_t _thread_init(struct rt_thread *thread, #ifdef RT_USING_SMART thread->lwp = RT_NULL; rt_list_init(&(thread->sibling)); - rt_memset(&thread->signal, 0, sizeof(lwp_sigset_t)); - rt_memset(&thread->signal_mask, 0, sizeof(lwp_sigset_t)); - thread->signal_mask_bak = 0; - thread->signal_in_process = 0; + + /* lwp thread-signal init */ + rt_memset(&thread->signal.sigset_mask, 0, sizeof(lwp_sigset_t)); + rt_memset(&thread->signal.sig_queue.sigset_pending, 0, sizeof(lwp_sigset_t)); + rt_list_init(&thread->signal.sig_queue.siginfo_list); + rt_memset(&thread->user_ctx, 0, sizeof thread->user_ctx); #endif @@ -935,7 +937,7 @@ rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg) RTM_EXPORT(rt_thread_control); #ifdef RT_USING_SMART -int lwp_suspend_sigcheck(rt_thread_t thread, int suspend_flag); +#include #endif static void rt_thread_set_suspend_state(struct rt_thread *thread, int suspend_flag) @@ -1004,7 +1006,7 @@ rt_err_t rt_thread_suspend_with_flag(rt_thread_t thread, int suspend_flag) RT_ASSERT(thread == rt_thread_self()); } #ifdef RT_USING_SMART - if (lwp_suspend_sigcheck(thread, suspend_flag) == 0) + if (lwp_thread_signal_suspend_check(thread, suspend_flag) == 0) { /* not to suspend */ rt_hw_interrupt_enable(level);