Skip to main content

dope_sys/thread/raw/
mod.rs

1use std::{mem, ptr};
2
3use o3::base::marker::ThreadBound;
4
5use crate::{
6    Errno, kernel,
7    thread::{Attrs, Handle},
8};
9
10cfg_select! {
11    target_arch = "x86_64" => {
12        mod x86;
13        pub(super) use x86::try_crc32;
14    }
15    all(target_arch = "aarch64", target_os = "linux") => {
16        mod linux;
17        pub(super) use linux::try_crc32;
18    }
19    all(target_arch = "aarch64", target_os = "macos") => {
20        mod macos;
21        pub(super) use macos::try_crc32;
22    }
23    _ => {
24        mod scalar;
25        pub(super) use scalar::try_crc32;
26    }
27}
28
29pub(super) fn entropy<S: kernel::raw::Source + ?Sized, const N: usize>(
30    bytes: &mut mem::MaybeUninit<[u8; N]>,
31) -> Result<&mut [u8; N], Errno> {
32    const { assert!(N <= 256) };
33    // SAFETY: bytes provides N writable bytes, within getentropy's 256-byte limit.
34    let result = unsafe { libc::getentropy(bytes.as_mut_ptr().cast(), N) };
35    // SAFETY: getentropy handles interruptions internally and returns zero or -1
36    // with unchanged native errno; success initializes the complete requested extent.
37    unsafe {
38        kernel::raw::Status::new(result).try_zero::<Errno>(|| kernel::raw::Code::last::<S>().into())
39    }?;
40    // SAFETY: success initializes all N bytes, including the empty array.
41    Ok(unsafe { bytes.assume_init_mut() })
42}
43
44/// # Safety
45/// Implementors access only their admitted context and resources, with the promised thread exclusivity.
46pub unsafe trait Task: Sized {
47    /// # Safety
48    /// The context and all resources it uses must retain their admitted access rights through this execution.
49    unsafe fn run(context: ptr::NonNull<Self>);
50}
51
52/// One typed context admitted for a single native execution.
53pub struct Entry<T: Task> {
54    context: ptr::NonNull<T>,
55}
56
57impl<T: Task> Entry<T> {
58    /// # Safety
59    /// Retain the initialized context and its borrowed resources at stable addresses through discard, creation failure, or successful join.
60    /// All accesses must satisfy T's thread exclusivity contract; forgetting the handle does not release these obligations.
61    pub const unsafe fn new(context: ptr::NonNull<T>) -> Self {
62        Self { context }
63    }
64
65    /// Transfers this admitted entry into one joinable native thread.
66    pub fn spawn(self, attrs: &Attrs) -> Result<Handle, Errno> {
67        let mut thread = mem::MaybeUninit::uninit();
68        // SAFETY: attrs and the writable handle outlive this call. The consumed
69        // entry preserves T's exact context and access through join.
70        // pthread_create returns zero or a positive error code directly.
71        unsafe {
72            kernel::raw::Status::new(libc::pthread_create(
73                thread.as_mut_ptr(),
74                attrs.as_ptr(),
75                Self::run,
76                self.context.as_ptr().cast(),
77            ))
78            .try_pthread()
79        }?;
80        // SAFETY: pthread_create wrote the handle before returning success.
81        Ok(Handle(unsafe { thread.assume_init() }, ThreadBound::NEW))
82    }
83
84    extern "C" fn run(context: *mut std::ffi::c_void) -> *mut std::ffi::c_void {
85        // SAFETY: spawn passes this admitted nonnull T context exactly once;
86        // its owner retains the allocation and access rights through join.
87        unsafe { T::run(ptr::NonNull::new_unchecked(context.cast())) };
88        ptr::null_mut()
89    }
90}