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