Add suuport for sleeping processes and a syscall to sleep waiting for IPC
This commit is contained in:
parent
8bbc165e58
commit
1376aa5f44
@ -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]",
|
||||
|
@ -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);
|
||||
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<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user