Skip to content

Commit 4d062ac

Browse files
authored
Implement futex_waitv. (#1329)
Implement the new `futex_waitv` syscall, as well as the corresponding io_uring support.
1 parent af13d29 commit 4d062ac

File tree

9 files changed

+461
-15
lines changed

9 files changed

+461
-15
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ event = []
123123
fs = []
124124

125125
# Enable `rustix::io_uring::*` (on platforms that support it).
126-
io_uring = ["event", "fs", "net", "linux-raw-sys/io_uring"]
126+
io_uring = ["event", "fs", "net", "thread", "linux-raw-sys/io_uring"]
127127

128128
# Enable `rustix::mount::*`.
129129
mount = []

src/backend/libc/thread/futex.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,42 @@ bitflags::bitflags! {
1111
const PRIVATE = bitcast!(c::FUTEX_PRIVATE_FLAG);
1212
/// `FUTEX_CLOCK_REALTIME`
1313
const CLOCK_REALTIME = bitcast!(c::FUTEX_CLOCK_REALTIME);
14+
15+
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
16+
const _ = !0;
17+
}
18+
}
19+
20+
bitflags::bitflags! {
21+
/// `FUTEX2_*` flags for use with the functions in [`Waitv`].
22+
///
23+
/// Not to be confused with [`WaitvFlags`], which is passed as an argument
24+
/// to the `waitv` function.
25+
///
26+
/// [`Waitv`]: crate::thread::futex::Waitv
27+
/// [`WaitvFlags`]: crate::thread::futex::WaitvFlags
28+
#[repr(transparent)]
29+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
30+
pub struct WaitFlags: u32 {
31+
/// `FUTEX_U8`
32+
const SIZE_U8 = linux_raw_sys::general::FUTEX2_SIZE_U8;
33+
/// `FUTEX_U16`
34+
const SIZE_U16 = linux_raw_sys::general::FUTEX2_SIZE_U16;
35+
/// `FUTEX_U32`
36+
const SIZE_U32 = linux_raw_sys::general::FUTEX2_SIZE_U32;
37+
/// `FUTEX_U64`
38+
const SIZE_U64 = linux_raw_sys::general::FUTEX2_SIZE_U64;
39+
/// `FUTEX_SIZE_MASK`
40+
const SIZE_MASK = linux_raw_sys::general::FUTEX2_SIZE_MASK;
41+
42+
/// `FUTEX2_NUMA`
43+
const NUMA = linux_raw_sys::general::FUTEX2_NUMA;
44+
45+
/// `FUTEX2_PRIVATE`
46+
const PRIVATE = linux_raw_sys::general::FUTEX2_PRIVATE;
47+
48+
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
49+
const _ = !0;
1450
}
1551
}
1652

src/backend/libc/thread/syscalls.rs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,7 @@ use crate::thread::{NanosleepRelativeResult, Timespec};
2727
use crate::timespec::LibcTimespec;
2828
#[cfg(not(fix_y2038))]
2929
use crate::timespec::{as_libc_timespec_mut_ptr, as_libc_timespec_ptr};
30-
#[cfg(all(
31-
linux_kernel,
32-
target_pointer_width = "32",
33-
not(any(target_arch = "aarch64", target_arch = "x86_64"))
34-
))]
30+
#[cfg(linux_kernel)]
3531
use crate::utils::option_as_ptr;
3632
use core::mem::MaybeUninit;
3733
#[cfg(linux_kernel)]
@@ -653,6 +649,42 @@ unsafe fn futex_old_timespec(
653649
) as isize)
654650
}
655651

