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}