feature: x86_64 signal entry
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user