Fix delivery of signals when a signal uses the default handler, make context status update on every switch
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user