feature: thread join() with exit value

This commit is contained in:
Mark Poliakov 2021-11-19 16:38:38 +02:00
parent d582a9b58b
commit 87c13d3920
7 changed files with 71 additions and 18 deletions

View File

@ -35,6 +35,7 @@ struct ThreadInner {
pub struct Thread {
inner: IrqSafeSpinLock<ThreadInner>,
exit_wait: Wait,
pub(super) ctx: UnsafeCell<Context>,
signal_ctx: UnsafeCell<Context>,
signal_pending: AtomicU32,
@ -68,6 +69,7 @@ impl Thread {
ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)),
signal_ctx: UnsafeCell::new(Context::empty()),
signal_pending: AtomicU32::new(0),
exit_wait: Wait::new(),
inner: IrqSafeSpinLock::new(ThreadInner {
signal_entry: 0,
signal_stack: 0,
@ -97,6 +99,7 @@ impl Thread {
ctx: UnsafeCell::new(Context::user(entry, arg, ttbr0, stack)),
signal_ctx: UnsafeCell::new(Context::empty()),
signal_pending: AtomicU32::new(0),
exit_wait: Wait::new(),
inner: IrqSafeSpinLock::new(ThreadInner {
signal_entry: 0,
signal_stack: 0,
@ -123,6 +126,7 @@ impl Thread {
ctx: UnsafeCell::new(Context::fork(frame, ttbr0)),
signal_ctx: UnsafeCell::new(Context::empty()),
signal_pending: AtomicU32::new(0),
exit_wait: Wait::new(),
inner: IrqSafeSpinLock::new(ThreadInner {
signal_entry: 0,
signal_stack: 0,
@ -213,6 +217,23 @@ impl Thread {
lock.wait_flag = true;
}
pub fn waittid(tid: u32) -> Result<(), Errno> {
loop {
let thread = THREADS
.lock()
.get(&tid)
.cloned()
.ok_or(Errno::DoesNotExist)?;
if thread.state() == State::Finished {
// TODO remove thread from its parent?
return Ok(());
}
thread.exit_wait.wait(None)?;
}
}
pub fn set_wait_reached(&self) {
let mut lock = self.inner.lock();
lock.wait_flag = false;
@ -308,6 +329,7 @@ impl Thread {
if let Some(wait) = wait {
wait.abort(tid);
}
self.exit_wait.wakeup_all();
}
}

View File

@ -144,6 +144,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
_ => todo!(),
}
}
abi::SYS_EX_THREAD_WAIT => {
let tid = args[0] as u32;
match Thread::waittid(tid) {
Ok(_) => {
Ok(0)
},
_ => todo!(),
}
},
abi::SYS_IOCTL => {
let fd = FileDescriptor::from(args[0] as u32);
let cmd = IoctlCmd::try_from(args[1] as u32)?;

View File

@ -7,6 +7,7 @@ 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_EX_THREAD_WAIT: usize = 136;
pub const SYS_EXIT: usize = 1;
pub const SYS_READ: usize = 2;

View File

@ -274,12 +274,7 @@ pub fn sys_ex_kill(pid: SignalDestination, signum: Signal) -> Result<(), Errno>
#[inline(always)]
pub fn sys_ex_clone(entry: usize, stack: usize, arg: usize) -> Result<usize, Errno> {
Errno::from_syscall(unsafe {
syscall!(
abi::SYS_EX_CLONE,
argn!(entry),
argn!(stack),
argn!(arg)
)
syscall!(abi::SYS_EX_CLONE, argn!(entry), argn!(stack), argn!(arg))
})
}
@ -291,6 +286,12 @@ pub fn sys_ex_thread_exit(status: ExitCode) -> ! {
unreachable!();
}
#[inline(always)]
pub fn sys_ex_thread_wait(tid: u32) -> Result<ExitCode, Errno> {
Errno::from_syscall(unsafe { syscall!(abi::SYS_EX_THREAD_WAIT, argn!(tid)) })
.map(|_| ExitCode::from(0))
}
#[inline(always)]
pub fn sys_ex_yield() {
unsafe {

View File

@ -53,6 +53,7 @@ extern "C" fn _start(_arg: usize) -> ! {
#[panic_handler]
fn panic_handler(pi: &PanicInfo) -> ! {
// TODO handle non-main thread panics
// TODO print to stdout/stderr (if available)
trace!("Panic ocurred: {}", pi);
sys::sys_exit(ExitCode::from(-1));

View File

@ -1,9 +1,8 @@
use alloc::boxed::Box;
use alloc::vec;
use alloc::{boxed::Box, sync::Arc, vec};
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use libsys::{
calls::{sys_ex_clone, sys_ex_thread_exit, sys_ex_signal},
calls::{sys_ex_clone, sys_ex_signal, sys_ex_thread_exit, sys_ex_thread_wait},
error::Errno,
proc::ExitCode,
};
@ -17,12 +16,24 @@ where
T: Send + 'static,
{
closure: F,
result: Arc<UnsafeCell<MaybeUninit<T>>>,
stack: usize,
}
pub struct JoinHandle<T> {
native: u32,
_pd: PhantomData<T>,
result: Arc<UnsafeCell<MaybeUninit<T>>>,
}
impl<T> JoinHandle<T> {
pub fn join(self) -> Result<T, ()> {
sys_ex_thread_wait(self.native).unwrap();
if let Ok(result) = Arc::try_unwrap(self.result) {
Ok(unsafe { result.into_inner().assume_init() })
} else {
Err(())
}
}
}
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
@ -32,6 +43,7 @@ where
T: Send + 'static,
{
let stack = vec![0u8; 8192].leak();
let result = Arc::new(UnsafeCell::new(MaybeUninit::uninit()));
#[inline(never)]
extern "C" fn thread_entry<F, T>(data: *mut NativeData<F, T>) -> !
@ -53,9 +65,12 @@ where
}
let data: Box<NativeData<F, T>> = unsafe { Box::from_raw(data) };
let res = (data.closure)();
unsafe {
(&mut *data.result.get()).write(res);
}
(data.stack, 8192)
};
@ -65,13 +80,14 @@ where
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 }));
let data: *mut NativeData<F, T> = Box::into_raw(Box::new(NativeData {
closure: f,
stack,
result: result.clone(),
}));
sys_ex_clone(thread_entry::<F, T> as usize, stack, data as usize).unwrap() as u32
};
JoinHandle {
native,
_pd: PhantomData,
}
JoinHandle { native, result }
}

View File

@ -23,12 +23,14 @@ fn main() -> i32 {
trace!("Closure is alive: {}", value);
sleep(2_000_000_000);
trace!("Closure will now exit");
value - 100
});
sleep(1_000_000_000);
trace!("???");
loop {}
trace!("Thread joined: {:?}", thread.join());
0
}