feature: spawn for closures
This commit is contained in:
parent
adb95ac52e
commit
d582a9b58b
@ -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<ExitCode> {
|
||||
let lock = self.inner.lock();
|
||||
if lock.state == ProcessState::Finished {
|
||||
|
@ -58,6 +58,10 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
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 => {
|
||||
|
@ -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;
|
||||
|
@ -283,6 +283,14 @@ pub fn sys_ex_clone(entry: usize, stack: usize, arg: usize) -> Result<usize, Err
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sys_ex_thread_exit(status: ExitCode) -> ! {
|
||||
unsafe {
|
||||
syscall!(abi::SYS_EX_THREAD_EXIT, argn!(i32::from(status)));
|
||||
}
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sys_ex_yield() {
|
||||
unsafe {
|
||||
|
36
libusr/src/allocator.rs
Normal file
36
libusr/src/allocator.rs
Normal file
@ -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;
|
@ -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 =>
|
||||
|
77
libusr/src/thread.rs
Normal file
77
libusr/src/thread.rs
Normal file
@ -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<F, T>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
F: Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
closure: F,
|
||||
stack: usize,
|
||||
}
|
||||
|
||||
pub struct JoinHandle<T> {
|
||||
native: u32,
|
||||
_pd: PhantomData<T>,
|
||||
}
|
||||
|
||||
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
F: Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
let stack = vec![0u8; 8192].leak();
|
||||
|
||||
#[inline(never)]
|
||||
extern "C" fn thread_entry<F, T>(data: *mut NativeData<F, T>) -> !
|
||||
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<NativeData<F, T>> = 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<F, T> = Box::into_raw(Box::new(NativeData { closure: f, stack }));
|
||||
|
||||
sys_ex_clone(thread_entry::<F, T> as usize, stack, data as usize).unwrap() as u32
|
||||
};
|
||||
|
||||
JoinHandle {
|
||||
native,
|
||||
_pd: PhantomData,
|
||||
}
|
||||
}
|
@ -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 {}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user