From 0abfd3952253a7125b6286456db5eb1226293452 Mon Sep 17 00:00:00 2001 From: pjht Date: Mon, 23 Sep 2024 13:25:15 -0500 Subject: [PATCH] Make task_yield and exit use a loop instead of a tail call (manual TCO) --- src/tasking.rs | 177 +++++++++++++++++++++++++------------------------ 1 file changed, 91 insertions(+), 86 deletions(-) diff --git a/src/tasking.rs b/src/tasking.rs index 1edf895..952bab3 100644 --- a/src/tasking.rs +++ b/src/tasking.rs @@ -222,63 +222,66 @@ impl Tasking { } pub fn task_yield(&self) { - self.freeable_kstacks.lock().clear(); - let Some(current_pid) = *self.current_pid.read() else { - self.wfi_loop.store(false, Ordering::Relaxed); - return; - }; - let next_process_pid = self.ready_to_run.lock().pop_front(); - if let Some(next_process_pid) = next_process_pid { - self.wfi_loop.store(false, Ordering::Relaxed); - if next_process_pid == self.current_pid().unwrap() { - println!("Yielding to currect process! Returning"); - return; + loop { + self.freeable_kstacks.lock().clear(); + let Some(current_pid) = *self.current_pid.read() else { + self.wfi_loop.store(false, Ordering::Relaxed); + break; + }; + let next_process_pid = self.ready_to_run.lock().pop_front(); + if let Some(next_process_pid) = next_process_pid { + self.wfi_loop.store(false, Ordering::Relaxed); + if next_process_pid == self.current_pid().unwrap() { + println!("Yielding to currect process! Returning"); + break; + } + #[expect( + clippy::expect_used, + reason = "This expect checks a critical invariant. If this fails, the kernel MUST panic" + )] + #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] + let current_address_space = self.processes.write()[next_process_pid] + .address_space + .take() + .expect("Non-current process has active page table") + .activate(); + #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] + self.processes.write()[current_pid].address_space = Some(current_address_space); + let processes = self.processes.read(); + #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] + let current_process = &processes[current_pid]; + #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] + let next_process = &processes[next_process_pid]; + gdt::set_tss_stack(next_process.kernel_esp_top); + if current_process.sleeping.read().is_none() { + self.ready_to_run.lock().push_back(current_pid); + } + let kernel_esp = next_process.kernel_esp; + let previous_process = current_pid; + *self.current_pid.write() = Some(next_process_pid); + core::mem::drop(processes); + let mut processes = self.processes.write(); + #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] + let curr_stack = addr_of_mut!(processes[previous_process].kernel_esp); + core::mem::drop(processes); + switch_to_asm(curr_stack, kernel_esp); + break; + } else if { + #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] + let res = self.processes.read()[current_pid].sleeping.read().is_some(); + res + } { + //println!("All processes sleeping, exiting QEMU"); + //self.print_stats(); + //qemu_exit::exit_qemu(); + //println!("All processes sleeping, waiting for interrupt"); + self.wfi_loop.store(true, Ordering::Relaxed); + x86_64::instructions::interrupts::enable_and_hlt(); + x86_64::instructions::interrupts::disable(); + } else { + self.wfi_loop.store(false, Ordering::Relaxed); + break; } - #[expect( - clippy::expect_used, - reason = "This expect checks a critical invariant. If this fails, the kernel MUST panic" - )] - #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] - let current_address_space = self.processes.write()[next_process_pid] - .address_space - .take() - .expect("Non-current process has active page table") - .activate(); - #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] - self.processes.write()[current_pid].address_space = Some(current_address_space); - let processes = self.processes.read(); - #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] - let current_process = &processes[current_pid]; - #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] - let next_process = &processes[next_process_pid]; - gdt::set_tss_stack(next_process.kernel_esp_top); - if current_process.sleeping.read().is_none() { - self.ready_to_run.lock().push_back(current_pid); - } - let kernel_esp = next_process.kernel_esp; - let previous_process = current_pid; - *self.current_pid.write() = Some(next_process_pid); - core::mem::drop(processes); - let mut processes = self.processes.write(); - #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] - let curr_stack = addr_of_mut!(processes[previous_process].kernel_esp); - core::mem::drop(processes); - switch_to_asm(curr_stack, kernel_esp); - } else if { - #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] - let res = self.processes.read()[current_pid].sleeping.read().is_some(); - res - } { - //println!("All processes sleeping, exiting QEMU"); - //self.print_stats(); - //qemu_exit::exit_qemu(); - //println!("All processes sleeping, waiting for interrupt"); - self.wfi_loop.store(true, Ordering::Relaxed); - x86_64::instructions::interrupts::enable_and_hlt(); - x86_64::instructions::interrupts::disable(); - self.task_yield(); - } else { - self.wfi_loop.store(false, Ordering::Relaxed); } } @@ -287,37 +290,39 @@ impl Tasking { } pub fn exit(&self) -> ! { - let next_process_pid = self.ready_to_run.lock().pop_front(); - if let Some(next_process_pid) = next_process_pid { - self.wfi_loop.store(false, Ordering::Relaxed); - #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] - let mut processes = self.processes.write(); - if let Some(current_pid) = *self.current_pid.read() { - self.freeable_kstacks.lock().push(processes.remove(current_pid).kernel_stack); + loop { + let next_process_pid = self.ready_to_run.lock().pop_front(); + if let Some(next_process_pid) = next_process_pid { + self.wfi_loop.store(false, Ordering::Relaxed); + #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] + let mut processes = self.processes.write(); + if let Some(current_pid) = *self.current_pid.read() { + self.freeable_kstacks.lock().push(processes.remove(current_pid).kernel_stack); + } + #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] + let next_process = &mut processes[next_process_pid]; + #[expect( + clippy::expect_used, + reason = "This expect checks a critical invariant. If this fails, the kernel MUST panic" + )] + next_process + .address_space + .take() + .expect("Non-current process has active page table") + .activate(); + gdt::set_tss_stack(next_process.kernel_esp_top); + let kernel_esp = next_process.kernel_esp; + *self.current_pid.write() = Some(next_process_pid); + core::mem::drop(processes); + switch_to_asm_exit(kernel_esp); + unreachable!() + } else { + //println!("Last non-sleeping process exited, exiting QEMU"); + self.wfi_loop.store(true, Ordering::Relaxed); + x86_64::instructions::interrupts::enable_and_hlt(); + x86_64::instructions::interrupts::disable(); + //self.exit(); } - #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] - let next_process = &mut processes[next_process_pid]; - #[expect( - clippy::expect_used, - reason = "This expect checks a critical invariant. If this fails, the kernel MUST panic" - )] - next_process - .address_space - .take() - .expect("Non-current process has active page table") - .activate(); - gdt::set_tss_stack(next_process.kernel_esp_top); - let kernel_esp = next_process.kernel_esp; - *self.current_pid.write() = Some(next_process_pid); - core::mem::drop(processes); - switch_to_asm_exit(kernel_esp); - unreachable!() - } else { - //println!("Last non-sleeping process exited, exiting QEMU"); - self.wfi_loop.store(true, Ordering::Relaxed); - x86_64::instructions::interrupts::enable_and_hlt(); - x86_64::instructions::interrupts::disable(); - self.exit(); } }