safa_api/syscalls/
futex.rs

1use core::sync::atomic::AtomicU32;
2use core::time::Duration;
3
4use safa_abi::errors::ErrorStatus;
5
6use crate::syscalls::types::OptionalPtrMut;
7use crate::syscalls::types::RequiredPtr;
8use crate::syscalls::types::RequiredPtrMut;
9
10use super::define_syscall;
11use super::err_from_u16;
12use super::SyscallNum;
13
14define_syscall! {
15    SyscallNum::SysTFutWake => {
16        /// Wakes up, up to `n` threads waiting on futex `addr` using [`syst_fut_wait`]
17        ///
18        /// puts the amount of threads that were woken up into `wake_results`
19        syst_fut_wake(addr: RequiredPtr<AtomicU32>, n: usize, wake_results: OptionalPtrMut<usize>)
20    },
21    SyscallNum::SysTFutWait => {
22        /// Waits for *addr to not be equal to val
23        /// only stops waiting if *addr != val and signaled by [`syst_fut_wake`] or timeout is reached
24        ///
25        /// `wait_results` is going to be set to true if *addr != val, false if timeout is reached
26        syst_fut_wait(addr: RequiredPtr<AtomicU32>, val: u32, timeout_ms: u64, wait_results: OptionalPtrMut<bool>)
27    }
28}
29
30/// Wakes up, up to `n` threads waiting on futex `addr` using [`futex_wait`]
31///
32/// returns the amount of threads that were woken up on success
33/// # Safety
34/// This function is safe because the value at `addr` is not accessed unless there were another thread waiting on it using `futex_wait`
35#[inline]
36pub fn futex_wake(addr: &AtomicU32, n: usize) -> Result<usize, ErrorStatus> {
37    let mut results = 0;
38
39    let results_ptr = RequiredPtrMut::new(&mut results).into();
40    // FIXME; RequiredPtr should be const
41    let addr = unsafe { RequiredPtr::new_unchecked(addr as *const _ as *mut _) };
42
43    err_from_u16!(syst_fut_wake(addr, n, results_ptr), results)
44}
45
46/// Waits for *addr to not be equal to val
47/// only stops waiting if *addr != val and signaled by [`futex_wake`] or timeout is reached
48///
49/// Returns true if *addr != val, false if timeout is reached
50#[inline]
51pub fn futex_wait(
52    addr: &AtomicU32,
53    val: u32,
54    timeout_duration: Duration,
55) -> Result<bool, ErrorStatus> {
56    let timeout_ms = timeout_duration.as_millis() as u64;
57
58    let mut results = false;
59    let results_ptr = RequiredPtrMut::new(&mut results).into();
60    let addr = unsafe { RequiredPtrMut::new_unchecked(addr as *const _ as *mut _) };
61
62    err_from_u16!(syst_fut_wait(addr, val, timeout_ms, results_ptr), results)
63}