use super::{
abi,
error::{expect_success, expect_success_aborting, ItronError},
task,
time::dur2reltims,
};
use crate::{
cell::UnsafeCell,
ffi::CStr,
hint, io,
mem::ManuallyDrop,
ptr::NonNull,
sync::atomic::{AtomicUsize, Ordering},
sys::thread_local_dtor::run_dtors,
time::Duration,
};
pub struct Thread {
p_inner: NonNull<ThreadInner>,
task: abi::ID,
}
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
struct ThreadInner {
start: UnsafeCell<ManuallyDrop<Box<dyn FnOnce()>>>,
lifecycle: AtomicUsize,
}
unsafe impl Sync for ThreadInner {}
const LIFECYCLE_INIT: usize = 0;
const LIFECYCLE_FINISHED: usize = usize::MAX;
const LIFECYCLE_DETACHED: usize = usize::MAX;
const LIFECYCLE_JOIN_FINALIZE: usize = usize::MAX;
const LIFECYCLE_DETACHED_OR_JOINED: usize = usize::MAX;
const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX;
pub const DEFAULT_MIN_STACK_SIZE: usize = 0x4000 * crate::mem::size_of::<usize>();
impl Thread {
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
let inner = Box::new(ThreadInner {
start: UnsafeCell::new(ManuallyDrop::new(p)),
lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
});
unsafe extern "C" fn trampoline(exinf: isize) {
let p_inner: *mut ThreadInner = crate::ptr::from_exposed_addr_mut(exinf as usize);
let inner = unsafe { &*p_inner };
let p = unsafe { ManuallyDrop::take(&mut *inner.start.get()) };
p();
let _ = unsafe { abi::unl_cpu() };
let _ = unsafe { abi::ena_dsp() };
unsafe { run_dtors() };
let old_lifecycle = inner
.lifecycle
.swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::AcqRel);
match old_lifecycle {
LIFECYCLE_DETACHED => {
let _ = unsafe { Box::from_raw(p_inner) };
unsafe { terminate_and_delete_current_task() };
}
LIFECYCLE_INIT => {
}
parent_tid => {
expect_success(
unsafe {
let mut er = abi::wup_tsk(parent_tid as _);
if er == abi::E_QOVR {
er = abi::E_OK;
}
er
},
&"wup_tsk",
);
}
}
}
let p_inner = unsafe { NonNull::new_unchecked(Box::into_raw(inner)) };
let new_task = ItronError::err_if_negative(unsafe {
abi::acre_tsk(&abi::T_CTSK {
tskatr: abi::TA_ACT,
exinf: p_inner.as_ptr().expose_addr() as abi::EXINF,
task: Some(trampoline),
itskpri: abi::TPRI_SELF,
stksz: stack,
stk: crate::ptr::null_mut(),
})
})
.map_err(|e| e.as_io_error())?;
Ok(Self { p_inner, task: new_task })
}
pub fn yield_now() {
expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
}
pub fn set_name(_name: &CStr) {
}
pub fn sleep(dur: Duration) {
for timeout in dur2reltims(dur) {
expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
}
}
pub fn join(self) {
let inner = unsafe { self.p_inner.as_ref() };
let current_task = task::current_task_id_aborting();
debug_assert!(usize::try_from(current_task).is_ok());
debug_assert_ne!(current_task as usize, LIFECYCLE_INIT);
debug_assert_ne!(current_task as usize, LIFECYCLE_DETACHED);
let current_task = current_task as usize;
match inner.lifecycle.swap(current_task, Ordering::AcqRel) {
LIFECYCLE_INIT => {
loop {
expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk");
if inner.lifecycle.load(Ordering::Acquire) == LIFECYCLE_JOIN_FINALIZE {
break;
}
}
}
LIFECYCLE_FINISHED => {
}
_ => unsafe { hint::unreachable_unchecked() },
}
unsafe { terminate_and_delete_task(self.task) };
let _inner = unsafe { Box::from_raw(self.p_inner.as_ptr()) };
crate::mem::forget(self);
}
}
impl Drop for Thread {
fn drop(&mut self) {
let inner = unsafe { self.p_inner.as_ref() };
match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::AcqRel) {
LIFECYCLE_INIT => {
}
LIFECYCLE_FINISHED => {
unsafe { terminate_and_delete_task(self.task) };
let _ = unsafe { Box::from_raw(self.p_inner.as_ptr()) };
}
_ => unsafe { hint::unreachable_unchecked() },
}
}
}
pub mod guard {
pub type Guard = !;
pub unsafe fn current() -> Option<Guard> {
None
}
pub unsafe fn init() -> Option<Guard> {
None
}
}
unsafe fn terminate_and_delete_task(deleted_task: abi::ID) {
match unsafe { abi::ter_tsk(deleted_task) } {
abi::E_OBJ => {}
er => {
expect_success_aborting(er, &"ter_tsk");
}
}
expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk");
}
unsafe fn terminate_and_delete_current_task() -> ! {
expect_success_aborting(unsafe { abi::exd_tsk() }, &"exd_tsk");
unsafe { crate::hint::unreachable_unchecked() };
}
pub fn available_parallelism() -> io::Result<crate::num::NonZeroUsize> {
super::unsupported()
}