twizzler_rt_abi/
thread.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Runtime interface for threads.

#![allow(unused_variables)]
use core::time::Duration;

/// Runtime-internal thread ID.
pub type ThreadId = crate::bindings::thread_id;
/// Index of a TLS variable.
pub type TlsIndex = crate::bindings::tls_index;
/// Type of a linux-like wait point.
pub type FutexWord = crate::bindings::futex_word;
/// Atomic futex word, for a linux-like thread wait.
pub type AtomicFutexWord = core::sync::atomic::AtomicU32;
/// Arguments to spawn.
pub type ThreadSpawnArgs = crate::bindings::spawn_args;

#[repr(u32)]
#[derive(Debug, Copy, Clone)]
/// Possible spawn error types.
pub enum SpawnError {
    /// Unclassified error.
    Other = crate::bindings::spawn_error_Spawn_Other,
    /// Argument was invalid.
    InvalidArgument = crate::bindings::spawn_error_Spawn_InvalidArgument,
    /// A specified object was not found.
    ObjectNotFound = crate::bindings::spawn_error_Spawn_ObjectNotFound,
    /// Permission was denied.
    PermissionDenied = crate::bindings::spawn_error_Spawn_PermissionDenied,
    /// The kernel encountered an error when spawning the thread.
    KernelError = crate::bindings::spawn_error_Spawn_KernelError,
}

impl From<SpawnError> for crate::bindings::spawn_error {
    fn from(value: SpawnError) -> Self {
        value as Self
    }
}

impl TryFrom<crate::bindings::spawn_error> for SpawnError {
    type Error = ();
    fn try_from(value: crate::bindings::spawn_error) -> Result<Self, ()> {
        Ok(match value {
            crate::bindings::spawn_error_Spawn_Other => SpawnError::Other,
            crate::bindings::spawn_error_Spawn_InvalidArgument => SpawnError::InvalidArgument,
            crate::bindings::spawn_error_Spawn_ObjectNotFound => SpawnError::ObjectNotFound,
            crate::bindings::spawn_error_Spawn_PermissionDenied => SpawnError::PermissionDenied,
            crate::bindings::spawn_error_Spawn_KernelError => SpawnError::KernelError,
            crate::bindings::spawn_error_Spawn_Success => return Err(()),
            _ => SpawnError::Other,
        })
    }
}

impl From<Result<ThreadId, SpawnError>> for crate::bindings::spawn_result {
    fn from(value: Result<ThreadId, SpawnError>) -> Self {
        match value {
            Ok(id) => Self {
                id,
                err: crate::bindings::spawn_error_Spawn_Success,
            },
            Err(e) => Self {
                id: 0,
                err: e.into(),
            },
        }
    }
}

impl Into<Result<ThreadId, SpawnError>> for crate::bindings::spawn_result {
    fn into(self) -> Result<ThreadId, SpawnError> {
        if let Ok(e) = self.err.try_into() {
            return Err(e);
        }
        Ok(self.id)
    }
}

#[repr(u32)]
/// Possible join error states.
pub enum JoinError {
    /// Unclassified error.
    Other = crate::bindings::join_result_Join_Other,
    /// The specified thread was not found.
    ThreadNotFound = crate::bindings::join_result_Join_ThreadNotFound,
    /// The operation timed out.
    Timeout = crate::bindings::join_result_Join_Timeout,
}

impl From<JoinError> for crate::bindings::join_result {
    fn from(value: JoinError) -> Self {
        value as Self
    }
}

/// If the futex word pointed to by `word` is equal to expected, put the thread to sleep. This
/// operation is atomic -- the thread is enqueued on the sleep queue _first_, before the equality
/// check. Returns false on timeout, true on all other cases.
pub fn twz_rt_futex_wait(
    word: &AtomicFutexWord,
    expected: FutexWord,
    timeout: Option<Duration>,
) -> bool {
    unsafe { crate::bindings::twz_rt_futex_wait(word.as_ptr().cast(), expected, timeout.into()) }
}

/// Wake up up to max threads waiting on `word`. If max is None, wake up all threads.
pub fn twz_rt_futex_wake(word: &AtomicFutexWord, max: Option<usize>) -> bool {
    let max = match max {
        Some(max) => max as i64,
        None => crate::bindings::FUTEX_WAKE_ALL,
    };
    unsafe { crate::bindings::twz_rt_futex_wake(word.as_ptr().cast(), max) }
}

/// Yield the calling thread.
pub fn twz_rt_yield() {
    unsafe {
        crate::bindings::twz_rt_yield_now();
    }
}

/// Sleep the calling thread for duration `dur`.
pub fn twz_rt_sleep(dur: Duration) {
    unsafe {
        crate::bindings::twz_rt_sleep(dur.into());
    }
}

/// Set the name of the calling thread.
pub fn twz_rt_set_thread_name(name: &core::ffi::CStr) {
    unsafe {
        crate::bindings::twz_rt_set_name(name.as_ptr());
    }
}

/// Get the address of a given TLS variable.
pub fn twz_rt_tls_get_addr(index: &TlsIndex) -> *mut u8 {
    unsafe { crate::bindings::twz_rt_tls_get_addr(index as *const _ as *mut _).cast() }
}

/// Spawn a thread. On success, that thread starts executing concurrently with the return of this
/// function.
pub fn twz_rt_spawn_thread(args: ThreadSpawnArgs) -> Result<ThreadId, SpawnError> {
    unsafe { crate::bindings::twz_rt_spawn_thread(args).into() }
}

/// Wait for a thread to exit, optionally timing out.
pub fn twz_rt_join_thread(id: ThreadId, timeout: Option<Duration>) -> Result<(), JoinError> {
    unsafe {
        match crate::bindings::twz_rt_join_thread(id, timeout.into()) {
            crate::bindings::join_result_Join_Success => Ok(()),
            crate::bindings::join_result_Join_Timeout => Err(JoinError::Timeout),
            crate::bindings::join_result_Join_ThreadNotFound => Err(JoinError::ThreadNotFound),
            _ => Err(JoinError::Other),
        }
    }
}