Skip to content

Commit 5177d92

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 5177d92

File tree

21 files changed

+511
-553
lines changed

21 files changed

+511
-553
lines changed

Cargo.toml

Lines changed: 5 additions & 1 deletion
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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 2 additions & 0 deletions
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

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

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

Lines changed: 8 additions & 8 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 0 additions & 2 deletions
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)