add userland call for requesting free memory

also refactor the startup API to no longer create and store
deprecated elements
This commit is contained in:
bunnie 2024-06-19 21:28:58 +08:00
parent 0f72117929
commit 3b6629e58f
2 changed files with 87 additions and 22 deletions

View file

@ -0,0 +1,55 @@
/// public userspace & swapper handler -> swapper userspace ABI
#[derive(Debug, num_derive::FromPrimitive, num_derive::ToPrimitive)]
#[repr(usize)]
pub enum Opcode {
/// Userspace request to GC some physical pages
GarbageCollect,
/// Test messages
#[cfg(feature = "swap-userspace-testing")]
Test0,
None,
}
pub const SWAPPER_PUBLIC_NAME: &'static str = "_swapper server_";
pub struct Swapper {
conn: xous::CID,
}
impl Swapper {
pub fn new() -> Result<Self, xous::Error> {
let xns = xous_api_names::XousNames::new().expect("couldn't connect to xous names");
REFCOUNT.fetch_add(1, Ordering::Relaxed);
let conn =
xns.request_connection_blocking(SWAPPER_PUBLIC_NAME).expect("Can't connect to TRNG server");
Ok(Swapper { conn })
}
/// Attempts to free `page_count` pages of RAM.
pub fn garbage_collect_pages(&self, page_count: usize) -> usize {
match xous::send_message(
self.conn,
xous::Message::new_blocking_scalar(Opcode::GarbageCollect as usize, page_count, 0, 0, 0),
) {
Ok(xous::Result::Scalar5(free_pages, _, _, _, _)) => free_pages,
_e => {
log::warn!("Garbage collect call failed with internal error: {:?}", _e);
0
}
}
// no result is given, but the call blocks until the GC call has completed in the swapper.
}
}
use core::sync::atomic::{AtomicU32, Ordering};
static REFCOUNT: AtomicU32 = AtomicU32::new(0);
impl Drop for Swapper {
fn drop(&mut self) {
// de-allocate myself. It's unsafe because we are responsible to make sure nobody else is using the
// connection.
if REFCOUNT.fetch_sub(1, Ordering::Relaxed) == 1 {
unsafe {
xous::disconnect(self.conn).unwrap();
}
}
}
}

View file

@ -58,7 +58,8 @@ use debug::*;
use loader::swap::{SwapAlloc, SwapSpec, SWAP_CFG_VADDR, SWAP_COUNT_VADDR, SWAP_PT_VADDR, SWAP_RPT_VADDR};
use num_traits::*;
use platform::{SwapHal, PAGE_SIZE};
use xous::{MemoryFlags, MemoryRange, Result, CID, PID, SID};
use xous::{MemoryFlags, MemoryRange, Result, PID};
use xous_swapper::Opcode;
/// Target of pages to free in case of a Hard OOM. Note that the PAGE_TARGET numbers
/// are imprecise, in that there is a chance that one target is active during another
@ -118,16 +119,6 @@ pub enum KernelOp {
HardOom = 3,
}
/// public userspace & swapper handler -> swapper userspace ABI
#[derive(Debug, num_derive::FromPrimitive, num_derive::ToPrimitive)]
#[repr(usize)]
pub enum Opcode {
/// Test messages
#[cfg(feature = "swap-userspace-testing")]
Test0,
None,
}
pub struct PtPage {
pub entries: [u32; 1024],
}
@ -217,20 +208,18 @@ impl SwapperSharedState {
}
struct SharedStateStorage {
pub inner: Option<SwapperSharedState>,
pub _conn: CID,
}
impl SharedStateStorage {
pub fn init(&mut self, sid: SID) {
pub fn init(&mut self) {
// Register the swapper with the kernel. Written as a raw syscall, since this is
// the only instance of its use (no point in use-once code to wrap it).
// This is an "early registration" which allows us to see debug output quickly,
// even before we can constitute all of our shared state
let (s0, s1, s2, s3) = sid.to_u32();
xous::rsyscall(xous::SysCall::RegisterSwapper(
s0,
s1,
s2,
s3,
0,
0,
0,
0,
swap_handler as *mut usize as usize,
self as *mut SharedStateStorage as usize,
))
@ -653,10 +642,8 @@ fn swap_handler(
}
fn main() {
let sid = xous::create_server().unwrap();
let conn = xous::connect(sid).unwrap();
let mut sss = Box::new(SharedStateStorage { _conn: conn, inner: None });
sss.init(sid);
let mut sss = Box::new(SharedStateStorage { inner: None });
sss.init();
// init the log, but this is mostly unused.
log_server::init_wait().unwrap();
@ -705,6 +692,7 @@ fn main() {
});
// This thread pings the free memory level and will try to clear memory to avoid OOM
// This claims sss, and is mutually exclusive with other options that claim sss
#[cfg(feature = "oom-doom")]
std::thread::spawn({
move || {
@ -720,6 +708,9 @@ fn main() {
}
});
let xns = xous_api_names::XousNames::new().unwrap();
let sid = xns.register_name(xous_swapper::SWAPPER_PUBLIC_NAME, None).unwrap();
let mut msg_opt = None;
loop {
xous::reply_and_receive_next(sid, &mut msg_opt).unwrap();
@ -727,6 +718,25 @@ fn main() {
let op: Option<Opcode> = FromPrimitive::from_usize(msg.body.id());
log::debug!("Swapper got {:x?}", op);
match op {
Some(Opcode::GarbageCollect) => {
if let Some(scalar) = msg.body.scalar_message_mut() {
let pages = scalar.arg1;
if pages > HARD_OOM_PAGE_TARGET * 2 {
log::warn!(
"Not honoring excessive GC request, reducing to {} pages",
HARD_OOM_PAGE_TARGET * 2
);
}
sss.inner.as_mut().unwrap().pages_to_free = pages.max(HARD_OOM_PAGE_TARGET * 2);
xous::rsyscall(xous::SysCall::SwapOp(SwapAbi::ClearMemoryNow as usize, 0, 0, 0, 0, 0, 0))
.expect("ClearMemoryNow syscall failed");
sss.inner.as_mut().unwrap().pages_to_free = HARD_OOM_PAGE_TARGET;
let free_pages = get_free_pages();
log::info!("Free pages after GC: {}", free_pages);
// return the current free page count
scalar.arg1 = free_pages;
}
}
#[cfg(feature = "swap-userspace-testing")]
Some(Opcode::Test0) => {
log::info!("Free mem: {}kiB", get_free_pages() * PAGE_SIZE / 1024);