diff --git a/src/interrupts.rs b/src/interrupts.rs index 9ee5cb7..4746ef6 100644 --- a/src/interrupts.rs +++ b/src/interrupts.rs @@ -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]", diff --git a/src/tasking.rs b/src/tasking.rs index 4746943..572fa16 100644 --- a/src/tasking.rs +++ b/src/tasking.rs @@ -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, data_buffers: Slab<*mut [u8]>, message_queue: SegQueue<(usize, usize)>, + sleeping: Option } 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); - self.ready_to_run.push(current_process); + 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 { + 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); + } + } }