Parcourir la source

fix: 临时修复进程execve没恢复默认的sighandler的问题 (#1232)

* feat: 添加测试fork/wait功能的用户程序

1. 在kernel错误日志中添加当前进程ID信息
2. 新增test-fork-wait用户程序,包含Makefile、main.c和配置文件
3. 程序用于测试fork和wait系统调用功能

Signed-off-by: longjin <longjin@DragonOS.org>

* fix: 临时修复进程execve没恢复默认的sighandle的问题

Signed-off-by: longjin <longjin@DragonOS.org>

---------

Signed-off-by: longjin <longjin@DragonOS.org>
LoGin il y a 1 semaine
Parent
commit
9156c83658

+ 3 - 1
kernel/src/arch/x86_64/mm/fault.rs

@@ -300,8 +300,10 @@ impl X86_64MMArch {
                         });
                 } else {
                     log::error!(
-                        "No mapped vma, error_code: {:?}, address: {:#x}, flags: {:?}",
+                        "pid: {} No mapped vma, error_code: {:?},rip:{:#x}, address: {:#x}, flags: {:?}",
+                        ProcessManager::current_pid().data(),
                         error_code,
+                        regs.rip,
                         address.data(),
                         flags
                     );

+ 7 - 5
kernel/src/ipc/signal.rs

@@ -461,6 +461,7 @@ pub(super) fn do_sigaction(
     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];
@@ -471,7 +472,7 @@ pub(super) fn do_sigaction(
     // }
 
     // 保存原有的 sigaction
-    let old_act: Option<&mut Sigaction> = {
+    let mut old_act: Option<&mut Sigaction> = {
         if let Some(oa) = old_act {
             *(oa) = *action;
             Some(oa)
@@ -480,7 +481,7 @@ pub(super) fn do_sigaction(
         }
     };
     // 清除所有的脏的sa_flags位(也就是清除那些未使用的)
-    let act = {
+    let mut act = {
         if let Some(ac) = act {
             *ac.flags_mut() &= SigFlags::SA_ALL;
             Some(ac)
@@ -489,17 +490,17 @@ pub(super) fn do_sigaction(
         }
     };
 
-    if let Some(act) = old_act {
+    if let Some(act) = &mut old_act {
         *act.flags_mut() &= SigFlags::SA_ALL;
     }
 
-    if let Some(ac) = act {
+    if let Some(ac) = &mut act {
         // 将act.sa_mask的SIGKILL SIGSTOP的屏蔽清除
         ac.mask_mut()
             .remove(<Signal as Into<SigSet>>::into(Signal::SIGKILL) | Signal::SIGSTOP.into());
 
         // 将新的sigaction拷贝到进程的action中
-        *action = *ac;
+        *action = **ac;
         /*
         * 根据POSIX 3.3.1.3规定:
         * 1.不管一个信号是否被阻塞,只要将其设置SIG_IGN,如果当前已经存在了正在pending的信号,那么就把这个信号忽略。
@@ -514,6 +515,7 @@ pub(super) fn do_sigaction(
             // todo: 当有了多个线程后,在这里进行操作,把每个线程的sigqueue都进行刷新
         }
     }
+
     return Ok(());
 }
 

+ 16 - 10
kernel/src/ipc/signal_types.rs

@@ -57,6 +57,20 @@ pub const SIG_KERNEL_IGNORE_MASK: SigSet = Signal::into_sigset(Signal::SIGCONT)
     .union(Signal::into_sigset(Signal::SIGIO_OR_POLL))
     .union(Signal::into_sigset(Signal::SIGSYS));
 
+pub fn default_sighandlers() -> Vec<Sigaction> {
+    let mut r = vec![Sigaction::default(); MAX_SIG_NUM];
+    let mut sig_ign = Sigaction::default();
+    // 收到忽略的信号,重启系统调用
+    // todo: 看看linux哪些
+    sig_ign.flags_mut().insert(SigFlags::SA_RESTART);
+
+    r[Signal::SIGCHLD as usize - 1] = sig_ign;
+    r[Signal::SIGURG as usize - 1] = sig_ign;
+    r[Signal::SIGWINCH as usize - 1] = sig_ign;
+
+    r
+}
+
 /// SignalStruct 在 pcb 中加锁
 #[derive(Debug)]
 pub struct SignalStruct {
@@ -75,17 +89,9 @@ pub struct InnerSignalStruct {
 impl SignalStruct {
     #[inline(never)]
     pub fn new() -> Self {
-        let mut r = Self {
+        let r = Self {
             inner: InnerSignalStruct::default(),
         };
-        let mut sig_ign = Sigaction::default();
-        // 收到忽略的信号,重启系统调用
-        // todo: 看看linux哪些
-        sig_ign.flags_mut().insert(SigFlags::SA_RESTART);
-
-        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
     }
@@ -115,7 +121,7 @@ impl Default for InnerSignalStruct {
     fn default() -> Self {
         Self {
             cnt: Default::default(),
-            handlers: vec![Sigaction::default(); MAX_SIG_NUM],
+            handlers: default_sighandlers(),
         }
     }
 }

+ 4 - 0
kernel/src/libs/elf.rs

@@ -804,6 +804,10 @@ impl BinaryLoader for ElfLoader {
         }
         Self::parse_gnu_property()?;
 
+        // todo: 设置exec信息的功能 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#1002
+        crate::process::execve::begin_new_exec(param)
+            .map_err(|e| ExecError::Other(format!("Failed to begin new exec: {:?}", e)))?;
+
         let mut elf_brk = VirtAddr::new(0);
         let mut elf_bss = VirtAddr::new(0);
         let mut start_code: Option<VirtAddr> = None;

+ 18 - 0
kernel/src/process/execve.rs

@@ -1,5 +1,6 @@
 use crate::arch::CurrentIrqArch;
 use crate::exception::InterruptArch;
+use crate::ipc::signal_types::SignalStruct;
 use crate::process::exec::{load_binary_file, ExecParam, ExecParamFlags};
 use crate::process::ProcessManager;
 use crate::syscall::Syscall;
@@ -8,6 +9,7 @@ use crate::{libs::rand::rand_bytes, mm::ucontext::AddressSpace};
 use crate::arch::interrupt::TrapFrame;
 use alloc::{ffi::CString, string::String, sync::Arc, vec::Vec};
 use system_error::SystemError;
+
 pub fn do_execve(
     path: String,
     argv: Vec<CString>,
@@ -111,3 +113,19 @@ fn do_execve_switch_user_vm(new_vm: Arc<AddressSpace>) -> Option<Arc<AddressSpac
 
     old_address_space
 }
+
+/// todo: 该函数未正确实现
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/exec.c?fi=begin_new_exec#1244
+pub fn begin_new_exec(_param: &mut ExecParam) -> Result<(), SystemError> {
+    de_thread()?;
+
+    Ok(())
+}
+
+/// todo: 该函数未正确实现
+/// https://code.dragonos.org.cn/xref/linux-6.1.9/fs/exec.c?fi=begin_new_exec#1042
+fn de_thread() -> Result<(), SystemError> {
+    *ProcessManager::current_pcb().sig_struct_irqsave() = SignalStruct::default();
+
+    Ok(())
+}

+ 2 - 0
kernel/src/process/fork.rs

@@ -288,6 +288,8 @@ impl ProcessManager {
                 .sig_struct_irqsave()
                 .cnt
                 .fetch_add(1, Ordering::SeqCst);
+
+            // todo: sighand结构体应该是个arc,这里要做arc赋值。下面要做创建新的arc。(现在的实现有问题)
             return Ok(());
         }
 

+ 20 - 6
kernel/src/syscall/mod.rs

@@ -94,13 +94,27 @@ impl Syscall {
         // 首先尝试从syscall_table获取处理函数
         if let Some(handler) = syscall_table().get(syscall_num) {
             // 使用以下代码可以打印系统调用号和参数,方便调试
-            // log::debug!(
-            //     "Syscall {} called with args {}",
-            //     handler.name,
-            //     handler.args_string(args)
-            // );
 
-            return handler.inner_handle.handle(args, frame);
+            // let show = false;
+            // if show {
+            //     log::debug!(
+            //         "pid: {} Syscall {} called with args {}",
+            //         ProcessManager::current_pid().data(),
+            //         handler.name,
+            //         handler.args_string(args)
+            //     );
+            // }
+
+            let r = handler.inner_handle.handle(args, frame);
+            // if show {
+            //     log::debug!(
+            //         "pid: {} Syscall {} returned {:?}",
+            //         ProcessManager::current_pid().data(),
+            //         handler.name,
+            //         r
+            //     );
+            // }
+            return r;
         }
 
         // 如果找不到,fallback到原有逻辑

+ 1 - 0
user/apps/test-fork-wait/.gitignore

@@ -0,0 +1 @@
+test-fork-wait

+ 20 - 0
user/apps/test-fork-wait/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
+BINFILE=test-fork-wait
+
+all: main.c
+	$(CC) -static -o $(BINFILE) main.c
+
+.PHONY: install clean
+install: all
+	mv $(BINFILE) $(DADK_CURRENT_BUILD_DIR)/
+
+clean:
+	rm $(BINFILE) *.o
+
+fmt:

+ 44 - 0
user/apps/test-fork-wait/main.c

@@ -0,0 +1,44 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/eventfd.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+
+// 子线程或子进程模拟事件发生
+void trigger_event(unsigned int delay_sec) {
+  printf("[child] triggere event after %u seconds...\n", delay_sec);
+  sleep(delay_sec);
+ 
+  printf("[child] Event triggered.\n");
+}
+
+int main() {
+ 
+  pid_t pid = fork();
+  if (pid < 0) {
+    perror("fork");
+    exit(1);
+  }
+
+  if (pid == 0) {
+    // 子进程:触发事件
+    trigger_event(3);
+    exit(0);
+  }
+  // 父进程:使用 select 等待事件发生
+  printf("[parent] Waiting for child %d exit...\n", pid);
+
+  // wait for child process to finish
+  int status;
+  waitpid(pid, &status, 0);
+  printf("[parent] Child exited with status: %d\n", WEXITSTATUS(status));
+
+  return 0;
+}

+ 47 - 0
user/dadk/config/test-fork-wait-0.1.0.toml

@@ -0,0 +1,47 @@
+# 用户程序名称
+name = "test-fork-wait"
+
+# 版本号
+version = "0.1.0"
+
+# 用户程序描述信息
+description = "测试fork等待子进程退出的程序"
+
+# 是否只构建一次
+build-once = false
+
+# 是否只安装一次
+install-once = false
+
+# 目标架构
+target-arch = ["x86_64"]
+
+# 任务源
+[task-source]
+# 构建类型
+type = "build-from-source"
+# 构建来源
+source = "local"
+# 路径或URL
+source-path = "user/apps/test-fork-wait"
+
+# 构建相关信息
+[build]
+# 构建命令
+build-command = "make install -j $(nproc)"
+
+# 安装相关信息
+[install]
+# 安装到DragonOS的路径
+in-dragonos-path = "/bin"
+
+# 清除相关信息
+[clean]
+# 清除命令
+clean-command = "make clean"
+
+# 依赖项
+# 注意:因为没有依赖项,所以这里不包含[[depends]]部分
+
+# 环境变量
+# 注意:因为没有环境变量,所以这里不包含[[envs]]部分