Browse Source

fix(wait): generate corrent wstatus to handle stop signals

greatbridf 3 weeks ago
parent
commit
e021390c95
4 changed files with 53 additions and 25 deletions
  1. 3 3
      src/kernel/syscall/procops.rs
  2. 1 1
      src/kernel/task.rs
  3. 5 3
      src/kernel/task/signal.rs
  4. 44 18
      src/kernel/task/thread.rs

+ 3 - 3
src/kernel/syscall/procops.rs

@@ -10,7 +10,7 @@ use crate::io::Buffer;
 use crate::kernel::constants::{PR_GET_NAME, PR_SET_NAME, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK};
 use crate::kernel::mem::VAddr;
 use crate::kernel::task::{
-    ProcessList, Scheduler, Signal, SignalAction, Thread, UserDescriptor, WaitObject,
+    ProcessList, Scheduler, Signal, SignalAction, Thread, UserDescriptor, WaitObject, WaitType,
 };
 use crate::kernel::user::dataflow::UserString;
 use crate::kernel::user::{UserPointer, UserPointerMut};
@@ -153,7 +153,7 @@ fn sys_execve(int_stack: &mut interrupt_stack, _mmxregs: &mut mmx_registers) ->
 // TODO: Find a better way.
 #[allow(unreachable_code)]
 fn do_exit(status: u32) -> KResult<()> {
-    ProcessList::get().do_kill_process(&Thread::current().process, (status & 0xff) << 8);
+    ProcessList::get().do_kill_process(&Thread::current().process, WaitType::Exited(status));
     Scheduler::schedule_noreturn();
     panic!("schedule_noreturn returned!");
 }
@@ -185,7 +185,7 @@ fn do_waitpid(waitpid: u32, arg1: *mut u32, options: u32) -> KResult<u32> {
         None => Ok(0),
         Some(WaitObject { pid, code }) => {
             if !arg1.is_null() {
-                UserPointerMut::new(arg1)?.write(code)?;
+                UserPointerMut::new(arg1)?.write(code.to_wstatus())?;
             }
             Ok(pid)
         }

+ 1 - 1
src/kernel/task.rs

@@ -9,5 +9,5 @@ pub use scheduler::Scheduler;
 pub use signal::{Signal, SignalAction};
 pub use thread::{
     init_multitasking, Process, ProcessGroup, ProcessList, Session, Thread, ThreadState,
-    UserDescriptor, UserDescriptorFlags, WaitObject,
+    UserDescriptor, UserDescriptorFlags, WaitObject, WaitType,
 };

+ 5 - 3
src/kernel/task/signal.rs

@@ -107,7 +107,7 @@ impl Signal {
         }
     }
 
