diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index 7506853..27fac7a 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -234,6 +234,38 @@ impl Process { panic!("This code should never run"); } + pub fn exit_thread(thread: ThreadRef) { + let switch = { + let switch = thread.state() == ThreadState::Running; + let process = thread.owner().unwrap(); + let mut lock = process.inner.lock(); + let tid = thread.id(); + + if lock.threads.len() == 1 { + // TODO call Process::exit instead? + todo!(); + } + + lock.threads.retain(|&e| e != tid); + + thread.terminate(); + SCHED.dequeue(tid); + debugln!("Thread {} terminated", tid); + + switch + }; + + if switch { + // TODO retain thread ID in process "finished" list and + // drop it when process finishes + SCHED.switch(true); + panic!("This code should not run"); + } else { + // Can drop this thread: it's not running + todo!(); + } + } + fn collect(&self) -> Option { let lock = self.inner.lock(); if lock.state == ProcessState::Finished { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index c58c416..e3d2818 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -58,6 +58,10 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { Process::exit(args[0] as i32); unreachable!(); } + abi::SYS_EX_THREAD_EXIT => { + Process::exit_thread(Thread::current()); + unreachable!(); + }, // I/O system calls abi::SYS_OPENAT => { diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 4f1ff3d..ff16f06 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -6,6 +6,7 @@ pub const SYS_EX_SIGRETURN: usize = 131; pub const SYS_EX_KILL: usize = 132; pub const SYS_EX_CLONE: usize = 133; pub const SYS_EX_YIELD: usize = 134; +pub const SYS_EX_THREAD_EXIT: usize = 135; pub const SYS_EXIT: usize = 1; pub const SYS_READ: usize = 2; diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index e506be4..ebbe22a 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -283,6 +283,14 @@ pub fn sys_ex_clone(entry: usize, stack: usize, arg: usize) -> Result ! { + unsafe { + syscall!(abi::SYS_EX_THREAD_EXIT, argn!(i32::from(status))); + } + unreachable!(); +} + #[inline(always)] pub fn sys_ex_yield() { unsafe { diff --git a/libusr/src/allocator.rs b/libusr/src/allocator.rs new file mode 100644 index 0000000..7976520 --- /dev/null +++ b/libusr/src/allocator.rs @@ -0,0 +1,36 @@ +use core::alloc::{Layout, GlobalAlloc}; +use core::sync::atomic::{AtomicUsize, Ordering}; +use libsys::mem::memset; + +use crate::trace; + +struct Allocator; + +static mut ALLOC_DATA: [u8; 65536] = [0; 65536]; +static ALLOC_PTR: AtomicUsize = AtomicUsize::new(0); + +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + assert!(layout.align() < 16); + let res = ALLOC_PTR.fetch_add((layout.size() + 15) & !15, Ordering::SeqCst); + if res > 65536 { + panic!("Out of memory"); + } + trace!("alloc({:?}) = {:p}", layout, &ALLOC_DATA[res]); + let res = &mut ALLOC_DATA[res] as *mut _; + memset(res, 0, layout.size()); + res + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + trace!("free({:p}, {:?})", ptr, layout); + } +} + +#[alloc_error_handler] +fn alloc_error_handler(_layout: Layout) -> ! { + loop {} +} + +#[global_allocator] +static ALLOC: Allocator = Allocator; diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index b973998..e14a47f 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -7,16 +7,20 @@ use libsys::proc::ExitCode; #[macro_use] extern crate lazy_static; +extern crate alloc; + +mod allocator; pub mod file; pub mod io; pub mod os; pub mod sys; pub mod sync; +pub mod thread; use sys::Signal; #[inline(never)] -extern "C" fn _signal_handler(arg: Signal) -> ! { +pub(crate) extern "C" fn _signal_handler(arg: Signal) -> ! { trace!("Entered signal handler: arg={:?}", arg); match arg { Signal::Interrupt | Signal::SegmentationFault => diff --git a/libusr/src/thread.rs b/libusr/src/thread.rs new file mode 100644 index 0000000..4792275 --- /dev/null +++ b/libusr/src/thread.rs @@ -0,0 +1,77 @@ +use alloc::boxed::Box; +use alloc::vec; +use core::cell::UnsafeCell; +use core::marker::PhantomData; +use libsys::{ + calls::{sys_ex_clone, sys_ex_thread_exit, sys_ex_signal}, + error::Errno, + proc::ExitCode, +}; + +use crate::trace; + +struct NativeData +where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, +{ + closure: F, + stack: usize, +} + +pub struct JoinHandle { + native: u32, + _pd: PhantomData, +} + +pub fn spawn(f: F) -> JoinHandle +where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, +{ + let stack = vec![0u8; 8192].leak(); + + #[inline(never)] + extern "C" fn thread_entry(data: *mut NativeData) -> ! + where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, + { + let (stack, len) = { + // Setup signal handling + let mut signal_stack = vec![0u8; 8192]; + + unsafe { + sys_ex_signal( + crate::_signal_handler as usize, + signal_stack.as_mut_ptr() as usize + signal_stack.len(), + ) + .unwrap(); + } + + let data: Box> = unsafe { Box::from_raw(data) }; + + let res = (data.closure)(); + + (data.stack, 8192) + }; + + // TODO free stack + sys_ex_thread_exit(ExitCode::from(0)); + } + + let native = unsafe { + let stack = stack.as_mut_ptr() as usize + stack.len(); + let data: *mut NativeData = Box::into_raw(Box::new(NativeData { closure: f, stack })); + + sys_ex_clone(thread_entry:: as usize, stack, data as usize).unwrap() as u32 + }; + + JoinHandle { + native, + _pd: PhantomData, + } +} diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 970ba36..1c32add 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -6,62 +6,27 @@ extern crate libusr; #[macro_use] extern crate lazy_static; +use libusr::thread; use libusr::io::{self, Read}; use libusr::sys::{Signal, SignalDestination}; use libusr::sync::Mutex; -static mut THREAD_STACK: [u8; 8192] = [0; 8192]; -static mut THREAD_SIGNAL_STACK: [u8; 8192] = [0; 8192]; -lazy_static! { - static ref MUTEX: Mutex<()> = Mutex::new(()); -} - fn sleep(ns: u64) { let mut rem = [0; 2]; libusr::sys::sys_ex_nanosleep(ns, &mut rem).unwrap(); } -fn fn0_signal(arg: Signal) { - trace!("fn0_signal"); - unsafe { - libusr::sys::sys_exit(libusr::sys::ExitCode::from(0)); - } -} - -fn fn0(_arg: usize) { - unsafe { - libusr::sys::sys_ex_signal(fn0_signal as usize, THREAD_SIGNAL_STACK.as_mut_ptr().add(8192) as usize); - } - - unsafe { - core::ptr::read_volatile(0x1234 as *const u32); - } - loop {} - //loop { - // sleep(100_000_000); - // println!("Tick from B"); - // { - // let lock = MUTEX.lock(); - // sleep(1_000_000_000); - // } - //} -} - -fn do_fault() { - unsafe { - core::ptr::read_volatile(0x1238 as *const u32); - } -} - #[no_mangle] fn main() -> i32 { - unsafe { - libusr::sys::sys_ex_clone(fn0 as usize, THREAD_STACK.as_mut_ptr().add(8192) as usize, 0); - } - + let value = 1234; + let thread = thread::spawn(move || { + trace!("Closure is alive: {}", value); + sleep(2_000_000_000); + trace!("Closure will now exit"); + }); sleep(1_000_000_000); - do_fault(); + trace!("???"); loop {}