From 686894640d96851ca94f2378bfcb3bcc29cb08e4 Mon Sep 17 00:00:00 2001 From: longjin Date: Sat, 7 Dec 2024 17:15:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(syscall):=20=E5=AE=9E=E7=8E=B0syscall=20re?= =?UTF-8?q?start?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 能够在系统调用返回ERESTARTSYS时,信号处理结束后,自动重启系统调用. TODO: 实现wait等需要restart_block的系统调用的重启 Signed-off-by: longjin --- kernel/Cargo.toml | 3 +- kernel/crates/system_error/Cargo.toml | 2 +- kernel/crates/system_error/src/lib.rs | 44 +++- kernel/src/arch/x86_64/asm/entry.S | 8 +- kernel/src/arch/x86_64/interrupt/mod.rs | 27 ++ kernel/src/arch/x86_64/ipc/signal.rs | 230 ++++++++++++------ kernel/src/arch/x86_64/syscall/mod.rs | 2 + kernel/src/driver/tty/tty_device.rs | 2 +- kernel/src/driver/tty/tty_job_control.rs | 12 +- kernel/src/driver/tty/tty_ldisc/ntty.rs | 18 +- kernel/src/exception/entry.rs | 46 ++++ kernel/src/exception/mod.rs | 1 + kernel/src/filesystem/eventfd.rs | 6 +- kernel/src/filesystem/vfs/file.rs | 26 +- kernel/src/ipc/pipe.rs | 5 +- kernel/src/ipc/signal.rs | 95 ++++++-- kernel/src/ipc/signal_types.rs | 16 +- kernel/src/ipc/syscall.rs | 6 + kernel/src/process/mod.rs | 73 +++++- kernel/src/syscall/mod.rs | 1 + user/apps/test-sigprocmask/main.c | 4 +- user/apps/test_signal_restart/.gitignore | 1 + user/apps/test_signal_restart/Makefile | 20 ++ user/apps/test_signal_restart/main.c | 106 ++++++++ .../config/test_signal_restart-0.1.0.toml | 41 ++++ 25 files changed, 627 insertions(+), 168 deletions(-) create mode 100644 kernel/src/exception/entry.rs create mode 100644 user/apps/test_signal_restart/.gitignore create mode 100644 user/apps/test_signal_restart/Makefile create mode 100644 user/apps/test_signal_restart/main.c create mode 100644 user/dadk/config/test_signal_restart-0.1.0.toml diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 414df828b..617ed5d36 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -76,6 +76,7 @@ unwinding = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/unwi "panic", "personality" ]} +defer = "0.2.1" # target为x86_64时,使用下面的依赖 [target.'cfg(target_arch = "x86_64")'.dependencies] @@ -106,4 +107,4 @@ debug = true # Controls whether the compiler passes `-g` # The release profile, used for `cargo build --release` [profile.release] -debug = false +debug = true diff --git a/kernel/crates/system_error/Cargo.toml b/kernel/crates/system_error/Cargo.toml index d166286a9..d143c3452 100644 --- a/kernel/crates/system_error/Cargo.toml +++ b/kernel/crates/system_error/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" [dependencies] num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false } -num-derive = "0.3" \ No newline at end of file +num-derive = "0.3" diff --git a/kernel/crates/system_error/src/lib.rs b/kernel/crates/system_error/src/lib.rs index 441b4b13e..a1cd1dd7a 100644 --- a/kernel/crates/system_error/src/lib.rs +++ b/kernel/crates/system_error/src/lib.rs @@ -277,31 +277,51 @@ pub enum SystemError { // === 以下错误码不应该被用户态程序使用 === ERESTARTSYS = 512, + ERESTARTNOINTR = 513, + /// restart if no handler + ERESTARTNOHAND = 514, + + /// 没有对应的ioctlcmd + ENOIOCTLCMD = 515, + /// restart by calling sys restart syscall + ERESTART_RESTARTBLOCK = 516, + + // === TODO: 这几个KVM的错误码不要放在这里 === + // VMX on 虚拟化开启指令出错 - EVMXONFailed = 513, + EVMXONFailed = 1513, // VMX off 虚拟化关闭指令出错 - EVMXOFFFailed = 514, + EVMXOFFFailed = 1514, // VMX VMWRITE 写入虚拟化VMCS内存出错 - EVMWRITEFailed = 515, - EVMREADFailed = 516, - EVMPRTLDFailed = 517, - EVMLAUNCHFailed = 518, - KVM_HVA_ERR_BAD = 519, - /// 没有对应的ioctlcmd - ENOIOCTLCMD = 520, + EVMWRITEFailed = 1515, + EVMREADFailed = 1516, + EVMPRTLDFailed = 1517, + EVMLAUNCHFailed = 1518, + KVM_HVA_ERR_BAD = 1519, + + MAXERRNO = 4095, } impl SystemError { - /// @brief 把posix错误码转换为系统错误枚举类型。 + /// 判断一个值是否是有效的posix错误码。 + pub fn is_valid_posix_errno(val: T) -> bool + where + T: PartialOrd + From, + { + let max_errno = T::from(-(Self::MAXERRNO as i32)); + val < T::from(0) && val >= max_errno + } + + /// 尝试把posix错误码转换为系统错误枚举类型。 pub fn from_posix_errno(errno: i32) -> Option { // posix 错误码是小于0的 - if errno >= 0 { + if !Self::is_valid_posix_errno(errno) { return None; } return ::from_i32(-errno); } - /// @brief 把系统错误枚举类型转换为负数posix错误码。 + /// 把系统错误枚举类型转换为负数posix错误码。 pub fn to_posix_errno(&self) -> i32 { return -::to_i32(self).unwrap(); } diff --git a/kernel/src/arch/x86_64/asm/entry.S b/kernel/src/arch/x86_64/asm/entry.S index 355d9938f..8df6566cf 100644 --- a/kernel/src/arch/x86_64/asm/entry.S +++ b/kernel/src/arch/x86_64/asm/entry.S @@ -64,9 +64,9 @@ ENTRY(ret_from_intr) // 进入信号处理流程 cli - // 将原本要返回的栈帧的栈指针传入do_signal的第一个参数 + // 将原本要返回的栈帧的栈指针传入irqentry_exit的第一个参数 movq %rsp, %rdi - callq do_signal + callq irqentry_exit cli __entry_ret_from_intr_before_gs_check_2: @@ -375,10 +375,10 @@ ENTRY(syscall_64) sti callq *%rdx //调用服务程序 - // 将原本要返回的栈帧的栈指针传入do_signal的第一个参数 + // 将原本要返回的栈帧的栈指针传入 irqentry_exit 的第一个参数 movq %rsp, %rdi - callq do_signal + callq irqentry_exit cli diff --git a/kernel/src/arch/x86_64/interrupt/mod.rs b/kernel/src/arch/x86_64/interrupt/mod.rs index e83566ca7..8198a0633 100644 --- a/kernel/src/arch/x86_64/interrupt/mod.rs +++ b/kernel/src/arch/x86_64/interrupt/mod.rs @@ -125,6 +125,8 @@ pub struct TrapFrame { pub es: ::core::ffi::c_ulong, pub rax: ::core::ffi::c_ulong, pub func: ::core::ffi::c_ulong, + /// - 该字段在异常发生时,保存的是错误码 + /// - 在系统调用时,由系统调用入口函数将其设置为系统调用号 pub errcode: ::core::ffi::c_ulong, pub rip: ::core::ffi::c_ulong, pub cs: ::core::ffi::c_ulong, @@ -182,6 +184,31 @@ impl TrapFrame { pub fn set_pc(&mut self, pc: usize) { self.rip = pc as u64; } + + /// 获取系统调用号 + /// + /// # Safety + /// 该函数只能在系统调用上下文中调用, + /// 在其他上下文中,该函数返回值未定义 + pub unsafe fn syscall_nr(&self) -> Option { + if self.errcode == u64::MAX { + return None; + } + Some(self.errcode as usize) + } + + /// 获取系统调用错误码 + /// + /// # Safety + /// 该函数只能在系统调用上下文中调用, + /// 在其他上下文中,该函数返回值未定义 + /// + /// # Returns + /// 返回一个 `Option`,表示系统调用的错误码。 + pub unsafe fn syscall_error(&self) -> Option { + let val = self.rax as i32; + SystemError::from_posix_errno(val) + } } impl ProbeArgs for TrapFrame { diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index 5b260cc9d..25e9eed62 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -1,5 +1,6 @@ use core::{ffi::c_void, intrinsics::unlikely, mem::size_of}; +use defer::defer; use log::error; use system_error::SystemError; @@ -8,11 +9,12 @@ use crate::{ fpu::FpState, interrupt::TrapFrame, process::table::{USER_CS, USER_DS}, + syscall::nr::SYS_RESTART_SYSCALL, CurrentIrqArch, MMArch, }, exception::InterruptArch, ipc::{ - signal::set_current_blocked, + signal::{restore_saved_sigmask, set_current_blocked}, signal_types::{SaHandlerType, SigInfo, Sigaction, SigactionType, SignalArch}, }, mm::MemoryManagementArch, @@ -405,99 +407,147 @@ pub struct SigStack { pub fpstate: FpState, } -#[no_mangle] -unsafe extern "C" fn do_signal(frame: &mut TrapFrame) { - X86_64SignalArch::do_signal(frame); - return; -} +unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) { + let pcb = ProcessManager::current_pcb(); -pub struct X86_64SignalArch; + let siginfo = pcb.try_siginfo_irqsave(5); -impl SignalArch for X86_64SignalArch { - unsafe fn do_signal(frame: &mut TrapFrame) { - let pcb = ProcessManager::current_pcb(); + if unlikely(siginfo.is_none()) { + return; + } - let siginfo = pcb.try_siginfo_irqsave(5); + let siginfo_read_guard = siginfo.unwrap(); - if unlikely(siginfo.is_none()) { - return; - } + // 检查sigpending是否为0 + if siginfo_read_guard.sig_pending().signal().bits() == 0 || !frame.is_from_user() { + // 若没有正在等待处理的信号,或者将要返回到的是内核态,则返回 + return; + } - let siginfo_read_guard = siginfo.unwrap(); + let mut sig_number: Signal; + let mut info: Option; + let mut sigaction: Option; + let sig_block: SigSet = *siginfo_read_guard.sig_blocked(); + drop(siginfo_read_guard); - // 检查sigpending是否为0 - if siginfo_read_guard.sig_pending().signal().bits() == 0 || !frame.is_from_user() { - // 若没有正在等待处理的信号,或者将要返回到的是内核态,则返回 - return; - } + let sig_guard = pcb.try_sig_struct_irqsave(5); + if unlikely(sig_guard.is_none()) { + return; + } + let siginfo_mut = pcb.try_siginfo_mut(5); + if unlikely(siginfo_mut.is_none()) { + return; + } - let mut sig_number: Signal; - let mut info: Option; - let mut sigaction: Sigaction; - let sig_block: SigSet = *siginfo_read_guard.sig_block(); - drop(siginfo_read_guard); + let sig_guard = sig_guard.unwrap(); + let mut siginfo_mut_guard = siginfo_mut.unwrap(); + loop { + (sig_number, info) = siginfo_mut_guard.dequeue_signal(&sig_block, &pcb); - let sig_guard = pcb.try_sig_struct_irqsave(5); - if unlikely(sig_guard.is_none()) { + // 如果信号非法,则直接返回 + if sig_number == Signal::INVALID { return; } - let siginfo_mut = pcb.try_siginfo_mut(5); - if unlikely(siginfo_mut.is_none()) { - return; + let sa = sig_guard.handlers[sig_number as usize - 1]; + + match sa.action() { + SigactionType::SaHandler(action_type) => match action_type { + SaHandlerType::Error => { + error!("Trying to handle a Sigerror on Process:{:?}", pcb.pid()); + return; + } + SaHandlerType::Default => { + sigaction = Some(sa); + } + SaHandlerType::Ignore => continue, + SaHandlerType::Customized(_) => { + sigaction = Some(sa); + } + }, + SigactionType::SaSigaction(_) => todo!(), } - let sig_guard = sig_guard.unwrap(); - let mut siginfo_mut_guard = siginfo_mut.unwrap(); - loop { - (sig_number, info) = siginfo_mut_guard.dequeue_signal(&sig_block); - // 如果信号非法,则直接返回 - if sig_number == Signal::INVALID { - return; - } + if sigaction.is_some() { + break; + } + } - sigaction = sig_guard.handlers[sig_number as usize - 1]; + let oldset = *siginfo_mut_guard.sig_blocked(); + //避免死锁 + drop(siginfo_mut_guard); + drop(sig_guard); + drop(pcb); + // 做完上面的检查后,开中断 + CurrentIrqArch::interrupt_enable(); - match sigaction.action() { - SigactionType::SaHandler(action_type) => match action_type { - SaHandlerType::Error => { - error!("Trying to handle a Sigerror on Process:{:?}", pcb.pid()); - return; - } - SaHandlerType::Default => { - sigaction = Sigaction::default(); - break; - } - SaHandlerType::Ignore => continue, - SaHandlerType::Customized(_) => { - break; - } - }, - SigactionType::SaSigaction(_) => todo!(), - } - // 如果当前动作是忽略这个信号,就继续循环。 + if sigaction.is_none() { + return; + } + *got_signal = true; + + let mut sigaction = sigaction.unwrap(); + + // 注意!由于handle_signal里面可能会退出进程, + // 因此这里需要检查清楚:上面所有的锁、arc指针都被释放了。否则会产生资源泄露的问题! + let res: Result = + handle_signal(sig_number, &mut sigaction, &info.unwrap(), &oldset, frame); + if res.is_err() { + error!( + "Error occurred when handling signal: {}, pid={:?}, errcode={:?}", + sig_number as i32, + ProcessManager::current_pcb().pid(), + res.as_ref().unwrap_err() + ); + } +} + +fn try_restart_syscall(frame: &mut TrapFrame) { + defer!({ + // 如果没有信号需要传递,我们只需恢复保存的信号掩码 + restore_saved_sigmask(); + }); + + if unsafe { frame.syscall_nr() }.is_none() { + return; + } + + let syscall_err = unsafe { frame.syscall_error() }; + if syscall_err.is_none() { + return; + } + let syscall_err = syscall_err.unwrap(); + + let mut restart = false; + match syscall_err { + SystemError::ERESTARTSYS | SystemError::ERESTARTNOHAND | SystemError::ERESTARTNOINTR => { + frame.rax = frame.errcode; + frame.rip -= 2; + restart = true; } + SystemError::ERESTART_RESTARTBLOCK => { + frame.rax = SYS_RESTART_SYSCALL as u64; + frame.rip -= 2; + restart = true; + } + _ => {} + } + log::debug!("try restart syscall: {:?}", restart); +} + +pub struct X86_64SignalArch; - let oldset = *siginfo_mut_guard.sig_block(); - //避免死锁 - drop(siginfo_mut_guard); - drop(sig_guard); - drop(pcb); - - // 做完上面的检查后,开中断 - CurrentIrqArch::interrupt_enable(); - - // 注意!由于handle_signal里面可能会退出进程, - // 因此这里需要检查清楚:上面所有的锁、arc指针都被释放了。否则会产生资源泄露的问题! - let res: Result = - handle_signal(sig_number, &mut sigaction, &info.unwrap(), &oldset, frame); - if res.is_err() { - error!( - "Error occurred when handling signal: {}, pid={:?}, errcode={:?}", - sig_number as i32, - ProcessManager::current_pcb().pid(), - res.as_ref().unwrap_err() - ); +impl SignalArch for X86_64SignalArch { + /// 处理信号,并尝试重启系统调用 + /// + /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/signal.c#865 + unsafe fn do_signal_or_restart(frame: &mut TrapFrame) { + let mut got_signal = false; + do_signal(frame, &mut got_signal); + + if got_signal { + return; } + try_restart_syscall(frame); } fn sys_rt_sigreturn(trap_frame: &mut TrapFrame) -> u64 { @@ -533,6 +583,8 @@ impl SignalArch for X86_64SignalArch { /// @param regs 之前的系统调用将要返回的时候,要弹出的栈帧的拷贝 /// /// @return Result<0,SystemError> 若Error, 则返回错误码,否则返回Ok(0) +/// +/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/signal.c#787 fn handle_signal( sig: Signal, sigaction: &mut Sigaction, @@ -540,8 +592,28 @@ fn handle_signal( oldset: &SigSet, frame: &mut TrapFrame, ) -> Result { - // TODO 这里要补充一段逻辑,好像是为了保证引入线程之后的地址空间不会出问题。详见https://code.dragonos.org.cn/xref/linux-6.1.9/arch/mips/kernel/signal.c#830 - + if unsafe { frame.syscall_nr() }.is_some() { + if let Some(syscall_err) = unsafe { frame.syscall_error() } { + match syscall_err { + SystemError::ERESTARTNOHAND | SystemError::ERESTART_RESTARTBLOCK => { + frame.rax = SystemError::EINTR.to_posix_errno() as i64 as u64; + } + SystemError::ERESTARTSYS => { + if !sigaction.flags().contains(SigFlags::SA_RESTART) { + frame.rax = SystemError::EINTR.to_posix_errno() as i64 as u64; + } else { + frame.rax = frame.errcode; + frame.rip -= 2; + } + } + SystemError::ERESTARTNOINTR => { + frame.rax = frame.errcode; + frame.rip -= 2; + } + _ => {} + } + } + } // 设置栈帧 return setup_frame(sig, sigaction, info, oldset, frame); } diff --git a/kernel/src/arch/x86_64/syscall/mod.rs b/kernel/src/arch/x86_64/syscall/mod.rs index 788517b0e..cc4756992 100644 --- a/kernel/src/arch/x86_64/syscall/mod.rs +++ b/kernel/src/arch/x86_64/syscall/mod.rs @@ -65,6 +65,8 @@ macro_rules! syscall_return { #[no_mangle] pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { + // 系统调用进入时,把系统调用号存入errcode字段,以便在syscall_handler退出后,仍能获取到系统调用号 + frame.errcode = frame.rax; let syscall_num = frame.rax as usize; // 防止sys_sched由于超时无法退出导致的死锁 if syscall_num == SYS_SCHED { diff --git a/kernel/src/driver/tty/tty_device.rs b/kernel/src/driver/tty/tty_device.rs index 0185db9f1..7b78ef4e2 100644 --- a/kernel/src/driver/tty/tty_device.rs +++ b/kernel/src/driver/tty/tty_device.rs @@ -263,7 +263,7 @@ impl IndexNode for TtyDevice { break; } - if pcb.sig_info_irqsave().sig_pending().has_pending() { + if pcb.has_pending_signal_fast() { return Err(SystemError::ERESTARTSYS); } } diff --git a/kernel/src/driver/tty/tty_job_control.rs b/kernel/src/driver/tty/tty_job_control.rs index 4cc078cce..8ca1f0beb 100644 --- a/kernel/src/driver/tty/tty_job_control.rs +++ b/kernel/src/driver/tty/tty_job_control.rs @@ -4,7 +4,7 @@ use system_error::SystemError; use crate::{ arch::ipc::signal::{SigSet, Signal}, mm::VirtAddr, - process::{Pid, ProcessManager}, + process::{Pid, ProcessFlags, ProcessManager}, syscall::{ user_access::{UserBufferReader, UserBufferWriter}, Syscall, @@ -51,9 +51,9 @@ impl TtyJobCtrlManager { if tty_pgid.is_some() && tty_pgid.unwrap() != pgid { if pcb .sig_info_irqsave() - .sig_block() + .sig_blocked() .contains(SigSet::from_bits_truncate(1 << sig as u64)) - || pcb.sig_struct_irqsave().handlers[sig as usize].is_ignore() + || pcb.sig_struct_irqsave().handlers[sig as usize - 1].is_ignore() { // 忽略该信号 if sig == Signal::SIGTTIN { @@ -62,7 +62,11 @@ impl TtyJobCtrlManager { } else { // 暂时使用kill而不是killpg Syscall::kill(pgid, sig as i32)?; - return Err(SystemError::ERESTART); + ProcessManager::current_pcb() + .flags() + .insert(ProcessFlags::HAS_PENDING_SIGNAL); + + return Err(SystemError::ERESTARTSYS); } } diff --git a/kernel/src/driver/tty/tty_ldisc/ntty.rs b/kernel/src/driver/tty/tty_ldisc/ntty.rs index df684e9d9..535e18d3a 100644 --- a/kernel/src/driver/tty/tty_ldisc/ntty.rs +++ b/kernel/src/driver/tty/tty_ldisc/ntty.rs @@ -21,7 +21,7 @@ use crate::{ }, mm::VirtAddr, net::event_poll::EPollEventType, - process::ProcessManager, + process::{ProcessFlags, ProcessManager}, syscall::{user_access::UserBufferWriter, Syscall}, }; @@ -1680,11 +1680,11 @@ impl TtyLineDiscipline for NTtyLinediscipline { break; } - if ProcessManager::current_pcb() - .sig_info_irqsave() - .sig_pending() - .has_pending() - { + if ProcessManager::current_pcb().has_pending_signal_fast() { + ProcessManager::current_pcb() + .flags() + .insert(ProcessFlags::HAS_PENDING_SIGNAL); + ret = Err(SystemError::ERESTARTSYS); break; } @@ -1763,7 +1763,11 @@ impl TtyLineDiscipline for NTtyLinediscipline { // drop(ldata); let mut offset = 0; loop { - if pcb.sig_info_irqsave().sig_pending().has_pending() { + if pcb.has_pending_signal_fast() { + ProcessManager::current_pcb() + .flags() + .insert(ProcessFlags::HAS_PENDING_SIGNAL); + return Err(SystemError::ERESTARTSYS); } if core.flags().contains(TtyFlag::HUPPED) { diff --git a/kernel/src/exception/entry.rs b/kernel/src/exception/entry.rs new file mode 100644 index 000000000..e54def7db --- /dev/null +++ b/kernel/src/exception/entry.rs @@ -0,0 +1,46 @@ +use crate::{ + arch::{interrupt::TrapFrame, CurrentSignalArch}, + ipc::signal_types::SignalArch, + process::{ProcessFlags, ProcessManager}, +}; + +#[no_mangle] +unsafe extern "C" fn irqentry_exit(frame: &mut TrapFrame) { + if frame.is_from_user() { + irqentry_exit_to_user_mode(frame); + } +} + +/// 退出到用户态之前,在这个函数内做最后的处理 +/// +/// # Safety +/// +/// 由于这个函数内可能会直接退出进程,因此,在进入函数之前, +/// 必须保证所有的栈上的Arc/Box指针等,都已经被释放。否则,可能会导致内存泄漏。 +unsafe fn irqentry_exit_to_user_mode(frame: &mut TrapFrame) { + exit_to_user_mode_prepare(frame); +} + +/// # Safety +/// +/// 由于这个函数内可能会直接退出进程,因此,在进入函数之前, +/// 必须保证所有的栈上的Arc/Box指针等,都已经被释放。否则,可能会导致内存泄漏。 +unsafe fn exit_to_user_mode_prepare(frame: &mut TrapFrame) { + let process_flags_work = *ProcessManager::current_pcb().flags(); + if !process_flags_work.exit_to_user_mode_work().is_empty() { + exit_to_user_mode_loop(frame, process_flags_work); + } +} + +/// # Safety +/// +/// 由于这个函数内可能会直接退出进程,因此,在进入函数之前, +/// 必须保证所有的栈上的Arc/Box指针等,都已经被释放。否则,可能会导致内存泄漏。 +unsafe fn exit_to_user_mode_loop(frame: &mut TrapFrame, mut process_flags_work: ProcessFlags) { + while !process_flags_work.exit_to_user_mode_work().is_empty() { + if process_flags_work.contains(ProcessFlags::HAS_PENDING_SIGNAL) { + unsafe { CurrentSignalArch::do_signal_or_restart(frame) }; + } + process_flags_work = *ProcessManager::current_pcb().flags(); + } +} diff --git a/kernel/src/exception/mod.rs b/kernel/src/exception/mod.rs index 8eb14dd6b..a12698b12 100644 --- a/kernel/src/exception/mod.rs +++ b/kernel/src/exception/mod.rs @@ -7,6 +7,7 @@ use crate::arch::CurrentIrqArch; pub mod debug; pub mod dummychip; pub mod ebreak; +pub mod entry; pub mod handle; pub mod init; pub mod ipi; diff --git a/kernel/src/filesystem/eventfd.rs b/kernel/src/filesystem/eventfd.rs index 9143697a9..908456c92 100644 --- a/kernel/src/filesystem/eventfd.rs +++ b/kernel/src/filesystem/eventfd.rs @@ -4,7 +4,7 @@ use crate::filesystem::vfs::{FilePrivateData, FileSystem, FileType, IndexNode, M use crate::libs::spinlock::{SpinLock, SpinLockGuard}; use crate::libs::wait_queue::WaitQueue; use crate::net::event_poll::{EPollEventType, EPollItem, EventPoll, KernelIoctlData}; -use crate::process::ProcessManager; +use crate::process::{ProcessFlags, ProcessManager}; use crate::sched::SchedMode; use crate::syscall::Syscall; use alloc::collections::LinkedList; @@ -127,6 +127,10 @@ impl IndexNode for EventFdInode { drop(lock_efd); let r = wq_wait_event_interruptible!(self.wait_queue, self.readable(), {}); if r.is_err() { + ProcessManager::current_pcb() + .flags() + .insert(ProcessFlags::HAS_PENDING_SIGNAL); + return Err(SystemError::ERESTARTSYS); } diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 3762474ea..33640bc73 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -311,14 +311,7 @@ impl File { let len = self .inode - .read_at(offset, len, buf, self.private_data.lock()) - .map_err(|e| { - if e == SystemError::ERESTARTSYS { - SystemError::EINTR - } else { - e - } - })?; + .read_at(offset, len, buf, self.private_data.lock())?; if update_offset { self.offset @@ -343,24 +336,11 @@ impl File { // 如果文件指针已经超过了文件大小,则需要扩展文件大小 if offset > self.inode.metadata()?.size as usize { - self.inode.resize(offset).map_err(|e| { - if e == SystemError::ERESTARTSYS { - SystemError::EINTR - } else { - e - } - })?; + self.inode.resize(offset)?; } let len = self .inode - .write_at(offset, len, buf, self.private_data.lock()) - .map_err(|e| { - if e == SystemError::ERESTARTSYS { - SystemError::EINTR - } else { - e - } - })?; + .write_at(offset, len, buf, self.private_data.lock())?; if update_offset { self.offset diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index 288a36628..32d574943 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -11,7 +11,7 @@ use crate::{ wait_queue::WaitQueue, }, net::event_poll::{EPollEventType, EPollItem, EventPoll}, - process::{ProcessManager, ProcessState}, + process::{ProcessFlags, ProcessManager, ProcessState}, sched::SchedMode, time::PosixTimeSpec, }; @@ -232,6 +232,9 @@ impl IndexNode for LockedPipeInode { drop(inode); let r = wq_wait_event_interruptible!(self.read_wait_queue, self.readable(), {}); if r.is_err() { + ProcessManager::current_pcb() + .flags() + .insert(ProcessFlags::HAS_PENDING_SIGNAL); return Err(SystemError::ERESTARTSYS); } diff --git a/kernel/src/ipc/signal.rs b/kernel/src/ipc/signal.rs index 3bf9db2e4..8c85182d0 100644 --- a/kernel/src/ipc/signal.rs +++ b/kernel/src/ipc/signal.rs @@ -8,7 +8,9 @@ use crate::{ arch::ipc::signal::{SigCode, SigFlags, SigSet, Signal}, ipc::signal_types::SigactionType, libs::spinlock::SpinLockGuard, - process::{pid::PidType, Pid, ProcessControlBlock, ProcessFlags, ProcessManager}, + process::{ + pid::PidType, Pid, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSignalInfo, + }, }; use super::signal_types::{ @@ -25,7 +27,7 @@ impl Signal { return false; } - if !pcb.has_pending_signal() { + if !pcb.has_pending_signal_fast() { return false; } @@ -112,7 +114,7 @@ impl Signal { } if !self.prepare_sianal(pcb.clone(), force_send) { - return Err(SystemError::EINVAL); + return Ok(0); } // debug!("force send={}", force_send); let pcb_info = pcb.sig_info_irqsave(); @@ -213,13 +215,18 @@ impl Signal { } } - /// @brief 本函数用于检测指定的进程是否想要接收SIG这个信号。 + /// 本函数用于检测指定的进程是否想要接收SIG这个信号。 + /// /// 当我们对于进程组中的所有进程都运行了这个检查之后,我们将可以找到组内愿意接收信号的进程。 /// 这么做是为了防止我们把信号发送给了一个正在或已经退出的进程,或者是不响应该信号的进程。 #[inline] fn wants_signal(&self, pcb: Arc) -> bool { // 如果改进程屏蔽了这个signal,则不能接收 - if pcb.sig_info_irqsave().sig_block().contains((*self).into()) { + if pcb + .sig_info_irqsave() + .sig_blocked() + .contains((*self).into()) + { return false; } @@ -291,7 +298,7 @@ impl Signal { // 一个被阻塞了的信号肯定是要被处理的 if pcb .sig_info_irqsave() - .sig_block() + .sig_blocked() .contains(self.into_sigset()) { return true; @@ -316,6 +323,7 @@ fn signal_wake_up(pcb: Arc, _guard: SpinLockGuard, _guard: SpinLockGuard bool { + sigset.bits() & (!blocked.bits()) != 0 } -/// @brief 刷新指定进程的sighand的sigaction,将满足条件的sigaction恢复为Default -/// 除非某个信号被设置为ignore且force_default为false,否则都不会将其恢复 +impl ProcessControlBlock { + /// 重新计算线程的flag中的TIF_SIGPENDING位 + /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/signal.c?r=&mo=4806&fi=182#182 + pub fn recalc_sigpending(&self, siginfo_guard: Option<&ProcessSignalInfo>) { + if !self.recalc_sigpending_tsk(siginfo_guard) { + self.flags().remove(ProcessFlags::HAS_PENDING_SIGNAL); + } + } + + fn recalc_sigpending_tsk(&self, siginfo_guard: Option<&ProcessSignalInfo>) -> bool { + let mut _siginfo_tmp_guard = None; + let siginfo = if let Some(siginfo_guard) = siginfo_guard { + siginfo_guard + } else { + _siginfo_tmp_guard = Some(self.sig_info_irqsave()); + _siginfo_tmp_guard.as_ref().unwrap() + }; + return siginfo.do_recalc_sigpending_tsk(self); + } +} + +impl ProcessSignalInfo { + fn do_recalc_sigpending_tsk(&self, pcb: &ProcessControlBlock) -> bool { + if has_pending_signals(&self.sig_pending().signal(), self.sig_blocked()) + || has_pending_signals(&self.sig_shared_pending().signal(), self.sig_blocked()) + { + pcb.flags().insert(ProcessFlags::HAS_PENDING_SIGNAL); + return true; + } + /* + * We must never clear the flag in another thread, or in current + * when it's possible the current syscall is returning -ERESTART*. + * So we don't clear it here, and only callers who know they should do. + */ + return false; + } +} +/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/sched/signal.h?fi=restore_saved_sigmask#547 +pub fn restore_saved_sigmask() { + if ProcessManager::current_pcb() + .flags() + .test_and_clear(ProcessFlags::RESTORE_SIG_MASK) + { + let saved = *ProcessManager::current_pcb() + .sig_info_irqsave() + .saved_sigmask(); + __set_current_blocked(&saved); + } +} + +/// 刷新指定进程的sighand的sigaction,将满足条件的sigaction恢复为默认状态。 +/// 除非某个信号被设置为忽略且 `force_default` 为 `false`,否则都不会将其恢复。 +/// +/// # 参数 /// -/// @param pcb 要被刷新的pcb -/// @param force_default 是否强制将sigaction恢复成默认状态 +/// - `pcb`: 要被刷新的pcb。 +/// - `force_default`: 是否强制将sigaction恢复成默认状态。 pub fn flush_signal_handlers(pcb: Arc, force_default: bool) { compiler_fence(core::sync::atomic::Ordering::SeqCst); // debug!("hand=0x{:018x}", hand as *const sighand_struct as usize); @@ -467,7 +526,7 @@ fn __set_task_blocked(pcb: &Arc, new_set: &SigSet) { if pcb.has_pending_signal() { let mut newblocked = *new_set; let guard = pcb.sig_info_irqsave(); - newblocked.remove(*guard.sig_block()); + newblocked.remove(*guard.sig_blocked()); drop(guard); // 从主线程开始去遍历 @@ -476,7 +535,7 @@ fn __set_task_blocked(pcb: &Arc, new_set: &SigSet) { } } *pcb.sig_info_mut().sig_block_mut() = *new_set; - recalc_sigpending(); + pcb.recalc_sigpending(None); } fn __set_current_blocked(new_set: &SigSet) { @@ -485,10 +544,10 @@ fn __set_current_blocked(new_set: &SigSet) { 如果当前pcb的sig_blocked和新的相等,那么就不用改变它。 请注意,一个进程的sig_blocked字段不能被其他进程修改! */ - if pcb.sig_info_irqsave().sig_block().eq(new_set) { + if pcb.sig_info_irqsave().sig_blocked().eq(new_set) { return; } - let guard = pcb.sig_struct_irqsave(); + let guard: SpinLockGuard<'_, SignalStruct> = pcb.sig_struct_irqsave(); __set_task_blocked(&pcb, new_set); @@ -560,7 +619,7 @@ pub fn set_current_blocked(new_set: &mut SigSet) { pub fn set_sigprocmask(how: SigHow, set: SigSet) -> Result { let pcb: Arc = ProcessManager::current_pcb(); let guard = pcb.sig_info_irqsave(); - let oset = *guard.sig_block(); + let oset = *guard.sig_blocked(); let mut res_set = oset; drop(guard); diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index d8d7b1677..befeda025 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -75,9 +75,15 @@ pub struct InnerSignalStruct { impl SignalStruct { #[inline(never)] pub fn new() -> Self { - Self { + let mut r = Self { inner: Box::::default(), - } + }; + let sig_ign = Sigaction::default(); + r.inner.handlers[Signal::SIGCHLD as usize - 1] = sig_ign; + r.inner.handlers[Signal::SIGURG as usize - 1] = sig_ign; + r.inner.handlers[Signal::SIGWINCH as usize - 1] = sig_ign; + + r } } @@ -447,8 +453,6 @@ impl SigPending { None }; - // 当一个进程具有多个线程之后,在这里需要重新计算线程的flag中的TIF_SIGPENDING位 - // recalc_sigpending(); return (sig, info); } /// @brief 从sigpending中删除mask中被置位的信号。也就是说,比如mask的第1位被置为1,那么就从sigqueue中删除所有signum为2的信号的信息。 @@ -539,10 +543,12 @@ impl SigQueue { pub trait SignalArch { /// 信号处理函数 /// + /// 处理信号或重启系统调用 + /// /// ## 参数 /// /// - `frame` 中断栈帧 - unsafe fn do_signal(frame: &mut TrapFrame); + unsafe fn do_signal_or_restart(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 362af1e49..15c2cf5ba 100644 --- a/kernel/src/ipc/syscall.rs +++ b/kernel/src/ipc/syscall.rs @@ -567,4 +567,10 @@ impl Syscall { Ok(0) } + + pub fn restart_syscall() -> Result { + // todo: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/signal.c#2998 + unimplemented!("restart_syscall with restart block"); + // Err(SystemError::ENOSYS) + } } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 0461f68e1..299b5aaa0 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -612,6 +612,32 @@ bitflags! { const NEED_MIGRATE = 1 << 7; /// 随机化的虚拟地址空间,主要用于动态链接器的加载 const RANDOMIZE = 1 << 8; + /// 进程有未处理的信号(这是一个用于快速判断的标志位) + /// 相当于Linux的TIF_SIGPENDING + const HAS_PENDING_SIGNAL = 1 << 9; + /// 进程需要恢复之前保存的信号掩码 + const RESTORE_SIG_MASK = 1 << 10; + } +} + +impl ProcessFlags { + pub const fn exit_to_user_mode_work(&self) -> Self { + Self::from_bits_truncate(self.bits & (Self::HAS_PENDING_SIGNAL.bits)) + } + + /// 测试并清除标志位 + /// + /// ## 参数 + /// + /// - `rhs` : 需要测试并清除的标志位 + /// + /// ## 返回值 + /// + /// 如果标志位在清除前是置位的,则返回 `true`,否则返回 `false` + pub const fn test_and_clear(&mut self, rhs: Self) -> bool { + let r = (self.bits & rhs.bits) != 0; + self.bits &= !rhs.bits; + r } } #[derive(Debug)] @@ -673,6 +699,7 @@ pub struct ProcessControlBlock { /// 进程作为主体的凭证集 cred: SpinLock, + self_ref: Weak, } impl ProcessControlBlock { @@ -734,7 +761,7 @@ impl ProcessControlBlock { let ppcb: Weak = ProcessManager::find(ppid) .map(|p| Arc::downgrade(&p)) .unwrap_or_default(); - let pcb = Self { + let mut pcb = Self { pid, tgid: pid, thread_pid: Arc::new(RwLock::new(PidStrcut::new())), @@ -759,6 +786,7 @@ impl ProcessControlBlock { robust_list: RwLock::new(None), nsproxy: Arc::new(RwLock::new(NsProxy::new())), cred: SpinLock::new(cred), + self_ref: Weak::new(), }; pcb.sig_info.write().set_tty(tty); @@ -769,7 +797,10 @@ impl ProcessControlBlock { .lock() .init_syscall_stack(&pcb.syscall_stack.read()); - let pcb = Arc::new(pcb); + let pcb = Arc::new_cyclic(|weak| { + pcb.self_ref = weak.clone(); + pcb + }); pcb.sched_info() .sched_entity() @@ -1017,6 +1048,11 @@ impl ProcessControlBlock { return has_pending; } + /// 根据 pcb 的 flags 判断当前进程是否有未处理的信号 + pub fn has_pending_signal_fast(&self) -> bool { + self.flags.get().contains(ProcessFlags::HAS_PENDING_SIGNAL) + } + pub fn sig_struct(&self) -> SpinLockGuard { self.sig_struct.lock_irqsave() } @@ -1546,8 +1582,9 @@ pub fn process_init() { #[derive(Debug)] pub struct ProcessSignalInfo { - // 当前进程 - sig_block: SigSet, + // 当前进程被屏蔽的信号 + sig_blocked: SigSet, + saved_sigmask: SigSet, // sig_pending 中存储当前线程要处理的信号 sig_pending: SigPending, // sig_shared_pending 中存储当前线程所属进程要处理的信号 @@ -1557,8 +1594,8 @@ pub struct ProcessSignalInfo { } impl ProcessSignalInfo { - pub fn sig_block(&self) -> &SigSet { - &self.sig_block + pub fn sig_blocked(&self) -> &SigSet { + &self.sig_blocked } pub fn sig_pending(&self) -> &SigPending { @@ -1570,7 +1607,15 @@ impl ProcessSignalInfo { } pub fn sig_block_mut(&mut self) -> &mut SigSet { - &mut self.sig_block + &mut self.sig_blocked + } + + pub fn saved_sigmask(&self) -> &SigSet { + &self.saved_sigmask + } + + pub fn saved_sigmask_mut(&mut self) -> &mut SigSet { + &mut self.saved_sigmask } pub fn sig_shared_pending_mut(&mut self) -> &mut SigPending { @@ -1595,12 +1640,19 @@ impl ProcessSignalInfo { /// /// - `sig_mask` 被忽略掉的信号 /// - pub fn dequeue_signal(&mut self, sig_mask: &SigSet) -> (Signal, Option) { + pub fn dequeue_signal( + &mut self, + sig_mask: &SigSet, + pcb: &Arc, + ) -> (Signal, Option) { let res = self.sig_pending.dequeue_signal(sig_mask); + pcb.recalc_sigpending(Some(self)); if res.0 != Signal::INVALID { return res; } else { - return self.sig_shared_pending.dequeue_signal(sig_mask); + let res = self.sig_shared_pending.dequeue_signal(sig_mask); + pcb.recalc_sigpending(Some(self)); + return res; } } } @@ -1608,7 +1660,8 @@ impl ProcessSignalInfo { impl Default for ProcessSignalInfo { fn default() -> Self { Self { - sig_block: SigSet::empty(), + sig_blocked: SigSet::empty(), + saved_sigmask: SigSet::empty(), sig_pending: SigPending::default(), sig_shared_pending: SigPending::default(), tty: None, diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index e15f9baab..f9f7db29c 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -1217,6 +1217,7 @@ impl Syscall { Self::sys_perf_event_open(attr, pid, cpu, group_fd, flags) } SYS_SETRLIMIT => Ok(0), + SYS_RESTART_SYSCALL => Self::restart_syscall(), _ => panic!("Unsupported syscall ID: {}", syscall_num), }; diff --git a/user/apps/test-sigprocmask/main.c b/user/apps/test-sigprocmask/main.c index bea9fd894..870d86d47 100644 --- a/user/apps/test-sigprocmask/main.c +++ b/user/apps/test-sigprocmask/main.c @@ -62,9 +62,11 @@ int main() { perror("signal"); exit(EXIT_FAILURE); } - + printf("Signal handler for SIGINT is registered.\n"); signal_received = 0; kill(getpid(), SIGINT); + sleep(5); + TEST_ASSERT(signal_received, 1, "SIGINT was received", "SIGINT was not received"); signal_received = 0; diff --git a/user/apps/test_signal_restart/.gitignore b/user/apps/test_signal_restart/.gitignore new file mode 100644 index 000000000..802b4439e --- /dev/null +++ b/user/apps/test_signal_restart/.gitignore @@ -0,0 +1 @@ +test_signal diff --git a/user/apps/test_signal_restart/Makefile b/user/apps/test_signal_restart/Makefile new file mode 100644 index 000000000..2a9e25aac --- /dev/null +++ b/user/apps/test_signal_restart/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH), x86_64) + CROSS_COMPILE=x86_64-linux-musl- +else ifeq ($(ARCH), riscv64) + CROSS_COMPILE=riscv64-linux-musl- +endif + +CC=$(CROSS_COMPILE)gcc + +.PHONY: all +all: main.c + $(CC) -static -o test_signal_restart main.c + +.PHONY: install clean +install: all + mv test_signal_restart $(DADK_CURRENT_BUILD_DIR)/test_signal_restart + +clean: + rm test_signal_restart *.o + +fmt: diff --git a/user/apps/test_signal_restart/main.c b/user/apps/test_signal_restart/main.c new file mode 100644 index 000000000..e0c90756b --- /dev/null +++ b/user/apps/test_signal_restart/main.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 + +#define MSG "Hello from parent!\n" + +static int handled_signal = 0; +// 子进程的信号处理函数 +void child_signal_handler(int sig) { + printf("Child received signal %d\n", sig); + handled_signal = 1; +} + +// 父进程的信号处理函数 +void parent_signal_handler(int sig) { + printf("Parent received signal %d\n", sig); +} + +int main() { + int pipefd[2]; + pid_t pid; + char buffer[BUFFER_SIZE]; + + // 创建管道 + if (pipe(pipefd) == -1) { + perror("pipe"); + exit(EXIT_FAILURE); + } + + // 创建子进程 + pid = fork(); + if (pid == -1) { + perror("fork"); + exit(EXIT_FAILURE); + } + + if (pid == 0) { + // 子进程 + close(pipefd[1]); // 关闭写端 + + // 设置子进程的信号处理函数 + signal(SIGUSR1, child_signal_handler); + + printf("Child: Waiting for data...\n"); + + // 尝试从管道中读取数据 + ssize_t bytes_read = read(pipefd[0], buffer, BUFFER_SIZE - 1); + if (bytes_read == -1) { + printf("[FAILED]: Child: read error, errno=%d\n", errno); + exit(EXIT_FAILURE); + } else if (bytes_read == 0) { + printf("Child: End of file\n"); + } + + if (bytes_read != sizeof(MSG) - 1) { + printf("[FAILED]: Child: read error: got %ld bytes, expected %ld\n", + bytes_read, sizeof(MSG) - 1); + } else { + printf("[PASS]: Child: read success: got %ld bytes, expected %ld\n", + bytes_read, sizeof(MSG) - 1); + } + + buffer[bytes_read] = '\0'; + printf("Child: Received message: %s", buffer); + + close(pipefd[0]); + + if (!handled_signal) + printf("[FAILED]: Parent: child did not handle signal\n"); + else + printf("[PASS]: Parent: child handled signal\n"); + exit(EXIT_SUCCESS); + } else { + // 父进程 + close(pipefd[0]); // 关闭读端 + + // 设置父进程的信号处理函数 + signal(SIGCHLD, parent_signal_handler); + + // 发送信号给子进程,中断它的读操作 + sleep(1); // 确保子进程已经开始读取 + // printf("Parent: Sending SIGCHLD to child...\n"); + // kill(pid, SIGCHLD); + printf("Parent: Sending SIGUSR1 to child...\n"); + kill(pid, SIGUSR1); + sleep(1); // 确保子进程已经处理了信号 + + write(pipefd[1], MSG, strlen(MSG)); + + printf("Parent: Sent message: %s", MSG); + + // 等待子进程结束 + waitpid(pid, NULL, 0); + + printf("Parent: Child process finished.\n"); + + close(pipefd[1]); + exit(EXIT_SUCCESS); + } +} \ No newline at end of file diff --git a/user/dadk/config/test_signal_restart-0.1.0.toml b/user/dadk/config/test_signal_restart-0.1.0.toml new file mode 100644 index 000000000..0b3896255 --- /dev/null +++ b/user/dadk/config/test_signal_restart-0.1.0.toml @@ -0,0 +1,41 @@ +# 用户程序名称 +name = "test_signal_restart" +# 版本号 +version = "0.1.0" +# 用户程序描述信息 +description = "一个用来测试signal能够正常运行的app" +# (可选)默认: false 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果 +build-once = false +# (可选) 默认: false 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装 +install-once = false +# 目标架构 +# 可选值:"x86_64", "aarch64", "riscv64" +target-arch = ["x86_64"] +# 任务源 +[task-source] +# 构建类型 +# 可选值:"build-from_source", "install-from-prebuilt" +type = "build-from-source" +# 构建来源 +# "build_from_source" 可选值:"git", "local", "archive" +# "install_from_prebuilt" 可选值:"local", "archive" +source = "local" +# 路径或URL +source-path = "user/apps/test_signal_restart" +# 构建相关信息 +[build] +# (可选)构建命令 +build-command = "make install" +# 安装相关信息 +[install] +# (可选)安装到DragonOS的路径 +in-dragonos-path = "/bin" +# 清除相关信息 +[clean] +# (可选)清除命令 +clean-command = "make clean" +# (可选)依赖项 +# 注意:如果没有依赖项,忽略此项,不允许只留一个[[depends]] +# 由于原文件中依赖项为空,此处省略[[depends]]部分 +# (可选)环境变量 +# 由于原文件中环境变量为空,此处省略[[envs]]部分