Skip to content

Commit 4f66307

Browse files
committed
Move futex to be a top-level module.
With `rustix::thread::futex` being both a deprecated function and a public module, I'm seeing warnings like this when I use it in some simple testcases: ```console warning: use of deprecated function `rustix::thread::futex`: There are now individual functions available to perform futex operations with improved type safety. See the futex module. --> test.rs:2:21 | 2 | use rustix::thread::futex; | ^^^^^ | = note: `#[warn(deprecated)]` on by default ``` I think we can fix this by moving `futex` to be a top-level module, at `rustix::futex`. And this also reflects that, strictly speaking, futexes aren't specific to threads and can be used between processes too. Of course, this leaves the deprecated `rustix::thread::futex` and the associated types and constants in place. Also while using the API, I found `futex::FutexFlags` to be a little redundant, so I think it makes sense to rename it to `futex::Flags`, and similarly rename `futex::FUTEX_WAITERS` to `futex::WAITERS` and so on.
1 parent 777fbc6 commit 4f66307

File tree

21 files changed

+513
-553
lines changed

21 files changed

+513
-553
lines changed

Cargo.toml

+5-1
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ event = []
134134
# Enable `rustix::fs::*`.
135135
fs = []
136136

137+
# Enable `rustix::futex::*`.
138+
futex = []
139+
137140
# Enable `rustix::io_uring::*` (on platforms that support it).
138141
io_uring = ["event", "fs", "net", "linux-raw-sys/io_uring"]
139142

@@ -144,7 +147,7 @@ mount = []
144147
net = ["linux-raw-sys/net", "linux-raw-sys/netlink", "linux-raw-sys/if_ether", "linux-raw-sys/xdp"]
145148

146149
# Enable `rustix::thread::*`.
147-
thread = ["linux-raw-sys/prctl"]
150+
thread = ["linux-raw-sys/prctl", "futex"]
148151

