diff --git a/rust/lib/mammoth/src/thread.rs b/rust/lib/mammoth/src/thread.rs index 9d2e688..8f74b59 100644 --- a/rust/lib/mammoth/src/thread.rs +++ b/rust/lib/mammoth/src/thread.rs @@ -42,3 +42,43 @@ impl Thread { syscall::thread_wait(&self.cap) } } + +pub struct JoinHandle { + cap: Capability, +} + +impl JoinHandle { + pub fn join(&self) -> Result<(), zion::ZError> { + syscall::thread_wait(&self.cap) + } +} + +#[no_mangle] +extern "C" fn entry_point(func: *mut c_void) -> ! { + unsafe { + Box::from_raw(func as *mut Box)(); + } + + syscall::thread_exit() +} + +pub fn spawn(f: F) -> JoinHandle +where + F: FnOnce() + Send + 'static, +{ + // This is very tricky. + // If we have been passed a closure that doesn't capture + // anything it will be 0 size and creating a Box of it + // will create a pointer with address 0x1. + // So we create this "main" closure that captures f to get around this. + // Also somehow having the explicit type annotation here is important. + let main: Box = Box::new(move || { + f(); + }); + let raw_main = Box::into_raw(Box::new(main)); + let proc_cap = Capability::take_copy(unsafe { crate::init::SELF_PROC_CAP }).unwrap(); + let cap = syscall::thread_create(&proc_cap).unwrap(); + syscall::thread_start(&cap, entry_point as u64, raw_main as u64, 0).unwrap(); + + JoinHandle { cap } +} diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index a6a5ca0..91a1913 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -3,6 +3,7 @@ extern crate alloc; +use alloc::boxed::Box; use alloc::string::ToString; use mammoth::debug; use mammoth::define_entry; @@ -12,6 +13,10 @@ use yellowstone_yunq::GetEndpointRequest; define_entry!(); +pub fn testthread() { + debug!("Testing 1, 8 ,9"); +} + #[no_mangle] pub extern "C" fn main() -> z_err_t { debug!("Testing!"); @@ -28,11 +33,24 @@ pub extern "C" fn main() -> z_err_t { debug!("Got endpoint w/ cap: {:#x}", endpoint.endpoint); + let a = Box::new(1); + let b = Box::new(1); + debug!("Addrs: {:p} {:p}", a, b); + let e: thread::ThreadEntry = |_| { debug!("Testing 1 2 3"); }; let t = thread::Thread::spawn(e, core::ptr::null()).expect("Failed to spawn thread"); + t.join().expect("Failed to wait."); + let x = Box::new(|| 1); + debug!("Addr: {:p}", x); + debug!("Addr: {:p}", &x); + + let t = thread::spawn(testthread); + t.join().expect("Failed to wait."); + + let t = thread::spawn(|| debug!("Testing 4, 5, 6")); t.join().expect("Failed to wait."); 0