diff --git a/kernel/src/arch/x86_64/asm/bitops.rs b/kernel/src/arch/x86_64/asm/bitops.rs new file mode 100644 index 00000000..9368db25 --- /dev/null +++ b/kernel/src/arch/x86_64/asm/bitops.rs @@ -0,0 +1,11 @@ +use core::arch::x86_64::_popcnt64; + +/// @brief ffz - 寻找u64中的第一个0所在的位(从第0位开始寻找) +/// 请注意,如果x中没有0,那么结果将是未定义的。请确保传入的x至少存在1个0 +/// +/// @param x 目标u64 +/// @return i32 bit-number(0..63) of the first (least significant) zero bit. +#[inline] +pub fn ffz(x: u64) -> i32 { + return unsafe { _popcnt64((x & ((!x) - 1)).try_into().unwrap()) }; +} diff --git a/kernel/src/arch/x86_64/asm/irqflags.rs b/kernel/src/arch/x86_64/asm/irqflags.rs index 2d17b995..00b4eb31 100644 --- a/kernel/src/arch/x86_64/asm/irqflags.rs +++ b/kernel/src/arch/x86_64/asm/irqflags.rs @@ -1,21 +1,15 @@ -use core::arch::asm; +use core::{arch::asm, ptr::read_volatile}; #[inline] pub fn local_irq_save(flags: &mut u64) { unsafe { - asm!( - "pushfq", - "pop rax", - "mov rax, {0}", - "cli", - out(reg)(*flags), - ); + asm!("pushfq", "pop rax", "mov rax, {0}", "cli", out(reg)(*flags),); } } #[inline] pub fn local_irq_restore(flags: &u64) { - let x = *flags; + let x = unsafe { read_volatile(flags) }; unsafe { asm!("push r15", diff --git a/kernel/src/arch/x86_64/asm/mod.rs b/kernel/src/arch/x86_64/asm/mod.rs index 941c53c9..6ed5e1f1 100644 --- a/kernel/src/arch/x86_64/asm/mod.rs +++ b/kernel/src/arch/x86_64/asm/mod.rs @@ -1,3 +1,5 @@ pub mod irqflags; #[macro_use] -pub mod current; \ No newline at end of file +pub mod current; +pub mod ptrace; +pub mod bitops; \ No newline at end of file diff --git a/kernel/src/arch/x86_64/asm/ptrace.rs b/kernel/src/arch/x86_64/asm/ptrace.rs new file mode 100644 index 00000000..d5faba63 --- /dev/null +++ b/kernel/src/arch/x86_64/asm/ptrace.rs @@ -0,0 +1,12 @@ +#![allow(dead_code)] +use crate::include::bindings::bindings::pt_regs; + +/// @brief 判断给定的栈帧是否来自用户态 +/// 判断方法为:根据代码段选择子是否具有ring3的访问权限(低2bit均为1) +pub fn user_mode(regs: *const pt_regs)->bool{ + if (unsafe{(*regs).cs} & 0x3) != 0{ + return true; + }else { + return false; + } +} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/interrupt/mod.rs b/kernel/src/arch/x86_64/interrupt/mod.rs new file mode 100644 index 00000000..909948f0 --- /dev/null +++ b/kernel/src/arch/x86_64/interrupt/mod.rs @@ -0,0 +1,18 @@ +#![allow(dead_code)] +use core::arch::asm; + +/// @brief 关闭中断 +#[inline] +pub fn cli(){ + unsafe{ + asm!("cli"); + } +} + +/// @brief 开启中断 +#[inline] +pub fn sti(){ + unsafe{ + asm!("sti"); + } +} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 42da5087..cfb7aaf5 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -1,3 +1,4 @@ #[macro_use] pub mod asm; -pub mod cpu; \ No newline at end of file +pub mod cpu; +pub mod interrupt; \ No newline at end of file diff --git a/kernel/src/driver/video/video.c b/kernel/src/driver/video/video.c index f65d66a9..626f569b 100644 --- a/kernel/src/driver/video/video.c +++ b/kernel/src/driver/video/video.c @@ -66,6 +66,7 @@ int video_refresh_daemon(void *unused) memcpy((void *)video_frame_buffer_info.vaddr, (void *)video_refresh_target->vaddr, video_refresh_target->size); spin_unlock(&daemon_refresh_lock); + video_daemon_pcb->virtual_runtime = 0xfffff0000000; // 临时解决由于显示刷新进程的虚拟运行时间过大/过小,导致其不运行,或者一直运行的问题。将来应使用实时调度解决它 } video_refresh_expire_jiffies = cal_next_n_ms_jiffies(REFRESH_INTERVAL << 1); } @@ -83,8 +84,11 @@ void video_refresh_framebuffer(void *data) { if (unlikely(video_daemon_pcb == NULL)) return; - - process_wakeup(video_daemon_pcb); + if (clock() >= video_refresh_expire_jiffies) + { + video_daemon_pcb->virtual_runtime = 0; + process_wakeup(video_daemon_pcb); + } } /** diff --git a/kernel/src/exception/entry.S b/kernel/src/exception/entry.S index 74368cfb..999da529 100644 --- a/kernel/src/exception/entry.S +++ b/kernel/src/exception/entry.S @@ -60,6 +60,14 @@ ret_from_exception: // === 从中断中返回 === ENTRY(ret_from_intr) + + // 进入信号处理流程 + cli + // 将原本要返回的栈帧的栈指针传入do_signal的第一个参数 + movq %rsp, %rdi + callq do_signal + + // 恢复寄存器 jmp Restore_all diff --git a/kernel/src/exception/trap.c b/kernel/src/exception/trap.c index fe2e2e69..45e31ead 100644 --- a/kernel/src/exception/trap.c +++ b/kernel/src/exception/trap.c @@ -24,8 +24,8 @@ void do_debug(struct pt_regs *regs, unsigned long error_code) { printk("[ "); printk_color(RED, BLACK, "ERROR / TRAP"); - printk(" ] do_debug(1),\tError Code:%#18lx,\tRSP:%#18lx,\tRIP:%#18lx\t CPU:%d\n", error_code, regs->rsp, regs->rip, - proc_current_cpu_id); + printk(" ] do_debug(1),\tError Code:%#18lx,\tRSP:%#18lx,\tRIP:%#18lx\t CPU:%d, pid:%d\n", error_code, regs->rsp, regs->rip, + proc_current_cpu_id, current_pcb->pid); while (1) hlt(); diff --git a/kernel/src/filesystem/VFS/VFS.c b/kernel/src/filesystem/VFS/VFS.c index 1a449f41..dfa817aa 100644 --- a/kernel/src/filesystem/VFS/VFS.c +++ b/kernel/src/filesystem/VFS/VFS.c @@ -359,7 +359,7 @@ uint64_t sys_mkdir(struct pt_regs *regs) // kdebug("path = %s", path); mode_t mode = (mode_t)regs->r9; - if (regs->cs & USER_CS) + if (user_mode(regs)) return vfs_mkdir(path, mode, true); else return vfs_mkdir(path, mode, false); diff --git a/kernel/src/filesystem/procfs/procfs.c b/kernel/src/filesystem/procfs/procfs.c index 2a8d1bdf..6f4d7191 100644 --- a/kernel/src/filesystem/procfs/procfs.c +++ b/kernel/src/filesystem/procfs/procfs.c @@ -124,18 +124,23 @@ static long procfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ switch (mode) { case 1: - data_puts(fdata, "Name:"); + data_puts(fdata, "Name:\t"); data_puts(fdata, pcb_t->name); - data_puts(fdata, "\nstate:"); + data_puts(fdata, "\nstate:\t"); data_puts(fdata, ltoa(pcb_t->state)); - data_puts(fdata, "\npid:"); + data_puts(fdata, "\npid:\t"); data_puts(fdata, ltoa(pcb_t->pid)); - data_puts(fdata, "\nPpid:"); + data_puts(fdata, "\nPpid:\t"); data_puts(fdata, ltoa(pcb_t->parent_pcb->pid)); - data_puts(fdata, "\ncpu_id:"); + data_puts(fdata, "\ncpu_id:\t"); data_puts(fdata, ltoa(pcb_t->cpu_id)); - data_puts(fdata, "\npriority:"); + data_puts(fdata, "\npriority:\t"); data_puts(fdata, ltoa(pcb_t->priority)); + data_puts(fdata, "\npreempt:\t"); + data_puts(fdata, ltoa(pcb_t->preempt_count)); + data_puts(fdata, "\nvrtime:\t"); + data_puts(fdata, ltoa(pcb_t->virtual_runtime)); + // data_puts(fdata,"\n"); uint64_t hiwater_vm, text, data; diff --git a/kernel/src/include/DragonOS/signal.h b/kernel/src/include/DragonOS/signal.h index 86057324..d3bc77b2 100644 --- a/kernel/src/include/DragonOS/signal.h +++ b/kernel/src/include/DragonOS/signal.h @@ -1,3 +1,12 @@ +/** + * @file signal.h + * @author longjin (longjin@RinGoTek.cn) + * @brief signal相关类型在C语言中的导出。(以rust版本为准) + * @version 0.1 + * + * @copyright Copyright (c) 2022 + * + */ #pragma once #include #include @@ -8,6 +17,8 @@ // 系统最大支持的信号数量 #define MAX_SIG_NUM 64 +// sigset所占用的u64的数量 +#define _NSIG_U64_CNT (MAX_SIG_NUM / 64) typedef void __signalfn_t(int); typedef __signalfn_t *__sighandler_t; @@ -97,6 +108,11 @@ struct sigaction void (*sa_restorer)(void); // 暂时未实现 }; +// ============ sigaction结构体中的的sa_flags的可选值 =========== +#define SA_FLAG_IGN (1UL << 0) // 当前sigaction表示忽略信号的动作 +#define SA_FLAG_DFL (1UL << 1) // 当前sigaction表示系统默认的动作 +#define SA_FLAG_RESTORER (1UL << 2) // 当前sigaction具有用户指定的restorer + /** * 由于signal_struct总是和sighand_struct一起使用,并且信号处理的过程中必定会对sighand加锁, * 因此signal_struct不用加锁 @@ -124,4 +140,5 @@ struct sighand_struct struct sigpending { sigset_t signal; + void *sigqueue; // 信号队列(在rust中实现) }; \ No newline at end of file diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 9a0337a2..e1acea99 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -1,17 +1,23 @@ -use core::ptr::read_volatile; +use core::{ffi::c_void, intrinsics::size_of, ptr::read_volatile, sync::atomic::compiler_fence}; use crate::{ - include::{ - bindings::bindings::{ - pid_t, process_control_block, process_find_pcb_by_pid, pt_regs, spinlock_t, EINVAL, - ENOTSUP, ESRCH, PF_EXITING, PF_KTHREAD, PF_WAKEKILL, PROC_INTERRUPTIBLE, - }, - + arch::x86_64::{ + asm::{bitops::ffz, current::current_pcb, ptrace::user_mode}, + interrupt::sti, }, - kBUG, kdebug, kwarn, + include::bindings::bindings::{ + pid_t, process_control_block, process_do_exit, process_find_pcb_by_pid, pt_regs, + spinlock_t, verify_area, EINVAL, ENOTSUP, EPERM, ESRCH, PF_EXITING, PF_KTHREAD, + PF_SIGNALED, PF_WAKEKILL, PROC_INTERRUPTIBLE, USER_CS, USER_DS, USER_MAX_LINEAR_ADDR, + }, + ipc::signal_types::sigset_add, + kBUG, kdebug, kerror, kwarn, libs::{ ffi_convert::FFIBind2Rust, - spinlock::{spin_is_locked, spin_lock_irqsave, spin_unlock_irqrestore}, + spinlock::{ + spin_is_locked, spin_lock_irq, spin_lock_irqsave, spin_unlock_irq, + spin_unlock_irqrestore, + }, }, println, process::{ @@ -21,18 +27,26 @@ use crate::{ }; use super::signal_types::{ - si_code_val, sigaction, sigaction__union_u, sighand_struct, siginfo, signal_struct, - sigpending, sigset_t, SignalNumber, MAX_SIG_NUM, + si_code_val, sigaction, sigaction__union_u, sigcontext, sigframe, sighand_struct, siginfo, + signal_struct, sigpending, sigset_clear, sigset_del, sigset_t, SignalNumber, MAX_SIG_NUM, + SA_FLAG_DFL, SA_FLAG_IGN, SA_FLAG_RESTORER, STACK_ALIGN, _NSIG_U64_CNT, }; - - use super::signal_types::{__siginfo_union, __siginfo_union_data}; /// 默认信号处理程序占位符(用于在sighand结构体中的action数组中占位) pub static DEFAULT_SIGACTION: sigaction = sigaction { _u: sigaction__union_u { _sa_handler: None }, - sa_flags: 0, + sa_flags: SA_FLAG_DFL, + sa_mask: 0, + sa_restorer: None, +}; + +/// 默认的“忽略信号”的sigaction +#[allow(dead_code)] +pub static DEFAULT_SIGACTION_IGNORE: sigaction = sigaction { + _u: sigaction__union_u { _sa_handler: None }, + sa_flags: SA_FLAG_IGN, sa_mask: 0, sa_restorer: None, }; @@ -50,8 +64,8 @@ pub extern "C" fn sys_kill(regs: &pt_regs) -> u64 { ); let pid: pid_t = regs.r8 as pid_t; - let sig: Option = SignalNumber::from_i32(regs.r9 as i32); - if sig.is_none() { + let sig: SignalNumber = SignalNumber::from(regs.r9 as i32); + if sig == SignalNumber::INVALID { // 传入的signal数值不合法 kwarn!("Not a valid signal number"); return (-(EINVAL as i64)) as u64; @@ -61,7 +75,7 @@ pub extern "C" fn sys_kill(regs: &pt_regs) -> u64 { let mut info = siginfo { _sinfo: __siginfo_union { data: __siginfo_union_data { - si_signo: sig.unwrap() as i32, + si_signo: sig as i32, si_code: si_code_val::SI_USER as i32, si_errno: 0, reserved: 0, @@ -71,8 +85,12 @@ pub extern "C" fn sys_kill(regs: &pt_regs) -> u64 { }, }, }; + compiler_fence(core::sync::atomic::Ordering::SeqCst); - return signal_kill_something_info(sig.unwrap(), Some(&mut info), pid) as u64; + let retval = signal_kill_something_info(sig, Some(&mut info), pid) as u64; + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + return retval; } /// 通过kill的方式向目标进程发送信号 @@ -103,10 +121,11 @@ fn signal_kill_proc_info(sig: SignalNumber, info: Option<&mut siginfo>, pid: pid return retval; } - println!("Target pcb = {:?}", pcb.as_ref().unwrap()); - + // println!("Target pcb = {:?}", pcb.as_ref().unwrap()); + compiler_fence(core::sync::atomic::Ordering::SeqCst); // step3: 调用signal_send_sig_info函数,发送信息 retval = signal_send_sig_info(sig, info, pcb.unwrap()); + compiler_fence(core::sync::atomic::Ordering::SeqCst); // step4: 解锁 return retval; } @@ -130,7 +149,7 @@ fn signal_send_sig_info( info: Option<&mut siginfo>, target_pcb: &mut process_control_block, ) -> i32 { - kdebug!("signal_send_sig_info"); + // kdebug!("signal_send_sig_info"); // 检查sig是否符合要求,如果不符合要求,则退出。 if !verify_signal(sig) { return -(EINVAL as i32); @@ -142,12 +161,13 @@ fn signal_send_sig_info( let mut flags: u64 = 0; // 如果上锁成功,则发送信号 if !lock_process_sighand(target_pcb, &mut flags).is_none() { + compiler_fence(core::sync::atomic::Ordering::SeqCst); // 发送信号 retval = send_signal_locked(sig, info, target_pcb, PidType::PID); - - kdebug!("flags=0x{:016x}", flags); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // kdebug!("flags=0x{:016x}", flags); // 对sighand放锁 - unlock_process_sighand(target_pcb, &flags); + unlock_process_sighand(target_pcb, flags); } return retval; } @@ -160,22 +180,18 @@ fn lock_process_sighand<'a>( pcb: &'a mut process_control_block, flags: &mut u64, ) -> Option<&'a mut sighand_struct> { - kdebug!("lock_process_sighand"); + // kdebug!("lock_process_sighand"); let sighand_ptr = sighand_struct::convert_mut(unsafe { &mut *pcb.sighand }); // kdebug!("sighand_ptr={:?}", &sighand_ptr); if !sighand_ptr.is_some() { kBUG!("Sighand ptr of process {pid} is NULL!", pid = pcb.pid); return None; - } else { - kdebug!("7777"); } + let lock = { &mut sighand_ptr.unwrap().siglock }; - kdebug!("123"); - kdebug!("lock={}", unsafe { *(lock as *mut spinlock_t as *mut i8) }); + spin_lock_irqsave(lock, flags); - kdebug!("lock={}", unsafe { *(lock as *mut spinlock_t as *mut i8) }); - kdebug!("locked"); let ret = unsafe { ((*pcb).sighand as *mut sighand_struct).as_mut() }; return ret; @@ -184,13 +200,10 @@ fn lock_process_sighand<'a>( /// @brief 对pcb的sighand结构体中的siglock进行放锁,并恢复之前存储的rflags /// @param pcb 目标pcb /// @param flags 用来保存rflags的变量,将这个值恢复到rflags寄存器中 -fn unlock_process_sighand(pcb: &mut process_control_block, flags: &u64) { - kdebug!("unlock_process_sighand"); +fn unlock_process_sighand(pcb: &mut process_control_block, flags: u64) { let lock = unsafe { &mut (*pcb.sighand).siglock }; - kdebug!("lock={:?}", lock); - spin_unlock_irqrestore(lock, flags); - kdebug!("lock={}", unsafe { *(lock as *mut spinlock_t as *mut i8) }); - kdebug!("123443"); + + spin_unlock_irqrestore(lock, &flags); } /// @brief 判断是否需要强制发送信号,然后发送信号 @@ -203,18 +216,17 @@ fn send_signal_locked( pcb: &mut process_control_block, pt: PidType, ) -> i32 { - kdebug!("send_signal_locked"); // 是否强制发送信号 let mut force_send = false; // signal的信息为空 if info.is_none() { // todo: 判断signal是否来自于一个祖先进程的namespace,如果是,则强制发送信号 } else { - force_send = unsafe { info.as_ref().unwrap()._sinfo.data }.si_code + force_send = unsafe { info.as_ref().unwrap()._sinfo.data.si_code } == (si_code_val::SI_KERNEL as i32); } - kdebug!("force send={}", force_send); + // kdebug!("force send={}", force_send); return __send_signal_locked(sig, info, pcb, pt, force_send); } @@ -234,18 +246,14 @@ fn __send_signal_locked( pt: PidType, _force_send: bool, ) -> i32 { - kdebug!("__send_signal_locked"); + // kdebug!("__send_signal_locked"); let mut retval = 0; // 判断该进入该函数时,是否已经持有了锁 - println!( - "locked={}", - spin_is_locked(unsafe { &(*pcb.sighand).siglock }) - ); - kdebug!("1234"); - let _pending: Option<&mut sigpending> = sigpending::convert_mut(&mut pcb.sig_pending); - kdebug!("567"); + assert!(spin_is_locked(unsafe { &(*pcb.sighand).siglock })); + let _pending: Option<&mut sigpending> = sigpending::convert_mut(&mut pcb.sig_pending); + compiler_fence(core::sync::atomic::Ordering::SeqCst); // 如果是kill或者目标pcb是内核线程,则无需获取sigqueue,直接发送信号即可 if sig == SignalNumber::SIGKILL || (pcb.flags & (PF_KTHREAD as u64)) != 0 { complete_signal(sig, pcb, pt); @@ -253,7 +261,7 @@ fn __send_signal_locked( // todo: 如果是其他信号,则加入到sigqueue内,然后complete_signal retval = -(ENOTSUP as i32); } - kdebug!("12342"); + compiler_fence(core::sync::atomic::Ordering::SeqCst); return retval; } @@ -263,14 +271,15 @@ fn __send_signal_locked( /// @param pcb 目标pcb /// @param pt siginfo结构体中,pid字段代表的含义 fn complete_signal(sig: SignalNumber, pcb: &mut process_control_block, pt: PidType) { + // kdebug!("complete_signal"); + // todo: 将信号产生的消息通知到正在监听这个信号的进程(引入signalfd之后,在这里调用signalfd_notify) - kdebug!("complete_signal"); // 将这个信号加到目标进程的sig_pending中 sigset_add( sigset_t::convert_mut(&mut pcb.sig_pending.signal).unwrap(), sig, ); - + compiler_fence(core::sync::atomic::Ordering::SeqCst); // ===== 寻找需要wakeup的目标进程 ===== // 备注:由于当前没有进程组的概念,每个进程只有1个对应的线程,因此不需要通知进程组内的每个进程。 // todo: 当引入进程组的概念后,需要完善这里,使得它能寻找一个目标进程来唤醒,接着执行信号处理的操作。 @@ -298,7 +307,7 @@ fn complete_signal(sig: SignalNumber, pcb: &mut process_control_block, pt: PidTy // todo:引入进程组后,在这里挑选一个进程来唤醒,让它执行相应的操作。 // todo!(); - + compiler_fence(core::sync::atomic::Ordering::SeqCst); // todo: 到这里,信号已经被放置在共享的pending队列中,我们在这里把目标进程唤醒。 if _target.is_some() { signal_wake_up(pcb, sig == SignalNumber::SIGKILL); @@ -346,12 +355,6 @@ fn sig_is_member(set: &sigset_t, _sig: SignalNumber) -> bool { }; } -/// @brief 将指定的信号在sigset中的对应bit进行置位 -#[inline] -fn sigset_add(set: &mut sigset_t, _sig: SignalNumber) { - *set |= 1 << ((_sig as u32) - 1); -} - /// @brief 判断signal的处理是否可能使得整个进程组退出 /// @return true 可能会导致退出(不一定) #[allow(dead_code)] @@ -386,6 +389,7 @@ fn has_sig_pending(pcb: &process_control_block) -> bool { #[inline] fn signal_wake_up(pcb: &mut process_control_block, fatal: bool) { + // kdebug!("signal_wake_up"); let mut state: u64 = 0; if fatal { state = PF_WAKEKILL as u64; @@ -394,11 +398,364 @@ fn signal_wake_up(pcb: &mut process_control_block, fatal: bool) { } fn signal_wake_up_state(pcb: &mut process_control_block, state: u64) { - assert!(spin_is_locked(&unsafe { *pcb.sighand }.siglock)); + assert!(spin_is_locked(&unsafe { (*pcb.sighand).siglock })); // todo: 设置线程结构体的标志位为TIF_SIGPENDING - + compiler_fence(core::sync::atomic::Ordering::SeqCst); // 如果目标进程已经在运行,则发起一个ipi,使得它陷入内核 if !process_wake_up_state(pcb, state | (PROC_INTERRUPTIBLE as u64)) { process_kick(pcb); } + compiler_fence(core::sync::atomic::Ordering::SeqCst); +} + +/// @brief 信号处理函数。该函数在进程退出内核态的时候会被调用,且调用前会关闭中断。 +#[no_mangle] +pub extern "C" fn do_signal(regs: &mut pt_regs) { + // 检查sigpending是否为0 + if current_pcb().sig_pending.signal == 0 || (!user_mode(regs)) { + // 若没有正在等待处理的信号,或者将要返回到的是内核态,则启用中断,然后返回 + sti(); + return; + } + + // 做完上面的检查后,开中断 + sti(); + // return; + // kdebug!("do_signal"); + let oldset = current_pcb().sig_blocked; + loop { + let (sig_number, info, ka) = get_signal_to_deliver(regs.clone()); + // 所有的信号都处理完了 + if sig_number == SignalNumber::INVALID { + return; + } + kdebug!( + "To handle signal [{}] for pid:{}", + sig_number as i32, + current_pcb().pid + ); + let res = handle_signal(sig_number, ka.unwrap(), &info.unwrap(), &oldset, regs); + if res.is_err() { + kerror!( + "Error occurred when handling signal: {}, pid={}, errcode={}", + sig_number as i32, + current_pcb().pid, + res.unwrap_err() + ); + } + } +} + +/// @brief 获取要被发送的信号的signumber, siginfo, 以及对应的sigaction结构体 +fn get_signal_to_deliver( + _regs: pt_regs, +) -> ( + SignalNumber, + Option, + Option<&'static mut sigaction>, +) { + let mut info: Option; + let ka: Option<&mut sigaction>; + let mut sig_number; + let sighand: &mut sighand_struct; + + { + let _tmp = sighand_struct::convert_mut(current_pcb().sighand); + if let Some(i) = _tmp { + sighand = i; + } else { + panic!("Sighand is NULL! pid={}", current_pcb().pid); + } + } + + spin_lock_irq(&mut sighand.siglock); + loop { + (sig_number, info) = + dequeue_signal(sigset_t::convert_mut(&mut current_pcb().sig_blocked).unwrap()); + + // 如果信号非法,则直接返回 + if sig_number == SignalNumber::INVALID { + spin_unlock_irq(unsafe { (&mut (*current_pcb().sighand).siglock) as *mut spinlock_t }); + return (sig_number, None, None); + } + + // 获取指向sigaction结构体的引用 + let hand = sighand_struct::convert_mut(current_pcb().sighand).unwrap(); + // kdebug!("hand=0x{:018x}", hand as *const sighand_struct as usize); + let tmp_ka = &mut hand.action[sig_number as usize - 1]; + + // 如果当前动作是忽略这个信号,则不管它了。 + if (tmp_ka.sa_flags & SA_FLAG_IGN) != 0 { + continue; + } else if (tmp_ka.sa_flags & SA_FLAG_DFL) == 0 { + // 当前不采用默认的信号处理函数 + ka = Some(tmp_ka); + break; + } + kdebug!( + "Use default handler to handle signal [{}] for pid {}", + sig_number as i32, + current_pcb().pid + ); + // ===== 经过上面的判断,如果能走到这一步,就意味着我们采用默认的信号处理函数来处理这个信号 ===== + spin_unlock_irq(&mut sighand.siglock); + // 标记当前进程由于信号而退出 + current_pcb().flags |= PF_SIGNALED as u64; + + // 执行进程的退出动作 + unsafe { process_do_exit(info.unwrap()._sinfo.data.si_signo as u64) }; + /* NOT REACHED 这部分代码将不会到达 */ + } + spin_unlock_irq(&mut sighand.siglock); + return (sig_number, info, ka); +} + +/// @brief 从当前进程的sigpending中取出下一个待处理的signal,并返回给调用者。(调用者应当处理这个信号) +/// 请注意,进入本函数前,当前进程应当持有current_pcb().sighand.siglock +fn dequeue_signal(sig_mask: &mut sigset_t) -> (SignalNumber, Option) { + // kdebug!("dequeue signal"); + // 获取下一个要处理的信号的编号 + let sig = next_signal( + sigpending::convert_ref(&(current_pcb().sig_pending)).unwrap(), + sig_mask, + ); + + let info: Option; + if sig != SignalNumber::INVALID { + // 如果下一个要处理的信号是合法的,则收集其siginfo + info = Some(collect_signal( + sig, + sigpending::convert_mut(&mut current_pcb().sig_pending).unwrap(), + )); + } else { + info = None; + } + + // 当一个进程具有多个线程之后,在这里需要重新计算线程的flag中的TIF_SIGPENDING位 + recalc_sigpending(); + return (sig, info); +} + +/// @brief 获取下一个要处理的信号(sig number越小的信号,优先级越高) +/// +/// @param pending 等待处理的信号 +/// @param sig_mask 屏蔽了的信号 +/// @return i32 下一个要处理的信号的number. 如果为0,则无效 +fn next_signal(pending: &sigpending, sig_mask: &sigset_t) -> SignalNumber { + let mut sig = SignalNumber::INVALID; + + let s = pending.signal; + let m = *sig_mask; + + // 获取第一个待处理的信号的号码 + let x = s & (!m); + if x != 0 { + sig = SignalNumber::from(ffz(!x) + 1); + return sig; + } + + // 暂时只支持64种信号信号 + assert_eq!(_NSIG_U64_CNT, 1); + + return sig; +} + +/// @brief 当一个进程具有多个线程之后,在这里需要重新计算线程的flag中的TIF_SIGPENDING位 +fn recalc_sigpending() { + // todo: +} + +/// @brief 收集信号的信息 +/// +/// @param sig 要收集的信号的信息 +/// @param pending 信号的排队等待标志 +/// @return siginfo 信号的信息 +fn collect_signal(sig: SignalNumber, pending: &mut sigpending) -> siginfo { + let (info, still_pending) = unsafe { pending.queue.as_mut() } + .unwrap() + .find_and_delete(sig); + + // 如果没有仍在等待的信号,则清除pending位 + if !still_pending { + sigset_del(&mut pending.signal, sig); + } + + if info.is_some() { + return info.unwrap(); + } else { + // 信号不在sigqueue中,这意味着当前信号是来自快速路径,因此直接把siginfo设置为0即可。 + let mut ret = siginfo::new(sig, 0, si_code_val::SI_USER); + ret._sinfo.data._sifields._kill._pid = 0; + return ret; + } +} + +/// @brief 真正发送signal,执行自定义的处理函数 +/// +/// @param sig 信号number +/// @param ka 信号响应动作 +/// @param info 信号信息 +/// @param oldset +/// @param regs 之前的系统调用将要返回的时候,要弹出的栈帧的拷贝 +/// +/// @return Result<0,i32> 若Error, 则返回错误码,否则返回Ok(0) +fn handle_signal( + sig: SignalNumber, + ka: &mut sigaction, + info: &siginfo, + oldset: &sigset_t, + regs: &mut pt_regs, +) -> Result { + // 设置栈帧 + let retval = setup_frame(sig, ka, info, oldset, regs); + if retval.is_err() { + return retval; + } + return Ok(0); +} + +/// @brief 在用户栈上开辟一块空间,并且把内核栈的栈帧以及需要在用户态执行的代码给保存进去。 +/// +/// @param regs 进入信号处理流程前,Restore all要弹出的内核栈栈帧 +fn setup_frame( + sig: SignalNumber, + ka: &mut sigaction, + info: &siginfo, + oldset: &sigset_t, + regs: &mut pt_regs, +) -> Result { + let mut err = 0; + let frame: *mut sigframe = get_stack(ka, ®s, size_of::()); + + // 要求这个frame的地址位于用户空间,因此进行校验 + let access_check_ok = unsafe { verify_area(frame as u64, size_of::() as u64) }; + if !access_check_ok { + // 如果地址区域位于内核空间,则直接报错 + // todo: 生成一个sigsegv + kerror!("In setup frame: access check failed"); + return Err(-(EPERM as i32)); + } + + unsafe { + (*frame).arg0 = sig as u64; + (*frame).arg1 = &((*frame).info) as *const siginfo as usize; + (*frame).arg2 = &((*frame).context) as *const sigcontext as usize; + (*frame).handler = ka._u._sa_handler.unwrap() as *mut core::ffi::c_void; + } + + // 将siginfo拷贝到用户栈 + err |= copy_siginfo_to_user(unsafe { &mut (*frame).info }, info).unwrap_or(1); + + // todo: 拷贝处理程序备用栈的地址、大小、ss_flags + + err |= setup_sigcontext(unsafe { &mut (*frame).context }, oldset, ®s).unwrap_or(1); + + // 为了与Linux的兼容性,64位程序必须由用户自行指定restorer + if ka.sa_flags & SA_FLAG_RESTORER != 0 { + unsafe { + (*frame).ret_code_ptr = + (&mut ka.sa_restorer.unwrap()) as *mut unsafe extern "C" fn() as *mut c_void; + } + } else { + kerror!( + "pid-{} forgot to set SA_FLAG_RESTORER for signal {}", + current_pcb().pid, + sig as i32 + ); + err = 1; + } + if err != 0 { + // todo: 在这里生成一个sigsegv,然后core dump + return Err(1); + } + + regs.rdi = sig as u64; + regs.rsi = unsafe { &(*frame).info as *const siginfo as u64 }; + regs.rsp = frame as u64; + regs.rip = unsafe { ka._u._sa_handler.unwrap() as *const unsafe extern "C" fn() as u64 }; + + // 如果handler位于内核空间 + if regs.rip >= USER_MAX_LINEAR_ADDR { + // 如果当前是SIGSEGV,则采用默认函数处理 + if sig == SignalNumber::SIGSEGV { + ka.sa_flags |= SA_FLAG_DFL; + } + + // 将rip设置为0 + regs.rip = 0; + } + + // 设置cs和ds寄存器 + regs.cs = (USER_CS | 0x3) as u64; + regs.ds = (USER_DS | 0x3) as u64; + + return if err == 0 { Ok(0) } else { Err(1) }; +} + +#[inline(always)] +fn get_stack(_ka: &sigaction, regs: &pt_regs, size: usize) -> *mut sigframe { + // 默认使用 用户栈的栈顶指针-128字节的红区-sigframe的大小 + let mut rsp: usize = (regs.rsp as usize) - 128 - size; + // 按照要求进行对齐 + rsp &= (-(STACK_ALIGN as i64)) as usize; + return rsp as *mut sigframe; +} + +/// @brief 将siginfo结构体拷贝到用户栈 +fn copy_siginfo_to_user(to: *mut siginfo, from: &siginfo) -> Result { + // 验证目标地址是否为用户空间 + if unsafe { !verify_area(to as u64, size_of::() as u64) } { + // 如果目标地址空间不为用户空间,则直接返回错误码 -EPERM + return Err(-(EPERM as i32)); + } + + let retval: Result = Ok(0); + + // todo: 将这里按照si_code的类型来分别拷贝不同的信息。 + // 这里参考linux-2.6.39 网址: http://opengrok.ringotek.cn/xref/linux-2.6.39/arch/ia64/kernel/signal.c#137 + + unsafe { + (*to)._sinfo.data._sifields._kill._pid = from._sinfo.data._sifields._kill._pid; + } + + return retval; +} + +/// @brief 设置目标的sigcontext +/// +/// @param context 要被设置的目标sigcontext +/// @param mask 要被暂存的信号mask标志位 +/// @param regs 进入信号处理流程前,Restore all要弹出的内核栈栈帧 +fn setup_sigcontext(context: &mut sigcontext, mask: &sigset_t, regs: &pt_regs) -> Result { + let current_thread = current_pcb().thread; + + context.oldmask = *mask; + context.regs = regs.clone(); + context.trap_num = unsafe { (*current_thread).trap_num }; + context.err_code = unsafe { (*current_thread).err_code }; + context.cr2 = unsafe { (*current_thread).cr2 }; + return Ok(0); +} + +/// @brief 刷新指定进程的sighand的sigaction,将满足条件的sigaction恢复为Default +/// 除非某个信号被设置为ignore且force_default为false,否则都不会将其恢复 +/// +/// @param pcb 要被刷新的pcb +/// @param force_default 是否强制将sigaction恢复成默认状态 +pub fn flush_signal_handlers(pcb: *mut process_control_block, force_default: bool) { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + let action = unsafe { &mut (*(*pcb).sighand).action }; + for ka in action.iter_mut() { + if force_default || (ka.sa_flags != SA_FLAG_IGN) { + ka.sa_flags = SA_FLAG_DFL; + ka._u._sa_handler = None; + } + // 清除flags中,除了DFL和IGN以外的所有标志 + ka.sa_flags &= SA_FLAG_DFL | SA_FLAG_IGN; + ka.sa_restorer = None; + sigset_clear(&mut ka.sa_mask); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + } + compiler_fence(core::sync::atomic::Ordering::SeqCst); } diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index 4d5613f6..aed0cde3 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -1,9 +1,16 @@ #![allow(non_camel_case_types)] // 这是signal暴露给其他模块的公有的接口文件 +use core::ffi::c_void; +use core::fmt::Debug; + +use alloc::vec::Vec; + // todo: 将这里更换为手动编写的ffi绑定 use crate::include::bindings::bindings::atomic_t; +use crate::include::bindings::bindings::pt_regs; use crate::include::bindings::bindings::spinlock_t; +use crate::kerror; use crate::libs::ffi_convert::FFIBind2Rust; use crate::libs::ffi_convert::__convert_mut; use crate::libs::ffi_convert::__convert_ref; @@ -14,8 +21,12 @@ pub type sigset_t = u64; pub type __signalfn_t = ::core::option::Option; pub type __sighandler_t = __signalfn_t; -// 最大的信号数量(改动这个值的时候请同步到signal.h) +/// 最大的信号数量(改动这个值的时候请同步到signal.h) pub const MAX_SIG_NUM: i32 = 64; +/// sigset所占用的u64的数量(改动这个值的时候请同步到signal.h) +pub const _NSIG_U64_CNT: i32 = MAX_SIG_NUM / 64; +/// 信号处理的栈的栈指针的最小对齐数量 +pub const STACK_ALIGN: u64 = 16; /// 由于signal_struct总是和sighand_struct一起使用,并且信号处理的过程中必定会对sighand加锁 /// 因此signal_struct不用加锁 @@ -26,9 +37,11 @@ pub struct signal_struct { pub sig_cnt: atomic_t, } -impl Default for signal_struct{ +impl Default for signal_struct { fn default() -> Self { - Self { sig_cnt: Default::default() } + Self { + sig_cnt: Default::default(), + } } } @@ -49,19 +62,23 @@ pub union sigaction__union_u { >, } -impl core::fmt::Debug for sigaction__union_u{ +impl core::fmt::Debug for sigaction__union_u { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str("sigaction__union_u") } } - impl Default for sigaction__union_u { fn default() -> Self { - Self{_sa_handler:None} + Self { _sa_handler: None } } } +// ============ sigaction结构体中的的sa_flags的可选值 =========== +pub const SA_FLAG_IGN: u64 = 1u64 << 0; // 当前sigaction表示忽略信号的动作 +pub const SA_FLAG_DFL: u64 = 1u64 << 1; // 当前sigaction表示系统默认的动作 +pub const SA_FLAG_RESTORER: u64 = 1u64 << 2; // 当前sigaction具有用户指定的restorer + /** * @brief 信号处理结构体 */ @@ -71,17 +88,21 @@ pub struct sigaction { pub _u: sigaction__union_u, pub sa_flags: u64, pub sa_mask: sigset_t, - pub sa_restorer: ::core::option::Option, // 暂时未实现该函数 + /// 信号处理函数执行结束后,将会跳转到这个函数内进行执行,然后执行sigreturn系统调用 + pub sa_restorer: ::core::option::Option, } -impl Default for sigaction{ +impl Default for sigaction { fn default() -> Self { - Self { _u: Default::default(), sa_flags: Default::default(), sa_mask: Default::default(), sa_restorer: Default::default() } + Self { + _u: Default::default(), + sa_flags: Default::default(), + sa_mask: Default::default(), + sa_restorer: Default::default(), + } } } - - /** * 信号消息的结构体,作为参数传入sigaction结构体中指向的处理函数 */ @@ -126,6 +147,38 @@ pub struct __sifields__kill { pub _pid: i64, /* 发起kill的进程的pid */ } +impl siginfo { + pub fn new(sig: SignalNumber, _si_errno: i32, _si_code: si_code_val) -> Self { + siginfo { + _sinfo: __siginfo_union { + data: __siginfo_union_data { + si_signo: sig as i32, + si_code: _si_code as i32, + si_errno: _si_errno, + reserved: 0, + _sifields: super::signal_types::__sifields { + _kill: super::signal_types::__sifields__kill { _pid: 0 }, + }, + }, + }, + } + } +} + +impl Debug for siginfo { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + unsafe { + f.write_fmt(format_args!( + "si_signo:{}, si_code:{}, si_errno:{}, _pid:{}", + self._sinfo.data.si_signo, + self._sinfo.data.si_code, + self._sinfo.data.si_errno, + self._sinfo.data._sifields._kill._pid + )) + } + } +} + /** * @brief 信号处理结构体,位于pcb之中 */ @@ -137,9 +190,13 @@ pub struct sighand_struct { pub action: [sigaction; MAX_SIG_NUM as usize], } -impl Default for sighand_struct{ +impl Default for sighand_struct { fn default() -> Self { - Self { siglock: Default::default(), count: Default::default(), action: [Default::default();MAX_SIG_NUM as usize] } + Self { + siglock: Default::default(), + count: Default::default(), + action: [Default::default(); MAX_SIG_NUM as usize], + } } } @@ -150,8 +207,12 @@ impl Default for sighand_struct{ #[derive(Debug, Copy, Clone)] pub struct sigpending { pub signal: sigset_t, + /// 信号队列 + pub queue: *mut SigQueue, } +/// siginfo中的si_code的可选值 +/// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态 #[allow(dead_code)] #[repr(i32)] pub enum si_code_val { @@ -192,6 +253,7 @@ impl si_code_val { #[derive(Debug, Clone, Copy)] #[repr(i32)] pub enum SignalNumber { + INVALID = 0, SIGHUP = 1, SIGINT, SIGQUIT, @@ -237,18 +299,18 @@ impl PartialEq for SignalNumber { } } -impl SignalNumber { - /// @brief 从i32转换为SignalNumber枚举类型,如果传入的x不符合要求,则返回None - #[allow(dead_code)] - pub fn from_i32(x: i32) -> Option { - if Self::valid_signal_number(x) { - let ret: SignalNumber = unsafe { core::mem::transmute(x) }; - return Some(ret); +impl From for SignalNumber { + fn from(value: i32) -> Self { + if Self::valid_signal_number(value) { + let ret: SignalNumber = unsafe { core::mem::transmute(value) }; + return ret; + } else { + kerror!("Try to convert an invalid number to SignalNumber"); + return SignalNumber::INVALID; } - - return None; } - +} +impl SignalNumber { /// 判断一个数字是否为可用的信号 fn valid_signal_number(x: i32) -> bool { if x > 0 && x < MAX_SIG_NUM { @@ -268,14 +330,14 @@ pub const SIGRTMAX: i32 = MAX_SIG_NUM; /// /// 这么做的主要原因在于,由于PCB是通过bindgen生成的FFI,因此pcb中的结构体类型都是bindgen自动生成的 impl FFIBind2Rust for signal_struct { - fn convert_mut<'a>( + fn convert_mut( src: *mut crate::include::bindings::bindings::signal_struct, - ) -> Option<&'a mut Self> { + ) -> Option<&'static mut Self> { return __convert_mut(src); } - fn convert_ref<'a>( + fn convert_ref( src: *const crate::include::bindings::bindings::signal_struct, - ) -> Option<&'a Self> { + ) -> Option<&'static Self> { return __convert_ref(src); } } @@ -284,32 +346,31 @@ impl FFIBind2Rust for signal_ /// /// 这么做的主要原因在于,由于PCB是通过bindgen生成的FFI,因此pcb中的结构体类型都是bindgen自动生成的 impl FFIBind2Rust for siginfo { - fn convert_mut<'a>( + fn convert_mut( src: *mut crate::include::bindings::bindings::siginfo, - ) -> Option<&'a mut Self> { + ) -> Option<&'static mut Self> { return __convert_mut(src); } - fn convert_ref<'a>( + fn convert_ref( src: *const crate::include::bindings::bindings::siginfo, - ) -> Option<&'a Self> { - return __convert_ref(src) + ) -> Option<&'static Self> { + return __convert_ref(src); } } - /// @brief 将给定的sigset_t解析为Rust的signal.rs中定义的sigset_t的引用 /// /// 这么做的主要原因在于,由于PCB是通过bindgen生成的FFI,因此pcb中的结构体类型都是bindgen自动生成的 impl FFIBind2Rust for sigset_t { - fn convert_mut<'a>( + fn convert_mut( src: *mut crate::include::bindings::bindings::sigset_t, - ) -> Option<&'a mut Self> { + ) -> Option<&'static mut Self> { return __convert_mut(src); } - fn convert_ref<'a>( + fn convert_ref( src: *const crate::include::bindings::bindings::sigset_t, - ) -> Option<&'a Self> { - return __convert_ref(src) + ) -> Option<&'static Self> { + return __convert_ref(src); } } @@ -317,44 +378,184 @@ impl FFIBind2Rust for sigset_t { /// /// 这么做的主要原因在于,由于PCB是通过bindgen生成的FFI,因此pcb中的结构体类型都是bindgen自动生成的 impl FFIBind2Rust for sigpending { - fn convert_mut<'a>( + fn convert_mut( src: *mut crate::include::bindings::bindings::sigpending, - ) -> Option<&'a mut Self> { + ) -> Option<&'static mut Self> { return __convert_mut(src); } - fn convert_ref<'a>( + fn convert_ref( src: *const crate::include::bindings::bindings::sigpending, - ) -> Option<&'a Self> { - return __convert_ref(src) + ) -> Option<&'static Self> { + return __convert_ref(src); } } /// @brief 将给定的来自bindgen的sighand_struct解析为Rust的signal.rs中定义的sighand_struct的引用 /// /// 这么做的主要原因在于,由于PCB是通过bindgen生成的FFI,因此pcb中的结构体类型都是bindgen自动生成的,会导致无法自定义功能的问题。 -impl FFIBind2Rust for sighand_struct{ - fn convert_mut<'a>( +impl FFIBind2Rust for sighand_struct { + fn convert_mut( src: *mut crate::include::bindings::bindings::sighand_struct, - ) -> Option<&'a mut Self> { + ) -> Option<&'static mut Self> { return __convert_mut(src); } - fn convert_ref<'a>( + fn convert_ref( src: *const crate::include::bindings::bindings::sighand_struct, - ) -> Option<&'a Self> { - return __convert_ref(src) + ) -> Option<&'static Self> { + return __convert_ref(src); } } /// @brief 将给定的来自bindgen的sigaction解析为Rust的signal.rs中定义的sigaction的引用 -impl FFIBind2Rust for sigaction{ - fn convert_mut<'a>( +impl FFIBind2Rust for sigaction { + fn convert_mut( src: *mut crate::include::bindings::bindings::sigaction, - ) -> Option<&'a mut Self> { + ) -> Option<&'static mut Self> { return __convert_mut(src); } - fn convert_ref<'a>( + fn convert_ref( src: *const crate::include::bindings::bindings::sigaction, - ) -> Option<&'a Self> { - return __convert_ref(src) + ) -> Option<&'static Self> { + return __convert_ref(src); } -} \ No newline at end of file +} + +/// @brief 进程接收到的信号的队列 +pub struct SigQueue { + pub q: Vec, +} + +#[allow(dead_code)] +impl SigQueue { + /// @brief 初始化一个新的信号队列 + pub fn new(capacity: usize) -> Self { + SigQueue { + q: Vec::with_capacity(capacity), + } + } + + /// @brief 在信号队列中寻找第一个满足要求的siginfo, 并返回它的引用 + /// + /// @return (第一个满足要求的siginfo的引用; 是否有多个满足条件的siginfo) + pub fn find(&self, sig: SignalNumber) -> (Option<&siginfo>, bool) { + // 是否存在多个满足条件的siginfo + let mut still_pending = false; + let mut info: Option<&siginfo> = None; + + for x in self.q.iter() { + if unsafe { x._sinfo.data.si_signo } == sig as i32 { + if info.is_some() { + still_pending = true; + break; + } else { + info = Some(x); + } + } + } + return (info, still_pending); + } + + /// @brief 在信号队列中寻找第一个满足要求的siginfo, 并将其从队列中删除,然后返回这个siginfo + /// + /// @return (第一个满足要求的siginfo; 从队列中删除前是否有多个满足条件的siginfo) + pub fn find_and_delete(&mut self, sig: SignalNumber) -> (Option, bool) { + // 是否存在多个满足条件的siginfo + let mut still_pending = false; + let mut first = true; // 标记变量,记录当前是否已经筛选出了一个元素 + + let filter = |x: &mut siginfo| { + if unsafe { x._sinfo.data.si_signo } == sig as i32 { + if !first { + // 如果之前已经筛选出了一个元素,则不把当前元素删除 + still_pending = true; + return false; + } else { + // 当前是第一个被筛选出来的元素 + first = false; + return true; + } + } else { + return false; + } + }; + // 从sigqueue中过滤出结果 + let mut filter_result: Vec = self.q.drain_filter(filter).collect(); + // 筛选出的结果不能大于1个 + assert!(filter_result.len() <= 1); + + return (filter_result.pop(), still_pending); + } +} + +impl Default for SigQueue { + fn default() -> Self { + Self { + q: Default::default(), + } + } +} + +/// @brief 清除sigset中,某个信号对应的标志位 +#[inline] +pub fn sigset_del(set: &mut sigset_t, sig: SignalNumber) { + let sig = sig as i32 - 1; + if _NSIG_U64_CNT == 1 { + *set &= !(1 << sig); + } else { + // 暂时不支持超过64个信号 + panic!("Unsupported signal number: {:?}", sig); + } +} + +/// @brief 将指定的信号在sigset中的对应bit进行置位 +#[inline] +pub fn sigset_add(set: &mut sigset_t, _sig: SignalNumber) { + *set |= 1 << ((_sig as u32) - 1); +} + +/// @brief 将sigset清零 +#[inline] +pub fn sigset_clear(set: &mut sigset_t) { + *set = 0; +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct sigframe { + /// 指向restorer的地址的指针。(该变量必须放在sigframe的第一位,因为这样才能在handler返回的时候,跳转到对应的代码,执行sigreturn) + pub ret_code_ptr: *mut core::ffi::c_void, + /// signum + pub arg0: u64, + /// siginfo pointer + pub arg1: usize, + /// sigcontext pointer + pub arg2: usize, + + pub handler: *mut c_void, + pub info: siginfo, + pub context: sigcontext, +} + +#[derive(Debug, Clone, Copy)] +pub struct sigcontext { + /// sigcontext的标志位 + pub sc_flags: u64, + pub sc_stack: signal_stack, // 信号处理程序备用栈信息 + + pub regs: pt_regs, // 暂存的系统调用/中断返回时,原本要弹出的内核栈帧 + pub trap_num: u64, // 用来保存线程结构体中的trap_num字段 + pub oldmask: u64, // 暂存的执行信号处理函数之前的sigmask + pub cr2: u64, // 用来保存线程结构体中的cr2字段 + pub err_code: u64, // 用来保存线程结构体中的err_code字段 + // todo: 支持x87浮点处理器后,在这里增加浮点处理器的状态结构体指针 + pub reserved_for_x87_state: u64, + pub reserved: [u64; 8], +} + +/// @brief 信号处理备用栈的信息 +#[derive(Debug, Clone, Copy)] +pub struct signal_stack { + pub sp: *mut c_void, + pub flags: u32, + pub size: u32, +} diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index bb68f0b0..58b565e1 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -3,6 +3,7 @@ #![feature(core_intrinsics)] // <2> #![feature(alloc_error_handler)] #![feature(panic_info_message)] +#![feature(drain_filter)]// 允许Vec的drain_filter特性 #[allow(non_upper_case_globals)] #[allow(non_camel_case_types)] diff --git a/kernel/src/libs/ffi_convert.rs b/kernel/src/libs/ffi_convert.rs index 77e50e45..97f13f40 100644 --- a/kernel/src/libs/ffi_convert.rs +++ b/kernel/src/libs/ffi_convert.rs @@ -1,9 +1,9 @@ /// @brief 由bindgen生成的结构体转换成rust原生定义的结构体的特性 pub trait FFIBind2Rust { /// 转换为不可变引用 - fn convert_ref<'a>(src: *const T) -> Option<&'a Self>; + fn convert_ref(src: *const T) -> Option<&'static Self>; /// 转换为可变引用 - fn convert_mut<'a>(src: *mut T) -> Option<&'a mut Self>; + fn convert_mut(src: *mut T) -> Option<&'static mut Self>; } diff --git a/kernel/src/libs/refcount.rs b/kernel/src/libs/refcount.rs index 95b3fff0..7f63e8f9 100644 --- a/kernel/src/libs/refcount.rs +++ b/kernel/src/libs/refcount.rs @@ -15,14 +15,14 @@ impl Default for RefCount{ /// @brief 将给定的来自bindgen的refcount_t解析为Rust的RefCount的引用 impl FFIBind2Rust for RefCount{ - fn convert_mut<'a>( + fn convert_mut( src: *mut crate::include::bindings::bindings::refcount_struct, - ) -> Option<&'a mut Self> { + ) -> Option<&'static mut Self> { return __convert_mut(src); } - fn convert_ref<'a>( + fn convert_ref( src: *const crate::include::bindings::bindings::refcount_struct, - ) -> Option<&'a Self> { + ) -> Option<&'static Self> { return __convert_ref(src) } } diff --git a/kernel/src/libs/spinlock.rs b/kernel/src/libs/spinlock.rs index 8d4e6c9d..39ab23da 100644 --- a/kernel/src/libs/spinlock.rs +++ b/kernel/src/libs/spinlock.rs @@ -2,9 +2,11 @@ use core::ptr::read_volatile; use crate::arch::x86_64::asm::irqflags::{local_irq_restore, local_irq_save}; +use crate::arch::x86_64::interrupt::{cli, sti}; use crate::include::bindings::bindings::{spin_lock, spin_unlock, spinlock_t}; /// @brief 保存中断状态到flags中,关闭中断,并对自旋锁加锁 +#[inline] pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut u64) { local_irq_save(flags); unsafe { @@ -13,7 +15,7 @@ pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut u64) { } /// @brief 恢复rflags以及中断状态并解锁自旋锁 -#[no_mangle] +#[inline] pub fn spin_unlock_irqrestore(lock: *mut spinlock_t, flags: &u64) { unsafe { spin_unlock(lock); @@ -23,6 +25,7 @@ pub fn spin_unlock_irqrestore(lock: *mut spinlock_t, flags: &u64) { } /// 判断一个自旋锁是否已经被加锁 +#[inline] pub fn spin_is_locked(lock: &spinlock_t) -> bool { let val = unsafe { read_volatile(&lock.lock as *const i8) }; @@ -33,4 +36,16 @@ impl Default for spinlock_t { fn default() -> Self { Self { lock: 1 } } +} + +/// @brief 关闭中断并加锁 +pub fn spin_lock_irq(lock: *mut spinlock_t){ + cli(); + unsafe{spin_lock(lock);} +} + +/// @brief 解锁并开中断 +pub fn spin_unlock_irq(lock: *mut spinlock_t){ + unsafe{spin_unlock(lock);} + sti(); } \ No newline at end of file diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index 96f5dacd..fc4bb951 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -1,4 +1,4 @@ -use core::ptr::null_mut; +use core::{ffi::c_void, ptr::null_mut, sync::atomic::compiler_fence}; use alloc::boxed::Box; @@ -8,10 +8,9 @@ use crate::{ process_control_block, CLONE_CLEAR_SIGHAND, CLONE_SIGHAND, CLONE_THREAD, ENOMEM, }, ipc::{ - signal::DEFAULT_SIGACTION, - signal_types::{sigaction, sighand_struct, signal_struct}, + signal::{flush_signal_handlers, DEFAULT_SIGACTION}, + signal_types::{sigaction, sighand_struct, signal_struct, SigQueue}, }, - kdebug, libs::{ atomic::atomic_set, ffi_convert::FFIBind2Rust, @@ -22,29 +21,38 @@ use crate::{ #[no_mangle] pub extern "C" fn process_copy_sighand(clone_flags: u64, pcb: *mut process_control_block) -> i32 { - kdebug!("process_copy_sighand"); + // kdebug!("process_copy_sighand"); + if (clone_flags & (CLONE_SIGHAND as u64)) != 0 { let r = RefCount::convert_mut(unsafe { &mut (*(current_pcb().sighand)).count }).unwrap(); refcount_inc(r); } + // 在这里使用Box::leak将动态申请的内存的生命周期转换为static的 let mut sig: &mut sighand_struct = Box::leak(Box::new(sighand_struct::default())); if (sig as *mut sighand_struct) == null_mut() { return -(ENOMEM as i32); } + // 将新的sighand赋值给pcb unsafe { (*pcb).sighand = sig as *mut sighand_struct as usize as *mut crate::include::bindings::bindings::sighand_struct; } + // kdebug!("DEFAULT_SIGACTION.sa_flags={}", DEFAULT_SIGACTION.sa_flags); + // 拷贝sigaction let mut flags: u64 = 0; + spin_lock_irqsave(unsafe { &mut (*current_pcb().sighand).siglock }, &mut flags); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + for (index, x) in unsafe { (*current_pcb().sighand).action } .iter() .enumerate() { + compiler_fence(core::sync::atomic::Ordering::SeqCst); if !(x as *const crate::include::bindings::bindings::sigaction).is_null() { sig.action[index] = *sigaction::convert_ref(x as *const crate::include::bindings::bindings::sigaction) @@ -53,20 +61,26 @@ pub extern "C" fn process_copy_sighand(clone_flags: u64, pcb: *mut process_contr sig.action[index] = DEFAULT_SIGACTION; } } + compiler_fence(core::sync::atomic::Ordering::SeqCst); spin_unlock_irqrestore(unsafe { &mut (*current_pcb().sighand).siglock }, &flags); + compiler_fence(core::sync::atomic::Ordering::SeqCst); - // 将所有屏蔽的信号的处理函数设置为default + // 将信号的处理函数设置为default(除了那些被手动屏蔽的) if (clone_flags & (CLONE_CLEAR_SIGHAND as u64)) != 0 { - todo!(); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + flush_signal_handlers(pcb, false); + compiler_fence(core::sync::atomic::Ordering::SeqCst); } + compiler_fence(core::sync::atomic::Ordering::SeqCst); return 0; } #[no_mangle] pub extern "C" fn process_copy_signal(clone_flags: u64, pcb: *mut process_control_block) -> i32 { - kdebug!("process_copy_signal"); + // kdebug!("process_copy_signal"); // 如果克隆的是线程,则不拷贝信号(同一进程的各个线程之间共享信号) if (clone_flags & (CLONE_THREAD as u64)) != 0 { return 0; @@ -81,6 +95,13 @@ pub extern "C" fn process_copy_signal(clone_flags: u64, pcb: *mut process_contro (*pcb).signal = sig as *mut signal_struct as usize as *mut crate::include::bindings::bindings::signal_struct; } + + // 创建新的sig_pending->sigqueue + unsafe { + (*pcb).sig_pending.signal = 0; + (*pcb).sig_pending.sigqueue = + Box::leak(Box::new(SigQueue::default())) as *mut SigQueue as *mut c_void; + } return 0; } @@ -88,9 +109,15 @@ pub extern "C" fn process_copy_signal(clone_flags: u64, pcb: *mut process_contro pub extern "C" fn process_exit_signal(pcb: *mut process_control_block) { // 回收进程的信号结构体 unsafe { + // 回收sighand let sighand = Box::from_raw((*pcb).sighand as *mut sighand_struct); + drop(sighand); (*pcb).sighand = 0 as *mut crate::include::bindings::bindings::sighand_struct; + + // 回收sigqueue + let queue = Box::from_raw((*pcb).sig_pending.sigqueue as *mut SigQueue); + drop(queue); } } diff --git a/kernel/src/process/initial_proc.rs b/kernel/src/process/initial_proc.rs index 42ca5904..1f76be7f 100644 --- a/kernel/src/process/initial_proc.rs +++ b/kernel/src/process/initial_proc.rs @@ -1,13 +1,17 @@ +use core::ffi::c_void; + +use alloc::boxed::Box; + use crate::{ - include::bindings::bindings::{atomic_t, spinlock_t}, - ipc::signal::DEFAULT_SIGACTION, + include::bindings::bindings::{atomic_t, process_control_block, spinlock_t}, + ipc::{signal::DEFAULT_SIGACTION, signal_types::SigQueue}, }; use crate::ipc::signal_types::{sighand_struct, signal_struct, MAX_SIG_NUM}; /// @brief 初始进程的signal结构体 #[no_mangle] -pub static INITIAL_SIGNALS: signal_struct = signal_struct { +pub static mut INITIAL_SIGNALS: signal_struct = signal_struct { sig_cnt: atomic_t { value: 0 }, }; @@ -18,3 +22,25 @@ pub static mut INITIAL_SIGHAND: sighand_struct = sighand_struct { siglock: spinlock_t { lock: 1 }, action: [DEFAULT_SIGACTION; MAX_SIG_NUM as usize], }; + +/// @brief 初始化pid=0的进程的信号相关的信息 +#[no_mangle] +pub extern "C" fn initial_proc_init_signal(pcb: *mut process_control_block) { + + // 所设置的pcb的pid一定为0 + assert_eq!(unsafe { (*pcb).pid }, 0); + + // 设置init进程的sighand和signal + unsafe { + (*pcb).sighand = &mut INITIAL_SIGHAND as *mut sighand_struct as usize + as *mut crate::include::bindings::bindings::sighand_struct; + (*pcb).signal = &mut INITIAL_SIGNALS as *mut signal_struct as usize + as *mut crate::include::bindings::bindings::signal_struct; + } + // 创建新的sig_pending->sigqueue + unsafe { + (*pcb).sig_pending.signal = 0; + (*pcb).sig_pending.sigqueue = + Box::leak(Box::new(SigQueue::default())) as *mut SigQueue as *mut c_void; + } +} diff --git a/kernel/src/process/proc-types.h b/kernel/src/process/proc-types.h index 77c22ef5..0cd593d4 100644 --- a/kernel/src/process/proc-types.h +++ b/kernel/src/process/proc-types.h @@ -67,6 +67,7 @@ struct thread_struct #define PF_NOFREEZE (1UL << 4) // 当前进程不能被冻结 #define PF_EXITING (1UL << 5) // 进程正在退出 #define PF_WAKEKILL (1UL << 6) // 进程由于接收到终止信号唤醒 +#define PF_SIGNALED (1UL << 7) // 进程由于接收到信号而退出 /** * @brief 进程控制块 * diff --git a/kernel/src/process/process.c b/kernel/src/process/process.c index 9eb9b062..c9c10694 100644 --- a/kernel/src/process/process.c +++ b/kernel/src/process/process.c @@ -49,6 +49,7 @@ extern struct sighand_struct INITIAL_SIGHAND; extern void process_exit_sighand(struct process_control_block *pcb); extern void process_exit_signal(struct process_control_block *pcb); +extern void initial_proc_init_signal(struct process_control_block *pcb); // 设置初始进程的PCB #define INITIAL_PROC(proc) \ @@ -439,7 +440,7 @@ ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[]) regs->rsi = (uint64_t)dst_argv; } // kdebug("execve ok"); - + // 设置进程的段选择子为用户态可访问 regs->cs = USER_CS | 3; regs->ds = USER_DS | 3; regs->ss = USER_DS | 0x3; @@ -464,7 +465,7 @@ exec_failed:; #pragma GCC optimize("O0") ul initial_kernel_thread(ul arg) { - kinfo("initial proc running...\targ:%#018lx", arg); + kinfo("initial proc running...\targ:%#018lx, vruntime=%d", arg, current_pcb->virtual_runtime); scm_enable_double_buffer(); @@ -624,6 +625,8 @@ void process_init() list_init(&initial_proc_union.pcb.list); wait_queue_init(&initial_proc_union.pcb.wait_child_proc_exit, NULL); + // 初始化init进程的signal相关的信息 + initial_proc_init_signal(current_pcb); // 临时设置IDLE进程的的虚拟运行时间为0,防止下面的这些内核线程的虚拟运行时间出错 current_pcb->virtual_runtime = 0; barrier(); diff --git a/kernel/src/process/ptrace.h b/kernel/src/process/ptrace.h index ba03a2e0..4d0c5d8d 100644 --- a/kernel/src/process/ptrace.h +++ b/kernel/src/process/ptrace.h @@ -8,30 +8,41 @@ struct pt_regs { - unsigned long r15; - unsigned long r14; - unsigned long r13; - unsigned long r12; - unsigned long r11; - unsigned long r10; - unsigned long r9; - unsigned long r8; - unsigned long rbx; - unsigned long rcx; - unsigned long rdx; - unsigned long rsi; - unsigned long rdi; - unsigned long rbp; - unsigned long ds; - unsigned long es; - unsigned long rax; - unsigned long func; - unsigned long errcode; - unsigned long rip; - unsigned long cs; - unsigned long rflags; - unsigned long rsp; - unsigned long ss; + unsigned long r15; + unsigned long r14; + unsigned long r13; + unsigned long r12; + unsigned long r11; + unsigned long r10; + unsigned long r9; + unsigned long r8; + unsigned long rbx; + unsigned long rcx; + unsigned long rdx; + unsigned long rsi; + unsigned long rdi; + unsigned long rbp; + unsigned long ds; + unsigned long es; + unsigned long rax; + unsigned long func; + unsigned long errcode; + unsigned long rip; + unsigned long cs; + unsigned long rflags; + unsigned long rsp; + unsigned long ss; }; +/** + * @brief 判断pt_regs是否来自用户态 + * + * @param regs + * @return __always_inline + */ +static inline int user_mode(struct pt_regs *regs) +{ + return !!(regs->cs & 3); +} + #endif diff --git a/kernel/src/syscall/syscall.c b/kernel/src/syscall/syscall.c index c0b07f9b..9bd2e29f 100644 --- a/kernel/src/syscall/syscall.c +++ b/kernel/src/syscall/syscall.c @@ -372,7 +372,7 @@ uint64_t sys_chdir(struct pt_regs *regs) // 计算输入的路径长度 int dest_path_len; - if (regs->cs & USER_CS) + if (user_mode(regs)) { dest_path_len = strnlen_user(dest_path, PAGE_4K_SIZE); } diff --git a/kernel/src/syscall/syscall.h b/kernel/src/syscall/syscall.h index 10ddbe57..dce746eb 100644 --- a/kernel/src/syscall/syscall.h +++ b/kernel/src/syscall/syscall.h @@ -17,7 +17,7 @@ extern void ret_from_system_call(void); // 导出从系统调用返回的函数 extern system_call_t system_call_table[MAX_SYSTEM_CALL_NUM]; // 判断系统调用是否来自用户态 -#define SYSCALL_FROM_USER(regs) ((regs)->cs & USER_CS) +#define SYSCALL_FROM_USER(regs) (user_mode(regs)) // 判断系统调用是否来自内核态 #define SYSCALL_FROM_KERNEL(regs) (!SYSCALL_FROM_USER(regs)) diff --git a/user/apps/Makefile b/user/apps/Makefile index adf7df74..0c9f3cf5 100644 --- a/user/apps/Makefile +++ b/user/apps/Makefile @@ -1,5 +1,5 @@ -user_apps_sub_dirs=shell about +user_apps_sub_dirs=shell about test_signal ECHO: @echo "$@" diff --git a/user/apps/shell/cmd.c b/user/apps/shell/cmd.c index e4065951..0b48e282 100644 --- a/user/apps/shell/cmd.c +++ b/user/apps/shell/cmd.c @@ -467,7 +467,7 @@ int shell_cmd_exec(int argc, char **argv) if (pid == 0) { - // printf("child proc\n"); + // 子进程 int path_len = 0; char *file_path = get_target_filepath(argv[1], &path_len); @@ -480,10 +480,13 @@ int shell_cmd_exec(int argc, char **argv) } else { - // printf("parent process wait for pid:[ %d ]\n", pid); - - waitpid(pid, &retval, 0); - // printf("parent process wait pid [ %d ], exit code=%d\n", pid, retval); + // 如果不指定后台运行,则等待退出 + if (strcmp(argv[argc - 1], "&") != 0) + waitpid(pid, &retval, 0); + else{ + // 输出子进程的pid + printf("[1] %d\n", pid); + } free(argv); } } @@ -513,8 +516,6 @@ int shell_cmd_kill(int argc, char **argv) retval = -EINVAL; goto out; } - printf("argc = %d, argv[1]=%s\n", argc, argv[1]); - printf("atoi(argv[1])=%d\n", atoi(argv[1])); retval = syscall_invoke(SYS_KILL, atoi(argv[1]), SIGKILL, 0, 0, 0, 0, 0, 0); out:; free(argv); diff --git a/user/apps/test_signal/Makefile b/user/apps/test_signal/Makefile new file mode 100644 index 00000000..b439375c --- /dev/null +++ b/user/apps/test_signal/Makefile @@ -0,0 +1,7 @@ +all: main.o + + ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/test_signal $(shell find . -name "*.o") $(shell find $(sys_libs_dir) -name "*.o") -T link.lds + + objcopy -I elf64-x86-64 -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/test_signal $(output_dir)/test_signal.elf +main.o: main.c + $(CC) $(CFLAGS) -c main.c -o main.o diff --git a/user/apps/test_signal/link.lds b/user/apps/test_signal/link.lds new file mode 100644 index 00000000..c9f7f159 --- /dev/null +++ b/user/apps/test_signal/link.lds @@ -0,0 +1,50 @@ + +OUTPUT_FORMAT("elf64-x86-64","elf64-x86-64","elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) + +SECTIONS +{ + + . = 0x800000; + + + .text : + { + _text = .; + + *(.text) + + _etext = .; + } + . = ALIGN(8); + + .data : + { + _data = .; + *(.data) + + _edata = .; + } + + + rodata_start_pa = .; + .rodata : + { + _rodata = .; + *(.rodata) + _erodata = .; + } + + + .bss : + { + _bss = .; + *(.bss) + _ebss = .; + } + + _end = .; + + +} \ No newline at end of file diff --git a/user/apps/test_signal/main.c b/user/apps/test_signal/main.c new file mode 100644 index 00000000..da6bd285 --- /dev/null +++ b/user/apps/test_signal/main.c @@ -0,0 +1,38 @@ +/** + * @file main.c + * @author longjin (longjin@RinGoTek.cn) + * @brief 测试signal用的程序 + * @version 0.1 + * @date 2022-12-06 + * + * @copyright Copyright (c) 2022 + * + */ + +/** + * 测试signal的kill命令的方法: + * 1.在DragonOS的控制台输入 exec bin/test_signal.elf & + * 请注意,一定要输入末尾的 '&',否则进程不会后台运行 + * 2.然后kill对应的进程的pid (上一条命令执行后,将会输出这样一行:"[1] 生成的pid") + * +*/ + +#include +#include +#include +#include +#include + +int main() +{ + printf("Test signal running...\n"); + clock_t last = clock(); + while (1) + { + if ((clock()-last)/CLOCKS_PER_SEC >= 1){ + // printf("Test signal running\n"); + last = clock(); + } + } + return 0; +} \ No newline at end of file