149152
# Enable `rustix::process::*`.
150153
process = ["linux-raw-sys/prctl"]
@@ -190,6 +193,7 @@ runtime = ["linux-raw-sys/prctl"]
190193
all-apis = [
191194
"event",
192195
"fs",
196+
"futex",
193197
"io_uring",
194198
"mm",
195199
"mount",

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ by default. The rest of the API is conditional with cargo feature flags:
5959
| ---------- | -------------------------------------------------------------- |
6060
| `event` | [`rustix::event`]—Polling and event operations. |
6161
| `fs` | [`rustix::fs`]—Filesystem operations. |
62+
| `futex` | [`rustix::futex`]—Linux futex operations. |
6263
| `io_uring` | [`rustix::io_uring`]—Linux io_uring. |
6364
| `mm` | [`rustix::mm`]—Memory map operations. |
6465
| `mount` | [`rustix::mount`]—Linux mount API. |
@@ -80,6 +81,7 @@ by default. The rest of the API is conditional with cargo feature flags:
8081

8182
[`rustix::event`]: https://docs.rs/rustix/*/rustix/event/index.html
8283
[`rustix::fs`]: https://docs.rs/rustix/*/rustix/fs/index.html
84+
[`rustix::futex`]: https://docs.rs/rustix/*/rustix/futex/index.html
8385
[`rustix::io_uring`]: https://docs.rs/rustix/*/rustix/io_uring/index.html
8486
[`rustix::mm`]: https://docs.rs/rustix/*/rustix/mm/index.html
8587
[`rustix::mount`]: https://docs.rs/rustix/*/rustix/mount/index.html

src/backend/libc/futex/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub(crate) mod syscalls;
2+
pub(crate) mod types;

src/backend/libc/futex/syscalls.rs

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
use crate::backend::c;
2+
use crate::backend::conv::ret_usize;
3+
use crate::futex;
4+
use crate::io;
5+
use crate::timespec::Timespec;
6+
use core::sync::atomic::AtomicU32;
7+
8+
pub(crate) unsafe fn futex_val2(
9+
uaddr: *const AtomicU32,
10+
op: super::types::Operation,
11+
flags: futex::Flags,
12+
val: u32,
13+
val2: u32,
14+
uaddr2: *const AtomicU32,
15+
val3: u32,
16+
) -> io::Result<usize> {
17+
// The least-significant four bytes of the timeout pointer are used as `val2`.
18+
// ["the kernel casts the timeout value first to unsigned long, then to uint32_t"](https://man7.org/linux/man-pages/man2/futex.2.html),
19+
// so we perform that exact conversion in reverse to create the pointer.
20+
let timeout = val2 as usize as *const Timespec;
21+
22+
#[cfg(all(
23+
target_pointer_width = "32",
24+
not(any(target_arch = "aarch64", target_arch = "x86_64"))
25+
))]
26+
{
27+
// TODO: Upstream this to the libc crate.
28+
#[allow(non_upper_case_globals)]
29+
const SYS_futex_time64: i32 = linux_raw_sys::general::__NR_futex_time64 as i32;
30+
31+
syscall! {
32+
fn futex_time64(
33+
uaddr: *const AtomicU32,
34+
futex_op: c::c_int,
35+
val: u32,
36+
timeout: *const Timespec,
37+
uaddr2: *const AtomicU32,
38+
val3: u32
39+
) via SYS_futex_time64 -> c::ssize_t
40+
}
41+
42+
ret_usize(futex_time64(
43+
uaddr,
44+
op as i32 | flags.bits() as i32,
45+
val,
46+
timeout,
47+
uaddr2,
48+
val3,
49+
))
50+
}
51+
52+
#[cfg(any(
53+
target_pointer_width = "64",
54+
target_arch = "aarch64",
55+
target_arch = "x86_64"
56+
))]
57+
{
58+
syscall! {
59+
fn futex(
60+
uaddr: *const AtomicU32,
61+
futex_op: c::c_int,
62+
val: u32,
63+
timeout: *const linux_raw_sys::general::__kernel_timespec,
64+
uaddr2: *const AtomicU32,
65+
val3: u32
66+
) via SYS_futex -> c::c_long
67+
}
68+
69+
ret_usize(futex(
70+
uaddr,
71+
op as i32 | flags.bits() as i32,
72+
val,
73+
timeout.cast(),
74+
uaddr2,
75+
val3,
76+
) as isize)
77+
}
78+
}
79+
80+
pub(crate) unsafe fn futex_timeout(
81+
uaddr: *const AtomicU32,
82+
op: super::types::Operation,
83+
flags: futex::Flags,
84+
val: u32,
85+
timeout: *const Timespec,
86+
uaddr2: *const AtomicU32,
87+
val3: u32,
88+
) -> io::Result<usize> {
89+
#[cfg(all(
90+
target_pointer_width = "32",
91+
not(any(target_arch = "aarch64", target_arch = "x86_64"))
92+
))]
93+
{
94+
// TODO: Upstream this to the libc crate.
95+
#[allow(non_upper_case_globals)]
96+
const SYS_futex_time64: i32 = linux_raw_sys::general::__NR_futex_time64 as i32;
97+
98+
syscall! {
99+
fn futex_time64(
100+
uaddr: *const AtomicU32,
101+
futex_op: c::c_int,
102+
val: u32,
103+
timeout: *const Timespec,
104+
uaddr2: *const AtomicU32,
105+
val3: u32
106+
) via SYS_futex_time64 -> c::ssize_t
107+
}
108+
109+
ret_usize(futex_time64(
110+
uaddr,
111+
op as i32 | flags.bits() as i32,
112+
val,
113+
timeout,
114+
uaddr2,
115+
val3,
116+
))
117+
.or_else(|err| {
118+
// See the comments in `rustix_clock_gettime_via_syscall` about
119+
// emulation.
120+
if err == io::Errno::NOSYS {
121+
futex_old_timespec(uaddr, op, flags, val, timeout, uaddr2, val3)
122+
} else {
123+
Err(err)
124+
}
125+
})
126+
}
127+
128+
#[cfg(any(
129+
target_pointer_width = "64",
130+
target_arch = "aarch64",
131+
target_arch = "x86_64"
132+
))]
133+
{
134+
syscall! {
135+
fn futex(
136+
uaddr: *const AtomicU32,
137+
futex_op: c::c_int,
138+
val: u32,
139+
timeout: *const linux_raw_sys::general::__kernel_timespec,
140+
uaddr2: *const AtomicU32,
141+
val3: u32
142+
) via SYS_futex -> c::c_long
143+
}
144+
145+
ret_usize(futex(
146+
uaddr,
147+
op as i32 | flags.bits() as i32,
148+
val,
149+
timeout.cast(),
150+
uaddr2,
151+
val3,
152+
) as isize)
153+
}
154+
}
155+
156+
#[cfg(all(
157+
target_pointer_width = "32",
158+
not(any(target_arch = "aarch64", target_arch = "x86_64"))
159+
))]
160+
unsafe fn futex_old_timespec(
161+
uaddr: *const AtomicU32,
162+
op: super::types::Operation,
163+
flags: futex::Flags,
164+
val: u32,
165+
timeout: *const Timespec,
166+
uaddr2: *const AtomicU32,
167+
val3: u32,
168+
) -> io::Result<usize> {
169+
syscall! {
170+
fn futex(
171+
uaddr: *const AtomicU32,
172+
futex_op: c::c_int,
173+
val: u32,
174+
timeout: *const linux_raw_sys::general::__kernel_old_timespec,
175+
uaddr2: *const AtomicU32,
176+
val3: u32
177+
) via SYS_futex -> c::c_long
178+
}
179+
180+
let old_timeout = if timeout.is_null() {
181+
None
182+
} else {
183+
Some(linux_raw_sys::general::__kernel_old_timespec {
184+
tv_sec: (*timeout).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
185+
tv_nsec: (*timeout)
186+
.tv_nsec
187+
.try_into()
188+
.map_err(|_| io::Errno::INVAL)?,
189+
})
190+
};
191+
ret_usize(futex(
192+
uaddr,
193+
op as i32 | flags.bits() as i32,
194+
val,
195+
old_timeout
196+
.as_ref()
197+
.map(|timeout| timeout as *const linux_raw_sys::general::__kernel_old_timespec)
198+
.unwrap_or(core::ptr::null()),
199+
uaddr2,
200+
val3,
201+
) as isize)
202+
}

