From f372ed65c73bb307135c960298102955549b5da4 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 22 Mar 2022 17:07:27 +0200 Subject: [PATCH] feature: x86_64 signal entry --- Makefile | 3 +- kernel/src/arch/x86_64/context.rs | 13 ++++- kernel/src/dev/tty.rs | 2 +- kernel/src/proc/process.rs | 87 ++++++++++++++++++++++++++++++- kernel/src/syscall/mod.rs | 42 +++++++-------- libusr/src/thread.rs | 10 ++-- 6 files changed, 126 insertions(+), 31 deletions(-) diff --git a/Makefile b/Makefile index 48f730d..00e88e7 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/kernel/src/arch/x86_64/context.rs b/kernel/src/arch/x86_64/context.rs index 5c63798..2a5e349 100644 --- a/kernel/src/arch/x86_64/context.rs +++ b/kernel/src/arch/x86_64/context.rs @@ -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` diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index ccb3f9f..2a06751 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -130,7 +130,7 @@ pub trait TtyDevice: SerialDevice { let proc = Process::get(pgid); if let Some(proc) = proc { // TODO - // proc.set_signal(Signal::Interrupt); + proc.set_signal(Signal::Interrupt); } } return; diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 32e9025..b5fa27d 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -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 { 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 { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 27bc679..63f8ba8 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -325,27 +325,27 @@ fn _syscall(num: SystemCall, args: &[usize]) -> Result { } 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 { let process = thread.owner().unwrap(); let result = _syscall(num, args); if !thread.is_handling_signal() { - // process.handle_pending_signals(); + process.handle_pending_signals(); } result } diff --git a/libusr/src/thread.rs b/libusr/src/thread.rs index 000090e..8289615 100644 --- a/libusr/src/thread.rs +++ b/libusr/src/thread.rs @@ -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() {