Add suuport for sleeping processes and a syscall to sleep waiting for IPC

This commit is contained in:
pjht 2024-06-08 06:54:53 -05:00
parent 8bbc165e58
commit 1376aa5f44
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
2 changed files with 45 additions and 8 deletions

View File

@ -1,5 +1,5 @@
use crate::{
bootinfo::BOOTINFO, dbg, print, println, virtual_memory::{ASpaceMutex, AddressSpace, ACTIVE_SPACE, KERNEL_SPACE}, TASKING
bootinfo::BOOTINFO, dbg, print, println, tasking::SleepReason, virtual_memory::{ASpaceMutex, AddressSpace, ACTIVE_SPACE, KERNEL_SPACE}, TASKING
};
use alloc::{boxed::Box, vec::Vec};
use core::{arch::asm, ptr::{addr_of, slice_from_raw_parts_mut}, slice, str};
@ -312,16 +312,20 @@ extern "C" fn syscall_handler() {
}
}
11 => {
let pid = regs.rcx as usize;
if let Some(buffer) = get_buffer(regs.rdx) {
assert!(regs.rsi as usize <= buffer.len());
let mut tasking = TASKING.lock();
if let Some(_queue) = tasking.message_queue_mut(regs.rcx as usize) {
if let Some(_queue) = tasking.message_queue_mut(pid) {
let len = regs.rsi as usize;
let buffer = Box::into_raw(buffer);
let new_buffer_key =
tasking.proc_data_buffers_mut(regs.rcx as usize).insert(buffer);
let queue = tasking.message_queue_mut(regs.rcx as usize).unwrap();
tasking.proc_data_buffers_mut(pid).insert(buffer);
let queue = tasking.message_queue_mut(pid).unwrap();
queue.push((new_buffer_key, len));
if tasking.proc_sleeping(pid) == Some(SleepReason::WaitingForIPC) {
tasking.wake(pid);
}
retval = 0;
} else {
retval = 1;
@ -380,9 +384,16 @@ extern "C" fn syscall_handler() {
let space = tasking.address_spaces_mut().get_mut((regs.rcx - 1) as usize).unwrap();
space.run(|| unsafe { slice::from_raw_parts_mut(regs.rdx as *mut u8, regs.rsi as usize).fill(0) });
retval = 0;
},
18 => {
let mut tasking = TASKING.lock();
if tasking.current_message_queue_mut().is_empty() {
tasking.sleep(SleepReason::WaitingForIPC);
}
}
_ => (),
};
unsafe { SYSCALL_REGS = regs };
unsafe {
asm!(
"mov rbx, [rip+SYSCALL_REGS+8]",

View File

@ -1,6 +1,5 @@
use crate::{
gdt, println, qemu_exit,
virtual_memory::{ASpaceMutex, AddressSpace, PagingError, KERNEL_SPACE},
dbg, gdt, println, qemu_exit, virtual_memory::{ASpaceMutex, AddressSpace, PagingError, KERNEL_SPACE}
};
use alloc::{boxed::Box, vec::Vec};
use core::{arch::asm, ptr::addr_of};
@ -77,6 +76,11 @@ extern "C" fn task_force_unlock() {
interrupts::enable();
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SleepReason {
WaitingForIPC,
}
#[derive(Debug)]
struct Process {
kernel_stack: Box<[usize], &'static ASpaceMutex>,
@ -86,6 +90,7 @@ struct Process {
address_spaces: Slab<AddressSpace>,
data_buffers: Slab<*mut [u8]>,
message_queue: SegQueue<(usize, usize)>,
sleeping: Option<SleepReason>
}
unsafe impl Send for Process {}
@ -129,6 +134,7 @@ impl Tasking {
address_spaces: Slab::new(),
data_buffers: Slab::new(),
message_queue: SegQueue::new(),
sleeping: None,
});
self.ready_to_run.push(pid);
Ok(pid)
@ -149,10 +155,14 @@ impl Tasking {
self.processes[current_process].address_space = Some(current_address_space);
let next_process = &self.processes[next_process_pid];
gdt::set_tss_stack(next_process.kernel_esp_top);
if self.processes[current_process].sleeping.is_none() {
self.ready_to_run.push(current_process);
}
let kernel_esp = next_process.kernel_esp;
let previous_process = self.current_process.replace(next_process_pid).unwrap();
switch_to_asm(&mut (self.processes[previous_process].kernel_esp), kernel_esp);
} else if self.processes[current_process].sleeping.is_some() {
qemu_exit::exit_qemu();
}
}
@ -177,7 +187,7 @@ impl Tasking {
switch_to_asm_exit(kernel_esp);
unreachable!()
} else {
println!("Last process exited, exiting QEMU");
println!("Last non-sleeping process exited, exiting QEMU");
qemu_exit::exit_qemu();
}
}
@ -201,4 +211,20 @@ impl Tasking {
pub fn message_queue_mut(&mut self, pid: usize) -> Option<&mut SegQueue<(usize, usize)>> {
Some(&mut self.processes.get_mut(pid)?.message_queue)
}
pub fn proc_sleeping(&mut self, pid: usize) -> Option<SleepReason> {
self.processes[pid].sleeping
}
pub fn sleep(&mut self, reason: SleepReason) {
self.processes[self.current_process.unwrap()].sleeping = Some(reason);
self.task_yield();
}
pub fn wake(&mut self, pid: usize) {
if self.processes[pid].sleeping.is_some() {
self.processes[pid].sleeping = None;
self.ready_to_run.push(pid);
}
}
}