twizzler_rt_abi/
thread.rs

1//! Runtime interface for threads.
2
3#![allow(unused_variables)]
4use core::{ffi::c_void, time::Duration};
5
6use crate::{error::RawTwzError, nk, Result};
7
8/// Runtime-internal thread ID.
9pub type ThreadId = crate::bindings::thread_id;
10/// Index of a TLS variable.
11pub type TlsIndex = crate::bindings::tls_index;
12/// TLS desc
13pub type TlsDesc = crate::bindings::tls_desc;
14/// Type of a linux-like wait point.
15pub type FutexWord = crate::bindings::futex_word;
16/// Atomic futex word, for a linux-like thread wait.
17pub type AtomicFutexWord = core::sync::atomic::AtomicU32;
18/// Arguments to spawn.
19pub type ThreadSpawnArgs = crate::bindings::spawn_args;
20
21impl From<Result<(ThreadId, *mut c_void)>> for crate::bindings::spawn_result {
22    fn from(value: Result<(ThreadId, *mut c_void)>) -> Self {
23        match value {
24            Ok((id, tcb)) => Self {
25                id,
26                tcb,
27                err: RawTwzError::success().raw(),
28            },
29            Err(e) => Self {
30                id: 0,
31                tcb: core::ptr::null_mut(),
32                err: e.raw(),
33            },
34        }
35    }
36}
37
38impl From<crate::bindings::spawn_result> for Result<ThreadId> {
39    fn from(value: crate::bindings::spawn_result) -> Self {
40        let raw = RawTwzError::new(value.err);
41        if raw.is_success() {
42            Ok(value.id)
43        } else {
44            Err(raw.error())
45        }
46    }
47}
48
49/// If the futex word pointed to by `word` is equal to expected, put the thread to sleep. This
50/// operation is atomic -- the thread is enqueued on the sleep queue _first_, before the equality
51/// check. Returns false on timeout, true on all other cases.
52pub fn twz_rt_futex_wait(
53    word: &AtomicFutexWord,
54    expected: FutexWord,
55    timeout: Option<Duration>,
56) -> Result<()> {
57    unsafe {
58        match nk!(crate::bindings::twz_rt_futex_wait(
59            word.as_ptr().cast(),
60            expected,
61            timeout.into()
62        )) {
63            0 => Ok(()),
64            e => Err(RawTwzError::new(e).error()),
65        }
66    }
67}
68
69/// Wake up up to max threads waiting on `word`. If max is None, wake up all threads.
70pub fn twz_rt_futex_wake(word: &AtomicFutexWord, max: Option<usize>) -> Result<()> {
71    let max = match max {
72        Some(max) => max as i64,
73        None => crate::bindings::FUTEX_WAKE_ALL,
74    };
75    unsafe {
76        match nk!(crate::bindings::twz_rt_futex_wake(
77            word.as_ptr().cast(),
78            max
79        )) {
80            0 => Ok(()),
81            e => Err(RawTwzError::new(e).error()),
82        }
83    }
84}
85
86/// Yield the calling thread.
87pub fn twz_rt_yield() {
88    unsafe {
89        nk!(crate::bindings::twz_rt_yield_now());
90    }
91}
92
93/// Sleep the calling thread for duration `dur`.
94pub fn twz_rt_sleep(dur: Duration) {
95    unsafe {
96        nk!(crate::bindings::twz_rt_sleep(dur.into()));
97    }
98}
99
100/// Set the name of the calling thread.
101pub fn twz_rt_set_thread_name(name: &core::ffi::CStr) {
102    unsafe {
103        nk!(crate::bindings::twz_rt_set_name(name.as_ptr()));
104    }
105}
106
107/// Get the address of a given TLS variable.
108pub fn twz_rt_tls_get_addr(index: &TlsIndex) -> *mut u8 {
109    unsafe { nk!(crate::bindings::twz_rt_tls_get_addr(index as *const _ as *mut _).cast()) }
110}
111
112/// Spawn a thread. On success, that thread starts executing concurrently with the return of this
113/// function.
114pub fn twz_rt_spawn_thread(args: ThreadSpawnArgs) -> Result<ThreadId> {
115    unsafe { nk!(crate::bindings::twz_rt_spawn_thread(args).into()) }
116}
117
118/// Wait for a thread to exit, optionally timing out.
119pub fn twz_rt_join_thread(id: ThreadId, timeout: Option<Duration>) -> Result<()> {
120    unsafe {
121        RawTwzError::new(nk!(crate::bindings::twz_rt_join_thread(id, timeout.into()))).result()
122    }
123}