| use crate::num::NonZero; |
| use crate::thread::ThreadInit; |
| use crate::time::Duration; |
| use crate::{io, ptr}; |
| |
| pub type Tid = hermit_abi::Tid; |
| |
| pub struct Thread { |
| tid: Tid, |
| } |
| |
| unsafe impl Send for Thread {} |
| unsafe impl Sync for Thread {} |
| |
| pub const DEFAULT_MIN_STACK_SIZE: usize = 1 << 20; |
| |
| impl Thread { |
| pub unsafe fn new_with_coreid( |
| stack: usize, |
| init: Box<ThreadInit>, |
| core_id: isize, |
| ) -> io::Result<Thread> { |
| let data = Box::into_raw(init); |
| let tid = unsafe { |
| hermit_abi::spawn2( |
| thread_start, |
| data.expose_provenance(), |
| hermit_abi::Priority::into(hermit_abi::NORMAL_PRIO), |
| stack, |
| core_id, |
| ) |
| }; |
| |
| return if tid == 0 { |
| // The thread failed to start and as a result data was not consumed. Therefore, it is |
| // safe to reconstruct the box so that it gets deallocated. |
| unsafe { |
| drop(Box::from_raw(data)); |
| } |
| Err(io::const_error!(io::ErrorKind::Uncategorized, "unable to create thread!")) |
| } else { |
| Ok(Thread { tid }) |
| }; |
| |
| extern "C" fn thread_start(data: usize) { |
| // SAFETY: we are simply recreating the box that was leaked earlier. |
| let init = |
| unsafe { Box::from_raw(ptr::with_exposed_provenance_mut::<ThreadInit>(data)) }; |
| let rust_start = init.init(); |
| rust_start(); |
| |
| // Run all destructors. |
| unsafe { |
| crate::sys::thread_local::destructors::run(); |
| } |
| crate::rt::thread_cleanup(); |
| } |
| } |
| |
| pub unsafe fn new(stack: usize, init: Box<ThreadInit>) -> io::Result<Thread> { |
| unsafe { |
| Thread::new_with_coreid(stack, init, -1 /* = no specific core */) |
| } |
| } |
| |
| pub fn join(self) { |
| unsafe { |
| let _ = hermit_abi::join(self.tid); |
| } |
| } |
| } |
| |
| pub fn available_parallelism() -> io::Result<NonZero<usize>> { |
| unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) } |
| } |
| |
| #[inline] |
| pub fn sleep(dur: Duration) { |
| let micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 }; |
| let micros = u64::try_from(micros).unwrap_or(u64::MAX); |
| |
| unsafe { |
| hermit_abi::usleep(micros); |
| } |
| } |
| |
| #[inline] |
| pub fn yield_now() { |
| unsafe { |
| hermit_abi::yield_now(); |
| } |
| } |