From: Minep Date: Mon, 20 Jun 2022 23:19:49 +0000 (+0100) Subject: feat: kill(2) implementation X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/cb529e7c1abcfe6b61241e47a780172031b82840?hp=2803826a2373620dbfce8a5bff1e6a01dd594953 feat: kill(2) implementation feat: support more signal (SIGKILL, SIGSTOP, SIGCONT) fix: [interrupt.S] change to callee-save register for safety chore: formatting, renaming things --- diff --git a/README.md b/README.md index d2a6c09..8f5b488 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ LunaixOS - 一个简单的,详细的,POSIX兼容的(但愿!),带有 + 多进程 + 14个常见的Linux/POSIX系统调用([附录1](#appendix1)) + 用户模式 -+ 信号机制(进行中) ++ 信号机制(测试中) ## 目录结构 @@ -67,7 +67,7 @@ LunaixOS - 一个简单的,详细的,POSIX兼容的(但愿!),带有 ## 附录1:支持的系统调用 ### Unix/Linux/POSIX -1. `sleep(2)` +1. `sleep(3)` 1. `wait(2)` 1. `waitpid(2)` 1. `fork(2)` @@ -80,7 +80,8 @@ LunaixOS - 一个简单的,详细的,POSIX兼容的(但愿!),带有 1. `_exit(2)` 1. `sigreturn(2)` 1. `sigprocmask(2)` -1. `signal(2) ` +1. `signal(2)` +1. `kill(2)` ### LunaixOS自有 diff --git a/lunaix-os/includes/lunaix/lunistd.h b/lunaix-os/includes/lunaix/lunistd.h index 7a1c368..67f3174 100644 --- a/lunaix-os/includes/lunaix/lunistd.h +++ b/lunaix-os/includes/lunaix/lunistd.h @@ -20,4 +20,6 @@ __LXSYSCALL1(unsigned int, sleep, unsigned int, seconds) __LXSYSCALL(int, pause) +__LXSYSCALL2(int, kill, pid_t, pid, int, signum) + #endif /* __LUNAIX_UNISTD_H */ diff --git a/lunaix-os/includes/lunaix/lxsignal.h b/lunaix-os/includes/lunaix/lxsignal.h new file mode 100644 index 0000000..5b54ffc --- /dev/null +++ b/lunaix-os/includes/lunaix/lxsignal.h @@ -0,0 +1,9 @@ +#ifndef __LUNAIX_LXSIGNAL_H +#define __LUNAIX_LXSIGNAL_H + +#include + +int +signal_send(pid_t pid, int signum); + +#endif /* __LUNAIX_LXSIGNAL_H */ diff --git a/lunaix-os/includes/lunaix/process.h b/lunaix-os/includes/lunaix/process.h index 2cd4330..589bfaa 100644 --- a/lunaix-os/includes/lunaix/process.h +++ b/lunaix-os/includes/lunaix/process.h @@ -22,6 +22,7 @@ #define PROC_TERMMASK 0x6 #define PROC_FINPAUSE 1 +#define PROC_FALRMSET (1 << 1) struct proc_mm { @@ -66,6 +67,7 @@ struct proc_info int32_t k_status; sigset_t sig_pending; sigset_t sig_mask; + sigset_t sig_inprogress; int flags; void* sig_handler[_SIG_NUM]; pid_t pgid; diff --git a/lunaix-os/includes/lunaix/signal.h b/lunaix-os/includes/lunaix/signal.h index d1f7041..5405aab 100644 --- a/lunaix-os/includes/lunaix/signal.h +++ b/lunaix-os/includes/lunaix/signal.h @@ -3,21 +3,24 @@ #include -#define _SIG_NUM 8 +#define _SIG_NUM 16 #define _SIG_PENDING(bitmap, sig) ((bitmap) & (1 << (sig))) -#define _SIGSEGV 0 -#define _SIGALRM 1 -#define _SIGCHLD 2 +#define _SIGSEGV 1 +#define _SIGALRM 2 +#define _SIGCHLD 3 #define _SIGCLD _SIGCHLD -#define _SIGINT 3 -#define _SIGKILL 4 -#define _SIGSTOP 5 -#define _SIGCONT 6 +#define _SIGINT 4 +#define _SIGKILL 5 +#define _SIGSTOP 6 +#define _SIGCONT 7 +#define _SIGTERM 8 #define __SIGNAL(num) (1 << (num)) -#define __SET_SIGNAL(bitmap, num) (bitmap = bitmap | __SIGNAL(num)) +#define __SIGSET(bitmap, num) (bitmap = bitmap | __SIGNAL(num)) +#define __SIGTEST(bitmap, num) (bitmap & __SIGNAL(num)) +#define __SIGCLEAR(bitmap, num) ((bitmap) = (bitmap) & ~__SIGNAL(num)) #define _SIGNAL_UNMASKABLE (__SIGNAL(_SIGKILL) | __SIGNAL(_SIGSTOP)) @@ -30,4 +33,13 @@ typedef void (*sighandler_t)(int); __LXSYSCALL2(int, signal, int, signum, sighandler_t, handler); +__LXSYSCALL3(int, + sigprocmask, + int, + how, + const sigset_t, + *set, + sigset_t, + *oldset); + #endif /* __LUNAIX_SIGNAL_H */ diff --git a/lunaix-os/includes/lunaix/syscall.h b/lunaix-os/includes/lunaix/syscall.h index f695cf7..e1d3403 100644 --- a/lunaix-os/includes/lunaix/syscall.h +++ b/lunaix-os/includes/lunaix/syscall.h @@ -17,6 +17,7 @@ #define __SYSCALL_sigprocmask 12 #define __SYSCALL_signal 13 #define __SYSCALL_pause 14 +#define __SYSCALL_kill 15 #define __SYSCALL_MAX 0x100 diff --git a/lunaix-os/includes/lunaix/types.h b/lunaix-os/includes/lunaix/types.h index 028792a..e91025a 100644 --- a/lunaix-os/includes/lunaix/types.h +++ b/lunaix-os/includes/lunaix/types.h @@ -3,15 +3,21 @@ #include -#define PROCTERM 0x10000 -#define PROCSTOP 0x20000 +#define PEXITTERM 0x100 +#define PEXITSTOP 0x200 +#define PEXITSIG 0x400 + +#define PEXITNUM(flag, code) (flag | (code & 0xff)) #define WNOHANG 1 #define WUNTRACED 2 -#define WEXITSTATUS(wstatus) ((wstatus & 0xffff)) -#define WIFSTOPPED(wstatus) ((wstatus & PROCSTOP)) +#define WEXITSTATUS(wstatus) ((wstatus & 0xff)) +#define WIFSTOPPED(wstatus) ((wstatus & PEXITSTOP)) #define WIFEXITED(wstatus) \ - ((wstatus & PROCTERM) && ((short)WEXITSTATUS(wstatus) >= 0)) + ((wstatus & PEXITTERM) && ((char)WEXITSTATUS(wstatus) >= 0)) + +#define WIFSIGNALED(wstatus) ((wstatus & PEXITSIG)) +// TODO: WTERMSIG typedef int32_t pid_t; diff --git a/lunaix-os/kernel/asm/x86/interrupt.S b/lunaix-os/kernel/asm/x86/interrupt.S index 48dff2f..7c40673 100644 --- a/lunaix-os/kernel/asm/x86/interrupt.S +++ b/lunaix-os/kernel/asm/x86/interrupt.S @@ -157,17 +157,17 @@ # 约定 # arg1: 目标进程PCB地址 (next - popl %ecx # next + popl %ebx # next movl __current, %eax - movl 88(%eax), %ebx # __current->pagetable - movl 88(%ecx), %eax # next->pagetable + movl 88(%eax), %ecx # __current->pagetable + movl 88(%ebx), %eax # next->pagetable - cmpl %ebx, %eax # if(next->pagtable != __current->pagetable) { + cmpl %ecx, %eax # if(next->pagtable != __current->pagetable) { jz 1f movl %eax, %cr3 # cpu_lcr3(next->pagetable) # } 1: - movl %ecx, __current # __current = next + movl %ebx, __current # __current = next # 我们已经处在了新的地址空间,为了避免影响其先前的栈布局 # 需要使用一个临时的栈空间 @@ -178,7 +178,7 @@ jz 1f jmp handle_signal 1: - leal 8(%ecx), %eax + leal 8(%ebx), %eax jmp soft_iret .global handle_signal diff --git a/lunaix-os/kernel/asm/x86/pfault.c b/lunaix-os/kernel/asm/x86/pfault.c index 30fd498..9e12444 100644 --- a/lunaix-os/kernel/asm/x86/pfault.c +++ b/lunaix-os/kernel/asm/x86/pfault.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -92,7 +93,8 @@ segv_term: ptr, param->cs, param->eip); - terminate_proc(LXSEGFAULT); + signal_send(__current->pid, _SIGSEGV); + schedule(); // should not reach while (1) ; diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S index 0922a96..b323640 100644 --- a/lunaix-os/kernel/asm/x86/syscall.S +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -22,6 +22,7 @@ .long __lxsys_sigprocmask .long __lxsys_signal .long __lxsys_pause + .long __lxsys_kill /* 15 */ 2: .rept __SYSCALL_MAX - (2b - 1b)/4 .long 0 diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index 257112e..447bff7 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -121,6 +121,7 @@ spawn_proc0() .eip = (void*)__proc0, .ss = KDATA_SEG, .eflags = cpu_reflags() }; + proc0->parent = proc0; // 方案1:必须在读取eflags之后禁用。否则当进程被调度时,中断依然是关闭的! // cpu_disable_interrupt(); diff --git a/lunaix-os/kernel/lxinit.c b/lunaix-os/kernel/lxinit.c index 2de87c5..fa5ce38 100644 --- a/lunaix-os/kernel/lxinit.c +++ b/lunaix-os/kernel/lxinit.c @@ -25,6 +25,14 @@ sigchild_handler(int signum) kprintf(KINFO "SIGCHLD received\n"); } +void __USER__ +sigsegv_handler(int signum) +{ + pid_t pid = getpid(); + kprintf(KWARN "SIGSEGV received on process %d\n", pid); + _exit(signum); +} + void __USER__ _lxinit_main() { @@ -39,6 +47,7 @@ _lxinit_main() #endif signal(_SIGCHLD, sigchild_handler); + signal(_SIGSEGV, sigsegv_handler); int status; #ifdef WAIT_DEMO @@ -67,9 +76,10 @@ _lxinit_main() waitpid(-1, &status, WNOHANG); - for (size_t i = 0; i < 10; i++) { + for (size_t i = 0; i < 5; i++) { pid_t pid = 0; if (!(pid = fork())) { + signal(_SIGSEGV, sigsegv_handler); sleep(i); if (i == 3) { i = *(int*)0xdeadc0de; // seg fault! @@ -83,7 +93,11 @@ _lxinit_main() while ((p = wait(&status)) >= 0) { short code = WEXITSTATUS(status); - if (WIFEXITED(status)) { + if (WIFSIGNALED(status)) { + kprintf(KINFO "Process %d terminated by signal, exit_code: %d\n", + p, + code); + } else if (WIFEXITED(status)) { kprintf(KINFO "Process %d exited with code %d\n", p, code); } else { kprintf(KWARN "Process %d aborted with code %d\n", p, code); diff --git a/lunaix-os/kernel/sched.c b/lunaix-os/kernel/sched.c index 50f5f67..f2ce4a2 100644 --- a/lunaix-os/kernel/sched.c +++ b/lunaix-os/kernel/sched.c @@ -44,9 +44,6 @@ sched_init() void run(struct proc_info* proc) { - if (!(__current->state & ~PROC_RUNNING)) { - __current->state = PROC_STOPPED; - } proc->state = PROC_RUNNING; /* @@ -65,6 +62,23 @@ run(struct proc_info* proc) "jmp switch_to\n" ::"r"(proc)); // kernel/asm/x86/interrupt.S } +int +can_schedule(struct proc_info* proc) +{ + if (__SIGTEST(proc->sig_pending, _SIGKILL)) { + // 如果进程受到SIGKILL,则直接终止,该进程不给予调度。 + terminate_proc(PEXITNUM(PEXITSIG, _SIGKILL)); + return 0; + } else if (__SIGTEST(proc->sig_pending, _SIGCONT)) { + __SIGCLEAR(proc->sig_pending, _SIGSTOP); + } else if (__SIGTEST(proc->sig_pending, _SIGSTOP)) { + // 如果进程受到SIGSTOP,则该进程不给予调度。 + return 0; + } + + return 1; +} + void schedule() { @@ -77,7 +91,13 @@ schedule() struct proc_info* next; int prev_ptr = sched_ctx.procs_index; int ptr = prev_ptr; + + if (!(__current->state & ~PROC_RUNNING)) { + __current->state = PROC_STOPPED; + } + // round-robin scheduler +redo: do { ptr = (ptr + 1) % sched_ctx.ptable_len; next = &sched_ctx._procs[ptr]; @@ -85,6 +105,11 @@ schedule() sched_ctx.procs_index = ptr; + if (!can_schedule(next)) { + // 如果该进程不给予调度,则尝试重新选择 + goto redo; + } + run(next); } @@ -117,6 +142,7 @@ __DEFINE_LXSYSCALL1(unsigned int, sleep, unsigned int, seconds) __DEFINE_LXSYSCALL1(void, exit, int, status) { terminate_proc(status); + schedule(); } __DEFINE_LXSYSCALL(void, yield) @@ -154,11 +180,11 @@ repeat: { if (!~wpid || proc->pid == wpid || proc->pgid == -wpid) { if (proc->state == PROC_TERMNAT && !options) { - status_flags |= PROCTERM; + status_flags |= PEXITTERM; goto done; } if (proc->state == PROC_STOPPED && (options & WUNTRACED)) { - status_flags |= PROCSTOP; + status_flags |= PEXITSTOP; goto done; } } @@ -172,7 +198,8 @@ repeat: done: cpu_disable_interrupt(); - *status = (proc->exit_code & 0xffff) | status_flags; + status_flags |= PEXITSIG * (proc->sig_inprogress != 0); + *status = proc->exit_code | status_flags; return destroy_process(proc->pid); } @@ -219,12 +246,12 @@ commit_process(struct proc_info* process) } // every process is the child of first process (pid=1) - if (process->parent) { - llist_append(&process->parent->children, &process->siblings); - } else { - process->parent = &sched_ctx._procs[0]; + if (!process->parent) { + process->parent = &sched_ctx._procs[1]; } + llist_append(&process->parent->children, &process->siblings); + process->state = PROC_STOPPED; } @@ -265,9 +292,7 @@ terminate_proc(int exit_code) __current->state = PROC_TERMNAT; __current->exit_code = exit_code; - __SET_SIGNAL(__current->parent->sig_pending, _SIGCHLD); - - schedule(); + __SIGSET(__current->parent->sig_pending, _SIGCHLD); } struct proc_info* diff --git a/lunaix-os/kernel/signal.c b/lunaix-os/kernel/signal.c index 80a7098..c3a6c07 100644 --- a/lunaix-os/kernel/signal.c +++ b/lunaix-os/kernel/signal.c @@ -1,33 +1,45 @@ +#include +#include #include #include #include +#include #include #include extern struct scheduler sched_ctx; /* kernel/sched.c */ +void __USER__ +default_sighandler_term(int signum) +{ + _exit(signum); +} + void* default_handlers[_SIG_NUM] = { // TODO: 添加默认handler + [_SIGINT] = default_sighandler_term, + [_SIGTERM] = default_sighandler_term, }; // Referenced in kernel/asm/x86/interrupt.S void* signal_dispatch() { - // if (!(SEL_RPL(__current->intr_ctx.cs))) { - // // 同特权级间调度不进行信号处理 - // return 0; - // } - if (!__current->sig_pending) { // 没有待处理信号 return 0; } int sig_selected = - 31 - __builtin_clz(__current->sig_pending & ~__current->sig_mask); + 31 - __builtin_clz(__current->sig_pending & + ~(__current->sig_mask | __current->sig_inprogress)); - __current->sig_pending = __current->sig_pending & ~__SIGNAL(sig_selected); + __SIGCLEAR(__current->sig_pending, sig_selected); + + if (sig_selected == 0) { + // SIG0 is reserved + return 0; + } if (!__current->sig_handler[sig_selected] && !default_handlers[sig_selected]) { @@ -54,16 +66,58 @@ signal_dispatch() sig_ctx->signal_handler = default_handlers[sig_selected]; } - __current->sig_mask |= __SIGNAL(sig_selected); + __SIGSET(__current->sig_inprogress, sig_selected); return sig_ctx; } +int +signal_send(pid_t pid, int signum) +{ + if (signum < 0 || signum >= _SIG_NUM) { + __current->k_status = LXINVL; + return -1; + } + + struct proc_info* proc; + if (pid > 0) { + proc = get_process(pid); + goto send_single; + } else if (!pid) { + proc = __current; + goto send_grp; + } else if (pid < -1) { + proc = get_process(-pid); + goto send_grp; + } else { + // TODO: send to all process. + // But I don't want to support it yet. + __current->k_status = LXINVL; + return -1; + } + +send_grp: + struct proc_info *pos, *n; + llist_for_each(pos, n, &proc->grp_member, grp_member) + { + __SIGSET(pos->sig_pending, signum); + } + return 0; + +send_single: + if ((proc->state & PROC_TERMMASK)) { + __current->k_status = LXINVL; + return -1; + } + __SIGSET(proc->sig_pending, signum); + return 0; +} + __DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx) { __current->intr_ctx = sig_ctx->prev_context; - __current->sig_mask &= ~__SIGNAL(sig_ctx->sig_num); __current->flags &= ~PROC_FINPAUSE; + __SIGCLEAR(__current->sig_inprogress, sig_ctx->sig_num); schedule(); } @@ -92,11 +146,11 @@ __DEFINE_LXSYSCALL3(int, __DEFINE_LXSYSCALL2(int, signal, int, signum, sighandler_t, handler) { - if (signum < 0 || signum >= _SIG_NUM) { + if (signum <= 0 || signum >= _SIG_NUM) { return -1; } - if (((1 << signum) & _SIGNAL_UNMASKABLE)) { + if ((__SIGNAL(signum) & _SIGNAL_UNMASKABLE)) { return -1; } @@ -116,4 +170,9 @@ __DEFINE_LXSYSCALL(int, pause) }) __current->k_status = EINTR; return -1; +} + +__DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum) +{ + return signal_send(pid, signum); } \ No newline at end of file