linux_api/
futex.rs
1use core::sync::atomic::AtomicU32;
2
3use linux_syscall::Result64 as LinuxSyscallResult64;
4use linux_syscall::syscall;
5
6use crate::errno::Errno;
7use crate::time::kernel_timespec;
8use crate::{bindings, const_conversions};
9
10pub use bindings::linux_robust_list_head;
11#[allow(non_camel_case_types)]
12pub type robust_list_head = linux_robust_list_head;
13unsafe impl shadow_pod::Pod for robust_list_head {}
14
15pub const FUTEX_CMD_MASK: i32 = bindings::LINUX_FUTEX_CMD_MASK;
16
17bitflags::bitflags! {
18 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
20 pub struct FutexOpFlags: i32 {
21 const FUTEX_WAIT = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAIT);
22 const FUTEX_WAKE = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAKE);
23 const FUTEX_FD = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_FD);
24 const FUTEX_REQUEUE = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_REQUEUE);
25 const FUTEX_CMP_REQUEUE = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_CMP_REQUEUE);
26 const FUTEX_WAKE_OP = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAKE_OP);
27 const FUTEX_LOCK_PI = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_LOCK_PI);
28 const FUTEX_UNLOCK_PI = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_UNLOCK_PI);
29 const FUTEX_TRYLOCK_PI = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_TRYLOCK_PI);
30 const FUTEX_WAIT_BITSET = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAIT_BITSET);
31 const FUTEX_WAKE_BITSET = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAKE_BITSET);
32 const FUTEX_WAIT_REQUEUE_PI = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAIT_REQUEUE_PI);
33 const FUTEX_CMP_REQUEUE_PI = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_CMP_REQUEUE_PI);
34 const FUTEX_LOCK_PI2 = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_LOCK_PI2);
35 const FUTEX_PRIVATE_FLAG = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_PRIVATE_FLAG);
36 const FUTEX_CLOCK_REALTIME = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_CLOCK_REALTIME);
37 }
38}
39
40pub unsafe fn futex_raw(
43 uaddr: *mut u32,
44 op: core::ffi::c_int,
45 val: u32,
46 utime: *const kernel_timespec,
47 uaddr2: *mut u32,
48 val3: u32,
49) -> Result<core::ffi::c_int, Errno> {
50 unsafe {
51 syscall!(
52 linux_syscall::SYS_futex,
53 uaddr,
54 op,
55 val,
56 utime,
57 uaddr2,
58 val3
59 )
60 }
61 .try_i64()
62 .map(|x| x.try_into().expect("futex() returned invalid int"))
64 .map_err(Errno::from)
65}
66
67pub fn futex(
70 uaddr: &AtomicU32,
71 op: FutexOpFlags,
72 val: u32,
73 utime: Option<&kernel_timespec>,
74 uaddr2: Option<&AtomicU32>,
75 val3: u32,
76) -> Result<core::ffi::c_int, Errno> {
77 let utime = utime
78 .map(core::ptr::from_ref)
79 .unwrap_or(core::ptr::null_mut());
80 let uaddr2 = uaddr2
81 .map(AtomicU32::as_ptr)
82 .unwrap_or(core::ptr::null_mut());
83
84 unsafe { futex_raw(uaddr.as_ptr(), op.bits(), val, utime, uaddr2, val3) }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[cfg(not(miri))]
93 #[test]
94 fn test_futex_error() {
95 let rv = unsafe {
96 futex_raw(
97 core::ptr::null_mut(),
98 0,
99 0,
100 core::ptr::null(),
101 core::ptr::null_mut(),
102 0,
103 )
104 };
105
106 assert_eq!(rv, Err(Errno::EFAULT));
108 }
109}