From 081f2009e8e6b361bf47687fa9de41ff4536a091 Mon Sep 17 00:00:00 2001 From: bunnie Date: Sat, 25 May 2024 00:01:22 +0800 Subject: [PATCH] make alloc_page_oomable re-entrant This version of the OOM handler uses a syscall in a syscall (previously forbidden) to make the OOM case deep in an alloc situation oomable, but also have multiple exit paths. this saves us from having to recode oodles of exit paths which is complicated and error-prone. I also think we should trim back some of the OOM handling paths because it is bloating the swapper, but let's commit the current working state before we trim stuff. --- kernel/src/mem.rs | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/kernel/src/mem.rs b/kernel/src/mem.rs index cdcf56092..c3248ec40 100644 --- a/kernel/src/mem.rs +++ b/kernel/src/mem.rs @@ -410,27 +410,29 @@ impl MemoryManager { /// Similar to alloc_page(), but this implementation can only be called in one location because /// we need to know where to resume from after the OOM is recovered. pub fn alloc_page_oomable(&mut self, pid: PID, vaddr: usize) -> Result { - // Go through all RAM pages looking for a free page. - // println!("Allocating page for PID {}", pid); - unsafe { - let end_point = self.ram_size / PAGE_SIZE; - let starting_point = self.last_ram_page.max(end_point); - for (allocation, index) in MEMORY_ALLOCATIONS[starting_point..end_point] - .iter_mut() - .zip(starting_point..) - .chain(MEMORY_ALLOCATIONS[..starting_point].iter_mut().zip(0..)) - { - if allocation.is_none() { - allocation.update(Some(pid), Some(vaddr)); - self.last_ram_page = index + 1; - let page = index * PAGE_SIZE + self.ram_start; - return Ok(page); + loop { + // Go through all RAM pages looking for a free page. + // println!("Allocating page for PID {}", pid); + unsafe { + let end_point = self.ram_size / PAGE_SIZE; + let starting_point = self.last_ram_page.max(end_point); + for (allocation, index) in MEMORY_ALLOCATIONS[starting_point..end_point] + .iter_mut() + .zip(starting_point..) + .chain(MEMORY_ALLOCATIONS[..starting_point].iter_mut().zip(0..)) + { + if allocation.is_none() { + allocation.update(Some(pid), Some(vaddr)); + self.last_ram_page = index + 1; + let page = index * PAGE_SIZE + self.ram_start; + return Ok(page); + } } } + if !crate::swap::Swap::with_mut(|s| s.hard_oom_inline()) { + break; + } } - crate::swap::Swap::with_mut(|s| { - s.hard_oom(vaddr); - }); // the call above actually diverges -- the final path will actually depend on how much memory // could be freed by the swapper. Err(xous_kernel::Error::OutOfMemory) @@ -553,9 +555,7 @@ impl MemoryManager { #[cfg(not(feature = "swap"))] let phys = self.alloc_page(pid)?; #[cfg(feature = "swap")] - // this should not be OOMable because the callers for map_zeroed page are exclusively from kernel - // services (process creation, queue creation) - let phys = self.alloc_page(pid, Some(virt))?; + let phys = self.alloc_page_oomable(pid, virt)?; // Actually perform the map. At this stage, every physical page should be owned by us. if let Err(e) = crate::arch::mem::map_page_inner(