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;
16pub const FUTEX_BITSET_MATCH_ANY: u32 = bindings::LINUX_FUTEX_BITSET_MATCH_ANY;
17
18bitflags::bitflags! {
19 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
21 pub struct FutexOpFlags: i32 {
22 const FUTEX_WAIT = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAIT);
23 const FUTEX_WAKE = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAKE);
24 const FUTEX_FD = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_FD);
25 const FUTEX_REQUEUE = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_REQUEUE);
26 const FUTEX_CMP_REQUEUE = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_CMP_REQUEUE);
27 const FUTEX_WAKE_OP = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAKE_OP);
28 const FUTEX_LOCK_PI = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_LOCK_PI);
29 const FUTEX_UNLOCK_PI = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_UNLOCK_PI);
30 const FUTEX_TRYLOCK_PI = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_TRYLOCK_PI);
31 const FUTEX_WAIT_BITSET = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAIT_BITSET);
32 const FUTEX_WAKE_BITSET = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAKE_BITSET);
33 const FUTEX_WAIT_REQUEUE_PI = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_WAIT_REQUEUE_PI);
34 const FUTEX_CMP_REQUEUE_PI = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_CMP_REQUEUE_PI);
35 const FUTEX_LOCK_PI2 = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_LOCK_PI2);
36 const FUTEX_PRIVATE_FLAG = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_PRIVATE_FLAG);
37 const FUTEX_CLOCK_REALTIME = const_conversions::i32_from_u32(bindings::LINUX_FUTEX_CLOCK_REALTIME);
38 }
39}
40
41pub unsafe fn futex_raw(
44 uaddr: *mut u32,
45 op: core::ffi::c_int,
46 val: u32,
47 utime: *const kernel_timespec,
48 uaddr2: *mut u32,
49 val3: u32,
50) -> Result<core::ffi::c_int, Errno> {
51 unsafe {
52 syscall!(
53 linux_syscall::SYS_futex,
54 uaddr,
55 op,
56 val,
57 utime,
58 uaddr2,
59 val3
60 )
61 }
62 .try_i64()
63 .map(|x| x.try_into().expect("futex() returned invalid int"))
65 .map_err(Errno::from)
66}
67
68pub fn futex(
71 uaddr: &AtomicU32,
72 op: FutexOpFlags,
73 val: u32,
74 utime: Option<&kernel_timespec>,
75 uaddr2: Option<&AtomicU32>,
76 val3: u32,
77) -> Result<core::ffi::c_int, Errno> {
78 let utime = utime
79 .map(core::ptr::from_ref)
80 .unwrap_or(core::ptr::null_mut());
81 let uaddr2 = uaddr2
82 .map(AtomicU32::as_ptr)
83 .unwrap_or(core::ptr::null_mut());
84
85 unsafe { futex_raw(uaddr.as_ptr(), op.bits(), val, utime, uaddr2, val3) }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[cfg(not(miri))]
94 #[test]
95 fn test_futex_error() {
96 let rv = unsafe {
97 futex_raw(
98 core::ptr::null_mut(),
99 0,
100 0,
101 core::ptr::null(),
102 core::ptr::null_mut(),
103 0,
104 )
105 };
106
107 assert_eq!(rv, Err(Errno::EFAULT));
109 }
110}