src/backend/libc/thread/futex.rs src/backend/libc/futex/types.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
use crate::backend::c;
22

33
bitflags::bitflags! {
4-
/// `FUTEX_*` flags for use with [`futex`].
4+
/// `FUTEX_*` flags for use with functions in [`futex`].
55
///
6-
/// [`futex`]: mod@crate::thread::futex
6+
/// [`futex`]: crate::futex
77
#[repr(transparent)]
88
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
9-
pub struct FutexFlags: u32 {
9+
pub struct Flags: u32 {
1010
/// `FUTEX_PRIVATE_FLAG`
1111
const PRIVATE = bitcast!(c::FUTEX_PRIVATE_FLAG);
1212
/// `FUTEX_CLOCK_REALTIME`
1313
const CLOCK_REALTIME = bitcast!(c::FUTEX_CLOCK_REALTIME);
1414
}
1515
}
1616

17-
/// `FUTEX_*` operations for use with [`futex`].
17+
/// `FUTEX_*` operations for use with functions in [`futex`].
1818
///
19-
/// [`futex`]: mod@crate::thread::futex
19+
/// [`futex`]: crate::futex
2020
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
2121
#[repr(u32)]
22-
pub enum FutexOperation {
22+
pub enum Operation {
2323
/// `FUTEX_WAIT`
2424
Wait = bitcast!(c::FUTEX_WAIT),
2525
/// `FUTEX_WAKE`
@@ -51,7 +51,7 @@ pub enum FutexOperation {
5151
}
5252

5353
/// `FUTEX_WAITERS`
54-
pub const FUTEX_WAITERS: u32 = linux_raw_sys::general::FUTEX_WAITERS;
54+
pub const WAITERS: u32 = linux_raw_sys::general::FUTEX_WAITERS;
5555

5656
/// `FUTEX_OWNER_DIED`
57-
pub const FUTEX_OWNER_DIED: u32 = linux_raw_sys::general::FUTEX_OWNER_DIED;
57+
pub const OWNER_DIED: u32 = linux_raw_sys::general::FUTEX_OWNER_DIED;

src/backend/libc/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ pub(crate) mod event;
107107
#[cfg(not(windows))]
108108
#[cfg(feature = "fs")]
109109
pub(crate) mod fs;
110+
#[cfg(linux_kernel)]
111+
#[cfg(feature = "futex")]
112+
pub(crate) mod futex;
110113
pub(crate) mod io;
111114
#[cfg(linux_kernel)]
112115
#[cfg(feature = "io_uring")]

src/backend/libc/thread/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
#[cfg(linux_kernel)]
2-
pub(crate) mod futex;
31
#[cfg(not(windows))]
42
pub(crate) mod syscalls;

0 commit comments

Comments
 (0)