From 87067c7f16425837971f5c1b5fd0fc5338757377 Mon Sep 17 00:00:00 2001 From: Minep Date: Fri, 21 Jul 2023 19:19:01 +0100 Subject: [PATCH] refactor: full rewrite of signal feature refactor: scheduler logic refactor: (hhk) initial page mapper. fix: remove debugging user access to kernel page feat: make signal.h more posix compliant --- lunaix-os/arch/i386/hhk.c | 42 ++++--- lunaix-os/includes/arch/x86/i386_abi.h | 20 ++++ lunaix-os/includes/lunaix/process.h | 67 +++++++++-- lunaix-os/includes/lunaix/signal.h | 15 ++- lunaix-os/includes/usr/lunaix/signal_defs.h | 12 ++ lunaix-os/includes/usr/lunaix/syscallid.h | 2 +- lunaix-os/kernel/asm/x86/interrupt.S | 32 ++--- lunaix-os/kernel/asm/x86/pfault.c | 32 +++-- lunaix-os/kernel/asm/x86/syscall.S | 2 +- lunaix-os/kernel/k_init.c | 8 -- lunaix-os/kernel/process/sched.c | 45 ++++--- lunaix-os/kernel/process/signal.c | 124 ++++++++++++-------- lunaix-os/kernel/process/task_attr.c | 4 +- lunaix-os/link/linker.ld | 8 +- lunaix-os/usr/libc/arch/i386/signal.c | 48 +++++++- lunaix-os/usr/libc/arch/i386/trampoline.S | 20 ++++ lunaix-os/usr/libc/arch/i386/unistd.c | 2 - lunaix-os/usr/libc/includes/signal.h | 11 +- lunaix-os/usr/libc/includes/unistd.h | 3 - lunaix-os/usr/signal_demo/signal_demo.c | 4 +- 20 files changed, 341 insertions(+), 160 deletions(-) create mode 100644 lunaix-os/usr/libc/arch/i386/trampoline.S diff --git a/lunaix-os/arch/i386/hhk.c b/lunaix-os/arch/i386/hhk.c index a9cb814..4250f79 100644 --- a/lunaix-os/arch/i386/hhk.c +++ b/lunaix-os/arch/i386/hhk.c @@ -26,31 +26,32 @@ // Provided by linker (see linker.ld) extern u8_t __kernel_start; extern u8_t __kernel_end; +extern u8_t __ktext_start; +extern u8_t __ktext_end; + extern u8_t __init_hhk_end; extern u8_t _k_stack; void -_init_page(ptd_t* ptd) +_init_page(x86_page_table* ptd) { - SET_PDE(ptd, 0, NEW_L1_ENTRY(PG_PREM_RW, ptd + PG_MAX_ENTRIES)) + ptd->entry[0] = NEW_L1_ENTRY(PG_PREM_RW, (ptd_t*)ptd + PG_MAX_ENTRIES); // 对低1MiB空间进行对等映射(Identity // mapping),也包括了我们的VGA,方便内核操作。 + x86_page_table* id_pt = + (x86_page_table*)GET_PG_ADDR(ptd->entry[PG_TABLE_IDENTITY]); + for (u32_t i = 0; i < 256; i++) { - SET_PTE(ptd, - PG_TABLE_IDENTITY, - i, - NEW_L2_ENTRY(PG_PREM_RW, (i << PG_SIZE_BITS))) + id_pt->entry[i] = NEW_L2_ENTRY(PG_PREM_RW, (i << PG_SIZE_BITS)); } // 对等映射我们的hhk_init,这样一来,当分页与地址转换开启后,我们依然能够照常执行最终的 // jmp 指令来跳转至 // 内核的入口点 for (u32_t i = 0; i < HHK_PAGE_COUNT; i++) { - SET_PTE(ptd, - PG_TABLE_IDENTITY, - 256 + i, - NEW_L2_ENTRY(PG_PREM_RW, 0x100000 + (i << PG_SIZE_BITS))) + id_pt->entry[256 + i] = + NEW_L2_ENTRY(PG_PREM_RW, 0x100000 + (i << PG_SIZE_BITS)); } // --- 将内核重映射至高半区 --- @@ -65,9 +66,8 @@ _init_page(ptd_t* ptd) // 当然,就现在而言,我们的内核只占用不到50个页(每个页表包含1024个页) // 这里分配了3个页表(12MiB),未雨绸缪。 for (u32_t i = 0; i < PG_TABLE_STACK - PG_TABLE_KERNEL; i++) { - SET_PDE(ptd, - kernel_pde_index + i, - NEW_L1_ENTRY(PG_PREM_URW, PT_ADDR(ptd, PG_TABLE_KERNEL + i))) + ptd->entry[kernel_pde_index + i] = + NEW_L1_ENTRY(PG_PREM_RW, PT_ADDR(ptd, PG_TABLE_KERNEL + i)); } // 首先,检查内核的大小是否可以fit进我们这几个表(12MiB) @@ -80,22 +80,26 @@ _init_page(ptd_t* ptd) // 计算内核.text段的物理地址 ptr_t kernel_pm = V2P(&__kernel_start); + ptr_t ktext_start = V2P(&__ktext_start); + ptr_t ktext_end = V2P(&ktext_end); // 重映射内核至高半区地址(>=0xC0000000) for (u32_t i = 0; i < kernel_pg_counts; i++) { - // FIXME: 只是用作用户模式(R3)测试! - // 在实际中,内核代码除了极少部分需要暴露给R3(如从信号返回),其余的应为R0。 + ptr_t paddr = kernel_pm + (i << PG_SIZE_BITS); + u32_t flags = PG_PREM_RW; -#warning "fixme: kernel pages should not be user-accessable" + if (paddr >= ktext_start && paddr <= ktext_end) { + flags = PG_PREM_R; + } SET_PTE(ptd, PG_TABLE_KERNEL, kernel_pte_index + i, - NEW_L2_ENTRY(PG_PREM_URW, kernel_pm + (i << PG_SIZE_BITS))) + NEW_L2_ENTRY(flags, paddr)) } // 最后一个entry用于循环映射 - SET_PDE(ptd, PG_MAX_ENTRIES - 1, NEW_L1_ENTRY(T_SELF_REF_PERM, ptd)); + ptd->entry[PG_MAX_ENTRIES - 1] = NEW_L1_ENTRY(T_SELF_REF_PERM, ptd); } u32_t @@ -130,7 +134,7 @@ _save_multiboot_info(multiboot_info_t* info, u8_t* destination) } void -_hhk_init(ptd_t* ptd, u32_t kpg_size) +_hhk_init(x86_page_table* ptd, u32_t kpg_size) { // 初始化 kpg 全为0 diff --git a/lunaix-os/includes/arch/x86/i386_abi.h b/lunaix-os/includes/arch/x86/i386_abi.h index 22481c9..8804bc9 100644 --- a/lunaix-os/includes/arch/x86/i386_abi.h +++ b/lunaix-os/includes/arch/x86/i386_abi.h @@ -21,4 +21,24 @@ "r"(pc) \ : "eax", "memory"); +#define push_arg1(stack_ptr, arg) *((typeof((arg))*)(stack_ptr)--) = arg +#define push_arg2(stack_ptr, arg1, arg2) \ + { \ + *((typeof((arg1))*)(stack_ptr)--) = arg1; \ + *((typeof((arg2))*)(stack_ptr)--) = arg2; \ + } +#define push_arg3(stack_ptr, arg1, arg2, arg3) \ + { \ + *((typeof((arg1))*)(stack_ptr)--) = arg1; \ + *((typeof((arg2))*)(stack_ptr)--) = arg2; \ + *((typeof((arg3))*)(stack_ptr)--) = arg3; \ + } +#define push_arg4(stack_ptr, arg1, arg2, arg3, arg4) \ + { \ + *((typeof((arg1))*)(stack_ptr)--) = arg1; \ + *((typeof((arg2))*)(stack_ptr)--) = arg2; \ + *((typeof((arg3))*)(stack_ptr)--) = arg3; \ + *((typeof((arg4))*)(stack_ptr)--) = arg4; \ + } + #endif /* __LUNAIX_ABI_H */ diff --git a/lunaix-os/includes/lunaix/process.h b/lunaix-os/includes/lunaix/process.h index 974907d..a8ac5d8 100644 --- a/lunaix-os/includes/lunaix/process.h +++ b/lunaix-os/includes/lunaix/process.h @@ -15,14 +15,35 @@ // 虽然内核不是进程,但为了区分,这里使用Pid=-1来指代内核。这主要是方便物理页所有权检查。 #define KERNEL_PID -1 +/* + |C|Bk|De|Tn|Pu|Rn| + \----/ + Dt + + Group Dt: whether this process is terminated. + + Rn: Running + Tn: Terminated + De: Destoryed + Pu: Paused + Bk: Blocked + C : Created +*/ + #define PS_READY 0 #define PS_RUNNING 1 #define PS_TERMNAT 2 #define PS_DESTROY 4 -#define PS_BLOCKED 8 -#define PS_CREATED 16 +#define PS_PAUSED 8 +#define PS_BLOCKED 16 +#define PS_CREATED 32 -#define PROC_TERMINATED(state) (state & 0x6) +#define PS_GrBP (PS_PAUSED | PS_BLOCKED) +#define PS_GrDT (PS_TERMNAT | PS_DESTROY) + +#define PROC_TERMINATED(state) ((state)&PS_GrDT) +#define PROC_HANGED(state) ((state)&PS_BLOCKED) +#define PROC_RUNNABLE(state) ((state)&PS_PAUSED) #define PROC_FINPAUSE 1 @@ -32,10 +53,28 @@ struct proc_sigstate char fxstate[512] __attribute__((aligned(16))); }; +struct sigact +{ + struct sigact* prev; + sigset_t sa_mask; + void* sa_actor; + void* sa_handler; + pid_t sender; +}; + +struct sighail +{ + sigset_t sig_pending; + sigset_t sig_mask; + struct sigact* inprogress; + struct sigact signals[_SIG_NUM]; +}; + struct proc_sig { - void* signal_handler; int sig_num; + void* sigact; + void* sighand; struct proc_sigstate prev_context; } __attribute__((packed)); @@ -76,11 +115,8 @@ struct proc_info u8_t state; int32_t exit_code; int32_t k_status; - sigset_t sig_pending; - sigset_t sig_mask; - sigset_t sig_inprogress; int flags; - void* sig_handler[_SIG_NUM]; + struct sighail sigctx; struct v_fdtable* fdtable; struct v_dnode* cwd; pid_t pgid; @@ -94,6 +130,18 @@ block_current() __current->state = PS_BLOCKED; } +static inline void +pause_current() +{ + __current->state = PS_PAUSED; +} + +static inline void +resume_current() +{ + __current->state = PS_RUNNING; +} + /** * @brief 分配并初始化一个进程控制块 * @@ -151,4 +199,7 @@ orphaned_proc(pid_t pid); struct proc_info* get_process(pid_t pid); +void +proc_setsignal(struct proc_info* proc, int signum); + #endif /* __LUNAIX_PROCESS_H */ diff --git a/lunaix-os/includes/lunaix/signal.h b/lunaix-os/includes/lunaix/signal.h index dbe9ce5..af191af 100644 --- a/lunaix-os/includes/lunaix/signal.h +++ b/lunaix-os/includes/lunaix/signal.h @@ -16,18 +16,17 @@ #define _SIGSTOP SIGSTOP #define _SIGCONT SIGCONT #define _SIGTERM SIGTERM - -#define __SIGNAL(num) (1 << (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)) - #define _SIG_BLOCK SIG_BLOCK #define _SIG_UNBLOCK SIG_UNBLOCK #define _SIG_SETMASK SIG_SETMASK +#define sigset(num) (1 << (num)) +#define sigset_add(set, num) (set = set | sigset(num)) +#define sigset_test(set, num) (set & sigset(num)) +#define sigset_clear(set, num) ((set) = (set) & ~sigset(num)) +#define sigset_union(set, set2) ((set) = (set) | (set2)) +#define sigset_intersect(set, set2) ((set) = (set) & (set2)) + int signal_send(pid_t pid, int signum); diff --git a/lunaix-os/includes/usr/lunaix/signal_defs.h b/lunaix-os/includes/usr/lunaix/signal_defs.h index 0bd3e70..d56a443 100644 --- a/lunaix-os/includes/usr/lunaix/signal_defs.h +++ b/lunaix-os/includes/usr/lunaix/signal_defs.h @@ -20,4 +20,16 @@ typedef unsigned int sigset_t; typedef void (*sighandler_t)(int); +struct sigaction +{ + sigset_t sa_mask; + void (*sa_handler)(int); + void (*sa_sigaction)(int, void*, void*); +}; + +struct siginfo +{ + // TODO +}; + #endif /* __LUNAIX_SIGNAL_DEFS_H */ diff --git a/lunaix-os/includes/usr/lunaix/syscallid.h b/lunaix-os/includes/usr/lunaix/syscallid.h index cc7ac7a..d388e12 100644 --- a/lunaix-os/includes/usr/lunaix/syscallid.h +++ b/lunaix-os/includes/usr/lunaix/syscallid.h @@ -14,7 +14,7 @@ #define __SYSCALL_sigreturn 11 #define __SYSCALL_sigprocmask 12 -#define __SYSCALL_signal 13 +#define __SYSCALL_sys_sigaction 13 #define __SYSCALL_pause 14 #define __SYSCALL_kill 15 #define __SYSCALL_alarm 16 diff --git a/lunaix-os/kernel/asm/x86/interrupt.S b/lunaix-os/kernel/asm/x86/interrupt.S index a6c0496..602f793 100644 --- a/lunaix-os/kernel/asm/x86/interrupt.S +++ b/lunaix-os/kernel/asm/x86/interrupt.S @@ -16,7 +16,7 @@ .section .bss .align 16 lo_tmp_stack: - .skip 128 + .skip 256 tmp_stack: /* @@ -94,14 +94,14 @@ movw %ax, %ds movw %ax, %es - # 保存用户栈顶指针。这是因为我们允许系统调用内进行上下文切换,而这样一来,我们就失去了用户栈的信息, - # 这样一来,就无法设置信号上下文。这主要是为了实现了pause()而做的准备 movl __current, %eax + # FIXME: Save x87 context to user stack, rather than kernel's memory. # 保存x87FPU的状态 movl 68(%eax), %ebx fxsave (%ebx) + # 保存用户栈顶指针。因为我们允许同级中断的产生,所以需要该手段跟踪用户栈的地址。 movl 124(%esp), %ebx # 取出esp movl %ebx, 60(%eax) # 存入__current->ustack_top @@ -217,14 +217,17 @@ handle_signal: # 注意1:任何对proc_sig的布局改动,都须及时的保证这里的一致性! # 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈! - leal 8(%eax), %ebx # arg1 in %eax: addr of proc_sig structure in user stack + # arg1 in %eax: addr of proc_sig structure in user stack + leal 12(%eax), %ebx # %ebx = &proc_sig->prev_context pushl $UDATA_SEG # proc_sig->prev_context.proc_regs.ss pushl %eax # esp + movl 48(%ebx), %ebx pushl 68(%ebx) # proc_sig->prev_context.proc_regs.execp->eflags + pushl $UCODE_SEG # cs - pushl $sig_wrapper # eip for sig wrapper + pushl 4(%eax) # %eip = proc_sig->sigact movw $UDATA_SEG, %cx # switch data seg to user mode movw %cx, %es @@ -232,21 +235,4 @@ movw %cx, %fs movw %cx, %gs - iret - -.section .usrtext - sig_wrapper: # in user mode - movl %esp, %eax - and $0xfffffff0, %esp - subl $8, %esp - pushl %eax # Addr to proc_sig structure - pushl 4(%eax) # proc_sig->sig_num ---- 16 bytes aligned - - call *(%eax) # invoke signal handler - - # invoke the sigreturn syscall to exit the signal wrapper - movl $__SYSCALL_sigreturn, %eax - movl 4(%esp), %ebx - int $LUNAIX_SYS_CALL - - ud2 # never reach! \ No newline at end of file + iret \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/pfault.c b/lunaix-os/kernel/asm/x86/pfault.c index 70d5e56..f527e12 100644 --- a/lunaix-os/kernel/asm/x86/pfault.c +++ b/lunaix-os/kernel/asm/x86/pfault.c @@ -11,6 +11,19 @@ #include +static u32_t +get_ptattr(struct mm_region* vmr) +{ + u32_t vmr_attr = vmr->attr; + u32_t ptattr = PG_PRESENT | PG_ALLOW_USER; + + if ((vmr_attr & PROT_WRITE)) { + ptattr |= PG_WRITE; + } + + return ptattr & 0xfff; +} + static void kprintf(const char* fmt, ...) { @@ -51,13 +64,16 @@ intr_routine_page_fault(const isr_param* param) goto segv_term; } - if ((errcode & PG_ALLOW_USER)) { - // invalid access - goto segv_term; - } - volatile x86_pte_t* pte = &PTE_MOUNTED(VMS_SELF, ptr >> 12); if (PG_IS_PRESENT(*pte)) { + if (((errcode ^ mapping.flags) & PG_ALLOW_USER)) { + // invalid access + kprintf(KDEBUG "invalid user access. (%p->%p, attr:0x%x)\n", + mapping.va, + mapping.pa, + mapping.flags); + goto segv_term; + } if ((hit_region->attr & COW_MASK) == COW_MASK) { // normal page fault, do COW cpu_invplg((ptr_t)pte); @@ -84,7 +100,7 @@ intr_routine_page_fault(const isr_param* param) goto oom; } - *pte = *pte | pa | PG_PRESENT | PG_ALLOW_USER; + *pte = *pte | pa | get_ptattr(hit_region); memset((void*)PG_ALIGN(ptr), 0, PG_SIZE); goto resolved; } @@ -107,7 +123,7 @@ intr_routine_page_fault(const isr_param* param) } cpu_invplg((ptr_t)pte); - *pte = (*pte & 0xFFF) | pa | PG_PRESENT | PG_ALLOW_USER; + *pte = (*pte & 0xFFF) | pa | get_ptattr(hit_region); memset((void*)ptr, 0, PG_SIZE); @@ -143,7 +159,7 @@ segv_term: param->execp->eip, param->execp->err_code); - __SIGSET(__current->sig_pending, _SIGSEGV); + sigset_add(__current->sigctx.sig_pending, _SIGSEGV); schedule(); // should not reach diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S index b48aead..ac3fe80 100644 --- a/lunaix-os/kernel/asm/x86/syscall.S +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -20,7 +20,7 @@ .long __lxsys_waitpid /* 10 */ .long __lxsys_sigreturn .long __lxsys_sigprocmask - .long __lxsys_signal + .long __lxsys_sys_sigaction .long __lxsys_pause .long __lxsys_kill /* 15 */ .long __lxsys_alarm diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index d399251..71adb30 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -179,9 +179,6 @@ spawn_proc0() assert_msg(0, "Unexpected Return"); } -extern u8_t __usrtext_start; -extern u8_t __usrtext_end; - // 按照 Memory map 标识可用的物理页 void setup_memory(multiboot_memory_map_t* map, size_t map_size) @@ -202,11 +199,6 @@ setup_memory(multiboot_memory_map_t* map, size_t map_size) size_t pg_count = V2P(&__kernel_end) >> PG_SIZE_BITS; pmm_mark_chunk_occupied(KERNEL_PID, 0, pg_count, PP_FGLOCKED); - for (ptr_t i = (ptr_t)&__usrtext_start; i < (ptr_t)&__usrtext_end; - i += PG_SIZE) { - vmm_set_mapping(VMS_SELF, i, V2P(i), PG_PREM_UR, VMAP_NULL); - } - // reserve higher half for (size_t i = L1_INDEX(KERNEL_MM_BASE); i < 1023; i++) { assert(vmm_set_mapping(VMS_SELF, i << 22, 0, 0, VMAP_NOMAP)); diff --git a/lunaix-os/kernel/process/sched.c b/lunaix-os/kernel/process/sched.c index b21d086..5e5db25 100644 --- a/lunaix-os/kernel/process/sched.c +++ b/lunaix-os/kernel/process/sched.c @@ -111,14 +111,24 @@ run(struct proc_info* proc) int can_schedule(struct proc_info* proc) { - if (__SIGTEST(proc->sig_pending, _SIGCONT)) { - __SIGCLEAR(proc->sig_pending, _SIGSTOP); - } else if (__SIGTEST(proc->sig_pending, _SIGSTOP)) { + if (!proc) { + return 0; + } + + struct sighail* sh = &proc->sigctx; + + if ((proc->state & PS_PAUSED)) { + return !!(sh->sig_pending & ~1); + } + + if (sigset_test(sh->sig_pending, _SIGCONT)) { + sigset_clear(sh->sig_pending, _SIGSTOP); + } else if (sigset_test(sh->sig_pending, _SIGSTOP)) { // 如果进程受到SIGSTOP,则该进程不给予调度。 return 0; } - return 1; + return (proc->state == PS_READY); } void @@ -143,7 +153,7 @@ check_sleepers() if (atime && now >= atime) { pos->sleep.alarm_time = 0; - __SIGSET(pos->sig_pending, _SIGALRM); + proc_setsignal(pos, _SIGALRM); } if (!wtime && !atime) { @@ -165,6 +175,7 @@ schedule() struct proc_info* next; int prev_ptr = sched_ctx.procs_index; int ptr = prev_ptr; + int found = 0; if (!(__current->state & ~PS_RUNNING)) { __current->state = PS_READY; @@ -174,23 +185,20 @@ schedule() // round-robin scheduler redo: + do { ptr = (ptr + 1) % sched_ctx.ptable_len; next = sched_ctx._procs[ptr]; - } while (!next || (next->state != PS_READY && ptr != prev_ptr)); - sched_ctx.procs_index = ptr; - - if (next->state != PS_READY) { - // schedule the dummy process if we're out of choice - next = &dummy_proc; - goto done; - } + if (!(found = can_schedule(next))) { + if (ptr == prev_ptr) { + next = &dummy_proc; + goto done; + } + } + } while (!found); - if (!can_schedule(next)) { - // 如果该进程不给予调度,则尝试重新选择 - goto redo; - } + sched_ctx.procs_index = ptr; done: run(next); @@ -305,7 +313,6 @@ repeat: goto repeat; done: - status_flags |= PEXITSIG * (proc->sig_inprogress != 0); if (status) { *status = proc->exit_code | status_flags; } @@ -433,7 +440,7 @@ terminate_proc(int exit_code) __current->state = PS_TERMNAT; __current->exit_code = exit_code; - __SIGSET(__current->parent->sig_pending, _SIGCHLD); + proc_setsignal(__current->parent, _SIGCHLD); } struct proc_info* diff --git a/lunaix-os/kernel/process/signal.c b/lunaix-os/kernel/process/signal.c index d12c62e..a8ec239 100644 --- a/lunaix-os/kernel/process/signal.c +++ b/lunaix-os/kernel/process/signal.c @@ -9,51 +9,55 @@ extern struct scheduler sched_ctx; /* kernel/sched.c */ -static u32_t term_sigs = - (1 << SIGSEGV) | (1 << SIGINT) | (1 << SIGKILL) | (1 << SIGTERM); +#define UNMASKABLE (sigset(SIGKILL) | sigset(SIGTERM)) +#define TERMSIG (sigset(SIGSEGV) | sigset(SIGINT) | UNMASKABLE) // Referenced in kernel/asm/x86/interrupt.S void* signal_dispatch() { - if (!__current->sig_pending) { + if (!__current->sigctx.sig_pending) { // 没有待处理信号 return 0; } - int sig_selected = - 31 - __builtin_clz(__current->sig_pending & - ~(__current->sig_mask | __current->sig_inprogress)); + struct sighail* psig = &__current->sigctx; + struct sigact* prev_working = psig->inprogress; + sigset_t mask = psig->sig_mask | (prev_working ? prev_working->sa_mask : 0); - __SIGCLEAR(__current->sig_pending, sig_selected); + int sig_selected = 31 - __builtin_clz(psig->sig_pending & ~mask); + + sigset_clear(psig->sig_pending, sig_selected); + + struct sigact* action = &psig->signals[sig_selected]; if (sig_selected == 0) { // SIG0 is reserved return 0; } - if (!__current->sig_handler[sig_selected]) { - if ((term_sigs & (1 << sig_selected))) { - terminate_proc(sig_selected); + if (!action->sa_actor) { + if (sigset_test(TERMSIG, sig_selected)) { + terminate_proc(sig_selected | PEXITSIG); schedule(); // never return } return 0; } - ptr_t ustack = __current->ustack_top & ~0xf; + ptr_t ustack = __current->ustack_top; if ((int)(ustack - USTACK_END) < (int)sizeof(struct proc_sig)) { // 用户栈没有空间存放信号上下文 return 0; } - struct proc_sig* sig_ctx = - (struct proc_sig*)(ustack - sizeof(struct proc_sig)); + struct proc_sig* sigframe = + (struct proc_sig*)((ustack - sizeof(struct proc_sig)) & ~0xf); /* 这是一个相当恶心的坑。 - 问题是出在原本的sig_ctx->prev_context = __current->intr_ctx的上面 + 问题是出在原本的sigframe->prev_context = __current->intr_ctx的上面 这个语句会被gcc在编译时,用更加高效的 rep movsl 来代替。 由于我们采用按需分页,所以在很多情况下,用户栈实际被分配的空间不允许我们进行完整的 @@ -75,14 +79,23 @@ signal_dispatch() __temp_save.proc_regs = __current->intr_ctx; memcpy(__temp_save.fxstate, __current->fxstate, 512); - sig_ctx->prev_context = __temp_save; + sigframe->sig_num = sig_selected; - sig_ctx->sig_num = sig_selected; - sig_ctx->signal_handler = __current->sig_handler[sig_selected]; + sigframe->sigact = action->sa_actor; + sigframe->sighand = action->sa_handler; + sigframe->prev_context = __temp_save; - __SIGSET(__current->sig_inprogress, sig_selected); + action->prev = prev_working; + psig->inprogress = action; - return sig_ctx; + return sigframe; +} + +void +proc_setsignal(struct proc_info* proc, int signum) +{ + sigset_add(proc->sigctx.sig_pending, signum); + proc->sigctx.signals[signum].sender = __current->pid; } int @@ -93,7 +106,9 @@ signal_send(pid_t pid, int signum) return -1; } + pid_t sender_pid = __current->pid; struct proc_info* proc; + if (pid > 0) { proc = get_process(pid); goto send_single; @@ -114,7 +129,9 @@ send_grp: struct proc_info *pos, *n; llist_for_each(pos, n, &proc->grp_member, grp_member) { - __SIGSET(pos->sig_pending, signum); + struct sighail* sh = &pos->sigctx; + sigset_add(sh->sig_pending, signum); + sh->signals[signum].sender = sender_pid; } send_single: @@ -122,7 +139,10 @@ send_single: __current->k_status = EINVAL; return -1; } - __SIGSET(proc->sig_pending, signum); + + sigset_add(proc->sigctx.sig_pending, signum); + proc->sigctx.signals[signum].sender = sender_pid; + return 0; } @@ -130,8 +150,15 @@ __DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx) { memcpy(__current->fxstate, sig_ctx->prev_context.fxstate, 512); __current->intr_ctx = sig_ctx->prev_context.proc_regs; - __current->flags &= ~PROC_FINPAUSE; - __SIGCLEAR(__current->sig_inprogress, sig_ctx->sig_num); + + struct sigact* current = __current->sigctx.inprogress; + if (current) { + __current->sigctx.inprogress = current->prev; + current->prev = NULL; + } else { + __current->sigctx.inprogress = NULL; + } + schedule(); // never reach! @@ -147,50 +174,48 @@ __DEFINE_LXSYSCALL3(int, sigset_t, *oldset) { - *oldset = __current->sig_mask; + struct sighail* sh = &__current->sigctx; + *oldset = sh->sig_mask; + if (how == _SIG_BLOCK) { - __current->sig_mask |= *set; + sigset_union(sh->sig_mask, *set); } else if (how == _SIG_UNBLOCK) { - __current->sig_mask &= ~(*set); + sigset_intersect(sh->sig_mask, ~(*set)); } else if (how == _SIG_SETMASK) { - __current->sig_mask = *set; + sh->sig_mask = *set; } else { return 0; } - __current->sig_mask &= ~_SIGNAL_UNMASKABLE; + + sigset_intersect(sh->sig_mask, ~UNMASKABLE); return 1; } -__DEFINE_LXSYSCALL2(int, signal, int, signum, sighandler_t, handler) +__DEFINE_LXSYSCALL2(int, sys_sigaction, int, signum, struct sigaction*, action) { if (signum <= 0 || signum >= _SIG_NUM) { return -1; } - if ((__SIGNAL(signum) & _SIGNAL_UNMASKABLE)) { + if (sigset_test(UNMASKABLE, signum)) { return -1; } - __current->sig_handler[signum] = (void*)handler; + struct sigact* sa = &__current->sigctx.signals[signum]; + + sa->sa_actor = (void*)action->sa_sigaction; + sa->sa_handler = (void*)action->sa_handler; + sigset_union(sa->sa_mask, sigset(signum)); return 0; } -void -__do_pause() +__DEFINE_LXSYSCALL(int, pause) { - __current->flags |= PROC_FINPAUSE; - - while ((__current->flags & PROC_FINPAUSE)) { - sched_yieldk(); - } + pause_current(); + sched_yieldk(); __current->k_status = EINTR; -} - -__DEFINE_LXSYSCALL(int, pause) -{ - __do_pause(); return -1; } @@ -201,15 +226,18 @@ __DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum) __DEFINE_LXSYSCALL1(int, sigpending, sigset_t, *sigset) { - *sigset = __current->sig_pending; + *sigset = __current->sigctx.sig_pending; return 0; } __DEFINE_LXSYSCALL1(int, sigsuspend, sigset_t, *mask) { - sigset_t tmp = __current->sig_mask; - __current->sig_mask = (*mask) & ~_SIGNAL_UNMASKABLE; - __do_pause(); - __current->sig_mask = tmp; + sigset_t tmp = __current->sigctx.sig_mask; + __current->sigctx.sig_mask = (*mask) & ~UNMASKABLE; + + pause_current(); + sched_yieldk(); + + __current->sigctx.sig_mask = tmp; return -1; } \ No newline at end of file diff --git a/lunaix-os/kernel/process/task_attr.c b/lunaix-os/kernel/process/task_attr.c index 7c954b3..1cca227 100644 --- a/lunaix-os/kernel/process/task_attr.c +++ b/lunaix-os/kernel/process/task_attr.c @@ -5,14 +5,14 @@ void __read_pending_sig(struct twimap* map) { struct proc_info* proc = twimap_data(map, struct proc_info*); - twimap_printf(map, "%bb", proc->sig_pending); + twimap_printf(map, "%bb", proc->sigctx.sig_pending); } void __read_masked_sig(struct twimap* map) { struct proc_info* proc = twimap_data(map, struct proc_info*); - twimap_printf(map, "%bb", proc->sig_mask); + twimap_printf(map, "%bb", proc->sigctx.sig_mask); } void diff --git a/lunaix-os/link/linker.ld b/lunaix-os/link/linker.ld index 4ea6b4e..d2d39f0 100644 --- a/lunaix-os/link/linker.ld +++ b/lunaix-os/link/linker.ld @@ -37,17 +37,15 @@ SECTIONS { /* 好了,我们的内核…… */ .text BLOCK(4K) : AT ( ADDR(.text) - 0xC0000000 ) { __kernel_start = .; + PROVIDE(__ktext_start = .); + kernel/*.o (.text) hal/*.o (.text) debug/*.o (.text) libs/*.o (.text) - } - __usrtext_start = ALIGN(4K); - .usrtext BLOCK(4K) : AT ( ADDR(.usrtext) - 0xC0000000 ) { - * (.usrtext) + PROVIDE(__ktext_end = .); } - __usrtext_end = ALIGN(4K); .data BLOCK(4K) : AT ( ADDR(.data) - 0xC0000000 ) { kernel/*.o (.data) diff --git a/lunaix-os/usr/libc/arch/i386/signal.c b/lunaix-os/usr/libc/arch/i386/signal.c index 681f193..d4026c6 100644 --- a/lunaix-os/usr/libc/arch/i386/signal.c +++ b/lunaix-os/usr/libc/arch/i386/signal.c @@ -1,7 +1,6 @@ #include "syscall.h" #include - -__LXSYSCALL2(int, signal, int, signum, sighandler_t, handler); +#include __LXSYSCALL1(int, sigpending, sigset_t, *set); __LXSYSCALL1(int, sigsuspend, const sigset_t, *mask); @@ -14,3 +13,48 @@ __LXSYSCALL3(int, *set, sigset_t, *oldset); + +__LXSYSCALL2(int, sys_sigaction, int, signum, struct sigaction*, action); + +__LXSYSCALL2(int, kill, pid_t, pid, int, signum); + +extern void +sigtrampoline(); + +sighandler_t +signal(int signum, sighandler_t handler) +{ + struct sigaction sa = { .sa_handler = (void*)handler, + .sa_mask = (sigset_t)-1, + .sa_sigaction = (void*)sigtrampoline }; + + sys_sigaction(signum, &sa); + + return handler; +} + +int +raise(int signum) +{ + return kill(0, signum); +} + +int +sigaction(int signum, struct sigaction* action) +{ + return sys_sigaction(signum, action); +} + +struct siguctx +{ + void* sigact; + void (*sa_handler)(int); + unsigned char saved_frame[0]; +}; + +void +sig_dohandling(int signum, void* siginfo, void* sigctx) +{ + struct siguctx* uctx = (struct siguctx*)sigctx; + uctx->sa_handler(signum); +} \ No newline at end of file diff --git a/lunaix-os/usr/libc/arch/i386/trampoline.S b/lunaix-os/usr/libc/arch/i386/trampoline.S new file mode 100644 index 0000000..9261e4b --- /dev/null +++ b/lunaix-os/usr/libc/arch/i386/trampoline.S @@ -0,0 +1,20 @@ +#include + +.section .text + .global sigtrampoline + sigtrampoline: + movl %esp, %eax + andl $0xfffffff0, %esp + pushl %eax + + leal 4(%eax), %eax + pushl %eax + pushl $0 + pushl -4(%eax) + call sig_dohandling + + addl $12, %esp + + movl $__SYSCALL_sigreturn, %eax + popl %ebx + int $33 \ No newline at end of file diff --git a/lunaix-os/usr/libc/arch/i386/unistd.c b/lunaix-os/usr/libc/arch/i386/unistd.c index 9790cb1..a8c8443 100644 --- a/lunaix-os/usr/libc/arch/i386/unistd.c +++ b/lunaix-os/usr/libc/arch/i386/unistd.c @@ -21,8 +21,6 @@ __LXSYSCALL1(unsigned int, sleep, unsigned int, seconds) __LXSYSCALL(int, pause) -__LXSYSCALL2(int, kill, pid_t, pid, int, signum) - __LXSYSCALL1(unsigned int, alarm, unsigned int, seconds) __LXSYSCALL2(int, link, const char*, oldpath, const char*, newpath) diff --git a/lunaix-os/usr/libc/includes/signal.h b/lunaix-os/usr/libc/includes/signal.h index 0e6cce2..b05dec5 100644 --- a/lunaix-os/usr/libc/includes/signal.h +++ b/lunaix-os/usr/libc/includes/signal.h @@ -4,9 +4,18 @@ #include #include -extern int +extern sighandler_t signal(int signum, sighandler_t handler); +extern int +kill(pid_t pid, int signum); + +extern int +raise(int signum); + +extern int +sigaction(int signum, struct sigaction* action); + extern int sigpending(sigset_t* set); diff --git a/lunaix-os/usr/libc/includes/unistd.h b/lunaix-os/usr/libc/includes/unistd.h index 24e519f..a5bf1e5 100644 --- a/lunaix-os/usr/libc/includes/unistd.h +++ b/lunaix-os/usr/libc/includes/unistd.h @@ -35,9 +35,6 @@ sleep(unsigned int); extern int pause(); -extern int -kill(pid_t pid, int signum); - extern unsigned int alarm(unsigned int seconds); diff --git a/lunaix-os/usr/signal_demo/signal_demo.c b/lunaix-os/usr/signal_demo/signal_demo.c index 612e132..b20f4ad 100644 --- a/lunaix-os/usr/signal_demo/signal_demo.c +++ b/lunaix-os/usr/signal_demo/signal_demo.c @@ -31,11 +31,11 @@ main() signal(SIGSEGV, sigsegv_handler); signal(SIGALRM, sigalrm_handler); - alarm(5); - int status; pid_t p = 0; + alarm(5); + printf("Child sleep 3s, parent pause.\n"); if (!fork()) { sleep(3); -- 2.27.0