feature: x86_64 signal entry

This commit is contained in:
2022-03-22 17:07:27 +02:00
parent cf104ecf28
commit f372ed65c7
6 changed files with 126 additions and 31 deletions
+1 -2
View File
@@ -33,8 +33,7 @@ MACH=none
QEMU_OPTS+=-cdrom $(O)/image.iso \
-M q35 \
-m 512 \
-chardev stdio,id=chr0,mux=on \
-serial chardev:chr0 \
-serial mon:stdio \
-net none
else
ifeq ($(MACH),qemu)
+12 -1
View File
@@ -76,7 +76,18 @@ impl Context {
///
/// Unsafe: may clobber an already active context
pub unsafe fn setup_signal_entry(&mut self, entry: usize, arg: usize, cr3: usize, ustack: usize) {
todo!()
let cr3 = cr3 & 0xFFFFFFFF;
let mut stack = Stack::from_base_size(self.stack_base, self.stack_page_count);
let stack_top = stack.sp;
stack.push(entry);
stack.push(arg);
stack.push(0);
stack.push(ustack);
stack.setup_common(__x86_64_ctx_enter_user as usize, cr3, stack_top);
self.k_sp = stack.sp;
}
/// Clones a process context from given `frame`
+1 -1
View File
@@ -130,7 +130,7 @@ pub trait TtyDevice<const N: usize>: SerialDevice {
let proc = Process::get(pgid);
if let Some(proc) = proc {
// TODO
// proc.set_signal(Signal::Interrupt);
proc.set_signal(Signal::Interrupt);
}
}
return;
+86 -1
View File
@@ -105,6 +105,61 @@ impl Process {
f(self.inner.lock().space.as_mut().unwrap())
}
/// Handles all pending signals (when returning from aborted syscall)
pub fn handle_pending_signals(&self) {
let mut lock = self.inner.lock();
let table = Self::space_phys(&mut lock);
let main_thread = Thread::get(lock.threads[0]).unwrap();
drop(lock);
loop {
let state = self.signal_state.load(Ordering::Acquire);
if let Some(signal) = Self::find1(state).map(|e| Signal::try_from(e as u32).unwrap()) {
self.signal_state.fetch_and(!(1 << (signal as u32)), Ordering::Release);
main_thread.clone().enter_signal(signal, table);
} else {
break;
}
}
}
pub fn set_signal(&self, signal: Signal) {
let mut lock = self.inner.lock();
let table = Self::space_phys(&mut lock);
let main_thread = Thread::get(lock.threads[0]).unwrap();
drop(lock);
// TODO check that `signal` is not a fault signal
// it is illegal to call this function with
// fault signals
match main_thread.state() {
ThreadState::Running => {
main_thread.enter_signal(signal, table);
}
ThreadState::Waiting => {
self.signal_state.fetch_or(1 << (signal as u32), Ordering::Release);
main_thread.interrupt_wait(true);
}
ThreadState::Ready => {
main_thread.clone().setup_signal(signal, table);
main_thread.interrupt_wait(false);
}
ThreadState::Finished => {
// TODO report error back
todo!()
}
}
}
// /// Immediately delivers a signal to requested thread
// pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) {
// let mut lock = self.inner.lock();
// let table = Self::space_phys(&lock);
// drop(lock);
// thread.enter_signal(signal, table);
// }
/// Creates a new kernel process
pub fn new_kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result<ProcessRef, Errno> {
let id = new_kernel_pid();
@@ -243,7 +298,37 @@ impl Process {
/// Terminates a thread of the process. If the thread is the only
/// one remaining, process itself is exited (see [Process::exit])
pub fn exit_thread(thread: ThreadRef, status: ExitCode) {
todo!()
let switch = {
let switch = thread.state() == ThreadState::Running;
let process = thread.owner().unwrap();
let mut lock = process.inner.lock();
let tid = thread.id();
if lock.threads.len() == 1 {
// TODO call Process::exit instead?
drop(lock);
process.exit(status);
return;
}
lock.threads.retain(|&e| e != tid);
thread.terminate(status);
SCHED.dequeue(tid);
debugln!("Thread {:?} terminated", tid);
switch
};
if switch {
// TODO retain thread ID in process "finished" list and
// drop it when process finishes
SCHED.switch(true);
panic!("This code should not run");
} else {
// Can drop this thread: it's not running
todo!();
}
}
fn collect(&self) -> Option<ExitCode> {
+21 -21
View File
@@ -325,27 +325,27 @@ fn _syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
}
res.map(|_| 0)
}
// SystemCall::SetSignalEntry => {
// Thread::current().set_signal_entry(args[0], args[1]);
// Ok(0)
// }
// SystemCall::SignalReturn => {
// Thread::current().return_from_signal();
// unreachable!();
// }
// SystemCall::SendSignal => {
// let target = SignalDestination::from(args[0] as isize);
// let signal = Signal::try_from(args[1] as u32)?;
SystemCall::SetSignalEntry => {
Thread::current().set_signal_entry(args[0], args[1]);
Ok(0)
}
SystemCall::SignalReturn => {
Thread::current().return_from_signal();
unreachable!();
}
SystemCall::SendSignal => {
let target = SignalDestination::from(args[0] as isize);
let signal = Signal::try_from(args[1] as u32)?;
// match target {
// SignalDestination::This => Process::current().set_signal(signal),
// SignalDestination::Process(pid) => Process::get(pid)
// .ok_or(Errno::DoesNotExist)?
// .set_signal(signal),
// _ => todo!(),
// };
// Ok(0)
// }
match target {
SignalDestination::This => Process::current().set_signal(signal),
SignalDestination::Process(pid) => Process::get(pid)
.ok_or(Errno::DoesNotExist)?
.set_signal(signal),
_ => todo!(),
};
Ok(0)
}
SystemCall::Yield => {
proc::switch();
Ok(0)
@@ -457,7 +457,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
let process = thread.owner().unwrap();
let result = _syscall(num, args);
if !thread.is_handling_signal() {
// process.handle_pending_signals();
process.handle_pending_signals();
}
result
}
+5 -5
View File
@@ -66,11 +66,11 @@ unsafe fn init_common(signal_stack_pointer: *mut u8) {
// thread::current() should be valid at this point
// sys_ex_signal(
// signal::signal_handler as usize,
// signal_stack_pointer as usize,
// )
// .unwrap();
sys_ex_signal(
signal::signal_handler as usize,
signal_stack_pointer as usize,
)
.unwrap();
}
pub(crate) unsafe fn init_main() {