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 { kernel::raw::Status::new(result).try_zero::<S, Errno>() }?;
38 // SAFETY: success initializes all N bytes, including the empty array.
39 Ok(unsafe { bytes.assume_init_mut() })
40}
41
42/// # Safety
43/// Implementors access only their admitted context and resources, with the promised thread exclusivity.
44pub unsafe trait Task: Sized {
45 /// # Safety
46 /// The context and all resources it uses must retain their admitted access rights through this execution.
47 unsafe fn run(context: ptr::NonNull<Self>);
48}
49
50/// One typed context admitted for a single native execution.
51pub struct Entry<T: Task> {
52 context: ptr::NonNull<T>,
53}
54
55impl<T: Task> Entry<T> {
56 /// # Safety
57 /// Retain the initialized context and its borrowed resources at stable addresses through discard, creation failure, or successful join.
58 /// All accesses must satisfy T's thread exclusivity contract; forgetting the handle does not release these obligations.
59 pub const unsafe fn new(context: ptr::NonNull<T>) -> Self {
60 Self { context }
61 }
62
63 /// Transfers this admitted entry into one joinable native thread.
64 pub fn spawn(self, attrs: &Attrs) -> Result<Handle, Errno> {
65 let mut thread = mem::MaybeUninit::uninit();
66 // SAFETY: attrs and the writable handle outlive this call. The consumed
67 // entry preserves T's exact context and access through join.
68 // pthread_create returns zero or a positive error code directly.
69 unsafe {
70 kernel::raw::Status::new(libc::pthread_create(
71 thread.as_mut_ptr(),
72 attrs.as_ptr(),
73 Self::run,
74 self.context.as_ptr().cast(),
75 ))
76 .try_pthread()
77 }?;
78 // SAFETY: pthread_create wrote the handle before returning success.
79 Ok(Handle(unsafe { thread.assume_init() }, ThreadBound::NEW))
80 }
81
82 extern "C" fn run(context: *mut std::ffi::c_void) -> *mut std::ffi::c_void {
83 // SAFETY: spawn passes this admitted nonnull T context exactly once;
84 // its owner retains the allocation and access rights through join.
85 unsafe { T::run(ptr::NonNull::new_unchecked(context.cast())) };
86 ptr::null_mut()
87 }
88}