hermit/syscalls/
futex.rs

1use core::sync::atomic::AtomicU32;
2
3use crate::errno::EINVAL;
4use crate::synch::futex::{self as synch, Flags};
5use crate::time::timespec;
6
7/// Like `synch::futex_wait`, but does extra sanity checks and takes a `timespec`.
8///
9/// Returns -EINVAL if
10/// * `address` is null
11/// * `timeout` is negative
12/// * `flags` contains unknown flags
13#[hermit_macro::system]
14#[unsafe(no_mangle)]
15pub unsafe extern "C" fn sys_futex_wait(
16	address: *mut u32,
17	expected: u32,
18	timeout: *const timespec,
19	flags: u32,
20) -> i32 {
21	if address.is_null() {
22		return -EINVAL;
23	}
24
25	let address = unsafe { &*(address as *const AtomicU32) };
26	let timeout = if timeout.is_null() {
27		None
28	} else {
29		match unsafe { timeout.read().into_usec() } {
30			Some(usec) if usec >= 0 => Some(usec as u64),
31			_ => return -EINVAL,
32		}
33	};
34	let Some(flags) = Flags::from_bits(flags) else {
35		return -EINVAL;
36	};
37
38	synch::futex_wait(address, expected, timeout, flags)
39}
40
41/// Like `synch::futex_wake`, but does extra sanity checks.
42///
43/// Returns -EINVAL if `address` is null.
44/// `address` is used only for its address.
45/// It is safe to pass a dangling pointer.
46#[hermit_macro::system]
47#[unsafe(no_mangle)]
48pub unsafe extern "C" fn sys_futex_wake(address: *mut u32, count: i32) -> i32 {
49	if address.is_null() {
50		return -EINVAL;
51	}
52
53	synch::futex_wake(address as *const AtomicU32, count)
54}