diff --git a/.vscode/settings.json b/.vscode/settings.json index 2c5cfc47..529e7021 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -160,7 +160,6 @@ "wait.h": "c", "__libc__.h": "c", "ctype.h": "c", - "signal.h": "c", "mmio.h": "c", "stdint-gcc.h": "c", "acpi.h": "c", diff --git a/kernel/src/arch/x86_64/fpu.rs b/kernel/src/arch/x86_64/fpu.rs index 7d54551a..b224a49c 100644 --- a/kernel/src/arch/x86_64/fpu.rs +++ b/kernel/src/arch/x86_64/fpu.rs @@ -60,9 +60,10 @@ impl FpState { } } - /// 清空fp_state + /// 清空浮点寄存器 #[allow(dead_code)] pub fn clear(&mut self) { *self = Self::default(); + self.restore(); } } diff --git a/kernel/src/arch/x86_64/ipc/mod.rs b/kernel/src/arch/x86_64/ipc/mod.rs index c872dd7b..a3c1b22f 100644 --- a/kernel/src/arch/x86_64/ipc/mod.rs +++ b/kernel/src/arch/x86_64/ipc/mod.rs @@ -1,10 +1 @@ -use super::interrupt::TrapFrame; - -use crate::{arch::CurrentIrqArch, exception::InterruptArch}; - -#[no_mangle] -pub unsafe extern "C" fn do_signal(_frame: &mut TrapFrame) { - CurrentIrqArch::interrupt_enable(); - // todo: 处理信号 - return; -} +pub mod signal; diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs new file mode 100644 index 00000000..9ce48b21 --- /dev/null +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -0,0 +1,679 @@ +use core::{ffi::c_void, mem::size_of}; + +use crate::{ + arch::{ + fpu::FpState, + interrupt::TrapFrame, + process::table::{USER_CS, USER_DS}, + sched::sched, + CurrentIrqArch, MMArch, + }, + exception::InterruptArch, + ipc::{ + signal::set_current_sig_blocked, + signal_types::{SaHandlerType, SigInfo, Sigaction, SigactionType, SignalArch}, + }, + kerror, + mm::MemoryManagementArch, + process::ProcessManager, + syscall::{user_access::UserBufferWriter, Syscall, SystemError}, +}; + +/// 信号处理的栈的栈指针的最小对齐数量 +pub const STACK_ALIGN: u64 = 16; +/// 信号最大值 +pub const MAX_SIG_NUM: usize = 64; +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, Eq)] +#[repr(usize)] +#[allow(non_camel_case_types)] +pub enum Signal { + INVALID = 0, + SIGHUP = 1, + SIGINT, + SIGQUIT, + SIGILL, + SIGTRAP, + /// SIGABRT和SIGIOT共用这个号码 + SIGABRT_OR_IOT, + SIGBUS, + SIGFPE, + SIGKILL, + SIGUSR1, + + SIGSEGV = 11, + SIGUSR2, + SIGPIPE, + SIGALRM, + SIGTERM, + SIGSTKFLT, + SIGCHLD, + SIGCONT, + SIGSTOP, + SIGTSTP, + + SIGTTIN = 21, + SIGTTOU, + SIGURG, + SIGXCPU, + SIGXFSZ, + SIGVTALRM, + SIGPROF, + SIGWINCH, + /// SIGIO和SIGPOLL共用这个号码 + SIGIO_OR_POLL, + SIGPWR, + + SIGSYS = 31, + + SIGRTMIN = 32, + SIGRTMAX = 64, +} + +/// 为Signal实现判断相等的trait +impl PartialEq for Signal { + fn eq(&self, other: &Signal) -> bool { + *self as usize == *other as usize + } +} + +impl From for Signal { + fn from(value: usize) -> Self { + if value <= MAX_SIG_NUM { + let ret: Signal = unsafe { core::mem::transmute(value) }; + return ret; + } else { + kerror!("Try to convert an invalid number to Signal"); + return Signal::INVALID; + } + } +} + +impl Into for Signal { + fn into(self) -> usize { + self as usize + } +} + +impl From for Signal { + fn from(value: i32) -> Self { + if value < 0 { + kerror!("Try to convert an invalid number to Signal"); + return Signal::INVALID; + } else { + return Self::from(value as usize); + } + } +} + +impl Into for Signal { + fn into(self) -> SigSet { + SigSet { + bits: (1 << (self as usize - 1) as u64), + } + } +} +impl Signal { + /// 判断一个数字是否为可用的信号 + #[inline] + pub fn is_valid(&self) -> bool { + return (*self) as usize <= MAX_SIG_NUM; + } + + /// const convertor between `Signal` and `SigSet` + pub const fn into_sigset(self) -> SigSet { + SigSet { + bits: (1 << (self as usize - 1) as u64), + } + } + + /// 判断一个信号是不是实时信号 + /// + /// ## 返回值 + /// + /// - `true` 这个信号是实时信号 + /// - `false` 这个信号不是实时信号 + #[inline] + pub fn is_rt_signal(&self) -> bool { + return (*self) as usize >= Signal::SIGRTMIN.into(); + } + + /// 调用信号的默认处理函数 + pub fn handle_default(&self) { + match self { + Signal::INVALID => { + kerror!("attempting to handler an Invalid"); + } + Signal::SIGHUP => sig_terminate(self.clone()), + Signal::SIGINT => sig_terminate(self.clone()), + Signal::SIGQUIT => sig_terminate_dump(self.clone()), + Signal::SIGILL => sig_terminate_dump(self.clone()), + Signal::SIGTRAP => sig_terminate_dump(self.clone()), + Signal::SIGABRT_OR_IOT => sig_terminate_dump(self.clone()), + Signal::SIGBUS => sig_terminate_dump(self.clone()), + Signal::SIGFPE => sig_terminate_dump(self.clone()), + Signal::SIGKILL => sig_terminate(self.clone()), + Signal::SIGUSR1 => sig_terminate(self.clone()), + Signal::SIGSEGV => sig_terminate_dump(self.clone()), + Signal::SIGUSR2 => sig_terminate(self.clone()), + Signal::SIGPIPE => sig_terminate(self.clone()), + Signal::SIGALRM => sig_terminate(self.clone()), + Signal::SIGTERM => sig_terminate(self.clone()), + Signal::SIGSTKFLT => sig_terminate(self.clone()), + Signal::SIGCHLD => sig_ignore(self.clone()), + Signal::SIGCONT => sig_continue(self.clone()), + Signal::SIGSTOP => sig_stop(self.clone()), + Signal::SIGTSTP => sig_stop(self.clone()), + Signal::SIGTTIN => sig_stop(self.clone()), + Signal::SIGTTOU => sig_stop(self.clone()), + Signal::SIGURG => sig_ignore(self.clone()), + Signal::SIGXCPU => sig_terminate_dump(self.clone()), + Signal::SIGXFSZ => sig_terminate_dump(self.clone()), + Signal::SIGVTALRM => sig_terminate(self.clone()), + Signal::SIGPROF => sig_terminate(self.clone()), + Signal::SIGWINCH => sig_ignore(self.clone()), + Signal::SIGIO_OR_POLL => sig_terminate(self.clone()), + Signal::SIGPWR => sig_terminate(self.clone()), + Signal::SIGSYS => sig_terminate(self.clone()), + Signal::SIGRTMIN => sig_terminate(self.clone()), + Signal::SIGRTMAX => sig_terminate(self.clone()), + } + } +} + +/// siginfo中的si_code的可选值 +/// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态 +#[derive(Copy, Debug, Clone)] +#[repr(i32)] +pub enum SigCode { + /// sent by kill, sigsend, raise + User = 0, + /// sent by kernel from somewhere + Kernel = 0x80, + /// 通过sigqueue发送 + Queue = -1, + /// 定时器过期时发送 + Timer = -2, + /// 当实时消息队列的状态发生改变时发送 + Mesgq = -3, + /// 当异步IO完成时发送 + AsyncIO = -4, + /// sent by queued SIGIO + SigIO = -5, +} + +impl SigCode { + /// 为SigCode这个枚举类型实现从i32转换到枚举类型的转换函数 + #[allow(dead_code)] + pub fn from_i32(x: i32) -> SigCode { + match x { + 0 => Self::User, + 0x80 => Self::Kernel, + -1 => Self::Queue, + -2 => Self::Timer, + -3 => Self::Mesgq, + -4 => Self::AsyncIO, + -5 => Self::SigIO, + _ => panic!("signal code not valid"), + } + } +} + +bitflags! { + #[repr(C,align(8))] + #[derive(Default)] + pub struct SigFlags:u32{ + const SA_NOCLDSTOP = 1; + const SA_NOCLDWAIT = 2; + const SA_SIGINFO = 4; + const SA_ONSTACK = 0x08000000; + const SA_RESTART = 0x10000000; + const SA_NODEFER = 0x40000000; + const SA_RESETHAND = 0x80000000; + const SA_RESTORER =0x04000000; + const SA_ALL = Self::SA_NOCLDSTOP.bits()|Self::SA_NOCLDWAIT.bits()|Self::SA_NODEFER.bits()|Self::SA_ONSTACK.bits()|Self::SA_RESETHAND.bits()|Self::SA_RESTART.bits()|Self::SA_SIGINFO.bits()|Self::SA_RESTORER.bits(); + } + + /// 请注意,sigset 这个bitmap, 第0位表示sig=1的信号。也就是说,Signal-1才是sigset_t中对应的位 + #[derive(Default)] + pub struct SigSet:u64{ + const SIGHUP = 1<<0; + const SIGINT = 1<<1; + const SIGQUIT = 1<<2; + const SIGILL = 1<<3; + const SIGTRAP = 1<<4; + /// SIGABRT和SIGIOT共用这个号码 + const SIGABRT_OR_IOT = 1<<5; + const SIGBUS = 1<<6; + const SIGFPE = 1<<7; + const SIGKILL = 1<<8; + const SIGUSR = 1<<9; + const SIGSEGV = 1<<10; + const SIGUSR2 = 1<<11; + const SIGPIPE = 1<<12; + const SIGALRM = 1<<13; + const SIGTERM = 1<<14; + const SIGSTKFLT= 1<<15; + const SIGCHLD = 1<<16; + const SIGCONT = 1<<17; + const SIGSTOP = 1<<18; + const SIGTSTP = 1<<19; + const SIGTTIN = 1<<20; + const SIGTTOU = 1<<21; + const SIGURG = 1<<22; + const SIGXCPU = 1<<23; + const SIGXFSZ = 1<<24; + const SIGVTALRM= 1<<25; + const SIGPROF = 1<<26; + const SIGWINCH = 1<<27; + /// SIGIO和SIGPOLL共用这个号码 + const SIGIO_OR_POLL = 1<<28; + const SIGPWR = 1<<29; + const SIGSYS = 1<<30; + const SIGRTMIN = 1<<31; + // TODO 写上实时信号 + const SIGRTMAX = 1<, + pub reserved: [u64; 8], +} + +impl SigContext { + /// 设置sigcontext + /// + /// ## 参数 + /// + /// - `mask` 要被暂存的信号mask标志位 + /// - `regs` 进入信号处理流程前,Restore all要弹出的内核栈栈帧 + /// + /// ## 返回值 + /// + /// - `Ok(0)` + /// - `Err(Systemerror)` (暂时不会返回错误) + pub fn setup_sigcontext( + &mut self, + mask: &SigSet, + frame: &TrapFrame, + ) -> Result { + //TODO 引入线程后补上 + // let current_thread = ProcessManager::current_pcb().thread; + let pcb = ProcessManager::current_pcb(); + let mut archinfo_guard = pcb.arch_info(); + self.oldmask = *mask; + self.frame = frame.clone(); + // context.trap_num = unsafe { (*current_thread).trap_num }; + // context.err_code = unsafe { (*current_thread).err_code }; + // context.cr2 = unsafe { (*current_thread).cr2 }; + self.reserved_for_x87_state = archinfo_guard.fp_state().clone(); + + // 保存完毕后,清空fp_state,以免下次save的时候,出现SIMD exception + archinfo_guard.clear_fp_state(); + return Ok(0); + } + + /// 指定的sigcontext恢复到当前进程的内核栈帧中,并将当前线程结构体的几个参数进行恢复 + /// + /// ## 参数 + /// - `frame` 目标栈帧(也就是把context恢复到这个栈帧中) + /// + /// ##返回值 + /// - `true` -> 成功恢复 + /// - `false` -> 执行失败 + pub fn restore_sigcontext(&mut self, frame: &mut TrapFrame) -> bool { + let guard = ProcessManager::current_pcb(); + let mut arch_info = guard.arch_info(); + (*frame) = self.frame.clone(); + // (*current_thread).trap_num = (*context).trap_num; + *arch_info.cr2_mut() = self.cr2 as usize; + // (*current_thread).err_code = (*context).err_code; + // 如果当前进程有fpstate,则将其恢复到pcb的fp_state中 + *arch_info.fp_state_mut() = self.reserved_for_x87_state.clone(); + arch_info.restore_fp_state(); + return true; + } +} +/// @brief 信号处理备用栈的信息 +#[derive(Debug, Clone, Copy)] +pub struct SigStack { + pub sp: *mut c_void, + pub flags: u32, + pub size: u32, + pub fpstate: FpState, +} + +#[no_mangle] +unsafe extern "C" fn do_signal(frame: &mut TrapFrame) { + X86_64SignalArch::do_signal(frame); +} + +pub struct X86_64SignalArch; + +impl SignalArch for X86_64SignalArch { + unsafe fn do_signal(frame: &mut TrapFrame) { + // 检查sigpending是否为0 + if ProcessManager::current_pcb() + .sig_info() + .sig_pending() + .signal() + .bits() + == 0 + || !frame.from_user() + { + // 若没有正在等待处理的信号,或者将要返回到的是内核态,则启用中断,然后返回 + CurrentIrqArch::interrupt_enable(); + return; + } + + // 做完上面的检查后,开中断 + CurrentIrqArch::interrupt_enable(); + let pcb = ProcessManager::current_pcb(); + let sig_guard = pcb.sig_struct(); + let mut sig_number: Signal; + let mut info: Option; + let mut sigaction: Sigaction; + let reader = pcb.sig_info(); + let sig_block: SigSet = reader.sig_block().clone(); + drop(reader); + loop { + (sig_number, info) = pcb.sig_info_mut().dequeue_signal(&sig_block); + // 如果信号非法,则直接返回 + if sig_number == Signal::INVALID { + return; + } + + sigaction = sig_guard.handlers[sig_number as usize - 1]; + match sigaction.action() { + SigactionType::SaHandler(action_type) => match action_type { + SaHandlerType::SigError => { + kerror!("Trying to handle a Sigerror on Process:{:?}", pcb.pid()); + return; + } + SaHandlerType::SigDefault => { + sigaction = Sigaction::default(); + break; + } + SaHandlerType::SigIgnore => continue, + SaHandlerType::SigCustomized(_) => { + break; + } + }, + SigactionType::SaSigaction(_) => todo!(), + } + // 如果当前动作是忽略这个信号,就继续循环。 + } + // 所有的信号都处理完了 + let reader = pcb.sig_info(); + let oldset = reader.sig_block().clone(); + //避免死锁 + drop(reader); + drop(sig_guard); + let res: Result = + handle_signal(sig_number, &mut sigaction, &info.unwrap(), &oldset, frame); + if res.is_err() { + kerror!( + "Error occurred when handling signal: {}, pid={:?}, errcode={:?}", + sig_number as i32, + ProcessManager::current_pcb().pid(), + res.unwrap_err() + ); + } + } + + fn sys_rt_sigreturn(trap_frame: &mut TrapFrame) -> u64 { + let frame = (trap_frame.rsp as usize) as *mut SigFrame; + + // 如果当前的rsp不来自用户态,则认为产生了错误(或被SROP攻击) + if UserBufferWriter::new(frame, size_of::(), true).is_err() { + kerror!("rsp doesn't from user level"); + let _r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32) + .map_err(|e| e.to_posix_errno()); + return trap_frame.rax; + } + let mut sigmask: SigSet = unsafe { (*frame).context.oldmask }; + set_current_sig_blocked(&mut sigmask); + // 从用户栈恢复sigcontext + if !unsafe { &mut (*frame).context }.restore_sigcontext(trap_frame) { + kerror!("unable to restore sigcontext"); + let _r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32) + .map_err(|e| e.to_posix_errno()); + // 如果这里返回 err 值的话会丢失上一个系统调用的返回值 + } + // 由于系统调用的返回值会被系统调用模块被存放在rax寄存器,因此,为了还原原来的那个系统调用的返回值,我们需要在这里返回恢复后的rax的值 + return trap_frame.rax; + } +} + +/// @brief 真正发送signal,执行自定义的处理函数 +/// +/// @param sig 信号number +/// @param sigaction 信号响应动作 +/// @param info 信号信息 +/// @param oldset +/// @param regs 之前的系统调用将要返回的时候,要弹出的栈帧的拷贝 +/// +/// @return Result<0,SystemError> 若Error, 则返回错误码,否则返回Ok(0) +fn handle_signal( + sig: Signal, + sigaction: &mut Sigaction, + info: &SigInfo, + oldset: &SigSet, + frame: &mut TrapFrame, +) -> Result { + // TODO 这里要补充一段逻辑,好像是为了保证引入线程之后的地址空间不会出问题。详见https://opengrok.ringotek.cn/xref/linux-6.1.9/arch/mips/kernel/signal.c#830 + + // 设置栈帧 + return setup_frame(sig, sigaction, info, oldset, frame); +} + +/// @brief 在用户栈上开辟一块空间,并且把内核栈的栈帧以及需要在用户态执行的代码给保存进去。 +/// +/// @param regs 进入信号处理流程前,Restore all要弹出的内核栈栈帧 +fn setup_frame( + sig: Signal, + sigaction: &mut Sigaction, + info: &SigInfo, + oldset: &SigSet, + trap_frame: &mut TrapFrame, +) -> Result { + let ret_code_ptr: *mut c_void; + let temp_handler: *mut c_void; + match sigaction.action() { + SigactionType::SaHandler(handler_type) => match handler_type { + SaHandlerType::SigDefault => { + sig.handle_default(); + return Ok(0); + } + SaHandlerType::SigCustomized(handler) => { + // 如果handler位于内核空间 + if handler >= MMArch::USER_END_VADDR { + // 如果当前是SIGSEGV,则采用默认函数处理 + if sig == Signal::SIGSEGV { + sig.handle_default(); + return Ok(0); + } else { + kerror!("attempting to execute a signal handler from kernel"); + sig.handle_default(); + return Err(SystemError::EINVAL); + } + } else { + // 为了与Linux的兼容性,64位程序必须由用户自行指定restorer + if sigaction.flags().contains(SigFlags::SA_RESTORER) { + ret_code_ptr = sigaction.restorer().unwrap().data() as *mut c_void; + } else { + kerror!( + "pid-{:?} forgot to set SA_FLAG_RESTORER for signal {:?}", + ProcessManager::current_pcb().pid(), + sig as i32 + ); + let r = Syscall::kill( + ProcessManager::current_pcb().pid(), + Signal::SIGSEGV as i32, + ); + if r.is_err() { + kerror!("In setup_sigcontext: generate SIGSEGV signal failed"); + } + return Err(SystemError::EINVAL); + } + if sigaction.restorer().is_none() { + kerror!( + "restorer in process:{:?} is not defined", + ProcessManager::current_pcb().pid() + ); + return Err(SystemError::EINVAL); + } + temp_handler = handler.data() as *mut c_void; + } + } + SaHandlerType::SigIgnore => { + return Ok(0); + } + _ => { + return Err(SystemError::EINVAL); + } + }, + SigactionType::SaSigaction(_) => { + //TODO 这里应该是可以恢复栈的,等后续来做 + kerror!("trying to recover from sigaction type instead of handler"); + return Err(SystemError::EINVAL); + } + } + let frame: *mut SigFrame = get_stack(&trap_frame, size_of::()); + // kdebug!("frame=0x{:016x}", frame as usize); + // 要求这个frame的地址位于用户空间,因此进行校验 + let r = UserBufferWriter::new(frame, size_of::(), true); + if r.is_err() { + // 如果地址区域位于内核空间,则直接报错 + // todo: 生成一个sigsegv + let r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32); + if r.is_err() { + kerror!("In setup frame: generate SIGSEGV signal failed"); + } + kerror!("In setup frame: access check failed"); + return Err(SystemError::EFAULT); + } + + // 将siginfo拷贝到用户栈 + info.copy_siginfo_to_user(unsafe { &mut ((*frame).info) as *mut SigInfo }) + .map_err(|e| -> SystemError { + let r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32); + if r.is_err() { + kerror!("In copy_siginfo_to_user: generate SIGSEGV signal failed"); + } + return e; + })?; + + // todo: 拷贝处理程序备用栈的地址、大小、ss_flags + + unsafe { + (*frame) + .context + .setup_sigcontext(oldset, &trap_frame) + .map_err(|e: SystemError| -> SystemError { + let r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32); + if r.is_err() { + kerror!("In setup_sigcontext: generate SIGSEGV signal failed"); + } + return e; + })? + }; + + unsafe { + // 在开头检验过sigaction.restorer是否为空了,实际上libc会保证 restorer始终不为空 + (*frame).ret_code_ptr = ret_code_ptr; + } + + unsafe { (*frame).handler = temp_handler }; + // 传入信号处理函数的第一个参数 + trap_frame.rdi = sig as u64; + trap_frame.rsi = unsafe { &(*frame).info as *const SigInfo as u64 }; + trap_frame.rsp = frame as u64; + trap_frame.rip = unsafe { (*frame).handler as u64 }; + // 设置cs和ds寄存器 + trap_frame.cs = (USER_CS.bits() | 0x3) as u64; + trap_frame.ds = (USER_DS.bits() | 0x3) as u64; + + // 禁用中断 + // trap_frame.rflags &= !(0x200); + + return Ok(0); +} + +#[inline(always)] +fn get_stack(frame: &TrapFrame, size: usize) -> *mut SigFrame { + // TODO:在 linux 中会根据 Sigaction 中的一个flag 的值来确定是否使用pcb中的 signal 处理程序备用堆栈,现在的 + // pcb中也没有这个备用堆栈 + + // 默认使用 用户栈的栈顶指针-128字节的红区-sigframe的大小 并且16字节对齐 + let mut rsp: usize = (frame.rsp as usize) - 128 - size; + // 按照要求进行对齐,别问为什么减8,不减8就是错的,可以看 + // https://sourcegraph.com/github.com/torvalds/linux@dd72f9c7e512da377074d47d990564959b772643/-/blob/arch/x86/kernel/signal.c?L124 + // 我猜测是跟x86汇编的某些弹栈行为有关系,它可能会出于某种原因递增 rsp + rsp &= (!(STACK_ALIGN - 1)) as usize - 8; + // rsp &= (!(STACK_ALIGN - 1)) as usize; + return rsp as *mut SigFrame; +} + +/// 信号默认处理函数——终止进程 +fn sig_terminate(sig: Signal) { + ProcessManager::exit(sig as usize); +} + +/// 信号默认处理函数——终止进程并生成 core dump +fn sig_terminate_dump(sig: Signal) { + ProcessManager::exit(sig as usize); + // TODO 生成 coredump 文件 +} + +/// 信号默认处理函数——暂停进程 +fn sig_stop(sig: Signal) { + let guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + ProcessManager::mark_stop().unwrap_or_else(|e| { + kerror!( + "sleep error :{:?},failed to sleep process :{:?}, with signal :{:?}", + e, + ProcessManager::current_pcb(), + sig + ); + }); + drop(guard); + sched(); + // TODO 暂停进程 +} +/// 信号默认处理函数——继续进程 +fn sig_continue(sig: Signal) { + ProcessManager::wakeup_stop(&ProcessManager::current_pcb()).unwrap_or_else(|_| { + kerror!( + "Failed to wake up process pid = {:?} with signal :{:?}", + ProcessManager::current_pcb().pid(), + sig + ); + }); +} +/// 信号默认处理函数——忽略 +fn sig_ignore(_sig: Signal) { + return; +} diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 5bef73d6..3be7b192 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -25,3 +25,4 @@ pub use self::mm::X86_64MMArch as MMArch; pub use interrupt::X86_64InterruptArch as CurrentIrqArch; pub use crate::arch::asm::pio::X86_64PortIOArch as CurrentPortIOArch; +pub use crate::arch::ipc::signal::X86_64SignalArch as CurrentSignalArch; diff --git a/kernel/src/arch/x86_64/process/mod.rs b/kernel/src/arch/x86_64/process/mod.rs index cae6cb91..c9c78e84 100644 --- a/kernel/src/arch/x86_64/process/mod.rs +++ b/kernel/src/arch/x86_64/process/mod.rs @@ -13,6 +13,7 @@ use x86::{controlregs::Cr4, segmentation::SegmentSelector}; use crate::{ arch::process::table::TSSManager, exception::InterruptArch, + kwarn, libs::spinlock::SpinLockGuard, mm::{ percpu::{PerCpu, PerCpuVar}, @@ -156,6 +157,20 @@ impl ArchPCBInfo { self.fp_state.as_mut().unwrap().restore(); } + /// 返回浮点寄存器结构体的副本 + pub fn fp_state(&self) -> &Option { + &self.fp_state + } + + // 清空浮点寄存器 + pub fn clear_fp_state(&mut self) { + if unlikely(self.fp_state.is_none()) { + kwarn!("fp_state is none"); + return; + } + + self.fp_state.as_mut().unwrap().clear(); + } pub unsafe fn save_fsbase(&mut self) { if x86::controlregs::cr4().contains(Cr4::CR4_ENABLE_FSGSBASE) { self.fsbase = x86::current::segmentation::rdfsbase() as usize; @@ -191,6 +206,14 @@ impl ArchPCBInfo { pub fn gsbase(&self) -> usize { self.gsbase } + + pub fn cr2_mut(&mut self) -> &mut usize { + &mut self.cr2 + } + + pub fn fp_state_mut(&mut self) -> &mut Option { + &mut self.fp_state + } } impl ProcessControlBlock { diff --git a/kernel/src/arch/x86_64/syscall.rs b/kernel/src/arch/x86_64/syscall.rs index 3ea976bf..a0c8ea09 100644 --- a/kernel/src/arch/x86_64/syscall.rs +++ b/kernel/src/arch/x86_64/syscall.rs @@ -3,7 +3,9 @@ use core::ffi::c_void; use alloc::string::String; use crate::{ + arch::ipc::signal::X86_64SignalArch, include::bindings::bindings::set_system_trap_gate, + ipc::signal_types::SignalArch, syscall::{Syscall, SystemError, SYS_RT_SIGRETURN}, }; @@ -39,7 +41,7 @@ pub extern "C" fn syscall_handler(frame: &mut TrapFrame) -> () { // 由于进程管理未完成重构,有些系统调用需要在这里临时处理,以后这里的特殊处理要删掉。 match syscall_num { SYS_RT_SIGRETURN => { - syscall_return!(SystemError::ENOSYS.to_posix_errno() as usize, frame); + syscall_return!(X86_64SignalArch::sys_rt_sigreturn(frame) as usize, frame); } _ => {} } diff --git a/kernel/src/debug/kallsyms.c b/kernel/src/debug/kallsyms.c index 288a31ca..3f95550c 100644 --- a/kernel/src/debug/kallsyms.c +++ b/kernel/src/debug/kallsyms.c @@ -51,8 +51,9 @@ int read_symbol(FILE *filp, struct kernel_symbol_entry_t *entry) { // 本函数假设nm命令输出的结果中,每行最大512字节 char str[512] = {0}; - char* s = fgets(str, sizeof(str), filp); - if (s != str) { + char *s = fgets(str, sizeof(str), filp); + if (s != str) + { return -1; } @@ -60,15 +61,29 @@ int read_symbol(FILE *filp, struct kernel_symbol_entry_t *entry) int retval = sscanf(str, "%llx %c %512c", &entry->vaddr, &entry->type, symbol_name); // 如果当前行不符合要求 - if (retval != 3) { + if (retval != 3) + { return -1; } // malloc一块内存,然后把str的内容拷贝进去,接着修改symbol指针 size_t len = strlen(symbol_name); - if (len >= 1 && symbol_name[len - 1] == '\n') { + if (len >= 1 && symbol_name[len - 1] == '\n') + { symbol_name[len - 1] = '\0'; len--; } + // 转义双引号 + for (int i = 0; i < len; i++) + { + if (symbol_name[i] == '"') + { + char temp[len - i]; + memcpy(temp, symbol_name + i, len - i); + symbol_name[i] = '\\'; + memcpy(symbol_name + i + 1, temp, len - i); + i++; + } + } entry->symbol = strdup(symbol_name); entry->symbol_length = len + 1; // +1的原因是.asciz指令会在字符串末尾自动添加结束符\0 return 0; @@ -191,12 +206,11 @@ void generate_result() // 输出符号名称 printf("\t.asciz\t\"%s\"\n", symbol_table[i].symbol); - + last_vaddr = symbol_table[i].vaddr; } putchar('\n'); - } int main(int argc, char **argv) { diff --git a/kernel/src/driver/tty/mod.rs b/kernel/src/driver/tty/mod.rs index ea4db91f..65a68d6e 100644 --- a/kernel/src/driver/tty/mod.rs +++ b/kernel/src/driver/tty/mod.rs @@ -58,7 +58,8 @@ struct TtyCore { /// 输出的mpsc队列输入输出端 output_rx: mpsc::Receiver, output_tx: mpsc::Sender, - + // 前台进程,以后改成前台进程组 + // front_job: Option, /// tty核心的状态 state: RwLock, } @@ -74,6 +75,8 @@ pub enum TtyError { Closed, /// End of file(已经读取的字符数,包含eof) EOF(usize), + /// 接收到信号终止 + Stopped(usize), Unknown(String), } @@ -106,7 +109,6 @@ impl TtyCore { /// @return Ok(成功传送的字节数) /// @return Err(TtyError) 内部错误信息 pub fn input(&self, buf: &[u8], block: bool) -> Result { - // TODO: 在这里考虑增加对信号发送的处理 let val = self.write_stdin(buf, block)?; // 如果开启了输入回显,那么就写一份到输出缓冲区 if self.echo_enabled() { @@ -281,11 +283,24 @@ impl TtyCore { _ => return Err(TtyError::Unknown(format!("{e:?}"))), } } else { + // TODO: 在这里考虑增加对信号发送的处理 + // if buf[cnt] == 3 { + // let pid = ProcessManager::current_pcb().pid(); + // Signal::SIGKILL.send_signal_info( + // Some(&mut SigInfo::new( + // Signal::SIGKILL, + // 0, + // SigCode::SI_USER, + // SigType::Kill(pid), + // )), + // pid, + // ); + // return Err(TtyError::Stopped(cnt)); + // } *r.unwrap() = buf[cnt]; cnt += 1; } } - return Ok(cnt); } diff --git a/kernel/src/include/DragonOS/signal.h b/kernel/src/include/DragonOS/signal.h deleted file mode 100644 index 9ca00de0..00000000 --- a/kernel/src/include/DragonOS/signal.h +++ /dev/null @@ -1,144 +0,0 @@ -/** - * @file signal.h - * @author longjin (longjin@RinGoTek.cn) - * @brief signal相关类型在C语言中的导出。(以rust版本为准) - * @version 0.1 - * - * @copyright Copyright (c) 2022 - * - */ -#pragma once -#include -#include -#include -#include -#include - -// 系统最大支持的信号数量 -#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; - -typedef uint64_t sigset_t; - -#define SIGHUP 1 -#define SIGINT 2 -#define SIGQUIT 3 -#define SIGILL 4 -#define SIGTRAP 5 -#define SIGABRT 6 -#define SIGIOT 6 -#define SIGBUS 7 -#define SIGFPE 8 -#define SIGKILL 9 -#define SIGUSR1 10 -#define SIGSEGV 11 -#define SIGUSR2 12 -#define SIGPIPE 13 -#define SIGALRM 14 -#define SIGTERM 15 -#define SIGSTKFLT 16 -#define SIGCHLD 17 -#define SIGCONT 18 -#define SIGSTOP 19 -#define SIGTSTP 20 -#define SIGTTIN 21 -#define SIGTTOU 22 -#define SIGURG 23 -#define SIGXCPU 24 -#define SIGXFSZ 25 -#define SIGVTALRM 26 -#define SIGPROF 27 -#define SIGWINCH 28 -#define SIGIO 29 -#define SIGPOLL SIGIO - -#define SIGPWR 30 -#define SIGSYS 31 - -/* These should not be considered constants from userland. */ -#define SIGRTMIN 32 -#define SIGRTMAX MAX_SIG_NUM - -// 注意,该结构体最大16字节 -union __sifields { - /* kill() */ - struct - { - pid_t _pid; /* 信号发送者的pid */ - } _kill; -}; - -// 注意,该结构体最大大小为32字节 -#define __SIGINFO \ - struct \ - { \ - int32_t si_signo; /* signal number */ \ - int32_t si_code; \ - int32_t si_errno; \ - uint32_t reserved; /* 保留备用 */ \ - union __sifields _sifields; \ - } - -struct siginfo -{ - union { - __SIGINFO; - uint64_t padding[4]; // 让siginfo占用32字节大小 - }; -}; - -/** - * @brief 信号处理结构体 - * - */ -struct sigaction -{ - // 信号处理函数的指针 - union { - __sighandler_t _sa_handler; - void (*_sa_sigaction)(int sig, struct siginfo *sinfo, void *); - } _u; - uint64_t sa_flags; - sigset_t sa_mask; - 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 -#define SA_FLAG_IMMUTABLE (1UL << 3) // 当前sigaction不可被更改 - -/** - * 由于signal_struct总是和sighand_struct一起使用,并且信号处理的过程中必定会对sighand加锁, - * 因此signal_struct不用加锁 - */ -struct signal_struct -{ - atomic_t sig_cnt; -}; - -/** - * @brief 信号处理结构体,位于pcb之中。 - * 请注意,该结构体需要与rust的版本一致,且以rust的为准 - */ -struct sighand_struct -{ - spinlock_t siglock; - refcount_t count; - // 为每个信号注册的处理函数的结构体 - struct sigaction action[MAX_SIG_NUM]; -}; - -/** - * @brief 正在等待的信号的标志位 - */ -struct sigpending -{ - sigset_t signal; - void *sigqueue; // 信号队列(在rust中实现) -}; \ No newline at end of file diff --git a/kernel/src/include/bindings/wrapper.h b/kernel/src/include/bindings/wrapper.h index 46334d85..605e373c 100644 --- a/kernel/src/include/bindings/wrapper.h +++ b/kernel/src/include/bindings/wrapper.h @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/kernel/src/ipc/mod.rs b/kernel/src/ipc/mod.rs index 3eddd993..1112d41f 100644 --- a/kernel/src/ipc/mod.rs +++ b/kernel/src/ipc/mod.rs @@ -1,2 +1,4 @@ pub mod pipe; +pub mod signal; +pub mod signal_types; pub mod syscall; diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs new file mode 100644 index 00000000..a3261cd6 --- /dev/null +++ b/kernel/src/ipc/signal.rs @@ -0,0 +1,416 @@ +use core::sync::atomic::compiler_fence; + +use alloc::sync::Arc; + +use crate::{ + arch::ipc::signal::{SigCode, SigFlags, SigSet, Signal}, + ipc::signal_types::SigactionType, + kwarn, + libs::spinlock::SpinLockGuard, + process::{pid::PidType, Pid, ProcessControlBlock, ProcessFlags, ProcessManager}, + syscall::SystemError, +}; + +use super::signal_types::{ + SaHandlerType, SigInfo, SigType, Sigaction, SignalStruct, SIG_KERNEL_STOP_MASK, +}; + +impl Signal { + /// 向目标进程发送信号 + /// + /// ## 参数 + /// + /// - `sig` 要发送的信号 + /// - `info` 要发送的信息 + /// - `pid` 进程id(目前只支持pid>0) + pub fn send_signal_info( + &self, + info: Option<&mut SigInfo>, + pid: Pid, + ) -> Result { + // TODO:暂时不支持特殊的信号操作,待引入进程组后补充 + // 如果 pid 大于 0,那么会发送信号给 pid 指定的进程 + // 如果 pid 等于 0,那么会发送信号给与调用进程同组的每个进程,包括调用进程自身 + // 如果 pid 小于 -1,那么会向组 ID 等于该 pid 绝对值的进程组内所有下属进程发送信号。向一个进程组的所有进程发送信号在 shell 作业控制中有特殊有途 + // 如果 pid 等于 -1,那么信号的发送范围是:调用进程有权将信号发往的每个目标进程,除去 init(进程 ID 为 1)和调用进程自身。如果特权级进程发起这一调用,那么会发送信号给系统中的所有进程,上述两个进程除外。显而易见,有时也将这种信号发送方式称之为广播信号 + // 如果并无进程与指定的 pid 相匹配,那么 kill() 调用失败,同时将 errno 置为 ESRCH(“查无此进程”) + if pid.lt(&Pid::from(0)) { + kwarn!("Kill operation not support: pid={:?}", pid); + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // 检查sig是否符合要求,如果不符合要求,则退出。 + if !self.is_valid() { + return Err(SystemError::EINVAL); + } + let mut retval = Err(SystemError::ESRCH); + let pcb = ProcessManager::find(pid); + + if pcb.is_none() { + kwarn!("No such process."); + return retval; + } + // println!("Target pcb = {:?}", pcb.as_ref().unwrap()); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // 发送信号 + retval = self.send_signal(info, pcb.unwrap(), PidType::PID); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + return retval; + } + + /// @brief 判断是否需要强制发送信号,然后发送信号 + /// 进入函数后加锁 + /// + /// @return SystemError 错误码 + fn send_signal( + &self, + info: Option<&mut SigInfo>, + pcb: Arc, + pt: PidType, + ) -> Result { + // 是否强制发送信号 + let mut force_send = false; + // signal的信息为空 + + if let Some(ref siginfo) = info { + force_send = matches!(siginfo.sig_code(), SigCode::Kernel); + } else { + // todo: 判断signal是否来自于一个祖先进程的namespace,如果是,则强制发送信号 + //详见 https://opengrok.ringotek.cn/xref/linux-6.1.9/kernel/signal.c?r=&mo=32170&fi=1220#1226 + } + + if !self.prepare_sianal(pcb.clone(), force_send) { + return Err(SystemError::EINVAL); + } + // kdebug!("force send={}", force_send); + let pcb_info = pcb.sig_info(); + let pending = if matches!(pt, PidType::PID) { + pcb_info.sig_shared_pending() + } else { + pcb_info.sig_pending() + }; + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // 如果是kill或者目标pcb是内核线程,则无需获取sigqueue,直接发送信号即可 + if matches!(self, Signal::SIGKILL) || pcb.flags().contains(ProcessFlags::KTHREAD) { + //避免死锁 + drop(pcb_info); + self.complete_signal(pcb.clone(), pt); + } + // 如果不是实时信号的话,同一时刻信号队列里只会有一个待处理的信号,如果重复接收就不做处理 + else if !self.is_rt_signal() && pending.queue().find(self.clone()).0.is_some() { + return Ok(0); + } else { + // TODO signalfd_notify 完善 signalfd 机制 + // 如果是其他信号,则加入到sigqueue内,然后complete_signal + let new_sig_info = match info { + Some(siginfo) => { + // 已经显式指定了siginfo,则直接使用它。 + (*siginfo).clone() + } + None => { + // 不需要显示指定siginfo,因此设置为默认值 + SigInfo::new( + self.clone(), + 0, + SigCode::User, + SigType::Kill(ProcessManager::current_pcb().pid()), + ) + } + }; + drop(pcb_info); + pcb.sig_info_mut() + .sig_pending_mut() + .queue_mut() + .q + .push(new_sig_info); + + if pt == PidType::PGID || pt == PidType::SID {} + self.complete_signal(pcb.clone(), pt); + } + compiler_fence(core::sync::atomic::Ordering::SeqCst); + return Ok(0); + } + + /// @brief 将信号添加到目标进程的sig_pending。在引入进程组后,本函数还将负责把信号传递给整个进程组。 + /// + /// @param sig 信号 + /// @param pcb 目标pcb + /// @param pt siginfo结构体中,pid字段代表的含义 + fn complete_signal(&self, pcb: Arc, pt: PidType) { + // kdebug!("complete_signal"); + // todo: 将信号产生的消息通知到正在监听这个信号的进程(引入signalfd之后,在这里调用signalfd_notify) + // 将这个信号加到目标进程的sig_pending中 + pcb.sig_info_mut() + .sig_pending_mut() + .signal_mut() + .insert(self.clone().into()); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // ===== 寻找需要wakeup的目标进程 ===== + // 备注:由于当前没有进程组的概念,每个进程只有1个对应的线程,因此不需要通知进程组内的每个进程。 + // todo: 当引入进程组的概念后,需要完善这里,使得它能寻找一个目标进程来唤醒,接着执行信号处理的操作。 + + // let _signal = pcb.sig_struct(); + + let mut _target: Option> = None; + + // 判断目标进程是否想接收这个信号 + if self.wants_signal(pcb.clone()) { + _target = Some(pcb.clone()); + } else if pt == PidType::PID { + /* + * There is just one thread and it does not need to be woken. + * It will dequeue unblocked signals before it runs again. + */ + return; + } else { + /* + * Otherwise try to find a suitable thread. + * 由于目前每个进程只有1个线程,因此当前情况可以返回。信号队列的dequeue操作不需要考虑同步阻塞的问题。 + */ + return; + } + + // TODO:引入进程组后,在这里挑选一个进程来唤醒,让它执行相应的操作。 + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // TODO: 到这里,信号已经被放置在共享的pending队列中,我们在这里把目标进程唤醒。 + if _target.is_some() { + let guard = pcb.sig_struct(); + signal_wake_up(pcb.clone(), guard, *self == Signal::SIGKILL); + } + } + + /// @brief 本函数用于检测指定的进程是否想要接收SIG这个信号。 + /// 当我们对于进程组中的所有进程都运行了这个检查之后,我们将可以找到组内愿意接收信号的进程。 + /// 这么做是为了防止我们把信号发送给了一个正在或已经退出的进程,或者是不响应该信号的进程。 + #[inline] + fn wants_signal(&self, pcb: Arc) -> bool { + // 如果改进程屏蔽了这个signal,则不能接收 + if pcb.sig_info().sig_block().contains(self.clone().into()) { + return false; + } + + // 如果进程正在退出,则不能接收信号 + if pcb.flags().contains(ProcessFlags::EXITING) { + return false; + } + + if *self == Signal::SIGKILL { + return true; + } + + if pcb.sched_info().state().is_blocked() { + return false; + } + + // todo: 检查目标进程是否正在一个cpu上执行,如果是,则返回true,否则继续检查下一项 + + // 检查目标进程是否有信号正在等待处理,如果是,则返回false,否则返回true + if pcb.sig_info().sig_pending().signal().bits() == 0 { + assert!(pcb.sig_info().sig_pending().queue().q.is_empty()); + return true; + } else { + return false; + } + } + + /// @brief 判断signal的处理是否可能使得整个进程组退出 + /// @return true 可能会导致退出(不一定) + #[allow(dead_code)] + #[inline] + fn sig_fatal(&self, pcb: Arc) -> bool { + let action = pcb.sig_struct().handlers[self.clone() as usize - 1].action(); + // 如果handler是空,采用默认函数,signal处理可能会导致进程退出。 + match action { + SigactionType::SaHandler(handler) => handler.is_sig_default(), + SigactionType::SaSigaction(sigaction) => sigaction.is_none(), + } + // todo: 参照linux的sig_fatal实现完整功能 + } + + /// 检查信号是否能被发送,并且而且要处理 SIGCONT 和 STOP 信号 + /// + /// ## 参数 + /// + /// - `pcb` 要发送信号的目标pcb + /// + /// - `force` 是否强制发送(指走 fast path , 不加入 sigpending按顺序处理,直接进入 complete_signal) + /// + /// ## 返回值 + /// + /// - `true` 能够发送信号 + /// + /// - `false` 不能发送信号 + fn prepare_sianal(&self, pcb: Arc, _force: bool) -> bool { + let flush: SigSet; + if !(self.into_sigset() & SIG_KERNEL_STOP_MASK).is_empty() { + flush = Signal::SIGCONT.into_sigset(); + pcb.sig_info_mut() + .sig_shared_pending_mut() + .flush_by_mask(&flush); + // TODO 对每个子线程 flush mask + } else if *self == Signal::SIGCONT { + flush = SIG_KERNEL_STOP_MASK; + assert!(!flush.is_empty()); + pcb.sig_info_mut() + .sig_shared_pending_mut() + .flush_by_mask(&flush); + let _r = ProcessManager::wakeup_stop(&pcb); + // TODO 对每个子线程 flush mask + // 这里需要补充一段逻辑,详见https://opengrok.ringotek.cn/xref/linux-6.1.9/kernel/signal.c#952 + } + + // 一个被阻塞了的信号肯定是要被处理的 + if pcb.sig_info().sig_block().contains(self.into_sigset()) { + return true; + } + return !pcb.sig_struct().handlers[self.clone() as usize - 1].is_ignore(); + + //TODO 仿照 linux 中的prepare signal完善逻辑,linux 中还会根据例如当前进程状态(Existing)进行判断,现在的信号能否发出就只是根据 ignored 来判断 + } +} + +/// 因收到信号而唤醒进程 +/// +/// ## 参数 +/// +/// - `pcb` 要唤醒的进程pcb +/// - `_guard` 信号结构体锁守卫,来保证信号结构体已上锁 +/// - `fatal` 表明这个信号是不是致命的(会导致进程退出) +#[inline] +fn signal_wake_up(pcb: Arc, _guard: SpinLockGuard, fatal: bool) { + // 如果是 fatal 的话就唤醒 stop 和 block 的进程来响应,因为唤醒后就会终止 + // 如果不是 fatal 的就只唤醒 stop 的进程来响应 + // kdebug!("signal_wake_up"); + // 如果目标进程已经在运行,则发起一个ipi,使得它陷入内核 + let r = ProcessManager::wakeup_stop(&pcb); + if r.is_ok() { + ProcessManager::kick(&pcb); + } else { + if fatal { + let _r = ProcessManager::wakeup(&pcb).map(|_| { + ProcessManager::kick(&pcb); + }); + } + } +} + +/// @brief 当一个进程具有多个线程之后,在这里需要重新计算线程的flag中的TIF_SIGPENDING位 +fn recalc_sigpending() { + // todo: +} + +/// @brief 刷新指定进程的sighand的sigaction,将满足条件的sigaction恢复为Default +/// 除非某个信号被设置为ignore且force_default为false,否则都不会将其恢复 +/// +/// @param pcb 要被刷新的pcb +/// @param force_default 是否强制将sigaction恢复成默认状态 +pub fn flush_signal_handlers(pcb: Arc, force_default: bool) { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // kdebug!("hand=0x{:018x}", hand as *const sighand_struct as usize); + let actions = &mut pcb.sig_struct().handlers; + + for sigaction in actions.iter_mut() { + if force_default || !sigaction.is_ignore() { + sigaction.set_action(SigactionType::SaHandler(SaHandlerType::SigDefault)); + } + // 清除flags中,除了DFL和IGN以外的所有标志 + sigaction.set_restorer(None); + sigaction.mask_mut().remove(SigSet::all()); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + } + compiler_fence(core::sync::atomic::Ordering::SeqCst); +} + +pub(super) fn do_sigaction( + sig: Signal, + act: Option<&mut Sigaction>, + old_act: Option<&mut Sigaction>, +) -> Result<(), SystemError> { + if sig == Signal::INVALID { + return Err(SystemError::EINVAL); + } + let pcb = ProcessManager::current_pcb(); + // 指向当前信号的action的引用 + let action: &mut Sigaction = &mut pcb.sig_struct().handlers[sig as usize - 1]; + + // 对比 MUSL 和 relibc , 暂时不设置这个标志位 + // if action.flags().contains(SigFlags::SA_FLAG_IMMUTABLE) { + // return Err(SystemError::EINVAL); + // } + + // 保存原有的 sigaction + let old_act: Option<&mut Sigaction> = { + if old_act.is_some() { + let oa = old_act.unwrap(); + *(oa) = (*action).clone(); + Some(oa) + } else { + None + } + }; + // 清除所有的脏的sa_flags位(也就是清除那些未使用的) + let act = { + if act.is_some() { + let ac = act.unwrap(); + *ac.flags_mut() &= SigFlags::SA_ALL; + Some(ac) + } else { + None + } + }; + + if old_act.is_some() { + *old_act.unwrap().flags_mut() &= SigFlags::SA_ALL; + } + + if act.is_some() { + let ac = act.unwrap(); + // 将act.sa_mask的SIGKILL SIGSTOP的屏蔽清除 + ac.mask_mut() + .remove(SigSet::from(Signal::SIGKILL.into()) | SigSet::from(Signal::SIGSTOP.into())); + + // 将新的sigaction拷贝到进程的action中 + *action = *ac; + /* + * 根据POSIX 3.3.1.3规定: + * 1.不管一个信号是否被阻塞,只要将其设置SIG_IGN,如果当前已经存在了正在pending的信号,那么就把这个信号忽略。 + * + * 2.不管一个信号是否被阻塞,只要将其设置SIG_DFL,如果当前已经存在了正在pending的信号, + 并且对这个信号的默认处理方式是忽略它,那么就会把pending的信号忽略。 + */ + if action.is_ignore() { + let mut mask: SigSet = SigSet::from_bits_truncate(0); + mask.insert(sig.into()); + pcb.sig_info_mut().sig_pending_mut().flush_by_mask(&mask); + // todo: 当有了多个线程后,在这里进行操作,把每个线程的sigqueue都进行刷新 + } + } + return Ok(()); +} + +/// 设置当前进程的屏蔽信号 (sig_block),待引入 [sigprocmask](https://man7.org/linux/man-pages/man2/sigprocmask.2.html) 系统调用后要删除这个散装函数 +/// +/// ## 参数 +/// +/// - `new_set` 新的屏蔽信号bitmap的值 +pub fn set_current_sig_blocked(new_set: &mut SigSet) { + new_set.remove(SigSet::from(Signal::SIGKILL.into()) | SigSet::from(Signal::SIGSTOP.into())); + //TODO 把这个散装函数用 sigsetops 替换掉 + let pcb = ProcessManager::current_pcb(); + + /* + 如果当前pcb的sig_blocked和新的相等,那么就不用改变它。 + 请注意,一个进程的sig_blocked字段不能被其他进程修改! + */ + if pcb.sig_info().sig_block().eq(new_set) { + return; + } + + let guard = pcb.sig_struct_irq(); + // todo: 当一个进程有多个线程后,在这里需要设置每个线程的block字段,并且 retarget_shared_pending(虽然我还没搞明白linux这部分是干啥的) + + // 设置当前进程的sig blocked + *pcb.sig_info_mut().sig_block_mut() = *new_set; + recalc_sigpending(); + drop(guard); +} diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs new file mode 100644 index 00000000..43654a2e --- /dev/null +++ b/kernel/src/ipc/signal_types.rs @@ -0,0 +1,529 @@ +use core::{ffi::c_void, mem::size_of, sync::atomic::AtomicI64}; + +use alloc::vec::Vec; + +use crate::{ + arch::{ + asm::bitops::ffz, + interrupt::TrapFrame, + ipc::signal::{SigCode, SigFlags, SigSet, Signal, MAX_SIG_NUM}, + }, + mm::VirtAddr, + process::Pid, + syscall::{user_access::UserBufferWriter, SystemError}, +}; + +/// 用户态程序传入的SIG_DFL的值 +pub const USER_SIG_DFL: u64 = 0; +/// 用户态程序传入的SIG_IGN的值 +pub const USER_SIG_IGN: u64 = 1; +/// 用户态程序传入的SIG_ERR的值 +pub const USER_SIG_ERR: u64 = 2; + +// 因为 Rust 编译器不能在常量声明中正确识别级联的 "|" 运算符(experimental feature: https://github.com/rust-lang/rust/issues/67792),因此 +// 暂时只能通过这种方法来声明这些常量,这些常量暂时没有全部用到,但是都出现在 linux 的判断逻辑中,所以都保留下来了 +#[allow(dead_code)] +pub const SIG_KERNEL_ONLY_MASK: SigSet = + Signal::into_sigset(Signal::SIGSTOP).union(Signal::into_sigset(Signal::SIGKILL)); + +pub const SIG_KERNEL_STOP_MASK: SigSet = Signal::into_sigset(Signal::SIGSTOP) + .union(Signal::into_sigset(Signal::SIGTSTP)) + .union(Signal::into_sigset(Signal::SIGTTIN)) + .union(Signal::into_sigset(Signal::SIGTTOU)); +#[allow(dead_code)] +pub const SIG_KERNEL_COREDUMP_MASK: SigSet = Signal::into_sigset(Signal::SIGQUIT) + .union(Signal::into_sigset(Signal::SIGILL)) + .union(Signal::into_sigset(Signal::SIGTRAP)) + .union(Signal::into_sigset(Signal::SIGABRT_OR_IOT)) + .union(Signal::into_sigset(Signal::SIGFPE)) + .union(Signal::into_sigset(Signal::SIGSEGV)) + .union(Signal::into_sigset(Signal::SIGBUS)) + .union(Signal::into_sigset(Signal::SIGSYS)) + .union(Signal::into_sigset(Signal::SIGXCPU)) + .union(Signal::into_sigset(Signal::SIGXFSZ)); +#[allow(dead_code)] +pub const SIG_KERNEL_IGNORE_MASK: SigSet = Signal::into_sigset(Signal::SIGCONT) + .union(Signal::into_sigset(Signal::SIGFPE)) + .union(Signal::into_sigset(Signal::SIGSEGV)) + .union(Signal::into_sigset(Signal::SIGBUS)) + .union(Signal::into_sigset(Signal::SIGTRAP)) + .union(Signal::into_sigset(Signal::SIGCHLD)) + .union(Signal::into_sigset(Signal::SIGIO_OR_POLL)) + .union(Signal::into_sigset(Signal::SIGSYS)); + +/// SignalStruct 在 pcb 中加锁 +#[derive(Debug)] +pub struct SignalStruct { + pub cnt: AtomicI64, + /// 如果对应linux,这部分会有一个引用计数,但是没发现在哪里有用到需要计算引用的地方,因此 + /// 暂时删掉,不然这个Arc会导致其他地方的代码十分丑陋 + pub handlers: [Sigaction; MAX_SIG_NUM as usize], +} + +impl Default for SignalStruct { + fn default() -> Self { + Self { + cnt: Default::default(), + handlers: [Sigaction::default(); MAX_SIG_NUM as usize], + } + } +} + +#[derive(Debug, Copy, Clone)] +#[allow(dead_code)] +pub enum SigactionType { + SaHandler(SaHandlerType), + SaSigaction( + Option< + unsafe extern "C" fn( + sig: ::core::ffi::c_int, + sinfo: *mut SigInfo, + arg1: *mut ::core::ffi::c_void, + ), + >, + ), // 暂时没有用上 +} + +impl SigactionType { + /// Returns `true` if the sa handler type is [`SaHandler(SaHandlerType::SigIgnore)`]. + /// + /// [`SigIgnore`]: SaHandlerType::SigIgnore + pub fn is_ignore(&self) -> bool { + return matches!(self, Self::SaHandler(SaHandlerType::SigIgnore)); + } + /// Returns `true` if the sa handler type is [`SaHandler(SaHandlerType::SigCustomized(_))`]. + /// + /// [`SigCustomized`]: SaHandlerType::SigCustomized(_) + pub fn is_customized(&self) -> bool { + return matches!(self, Self::SaHandler(SaHandlerType::SigCustomized(_))); + } +} + +#[derive(Debug, Copy, Clone)] +#[allow(dead_code)] +pub enum SaHandlerType { + SigError, // 暂时没有用上 + SigDefault, + SigIgnore, + SigCustomized(VirtAddr), +} + +impl Into for SaHandlerType { + fn into(self) -> usize { + match self { + Self::SigError => 2 as usize, + Self::SigIgnore => 1 as usize, + Self::SigDefault => 0 as usize, + Self::SigCustomized(handler) => handler.data(), + } + } +} + +impl SaHandlerType { + /// Returns `true` if the sa handler type is [`SigDefault`]. + /// + /// [`SigDefault`]: SaHandlerType::SigDefault + pub fn is_sig_default(&self) -> bool { + matches!(self, Self::SigDefault) + } + + /// Returns `true` if the sa handler type is [`SigIgnore`]. + /// + /// [`SigIgnore`]: SaHandlerType::SigIgnore + pub fn is_sig_ignore(&self) -> bool { + matches!(self, Self::SigIgnore) + } + + /// Returns `true` if the sa handler type is [`SigError`]. + /// + /// [`SigError`]: SaHandlerType::SigError + pub fn is_sig_error(&self) -> bool { + matches!(self, Self::SigError) + } +} + +/// 信号处理结构体 +/// +#[derive(Debug, Copy, Clone)] +pub struct Sigaction { + action: SigactionType, + flags: SigFlags, + mask: SigSet, // 为了可扩展性而设置的sa_mask + /// 信号处理函数执行结束后,将会跳转到这个函数内进行执行,然后执行sigreturn系统调用 + restorer: Option, +} + +impl Default for Sigaction { + fn default() -> Self { + Self { + action: SigactionType::SaHandler(SaHandlerType::SigDefault), + flags: Default::default(), + mask: Default::default(), + restorer: Default::default(), + } + } +} + +impl Sigaction { + /// 判断传入的信号是否被忽略 + /// + /// ## 参数 + /// + /// - `sig` 传入的信号 + /// + /// ## 返回值 + /// + /// - `true` 被忽略 + /// - `false`未被忽略 + pub fn is_ignore(&self) -> bool { + return self.action.is_ignore(); + } + pub fn new( + action: SigactionType, + flags: SigFlags, + mask: SigSet, + restorer: Option, + ) -> Self { + Self { + action, + flags, + mask, + restorer, + } + } + + pub fn action(&self) -> SigactionType { + self.action + } + + pub fn flags(&self) -> SigFlags { + self.flags + } + + pub fn restorer(&self) -> Option { + self.restorer + } + + pub fn flags_mut(&mut self) -> &mut SigFlags { + &mut self.flags + } + + pub fn set_action(&mut self, action: SigactionType) { + self.action = action; + } + + pub fn mask(&self) -> SigSet { + self.mask + } + + pub fn mask_mut(&mut self) -> &mut SigSet { + &mut self.mask + } + + pub fn set_restorer(&mut self, restorer: Option) { + self.restorer = restorer; + } + + /// 默认信号处理程序占位符(用于在sighand结构体中的action数组中占位) + pub const DEFAULT_SIGACTION: Sigaction = Sigaction { + action: SigactionType::SaHandler(SaHandlerType::SigDefault), + flags: SigFlags::empty(), + mask: SigSet::from_bits_truncate(0), + restorer: None, + }; + + /// 默认的“忽略信号”的sigaction + pub const DEFAULT_SIGACTION_IGNORE: Sigaction = Sigaction { + action: SigactionType::SaHandler(SaHandlerType::SigIgnore), + flags: SigFlags::empty(), + mask: SigSet::from_bits_truncate(0), + restorer: None, + }; +} + +/// 用户态传入的sigaction结构体(符合posix规范) +/// 请注意,我们会在sys_sigaction函数里面将其转换成内核使用的sigaction结构体 +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct UserSigaction { + pub handler: *mut core::ffi::c_void, + pub flags: SigFlags, + pub restorer: *mut core::ffi::c_void, + pub mask: SigSet, +} + +/** + * siginfo中,根据signal的来源不同,该info中对应了不同的数据./= + * 请注意,该info最大占用16字节 + */ + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct SigInfo { + sig_no: i32, + sig_code: SigCode, + errno: i32, + sig_type: SigType, +} + +impl SigInfo { + pub fn sig_code(&self) -> SigCode { + self.sig_code + } + + pub fn set_sig_type(&mut self, sig_type: SigType) { + self.sig_type = sig_type; + } + /// @brief 将siginfo结构体拷贝到用户栈 + /// ## 参数 + /// + /// `to` 用户空间指针 + /// + /// ## 注意 + /// + /// 该函数对应Linux中的https://opengrok.ringotek.cn/xref/linux-6.1.9/kernel/signal.c#3323 + /// Linux还提供了 https://opengrok.ringotek.cn/xref/linux-6.1.9/kernel/signal.c#3383 用来实现 + /// kernel_siginfo 保存到 用户的 compact_siginfo 的功能,但是我们系统内还暂时没有对这两种 + /// siginfo做区分,因此暂时不需要第二个函数 + pub fn copy_siginfo_to_user(&self, to: *mut SigInfo) -> Result { + // 验证目标地址是否为用户空间 + let mut user_buffer = UserBufferWriter::new(to, size_of::(), true)?; + + let retval: Result = Ok(0); + + user_buffer.copy_one_to_user(self, 0)?; + return retval; + } +} + +#[derive(Copy, Clone, Debug)] +pub enum SigType { + Kill(Pid), + // 后续完善下列中的具体字段 + // Timer, + // Rt, + // SigChild, + // SigFault, + // SigPoll, + // SigSys, +} + +impl SigInfo { + pub fn new(sig: Signal, sig_errno: i32, sig_code: SigCode, sig_type: SigType) -> Self { + Self { + sig_no: sig as i32, + sig_code, + errno: sig_errno, + sig_type, + } + } +} + +#[derive(Debug)] +pub struct SigPending { + signal: SigSet, + queue: SigQueue, +} + +impl Default for SigPending { + fn default() -> Self { + SigPending { + signal: SigSet::default(), + queue: SigQueue::default(), + } + } +} + +impl SigPending { + pub fn signal(&self) -> SigSet { + self.signal + } + + pub fn queue(&self) -> &SigQueue { + &self.queue + } + + pub fn queue_mut(&mut self) -> &mut SigQueue { + &mut self.queue + } + + pub fn signal_mut(&mut self) -> &mut SigSet { + &mut self.signal + } + /// @brief 获取下一个要处理的信号(sig number越小的信号,优先级越高) + /// + /// @param pending 等待处理的信号 + /// @param sig_mask 屏蔽了的信号 + /// @return i32 下一个要处理的信号的number. 如果为0,则无效 + pub fn next_signal(&self, sig_mask: &SigSet) -> Signal { + let mut sig = Signal::INVALID; + + let s = self.signal(); + let m = *sig_mask; + m.is_empty(); + // 获取第一个待处理的信号的号码 + let x = s & (!m); + if x.bits() != 0 { + sig = Signal::from(ffz(x.complement().bits()) + 1); + return sig; + } + + // 暂时只支持64种信号 + assert_eq!(MAX_SIG_NUM, 64); + + return sig; + } + /// @brief 收集信号的信息 + /// + /// @param sig 要收集的信号的信息 + /// @param pending 信号的排队等待标志 + /// @return SigInfo 信号的信息 + pub fn collect_signal(&mut self, sig: Signal) -> SigInfo { + let (info, still_pending) = self.queue_mut().find_and_delete(sig); + + // 如果没有仍在等待的信号,则清除pending位 + if !still_pending { + self.signal_mut().remove(sig.into()); + } + + if info.is_some() { + return info.unwrap(); + } else { + // 信号不在sigqueue中,这意味着当前信号是来自快速路径,因此直接把siginfo设置为0即可。 + let mut ret = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(Pid::from(0))); + ret.set_sig_type(SigType::Kill(Pid::new(0))); + return ret; + } + } + + /// @brief 从当前进程的sigpending中取出下一个待处理的signal,并返回给调用者。(调用者应当处理这个信号) + /// 请注意,进入本函数前,当前进程应当持有current_pcb().sighand.siglock + pub fn dequeue_signal(&mut self, sig_mask: &SigSet) -> (Signal, Option) { + // kdebug!("dequeue signal"); + // 获取下一个要处理的信号的编号 + let sig = self.next_signal(sig_mask); + + let info: Option; + if sig != Signal::INVALID { + // 如果下一个要处理的信号是合法的,则收集其siginfo + info = Some(self.collect_signal(sig)); + } else { + info = None; + } + + // 当一个进程具有多个线程之后,在这里需要重新计算线程的flag中的TIF_SIGPENDING位 + // recalc_sigpending(); + return (sig, info); + } + /// @brief 从sigpending中删除mask中被置位的信号。也就是说,比如mask的第1位被置为1,那么就从sigqueue中删除所有signum为2的信号的信息。 + pub fn flush_by_mask(&mut self, mask: &SigSet) { + // 定义过滤器,从sigqueue中删除mask中被置位的信号 + let filter = |x: &mut SigInfo| { + if mask.contains(SigSet::from_bits_truncate(x.sig_no as u64)) { + return true; + } + return false; + }; + let filter_result: Vec = self.queue.q.drain_filter(filter).collect(); + // 回收这些siginfo + for x in filter_result { + drop(x) + } + } +} + +/// @brief 进程接收到的信号的队列 +#[derive(Debug, Clone)] +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: Signal) -> (Option<&SigInfo>, bool) { + // 是否存在多个满足条件的siginfo + let mut still_pending = false; + let mut info: Option<&SigInfo> = None; + + for x in self.q.iter() { + if x.sig_no == 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: Signal) -> (Option, bool) { + // 是否存在多个满足条件的siginfo + let mut still_pending = false; + let mut first = true; // 标记变量,记录当前是否已经筛选出了一个元素 + + let filter = |x: &mut SigInfo| { + if x.sig_no == sig as i32 { + if !first { + // 如果之前已经筛选出了一个元素,则不把当前元素删除 + still_pending = true; + return false; + } else { + // 当前是第一个被筛选出来的元素 + first = false; + return true; + } + } + 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); + } + + /// @brief 从C的void*指针转换为static生命周期的可变引用 + pub fn from_c_void(p: *mut c_void) -> &'static mut SigQueue { + let sq = p as *mut SigQueue; + let sq = unsafe { sq.as_mut::<'static>() }.unwrap(); + return sq; + } +} + +impl Default for SigQueue { + fn default() -> Self { + Self { + q: Default::default(), + } + } +} + +/// +/// 定义了不同架构下实现 Signal 要实现的接口 +/// +pub trait SignalArch { + /// 信号处理函数 + /// + /// ## 参数 + /// + /// - `frame` 中断栈帧 + unsafe fn do_signal(frame: &mut TrapFrame); + + fn sys_rt_sigreturn(trap_frame: &mut TrapFrame) -> u64; +} diff --git a/kernel/src/ipc/syscall.rs b/kernel/src/ipc/syscall.rs index 5d36addd..4eacc55f 100644 --- a/kernel/src/ipc/syscall.rs +++ b/kernel/src/ipc/syscall.rs @@ -1,15 +1,27 @@ -use core::ffi::c_int; +use core::{ + ffi::{c_int, c_void}, + sync::atomic::compiler_fence, +}; use crate::{ + arch::ipc::signal::{SigCode, SigFlags, SigSet, Signal}, filesystem::vfs::{ file::{File, FileMode}, FilePrivateData, }, + kerror, kwarn, + mm::VirtAddr, process::{Pid, ProcessManager}, syscall::{user_access::UserBufferWriter, Syscall, SystemError}, }; -use super::pipe::{LockedPipeInode, PipeFsPrivateData}; +use super::{ + pipe::{LockedPipeInode, PipeFsPrivateData}, + signal_types::{ + SaHandlerType, SigInfo, SigType, Sigaction, SigactionType, UserSigaction, USER_SIG_DFL, + USER_SIG_ERR, USER_SIG_IGN, + }, +}; impl Syscall { /// # 创建带参数的匿名管道 @@ -52,26 +64,158 @@ impl Syscall { } } - pub fn kill(_pid: Pid, _sig: c_int) -> Result { - // todo: 由于进程管理重构,目前删除了signal功能,将来重新实现它。 - return Err(SystemError::ENOSYS); + pub fn kill(pid: Pid, sig: c_int) -> Result { + let sig = Signal::from(sig); + if sig == Signal::INVALID { + // 传入的signal数值不合法 + kwarn!("Not a valid signal number"); + return Err(SystemError::EINVAL); + } + + // 初始化signal info + let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pid)); + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + let retval = sig + .send_signal_info(Some(&mut info), pid) + .map(|x| x as usize); + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + return retval; } - /// @brief 用户程序用于设置信号处理动作的函数(遵循posix2008) + /// 通用信号注册函数 /// - /// @param regs->r8 signumber 信号的编号 - /// @param regs->r9 act 新的,将要被设置的sigaction - /// @param regs->r10 oact 返回给用户的原本的sigaction(内核将原本的sigaction的值拷贝给这个地址) + /// ## 参数 + /// + /// - `sig` 信号的值 + /// - `act` 用户空间传入的 Sigaction 指针 + /// - `old_act` 用户空间传入的用来保存旧 Sigaction 的指针 + /// - `from_user` 用来标识这个函数调用是否来自用户空间 /// /// @return int 错误码 #[no_mangle] pub fn sigaction( - _sig: c_int, - _act: usize, - _old_act: usize, - _from_user: bool, + sig: c_int, + new_act: usize, + old_act: usize, + from_user: bool, ) -> Result { - // todo: 由于进程管理重构,目前删除了signal功能,将来重新实现它。 - return Err(SystemError::ENOSYS); + // 请注意:用户态传进来的user_sigaction结构体类型,请注意,这个结构体与内核实际的不一样 + let act: *mut UserSigaction = new_act as *mut UserSigaction; + let mut old_act = old_act as *mut UserSigaction; + let mut new_ka: Sigaction = Default::default(); + let mut old_sigaction: Sigaction = Default::default(); + // 如果传入的,新的sigaction不为空 + if !act.is_null() { + // 如果参数的范围不在用户空间,则返回错误 + let r = UserBufferWriter::new(act, core::mem::size_of::(), from_user); + if r.is_err() { + return Err(SystemError::EFAULT); + } + let mask: SigSet = unsafe { (*act).mask }; + let input_sighandler = unsafe { (*act).handler as u64 }; + match input_sighandler { + USER_SIG_DFL => { + new_ka = Sigaction::DEFAULT_SIGACTION.clone(); + *new_ka.flags_mut() = unsafe { (*act).flags }; + new_ka.set_restorer(None); + } + + USER_SIG_IGN => { + new_ka = Sigaction::DEFAULT_SIGACTION_IGNORE.clone(); + *new_ka.flags_mut() = unsafe { (*act).flags }; + + new_ka.set_restorer(None); + } + _ => { + // 从用户空间获得sigaction结构体 + // TODO mask是default还是用户空间传入 + new_ka = Sigaction::new( + SigactionType::SaHandler(SaHandlerType::SigCustomized(unsafe { + VirtAddr::new((*act).handler as usize) + })), + unsafe { (*act).flags }, + SigSet::default(), + unsafe { Some(VirtAddr::new((*act).restorer as usize)) }, + ); + } + } + + // TODO 如果为空,赋默认值? + // kdebug!("new_ka={:?}", new_ka); + // 如果用户手动给了sa_restorer,那么就置位SA_FLAG_RESTORER,否则报错。(用户必须手动指定restorer) + if new_ka.restorer().is_some() { + new_ka.flags_mut().insert(SigFlags::SA_RESTORER); + } else if new_ka.action().is_customized() { + kerror!( + "pid:{:?}: in sys_sigaction: User must manually sprcify a sa_restorer for signal {}.", + ProcessManager::current_pcb().pid(), + sig + ); + return Err(SystemError::EINVAL); + } + *new_ka.mask_mut() = mask; + } + + let sig = Signal::from(sig as i32); + // 如果给出的信号值不合法 + if sig == Signal::INVALID { + return Err(SystemError::EINVAL); + } + + let retval = super::signal::do_sigaction( + sig, + if act.is_null() { + None + } else { + Some(&mut new_ka) + }, + if old_act.is_null() { + None + } else { + Some(&mut old_sigaction) + }, + ); + + // + if (retval == Ok(())) && (!old_act.is_null()) { + let r = + UserBufferWriter::new(old_act, core::mem::size_of::(), from_user); + if r.is_err() { + return Err(SystemError::EFAULT); + } + + let sigaction_handler: VirtAddr; + sigaction_handler = match old_sigaction.action() { + SigactionType::SaHandler(handler) => { + if let SaHandlerType::SigCustomized(hand) = handler { + hand + } else if handler.is_sig_ignore() { + VirtAddr::new(USER_SIG_IGN as usize) + } else if handler.is_sig_error() { + VirtAddr::new(USER_SIG_ERR as usize) + } else { + VirtAddr::new(USER_SIG_DFL as usize) + } + } + SigactionType::SaSigaction(_) => { + kerror!("unsupported type: SaSigaction"); + VirtAddr::new(USER_SIG_DFL as usize) + } + }; + + unsafe { + (*old_act).handler = sigaction_handler.data() as *mut c_void; + (*old_act).flags = old_sigaction.flags(); + (*old_act).mask = old_sigaction.mask(); + if old_sigaction.restorer().is_some() { + (*old_act).restorer = old_sigaction.restorer().unwrap().data() as *mut c_void; + } + } + } + return retval.map(|_| 0); } } diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index 0a836d16..8e576a82 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -1,8 +1,9 @@ use alloc::{string::ToString, sync::Arc}; use crate::{ - arch::interrupt::TrapFrame, filesystem::procfs::procfs_register_pid, libs::rwlock::RwLock, - process::ProcessFlags, syscall::SystemError, + arch::interrupt::TrapFrame, filesystem::procfs::procfs_register_pid, + ipc::signal::flush_signal_handlers, libs::rwlock::RwLock, process::ProcessFlags, + syscall::SystemError, }; use super::{ @@ -87,7 +88,13 @@ impl ProcessManager { ) }); - // todo: 拷贝信号相关数据 + //拷贝信号相关数据 + ProcessManager::copy_sighand(&clone_flags, ¤t_pcb, &pcb).unwrap_or_else(|e| { + panic!( + "fork: Failed to copy sighands from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}", + current_pcb.pid(), pcb.pid(), e + ) + }); // 拷贝线程 ProcessManager::copy_thread(&clone_flags, ¤t_pcb, &pcb, ¤t_trapframe).unwrap_or_else(|e| { @@ -194,11 +201,18 @@ impl ProcessManager { #[allow(dead_code)] fn copy_sighand( - _clone_flags: &CloneFlags, - _current_pcb: &Arc, - _new_pcb: &Arc, + clone_flags: &CloneFlags, + current_pcb: &Arc, + new_pcb: &Arc, ) -> Result<(), SystemError> { - // todo: 由于信号原来写的太烂,移植到新的进程管理的话,需要改动很多。因此决定重写。这里先空着 + // // 将信号的处理函数设置为default(除了那些被手动屏蔽的) + if clone_flags.contains(CloneFlags::CLONE_CLEAR_SIGHAND) { + flush_signal_handlers(new_pcb.clone(), false); + } + + if clone_flags.contains(CloneFlags::CLONE_SIGHAND) { + (*new_pcb.sig_struct()).handlers = current_pcb.sig_struct().handlers.clone(); + } return Ok(()); } } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index cd4baf0b..e3d06d72 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -13,12 +13,18 @@ use alloc::{ use hashbrown::HashMap; use crate::{ - arch::{process::ArchPCBInfo, sched::sched, CurrentIrqArch}, + arch::{ + ipc::signal::{SigSet, Signal}, + process::ArchPCBInfo, + sched::sched, + CurrentIrqArch, + }, exception::InterruptArch, filesystem::{ procfs::procfs_unregister_pid, vfs::{file::FileDescriptorVec, FileType}, }, + ipc::signal_types::{SigInfo, SigPending, SignalStruct}, kdebug, kinfo, libs::{ align::AlignedBox, @@ -34,7 +40,7 @@ use crate::{ SchedPolicy, SchedPriority, }, smp::kick_cpu, - syscall::SystemError, + syscall::{Syscall, SystemError}, }; use self::kthread::WorkerPrivate; @@ -46,6 +52,7 @@ pub mod fork; pub mod idle; pub mod init; pub mod kthread; +pub mod pid; pub mod process; pub mod syscall; @@ -184,6 +191,32 @@ impl ProcessManager { } } + /// 唤醒暂停的进程 + pub fn wakeup_stop(pcb: &Arc) -> Result<(), SystemError> { + let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + let state = pcb.sched_info().state(); + if let ProcessState::Stopped = state { + let mut writer = pcb.sched_info_mut(); + let state = writer.state(); + if let ProcessState::Stopped = state { + writer.set_state(ProcessState::Runnable); + // avoid deadlock + drop(writer); + + sched_enqueue(pcb.clone(), true); + return Ok(()); + } else if state.is_runnable() { + return Ok(()); + } else { + return Err(SystemError::EINVAL); + } + } else if state.is_runnable() { + return Ok(()); + } else { + return Err(SystemError::EINVAL); + } + } + /// 标志当前进程永久睡眠,但是发起调度的工作,应该由调用者完成 /// /// ## 注意 @@ -199,7 +232,7 @@ impl ProcessManager { let pcb = ProcessManager::current_pcb(); let mut writer = pcb.sched_info_mut_irqsave(); - if writer.state() != ProcessState::Exited(0) { + if !matches!(writer.state(), ProcessState::Exited(_)) { writer.set_state(ProcessState::Blocked(interruptable)); pcb.flags().insert(ProcessFlags::NEED_SCHEDULE); drop(writer); @@ -209,6 +242,30 @@ impl ProcessManager { return Err(SystemError::EINTR); } + /// 标志当前进程为停止状态,但是发起调度的工作,应该由调用者完成 + /// + /// ## 注意 + /// + /// - 进入当前函数之前,不能持有sched_info的锁 + /// - 进入当前函数之前,必须关闭中断 + pub fn mark_stop() -> Result<(), SystemError> { + assert_eq!( + CurrentIrqArch::is_irq_enabled(), + false, + "interrupt must be disabled before enter ProcessManager::mark_sleep()" + ); + + let pcb = ProcessManager::current_pcb(); + let mut writer = pcb.sched_info_mut_irqsave(); + if !matches!(writer.state(), ProcessState::Exited(_)) { + writer.set_state(ProcessState::Stopped); + pcb.flags().insert(ProcessFlags::NEED_SCHEDULE); + drop(writer); + + return Ok(()); + } + return Err(SystemError::EINTR); + } /// 当子进程退出后向父进程发送通知 fn exit_notify() { let current = ProcessManager::current_pcb(); @@ -219,6 +276,19 @@ impl ProcessManager { .adopt_childen() .unwrap_or_else(|e| panic!("adopte_childen failed: error: {e:?}")) }; + let r = current.parent_pcb.read().upgrade(); + if r.is_none() { + return; + } + let parent_pcb = r.unwrap(); + let r = Syscall::kill(parent_pcb.pid(), Signal::SIGCHLD as i32); + if r.is_err() { + kwarn!( + "failed to send kill signal to {:?}'s parent pcb {:?}", + current.pid(), + parent_pcb.pid() + ); + } // todo: 当信号机制重写后,这里需要向父进程发送SIGCHLD信号 } } @@ -332,7 +402,7 @@ pub enum ProcessState { /// - 如果该bool为false,那么,这个进程必须被显式的唤醒,才能重新进入Runnable状态。 Blocked(bool), /// 进程被信号终止 - // Stopped(SignalNumber), + Stopped, /// 进程已经退出,usize表示进程的退出码 Exited(usize), } @@ -353,6 +423,14 @@ impl ProcessState { pub fn is_exited(&self) -> bool { return matches!(self, ProcessState::Exited(_)); } + + /// Returns `true` if the process state is [`Stopped`]. + /// + /// [`Stopped`]: ProcessState::Stopped + #[inline(always)] + pub fn is_stopped(&self) -> bool { + matches!(self, ProcessState::Stopped) + } } bitflags! { @@ -395,6 +473,10 @@ pub struct ProcessControlBlock { sched_info: RwLock, /// 与处理器架构相关的信息 arch_info: SpinLock, + /// 与信号处理相关的信息(似乎可以是无锁的) + sig_info: RwLock, + /// 信号处理结构体 + sig_struct: SpinLock, /// 父进程指针 parent_pcb: RwLock>, @@ -460,6 +542,8 @@ impl ProcessControlBlock { worker_private: SpinLock::new(None), sched_info, arch_info, + sig_info: RwLock::new(ProcessSignalInfo::default()), + sig_struct: SpinLock::new(SignalStruct::default()), parent_pcb: RwLock::new(ppcb), children: RwLock::new(HashMap::new()), wait_queue: WaitQueue::INIT, @@ -638,6 +722,22 @@ impl ProcessControlBlock { } return name; } + + pub fn sig_info(&self) -> RwLockReadGuard { + self.sig_info.read() + } + + pub fn sig_info_mut(&self) -> RwLockWriteGuard { + self.sig_info.write() + } + + pub fn sig_struct(&self) -> SpinLockGuard { + self.sig_struct.lock() + } + + pub fn sig_struct_irq(&self) -> SpinLockGuard { + self.sig_struct.lock_irqsave() + } } impl Drop for ProcessControlBlock { @@ -948,3 +1048,64 @@ impl Drop for KernelStack { pub fn process_init() { ProcessManager::init(); } + +#[derive(Debug)] +pub struct ProcessSignalInfo { + // 当前进程 + sig_block: SigSet, + // sig_pending 中存储当前线程要处理的信号 + sig_pending: SigPending, + // sig_shared_pending 中存储当前线程所属进程要处理的信号 + sig_shared_pending: SigPending, +} + +impl ProcessSignalInfo { + pub fn sig_block(&self) -> &SigSet { + &self.sig_block + } + + pub fn sig_pending(&self) -> &SigPending { + &self.sig_pending + } + + pub fn sig_pending_mut(&mut self) -> &mut SigPending { + &mut self.sig_pending + } + + pub fn sig_block_mut(&mut self) -> &mut SigSet { + &mut self.sig_block + } + + pub fn sig_shared_pending_mut(&mut self) -> &mut SigPending { + &mut self.sig_shared_pending + } + + pub fn sig_shared_pending(&self) -> &SigPending { + &self.sig_shared_pending + } + + /// 从 pcb 的 siginfo中取出下一个要处理的信号,先处理线程信号,再处理进程信号 + /// + /// ## 参数 + /// + /// - `sig_mask` 被忽略掉的信号 + /// + pub fn dequeue_signal(&mut self, sig_mask: &SigSet) -> (Signal, Option) { + let res = self.sig_pending.dequeue_signal(sig_mask); + if res.0 != Signal::INVALID { + return res; + } else { + return self.sig_shared_pending.dequeue_signal(sig_mask); + } + } +} + +impl Default for ProcessSignalInfo { + fn default() -> Self { + Self { + sig_block: SigSet::empty(), + sig_pending: SigPending::default(), + sig_shared_pending: SigPending::default(), + } + } +} diff --git a/kernel/src/process/pid.rs b/kernel/src/process/pid.rs new file mode 100644 index 00000000..471acf7a --- /dev/null +++ b/kernel/src/process/pid.rs @@ -0,0 +1,18 @@ +#[allow(dead_code)] +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +pub enum PidType { + /// pid类型是进程id + PID = 1, + TGID = 2, + PGID = 3, + SID = 4, + MAX = 5, +} + +/// 为PidType实现判断相等的trait +impl PartialEq for PidType { + fn eq(&self, other: &PidType) -> bool { + *self as u8 == *other as u8 + } +} diff --git a/kernel/src/process/proc-types.h b/kernel/src/process/proc-types.h index fe54ff34..cca2d449 100644 --- a/kernel/src/process/proc-types.h +++ b/kernel/src/process/proc-types.h @@ -1,7 +1,6 @@ #pragma once #include "ptrace.h" -#include #include // 进程最大可拥有的文件描述符数量 diff --git a/kernel/src/process/syscall.rs b/kernel/src/process/syscall.rs index 88d62fcb..c8f83e7e 100644 --- a/kernel/src/process/syscall.rs +++ b/kernel/src/process/syscall.rs @@ -111,7 +111,7 @@ impl Syscall { return Ok(0); } } - ProcessState::Blocked(_) => { + ProcessState::Blocked(_) | ProcessState::Stopped => { // 指定WUNTRACED则等待暂停的进程,不指定则返回0 if !options.contains(WaitOption::WUNTRACED) || options.contains(WaitOption::WNOWAIT) diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 53e7bc5f..f497c766 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -670,7 +670,7 @@ impl Syscall { SYS_KILL => { let pid = Pid::new(args[0]); let sig = args[1] as c_int; - + // kdebug!("KILL SYSCALL RECEIVED"); Self::kill(pid, sig) } diff --git a/kernel/src/syscall/user_access.rs b/kernel/src/syscall/user_access.rs index abd5fbb8..c500b5e4 100644 --- a/kernel/src/syscall/user_access.rs +++ b/kernel/src/syscall/user_access.rs @@ -286,7 +286,7 @@ impl<'a> UserBufferWriter<'a> { /// /// @param data 要写入的数据地址 /// @param offset 在UserBuffer中的字节偏移量 - /// @return 返回写入元素的数量 + /// @return Ok/Err /// pub fn copy_one_to_user( &'a mut self, diff --git a/user/apps/Makefile b/user/apps/Makefile index 4daffef4..7fbb4afb 100644 --- a/user/apps/Makefile +++ b/user/apps/Makefile @@ -1,5 +1,5 @@ -user_apps_sub_dirs=shell about test_signal +user_apps_sub_dirs=shell about ECHO: @echo "$@" diff --git a/user/apps/test_signal/Makefile b/user/apps/test_signal/Makefile index 080cc67f..d25e475b 100644 --- a/user/apps/test_signal/Makefile +++ b/user/apps/test_signal/Makefile @@ -1,9 +1,25 @@ -OLD_LIBC_INSTALL_PATH=$(ROOT_PATH)/bin/sysroot/usr/old_libc +CC=$(DragonOS_GCC)/x86_64-elf-gcc +LD=ld +OBJCOPY=objcopy +# 修改这里,把它改为你的relibc的sysroot路径 +RELIBC_OPT=$(DADK_BUILD_CACHE_DIR_RELIBC_0_1_0) +CFLAGS=-I $(RELIBC_OPT)/include -D__dragonos__ + +tmp_output_dir=$(ROOT_PATH)/bin/tmp/user +output_dir=$(DADK_BUILD_CACHE_DIR_TEST_SIGNAL_0_1_0) + + +LIBC_OBJS:=$(shell find $(RELIBC_OPT)/lib -name "*.o" | sort ) +LIBC_OBJS+=$(RELIBC_OPT)/lib/libc.a all: main.o - $(LD) -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/test_signal $(shell find . -name "*.o") $(OLD_LIBC_INSTALL_PATH)/lib/libc.a -T link.lds + $(LD) -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/test_signal $(shell find . -name "*.o") $(LIBC_OBJS) -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 + mv $(output_dir)/test_signal.elf $(output_dir)/test_signal main.o: main.c $(CC) $(CFLAGS) -c main.c -o main.o + +clean: + rm -f *.o \ No newline at end of file diff --git a/user/apps/test_signal/link.lds b/user/apps/test_signal/link.lds index 6634d5e7..1f2e57e4 100644 --- a/user/apps/test_signal/link.lds +++ b/user/apps/test_signal/link.lds @@ -1,54 +1,239 @@ - -OUTPUT_FORMAT("elf64-x86-64","elf64-x86-64","elf64-x86-64") +/* Script for -z combreloc */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", + "elf64-x86-64") OUTPUT_ARCH(i386:x86-64) ENTRY(_start) SECTIONS { - - . = 0x800000; - - - .text : - { - _text = .; - - *(.text) - *(.text.*) - - _etext = .; - } - . = ALIGN(8); - - .data : - { - _data = .; - *(.data) - *(.data.*) - - _edata = .; - } - - - rodata_start_pa = .; - .rodata : - { - _rodata = .; - *(.rodata) - *(.rodata.*) - _erodata = .; - } - - - .bss : - { - _bss = .; - *(.bss) - *(.bss.*) - _ebss = .; - } - - _end = .; - - -} \ No newline at end of file + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) + } + .rela.plt : + { + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} diff --git a/user/apps/test_signal/main.c b/user/apps/test_signal/main.c index 0d35b182..7f74b60c 100644 --- a/user/apps/test_signal/main.c +++ b/user/apps/test_signal/main.c @@ -23,35 +23,35 @@ #include #include #include - +#include bool handle_ok = false; - +int count = 0; void handler(int sig) { printf("handle %d\n", sig); handle_ok = true; + count++; } int main() { - printf("Test signal running...\n"); signal(SIGKILL, &handler); printf("registered.\n"); - clock_t last = clock(); - while (1) { - if ((clock() - last) / CLOCKS_PER_SEC >= 1) - { - // printf("Test signal running\n"); - last = clock(); - } + // handler(SIGKILL); + printf("Test signal running\n"); + raise(SIGKILL); if (handle_ok) { printf("Handle OK!\n"); handle_ok = false; } + if (count > 0) + { + signal(SIGKILL, SIG_DFL); + } } return 0; diff --git a/user/apps/test_uart/Makefile b/user/apps/test_uart/Makefile index bf1fa624..abcb04f1 100644 --- a/user/apps/test_uart/Makefile +++ b/user/apps/test_uart/Makefile @@ -22,4 +22,4 @@ main.o: main.c $(CC) $(CFLAGS) -c main.c -o main.o clean: - rm -f *.o \ No newline at end of file + rm -f *.o diff --git a/user/dadk/config/relibc-0.1.0.dadk b/user/dadk/config/relibc-0.1.0.dadk index 9bdca94d..92a18d1d 100644 --- a/user/dadk/config/relibc-0.1.0.dadk +++ b/user/dadk/config/relibc-0.1.0.dadk @@ -6,7 +6,7 @@ "BuildFromSource": { "Git": { "url": "https://git.mirrors.dragonos.org/DragonOS-Community/relibc.git", - "revision": "66739c1b10" + "revision": "0a1b6ce239" } } }, diff --git a/user/dadk/config/test_signal-0.1.0.dadk b/user/dadk/config/test_signal-0.1.0.dadk new file mode 100644 index 00000000..44b3847f --- /dev/null +++ b/user/dadk/config/test_signal-0.1.0.dadk @@ -0,0 +1,28 @@ +{ + "name": "test_signal", + "version": "0.1.0", + "description": "一个用来测试signal能够正常运行的app", + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/test_signal" + } + } + }, + "depends": [ + { + "name": "relibc", + "version": "0.1.0" + } + ], + "build": { + "build_command": "make" + }, + "install": { + "in_dragonos_path": "/bin" + }, + "clean": { + "clean_command": "make clean" + }, + "envs": [] +}