From c020ce7d8ac76913b93850b162fe9783514d7c63 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Sat, 24 Feb 2018 17:47:46 -0700
Subject: [PATCH] Fix delivery of signals when a signal uses the default
 handler, make context status update on every switch

---
 src/context/signal.rs |   4 +-
 src/context/switch.rs | 104 +++++++++++++++++++++++-------------------
 2 files changed, 60 insertions(+), 48 deletions(-)

diff --git a/src/context/signal.rs b/src/context/signal.rs
index ad70ca6c..2f917252 100644
--- a/src/context/signal.rs
+++ b/src/context/signal.rs
@@ -50,7 +50,7 @@ pub extern "C" fn signal_handler(sig: usize) {
                 }
             },
             SIGSTOP | SIGTSTP | SIGTTIN | SIGTTOU => {
-                // println!("Stop {}", sig);
+                println!("Stop {}", sig);
 
                 {
                     let contexts = contexts();
@@ -100,4 +100,6 @@ pub extern "C" fn signal_handler(sig: usize) {
             usermode(handler, sp, sig);
         }
     }
+
+    syscall::sigreturn().unwrap();
 }
diff --git a/src/context/switch.rs b/src/context/switch.rs
index 4c0e9110..42de9c71 100644
--- a/src/context/switch.rs
+++ b/src/context/switch.rs
@@ -7,6 +7,57 @@ use interrupt;
 use interrupt::irq::PIT_TICKS;
 use time;
 
+unsafe fn update(context: &mut Context, cpu_id: usize) {
+    // Take ownership if not already owned
+    if context.cpu_id == None {
+        context.cpu_id = Some(cpu_id);
+        // println!("{}: take {} {}", cpu_id, context.id, ::core::str::from_utf8_unchecked(&context.name.lock()));
+    }
+
+    // Restore from signal, must only be done from another context to avoid overwriting the stack!
+    if context.ksig_restore && ! context.running {
+        let ksig = context.ksig.take().expect("context::switch: ksig not set with ksig_restore");
+        context.arch = ksig.0;
+
+        if let Some(ref mut kfx) = context.kfx {
+            kfx.clone_from_slice(&ksig.1.expect("context::switch: ksig kfx not set with ksig_restore"));
+        } else {
+            panic!("context::switch: kfx not set with ksig_restore");
+        }
+
+        if let Some(ref mut kstack) = context.kstack {
+            kstack.clone_from_slice(&ksig.2.expect("context::switch: ksig kstack not set with ksig_restore"));
+        } else {
+            panic!("context::switch: kstack not set with ksig_restore");
+        }
+
+        context.ksig_restore = false;
+
+        context.unblock();
+    }
+
+    // Unblock when there are pending signals
+    if context.status == Status::Blocked && !context.pending.is_empty() {
+        context.unblock();
+    }
+
+    // Wake from sleep
+    if context.status == Status::Blocked && context.wake.is_some() {
+        let wake = context.wake.expect("context::switch: wake not set");
+
+        let current = time::monotonic();
+        if current.0 > wake.0 || (current.0 == wake.0 && current.1 >= wake.1) {
+            context.wake = None;
+            context.unblock();
+        }
+    }
+}
+
+unsafe fn runnable(context: &Context, cpu_id: usize) -> bool {
+    // Switch to context if it needs to run, is not currently running, and is owned by the current CPU
+    !context.running && context.status == Status::Runnable && context.cpu_id == Some(cpu_id)
+}
+
 /// Switch to the next context
 ///
 /// # Safety
@@ -38,56 +89,15 @@ pub unsafe fn switch() -> bool {
             from_ptr = context.deref_mut() as *mut Context;
         }
 
-        let check_context = |context: &mut Context| -> bool {
-            // Take ownership if not already owned
-            if context.cpu_id == None {
-                context.cpu_id = Some(cpu_id);
-                // println!("{}: take {} {}", cpu_id, context.id, ::core::str::from_utf8_unchecked(&context.name.lock()));
-            }
-
-            // Restore from signal
-            if context.ksig_restore {
-                let ksig = context.ksig.take().expect("context::switch: ksig not set with ksig_restore");
-                context.arch = ksig.0;
-                if let Some(ref mut kfx) = context.kfx {
-                    kfx.clone_from_slice(&ksig.1.expect("context::switch: ksig kfx not set with ksig_restore"));
-                } else {
-                    panic!("context::switch: kfx not set with ksig_restore");
-                }
-                if let Some(ref mut kstack) = context.kstack {
-                    kstack.clone_from_slice(&ksig.2.expect("context::switch: ksig kstack not set with ksig_restore"));
-                } else {
-                    panic!("context::switch: kstack not set with ksig_restore");
-                }
-                context.ksig_restore = false;
-
-                context.unblock();
-            }
-
-            // Unblock when there are pending signals
-            if context.status == Status::Blocked && !context.pending.is_empty() {
-                context.unblock();
-            }
-
-            // Wake from sleep
-            if context.status == Status::Blocked && context.wake.is_some() {
-                let wake = context.wake.expect("context::switch: wake not set");
-
-                let current = time::monotonic();
-                if current.0 > wake.0 || (current.0 == wake.0 && current.1 >= wake.1) {
-                    context.wake = None;
-                    context.unblock();
-                }
-            }
-
-            // Switch to context if it needs to run, is not currently running, and is owned by the current CPU
-            !context.running && context.status == Status::Runnable && context.cpu_id == Some(cpu_id)
-        };
+        for (pid, context_lock) in contexts.iter() {
+            let mut context = context_lock.write();
+            update(&mut context, cpu_id);
+        }
 
         for (pid, context_lock) in contexts.iter() {
             if *pid > (*from_ptr).id {
                 let mut context = context_lock.write();
-                if check_context(&mut context) {
+                if runnable(&mut context, cpu_id) {
                     to_ptr = context.deref_mut() as *mut Context;
                     if (&mut *to_ptr).ksig.is_none() {
                         to_sig = context.pending.pop_front();
@@ -101,7 +111,7 @@ pub unsafe fn switch() -> bool {
             for (pid, context_lock) in contexts.iter() {
                 if *pid < (*from_ptr).id {
                     let mut context = context_lock.write();
-                    if check_context(&mut context) {
+                    if runnable(&mut context, cpu_id) {
                         to_ptr = context.deref_mut() as *mut Context;
                         if (&mut *to_ptr).ksig.is_none() {
                             to_sig = context.pending.pop_front();
-- 
GitLab