652+
#[cfg(linux_kernel)]
653+
pub(crate) fn futex_waitv(
654+
waiters: &[futex::Wait],
655+
flags: futex::WaitvFlags,
656+
timeout: Option<&Timespec>,
657+
clockid: ClockId,
658+
) -> io::Result<usize> {
659+
use futex::Wait as FutexWait;
660+
use linux_raw_sys::general::{__kernel_clockid_t as clockid_t, __kernel_timespec as timespec};
661+
syscall! {
662+
fn futex_waitv(
663+
waiters: *const FutexWait,
664+
nr_futexes: c::c_uint,
665+
flags: c::c_uint,
666+
timeout: *const timespec,
667+
clockid: clockid_t
668+
) via SYS_futex_waitv -> c::c_int
669+
}
670+
671+
let nr_futexes: c::c_uint = waiters.len().try_into().map_err(|_| io::Errno::INVAL)?;
672+
673+
#[cfg(test)]
674+
assert_eq_size!(timespec, Timespec);
675+
676+
unsafe {
677+
ret_c_int(futex_waitv(
678+
waiters.as_ptr(),
679+
nr_futexes,
680+
flags.bits(),
681+
option_as_ptr(timeout).cast(),
682+
clockid as _,
683+
))
684+
.map(|n| n as usize)
685+
}
686+
}
687+
656688
#[cfg(linux_kernel)]
657689
#[inline]
658690
pub(crate) fn setgroups_thread(groups: &[crate::ugid::Gid]) -> io::Result<()> {

src/backend/linux_raw/c.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ pub(crate) use linux_raw_sys::errno::{EBADF, EINVAL};
1212
pub(crate) use linux_raw_sys::general::{__kernel_fd_set as fd_set, __FD_SETSIZE as FD_SETSIZE};
1313
pub(crate) use linux_raw_sys::ioctl::{FIONBIO, FIONREAD};
1414
// Import the kernel's `uid_t` and `gid_t` if they're 32-bit.
15+
#[cfg(feature = "thread")]
16+
pub(crate) use linux_raw_sys::general::futex_waitv;
1517
#[cfg(not(any(target_arch = "arm", target_arch = "sparc", target_arch = "x86")))]
1618
pub(crate) use linux_raw_sys::general::{__kernel_gid_t as gid_t, __kernel_uid_t as uid_t};
1719
pub(crate) use linux_raw_sys::general::{

src/backend/linux_raw/thread/futex.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,41 @@ bitflags::bitflags! {
1010
/// `FUTEX_CLOCK_REALTIME`
1111
const CLOCK_REALTIME = linux_raw_sys::general::FUTEX_CLOCK_REALTIME;
1212

13-
// This deliberately lacks a `const _ = !0`, so that users can use
14-
// `from_bits_truncate` to extract the `SocketFlags` from a flags
15-
// value that also includes a `SocketType`.
13+
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
14+
const _ = !0;
15+
}
16+
}
17+
18+
bitflags::bitflags! {
19+
/// `FUTEX2_*` flags for use with the functions in [`Waitv`].
20+
///
21+
/// Not to be confused with [`WaitvFlags`], which is passed as an argument
22+
/// to the `waitv` function.
23+
///
24+
/// [`Waitv`]: crate::thread::futex::Waitv
25+
/// [`WaitvFlags`]: crate::thread::futex::WaitvFlags
26+
#[repr(transparent)]
27+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
28+
pub struct WaitFlags: u32 {
29+
/// `FUTEX_U8`
30+
const SIZE_U8 = linux_raw_sys::general::FUTEX2_SIZE_U8;
31+
/// `FUTEX_U16`
32+
const SIZE_U16 = linux_raw_sys::general::FUTEX2_SIZE_U16;
33+
/// `FUTEX_U32`
34+
const SIZE_U32 = linux_raw_sys::general::FUTEX2_SIZE_U32;
35+
/// `FUTEX_U64`
36+
const SIZE_U64 = linux_raw_sys::general::FUTEX2_SIZE_U64;
37+
/// `FUTEX_SIZE_MASK`
38+
const SIZE_MASK = linux_raw_sys::general::FUTEX2_SIZE_MASK;
39+
40+
/// `FUTEX2_NUMA`
41+
const NUMA = linux_raw_sys::general::FUTEX2_NUMA;
42+
43+
/// `FUTEX2_PRIVATE`
44+
const PRIVATE = linux_raw_sys::general::FUTEX2_PRIVATE;
45+
46+
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
47+
const _ = !0;
1648
}
1749
}
1850

src/backend/linux_raw/thread/syscalls.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ use crate::pid::Pid;
1717
use crate::thread::{
1818
futex, ClockId, Cpuid, MembarrierCommand, MembarrierQuery, NanosleepRelativeResult, Timespec,
1919
};
20-
use crate::utils::as_mut_ptr;
20+
use crate::utils::{as_mut_ptr, option_as_ptr};
2121
use core::mem::MaybeUninit;
2222
use core::sync::atomic::AtomicU32;
23-
use linux_raw_sys::general::{membarrier_cmd, membarrier_cmd_flag, TIMER_ABSTIME};
2423
#[cfg(target_pointer_width = "32")]
25-
use {crate::utils::option_as_ptr, linux_raw_sys::general::timespec as __kernel_old_timespec};
24+
use linux_raw_sys::general::timespec as __kernel_old_timespec;
25+
use linux_raw_sys::general::{membarrier_cmd, membarrier_cmd_flag, TIMER_ABSTIME};
2626

2727
#[inline]
2828
pub(crate) fn clock_nanosleep_relative(id: ClockId, req: &Timespec) -> NanosleepRelativeResult {
@@ -327,6 +327,27 @@ unsafe fn futex_old_timespec(
327327
c_uint(val3)
328328
))
329329
}
330+
331+
#[inline]
332+
pub(crate) fn futex_waitv(
333+
waiters: &[futex::Wait],
334+
flags: futex::WaitvFlags,
335+
timeout: Option<&Timespec>,
336+
clockid: ClockId,
337+
) -> io::Result<usize> {
338+
let (waiters_addr, waiters_len) = slice(waiters);
339+
unsafe {
340+
ret_usize(syscall!(
341+
__NR_futex_waitv,
342+
waiters_addr,
343+
waiters_len,
344+
c_uint(flags.bits()),
345+
option_as_ptr(timeout),
346+
clockid
347+
))
348+
}
349+
}
350+
330351
#[inline]
331352
pub(crate) fn setns(fd: BorrowedFd<'_>, nstype: c::c_int) -> io::Result<c::c_int> {
332353
unsafe { ret_c_int(syscall_readonly!(__NR_setns, fd, c_int(nstype))) }

src/io_uring/mod.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use core::ptr::{null_mut, write_bytes};
3535
use linux_raw_sys::net;
3636

3737
// Export types used in io_uring APIs.
38+
pub use crate::clockid::ClockId;
3839
pub use crate::event::epoll::{
3940
Event as EpollEvent, EventData as EpollEventData, EventFlags as EpollEventFlags,
4041
};
@@ -44,6 +45,10 @@ pub use crate::fs::{
4445
};
4546
pub use crate::io::ReadWriteFlags;
4647
pub use crate::net::{RecvFlags, SendFlags, SocketFlags};
48+
pub use crate::thread::futex::{
49+
Wait as FutexWait, WaitFlags as FutexWaitFlags, WaitPtr as FutexWaitPtr,
50+
WaitvFlags as FutexWaitvFlags,
51+
};
4752
pub use crate::timespec::{Nsecs, Secs, Timespec};
4853
pub use linux_raw_sys::general::sigset_t;
4954

@@ -420,6 +425,15 @@ pub enum IoringOp {
420425

421426
/// `IORING_OP_SENDMSG_ZC`
422427
SendmsgZc = sys::io_uring_op::IORING_OP_SENDMSG_ZC as _,
428+
429+
/// `IORING_OP_FUTEX_WAIT`
430+
FutexWait = sys::io_uring_op::IORING_OP_FUTEX_WAIT as _,
431+
432+
/// `IORING_OP_FUTEX_WAKE`
433+
FutexWake = sys::io_uring_op::IORING_OP_FUTEX_WAKE as _,
434+
435+
/// `IORING_OP_FUTEX_WAITV`
436+
FutexWaitv = sys::io_uring_op::IORING_OP_FUTEX_WAITV as _,
423437
}
424438

425439
impl Default for IoringOp {
@@ -660,6 +674,22 @@ bitflags::bitflags! {
660674
}
661675
}
662676

677+
bitflags::bitflags! {
678+
/// `IORING_URING_CMD_*` flags for use with [`io_uring_sqe`].
679+
#[repr(transparent)]
680+
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
681+
pub struct IoringUringCmdFlags: u32 {
682+
/// `IORING_URING_CMD_FIXED`
683+
const FIXED = sys::IORING_URING_CMD_FIXED;
684+
685+
/// `IORING_URING_CMD_MASK`
686+
const MASK = sys::IORING_URING_CMD_MASK;
687+
688+
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
689+
const _ = !0;
690+
}
691+
}
692+
663693
bitflags::bitflags! {
664694
/// `IORING_ASYNC_CANCEL_*` flags for use with [`io_uring_sqe`].
665695
#[repr(transparent)]
@@ -969,6 +999,12 @@ impl Default for io_uring_ptr {
969999
}
9701000
}
9711001

1002+
impl core::fmt::Debug for io_uring_ptr {
1003+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1004+
self.ptr.fmt(f)
1005+
}
1006+
}
1007+
9721008
/// User data in the io_uring API.
9731009
///
9741010
/// `io_uring`'s native API represents `user_data` fields as `u64` values. In
@@ -1147,6 +1183,8 @@ pub union op_flags_union {
11471183
pub hardlink_flags: AtFlags,
11481184
pub xattr_flags: XattrFlags,
11491185
pub msg_ring_flags: IoringMsgringFlags,
1186+
pub uring_cmd_flags: IoringUringCmdFlags,
1187+
pub futex_flags: FutexWaitvFlags,
11501188
}
11511189

11521190
#[allow(missing_docs)]

0 commit comments

Comments
 (0)