From aa8afd3a17a7433230b76a1910ab3ddb83bcd227 Mon Sep 17 00:00:00 2001 From: Minep Date: Sun, 19 Jun 2022 18:56:28 +0100 Subject: [PATCH 1/1] feat: signal support (tested!) feat: signal demo. --- lunaix-os/includes/lunaix/signal.h | 11 ++++++-- lunaix-os/includes/lunaix/spike.h | 2 +- lunaix-os/kernel/asm/x86/interrupt.S | 37 +++++++++++++++++++-------- lunaix-os/kernel/asm/x86/interrupts.c | 1 + lunaix-os/kernel/lxinit.c | 11 +++++++- lunaix-os/kernel/sched.c | 13 ++++++++-- lunaix-os/kernel/signal.c | 7 +++-- 7 files changed, 64 insertions(+), 18 deletions(-) diff --git a/lunaix-os/includes/lunaix/signal.h b/lunaix-os/includes/lunaix/signal.h index 4a4cf0b..d1f7041 100644 --- a/lunaix-os/includes/lunaix/signal.h +++ b/lunaix-os/includes/lunaix/signal.h @@ -1,6 +1,8 @@ #ifndef __LUNAIX_SIGNAL_H #define __LUNAIX_SIGNAL_H +#include + #define _SIG_NUM 8 #define _SIG_PENDING(bitmap, sig) ((bitmap) & (1 << (sig))) @@ -8,13 +10,16 @@ #define _SIGSEGV 0 #define _SIGALRM 1 #define _SIGCHLD 2 -#define _SIGCLD SIGCHLD +#define _SIGCLD _SIGCHLD #define _SIGINT 3 #define _SIGKILL 4 #define _SIGSTOP 5 #define _SIGCONT 6 -#define _SIGNAL_UNMASKABLE ((1 << _SIGKILL) | (1 << _SIGSTOP)) +#define __SIGNAL(num) (1 << (num)) +#define __SET_SIGNAL(bitmap, num) (bitmap = bitmap | __SIGNAL(num)) + +#define _SIGNAL_UNMASKABLE (__SIGNAL(_SIGKILL) | __SIGNAL(_SIGSTOP)) #define _SIG_BLOCK 1 #define _SIG_UNBLOCK 2 @@ -23,4 +28,6 @@ typedef unsigned int sigset_t; typedef void (*sighandler_t)(int); +__LXSYSCALL2(int, signal, int, signum, sighandler_t, handler); + #endif /* __LUNAIX_SIGNAL_H */ diff --git a/lunaix-os/includes/lunaix/spike.h b/lunaix-os/includes/lunaix/spike.h index 1ce7481..48a1904 100644 --- a/lunaix-os/includes/lunaix/spike.h +++ b/lunaix-os/includes/lunaix/spike.h @@ -15,7 +15,7 @@ // 获取v最近的最小k倍数 #define ROUNDDOWN(v, k) ((v) & ~((k)-1)) -#define __USER__ __attribute__((section("usrtext"))) +#define __USER__ __attribute__((section(".usrtext"))) inline static void spin() diff --git a/lunaix-os/kernel/asm/x86/interrupt.S b/lunaix-os/kernel/asm/x86/interrupt.S index e941983..48dff2f 100644 --- a/lunaix-os/kernel/asm/x86/interrupt.S +++ b/lunaix-os/kernel/asm/x86/interrupt.S @@ -22,6 +22,12 @@ .skip 16 #endif +.section .bss + .align 16 + lo_tmp_stack: + .skip 128 + tmp_stack: + .section .text isr_template FAULT_DIVISION_ERROR isr_template FAULT_GENERAL_PROTECTION, no_error_code=0 @@ -128,23 +134,30 @@ addl $8, %esp -#ifdef __ASM_INTR_DIAGNOSIS pushl %eax +#ifdef __ASM_INTR_DIAGNOSIS movl 4(%esp), %eax movl %eax, debug_resv - popl %eax #endif + # 处理TSS.ESP的一些边界条件。如果是正常iret(即从内核模式*优雅地*退出) + # 那么TSS.ESP0应该为iret进行弹栈后,%esp的值。 + # 所以这里的边界条件是:如返回用户模式,iret会额外弹出8个字节(ss,esp) + movl 8(%esp), %eax + andl $3, %eax + setnz %al + shll $3, %eax + addl $16, %eax + addl %esp, %eax + movl %eax, (_tss + 4) + popl %eax iret .global switch_to switch_to: # 约定 - # arg1: 目标进程PCB地址 (next) - popl %ecx # next - - call signal_dispatch # kernel/signal.c - movl %eax, %edx + # arg1: 目标进程PCB地址 (next + popl %ecx # next movl __current, %eax movl 88(%eax), %ebx # __current->pagetable movl 88(%ecx), %eax # next->pagetable @@ -156,9 +169,13 @@ 1: movl %ecx, __current # __current = next - test %edx, %edx # do we have signal to handle? + # 我们已经处在了新的地址空间,为了避免影响其先前的栈布局 + # 需要使用一个临时的栈空间 + movl $tmp_stack, %esp + call signal_dispatch # kernel/signal.c + + test %eax, %eax # do we have signal to handle? jz 1f - movl %edx, %eax jmp handle_signal 1: leal 8(%ecx), %eax @@ -170,7 +187,7 @@ # 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈! leal 8(%eax), %ebx # arg1 in %eax: addr of proc_sig structure in user stack - pushl 72(%ebx) # proc_sig->prev_context.ss + pushl $UDATA_SEG # proc_sig->prev_context.ss pushl %eax # esp pushl 64(%ebx) # proc_sig->prev_context.eflags pushl $UCODE_SEG # cs diff --git a/lunaix-os/kernel/asm/x86/interrupts.c b/lunaix-os/kernel/asm/x86/interrupts.c index 688799f..864c7da 100644 --- a/lunaix-os/kernel/asm/x86/interrupts.c +++ b/lunaix-os/kernel/asm/x86/interrupts.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/lunaix-os/kernel/lxinit.c b/lunaix-os/kernel/lxinit.c index 57e2bda..1485c34 100644 --- a/lunaix-os/kernel/lxinit.c +++ b/lunaix-os/kernel/lxinit.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,12 @@ LOG_MODULE("INIT") #define WAIT_DEMO #define IN_USER_MODE +void __USER__ +sigchild_handler(int signum) +{ + kprintf(KINFO "SIGCHLD received\n"); +} + void __USER__ _lxinit_main() { @@ -31,6 +38,8 @@ _lxinit_main() } #endif + signal(_SIGCHLD, sigchild_handler); + int status; #ifdef WAIT_DEMO // 测试wait @@ -57,7 +66,7 @@ _lxinit_main() waitpid(-1, &status, WNOHANG); - for (size_t i = 0; i < 5; i++) { + for (size_t i = 0; i < 10; i++) { pid_t pid = 0; if (!(pid = fork())) { sleep(i); diff --git a/lunaix-os/kernel/sched.c b/lunaix-os/kernel/sched.c index 1a9743d..50f5f67 100644 --- a/lunaix-os/kernel/sched.c +++ b/lunaix-os/kernel/sched.c @@ -49,8 +49,15 @@ run(struct proc_info* proc) } proc->state = PROC_RUNNING; - // XXX: 我们需要这一步吗? - // tss_update_esp(__current->intr_ctx.esp); + /* + 将tss.esp0设置为上次调度前的esp值。 + 当处理信号时,上下文信息是不会恢复的,而是保存在用户栈中,然后直接跳转进位于用户空间的sig_wrapper进行 + 信号的处理。当用户自定义的信号处理函数返回时,sigreturn的系统调用才开始进行上下文的恢复(或者说是进行 + 另一次调度。 + 由于这中间没有进行地址空间的交换,所以第二次跳转使用的是同一个内核栈,而之前默认tss.esp0的值是永远指向最顶部 + 这样一来就有可能会覆盖更早的上下文信息(比如嵌套的信号捕获函数) + */ + tss_update_esp(proc->intr_ctx.registers.esp); apic_done_servicing(); @@ -258,6 +265,8 @@ terminate_proc(int exit_code) __current->state = PROC_TERMNAT; __current->exit_code = exit_code; + __SET_SIGNAL(__current->parent->sig_pending, _SIGCHLD); + schedule(); } diff --git a/lunaix-os/kernel/signal.c b/lunaix-os/kernel/signal.c index 4c0bb56..49f1e53 100644 --- a/lunaix-os/kernel/signal.c +++ b/lunaix-os/kernel/signal.c @@ -26,7 +26,7 @@ signal_dispatch() int sig_selected = 31 - __builtin_clz(__current->sig_pending & ~__current->sig_mask); - __current->sig_pending = __current->sig_pending & ~(1 << sig_selected); + __current->sig_pending = __current->sig_pending & ~__SIGNAL(sig_selected); if (!__current->sig_handler[sig_selected] && !default_handlers[sig_selected]) { @@ -34,7 +34,7 @@ signal_dispatch() return 0; } - uintptr_t ustack = __current->ustack_top; + uintptr_t ustack = __current->ustack_top & ~0xf; if ((int)(ustack - USTACK_END) < (int)sizeof(struct proc_sig)) { // 用户栈没有空间存放信号上下文 @@ -53,12 +53,15 @@ signal_dispatch() sig_ctx->signal_handler = default_handlers[sig_selected]; } + __current->sig_mask |= __SIGNAL(sig_selected); + return sig_ctx; } __DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx) { __current->intr_ctx = sig_ctx->prev_context; + __current->sig_mask &= ~__SIGNAL(sig_ctx->sig_num); schedule(); } -- 2.27.0