-    fn is_coredump(&self) -> bool {
+    pub fn is_coredump(&self) -> bool {
         match self.0 {
             SIGQUIT | SIGILL | SIGABRT | SIGFPE | SIGSEGV | SIGBUS | SIGTRAP | SIGSYS | SIGXCPU
             | SIGXFSZ => true,
@@ -355,13 +355,15 @@ impl SignalList {
 
             // Default actions.
             match signal {
-                Signal::SIGSTOP => Thread::current().do_stop(),
+                Signal::SIGSTOP => Thread::current().do_stop(Signal::SIGSTOP),
                 Signal::SIGCONT => Thread::current().do_continue(),
                 Signal::SIGKILL => ProcessList::kill_current(signal),
                 // Ignored
                 Signal::SIGCHLD | Signal::SIGURG | Signal::SIGWINCH => continue,
                 // "Soft" stops.
-                Signal::SIGTSTP | Signal::SIGTTIN | Signal::SIGTTOU => Thread::current().do_stop(),
+                Signal::SIGTSTP | Signal::SIGTTIN | Signal::SIGTTOU => {
+                    Thread::current().do_stop(signal)
+                }
                 // TODO!!!!!!: Check exit status format.
                 s if s.is_coredump() => ProcessList::kill_current(signal),
                 signal => ProcessList::kill_current(signal),

+ 44 - 18
src/kernel/task/thread.rs

@@ -43,19 +43,43 @@ pub enum ThreadState {
     USleep,
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum WaitType {
+    Exited(u32),
+    Signaled(Signal),
+    Stopped(Signal),
+    Continued,
+}
+
 #[derive(Debug, Clone, Copy)]
 pub struct WaitObject {
     pub pid: u32,
-    pub code: u32,
+    pub code: WaitType,
+}
+
+impl WaitType {
+    pub fn to_wstatus(self) -> u32 {
+        match self {
+            WaitType::Exited(status) => (status & 0xff) << 8,
+            WaitType::Signaled(signal) if signal.is_coredump() => signal.to_signum() | 0x80,
+            WaitType::Signaled(signal) => signal.to_signum(),
+            WaitType::Stopped(signal) => 0x7f | (signal.to_signum() << 8),
+            WaitType::Continued => 0xffff,
+        }
+    }
 }
 
 impl WaitObject {
-    pub fn is_stopped(&self) -> bool {
-        self.code & 0x7f == 0x7f
+    pub fn stopped(&self) -> Option<Signal> {
+        if let WaitType::Stopped(signal) = self.code {
+            Some(signal)
+        } else {
+            None
+        }
     }
 
     pub fn is_continue(&self) -> bool {
-        self.code == 0xffff
+        matches!(self.code, WaitType::Continued)
     }
 }
 
@@ -405,11 +429,7 @@ impl ProcessList {
     }
 
     pub fn kill_current(signal: Signal) -> ! {
-        ProcessList::get().do_kill_process(
-            &Thread::current().process,
-            ((signal.to_signum() + 128) << 8) | (signal.to_signum() & 0xff),
-        );
-
+        ProcessList::get().do_kill_process(&Thread::current().process, WaitType::Signaled(signal));
         Scheduler::schedule_noreturn()
     }
 
@@ -437,7 +457,7 @@ impl ProcessList {
     }
 
     /// Make the process a zombie and notify the parent.
-    pub fn do_kill_process(&self, process: &Arc<Process>, status: u32) {
+    pub fn do_kill_process(&self, process: &Arc<Process>, status: WaitType) {
         if &self.init == process {
             panic!("init exited");
         }
@@ -485,7 +505,7 @@ impl ProcessList {
 
             let mut done_some_work = false;
             waits.retain(|item| {
-                if !item.is_stopped() && !item.is_continue() {
+                if item.stopped().is_none() && !item.is_continue() {
                     init_waits.push_back(*item);
                     done_some_work = true;
                 }
@@ -623,7 +643,7 @@ impl Process {
                 .iter()
                 .enumerate()
                 .filter(|(_, item)| {
-                    if item.is_stopped() {
+                    if item.stopped().is_some() {
                         trace_stop
                     } else if item.is_continue() {
                         trace_continue
@@ -649,7 +669,7 @@ impl Process {
             }
         };
 
-        if wait_object.is_stopped() || wait_object.is_continue() {
+        if wait_object.stopped().is_some() || wait_object.is_continue() {
             Ok(Some(wait_object))
         } else {
             ProcessList::get().remove(wait_object.pid);
@@ -847,9 +867,9 @@ impl Thread {
         Scheduler::current()
     }
 
-    pub fn do_stop(self: &Arc<Self>) {
+    pub fn do_stop(self: &Arc<Self>, signal: Signal) {
         if let Some(parent) = self.process.parent() {
-            parent.wait_list.notify_stop(self.process.pid);
+            parent.wait_list.notify_stop(self.process.pid, signal);
         }
 
         preempt::disable();
@@ -979,13 +999,19 @@ impl WaitList {
 
     pub fn notify_continue(&self, pid: u32) {
         let mut wait_procs = self.wait_procs.lock();
-        wait_procs.push_back(WaitObject { pid, code: 0xffff });
+        wait_procs.push_back(WaitObject {
+            pid,
+            code: WaitType::Continued,
+        });
         self.cv_wait_procs.notify_all();
     }
 
-    pub fn notify_stop(&self, pid: u32) {
+    pub fn notify_stop(&self, pid: u32, signal: Signal) {
         let mut wait_procs = self.wait_procs.lock();
-        wait_procs.push_back(WaitObject { pid, code: 0x7f });
+        wait_procs.push_back(WaitObject {
+            pid,
+            code: WaitType::Stopped(signal),
+        });
         self.cv_wait_procs.notify_all();
     }
 }