Skip to content

Commit 6012fad

Browse files
futex: split backend into val2 and timespec versions, reorganize new functions
1 parent 89dac89 commit 6012fad

File tree

6 files changed

+246
-104
lines changed

6 files changed

+246
-104
lines changed

src/backend/libc/thread/futex.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::backend::c;
33
bitflags::bitflags! {
44
/// `FUTEX_*` flags for use with [`futex`].
55
///
6-
/// [`futex`]: crate::thread::futex
6+
/// [`futex`]: mod@crate::thread::futex
77
#[repr(transparent)]
88
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
99
pub struct FutexFlags: u32 {
@@ -16,7 +16,7 @@ bitflags::bitflags! {
1616

1717
/// `FUTEX_*` operations for use with [`futex`].
1818
///
19-
/// [`futex`]: crate::thread::futex
19+
/// [`futex`]: mod@crate::thread::futex
2020
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
2121
#[repr(u32)]
2222
pub enum FutexOperation {

src/backend/libc/thread/syscalls.rs

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,81 @@ pub(crate) fn setresgid_thread(
417417
unsafe { ret(setresgid(rgid.as_raw(), egid.as_raw(), sgid.as_raw())) }
418418
}
419419

420-
// TODO: This could be de-multiplexed.
421420
#[cfg(linux_kernel)]
422-
pub(crate) unsafe fn futex(
421+
pub(crate) unsafe fn futex_val2(
422+
uaddr: *const AtomicU32,
423+
op: FutexOperation,
424+
flags: FutexFlags,
425+
val: u32,
426+
val2: u32,
427+
uaddr2: *const AtomicU32,
428+
val3: u32,
429+
) -> io::Result<usize> {
430+
// the least significant four bytes of the timeout pointer are used as `val2`.
431+
// ["the kernel casts the timeout value first to unsigned long, then to uint32_t"](https://man7.org/linux/man-pages/man2/futex.2.html),
432+
// so we perform that exact conversion in reverse to create the pointer.
433+
let utime = val2 as usize as *const Timespec;
434+
435+
#[cfg(all(
436+
target_pointer_width = "32",
437+
not(any(target_arch = "aarch64", target_arch = "x86_64"))
438+
))]
439+
{
440+
// TODO: Upstream this to the libc crate.
441+
#[allow(non_upper_case_globals)]
442+
const SYS_futex_time64: i32 = linux_raw_sys::general::__NR_futex_time64 as i32;
443+
444+
syscall! {
445+
fn futex_time64(
446+
uaddr: *const AtomicU32,
447+
futex_op: c::c_int,
448+
val: u32,
449+
timeout: *const Timespec,
450+
uaddr2: *const AtomicU32,
451+
val3: u32
452+
) via SYS_futex_time64 -> c::ssize_t
453+
}
454+
455+
ret_usize(futex_time64(
456+
uaddr,
457+
op as i32 | flags.bits() as i32,
458+
val,
459+
utime,
460+
uaddr2,
461+
val3,
462+
))
463+
}
464+
465+
#[cfg(any(
466+
target_pointer_width = "64",
467+
target_arch = "aarch64",
468+
target_arch = "x86_64"
469+
))]
470+
{
471+
syscall! {
472+
fn futex(
473+
uaddr: *const AtomicU32,
474+
futex_op: c::c_int,
475+
val: u32,
476+
timeout: *const linux_raw_sys::general::__kernel_timespec,
477+
uaddr2: *const AtomicU32,
478+
val3: u32
479+
) via SYS_futex -> c::c_long
480+
}
481+
482+
ret_usize(futex(
483+
uaddr,
484+
op as i32 | flags.bits() as i32,
485+
val,
486+
utime.cast(),
487+
uaddr2,
488+
val3,
489+
) as isize)
490+
}
491+
}
492+
493+
#[cfg(linux_kernel)]
494+
pub(crate) unsafe fn futex_timespec(
423495
uaddr: *const AtomicU32,
424496
op: FutexOperation,
425497
flags: FutexFlags,
@@ -460,7 +532,7 @@ pub(crate) unsafe fn futex(
460532
// See the comments in `rustix_clock_gettime_via_syscall` about
461533
// emulation.
462534
if err == io::Errno::NOSYS {
463-
futex_old(uaddr, op, flags, val, utime, uaddr2, val3)
535+
futex_old_timespec(uaddr, op, flags, val, utime, uaddr2, val3)
464536
} else {
465537
Err(err)
466538
}
@@ -500,7 +572,7 @@ pub(crate) unsafe fn futex(
500572
target_pointer_width = "32",
501573
not(any(target_arch = "aarch64", target_arch = "x86_64"))
502574
))]
503-
unsafe fn futex_old(
575+
unsafe fn futex_old_timespec(
504576
uaddr: *const AtomicU32,
505577
op: FutexOperation,
506578
flags: FutexFlags,
@@ -520,15 +592,22 @@ unsafe fn futex_old(
520592
) via SYS_futex -> c::c_long
521593
}
522594

523-
let old_utime = linux_raw_sys::general::__kernel_old_timespec {
524-
tv_sec: (*utime).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
525-
tv_nsec: (*utime).tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
595+
let old_utime = if utime.is_null() {
596+
None
597+
} else {
598+
Some(linux_raw_sys::general::__kernel_old_timespec {
599+
tv_sec: (*utime).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
600+
tv_nsec: (*utime).tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
601+
})
526602
};
527603
ret_usize(futex(
528604
uaddr,
529605
op as i32 | flags.bits() as i32,
530606
val,
531-
&old_utime,
607+
old_utime
608+
.as_ref()
609+
.map(|r| r as *const linux_raw_sys::general::__kernel_old_timespec)
610+
.unwrap_or(core::ptr::null()),
532611
uaddr2,
533612
val3,
534613
) as isize)

src/backend/linux_raw/thread/futex.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
bitflags::bitflags! {
22
/// `FUTEX_*` flags for use with [`futex`].
33
///
4-
/// [`futex`]: crate::thread::futex
4+
/// [`futex`]: mod@crate::thread::futex
55
#[repr(transparent)]
66
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
77
pub struct FutexFlags: u32 {
@@ -18,7 +18,7 @@ bitflags::bitflags! {
1818

1919
/// `FUTEX_*` operations for use with [`futex`].
2020
///
21-
/// [`futex`]: crate::thread::futex
21+
/// [`futex`]: mod@crate::thread::futex
2222
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
2323
#[repr(u32)]
2424
pub enum FutexOperation {

src/backend/linux_raw/thread/syscalls.rs

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,47 @@ pub(crate) fn gettid() -> Pid {
205205
}
206206
}
207207

208-
// TODO: This could be de-multiplexed.
209208
#[inline]
210-
pub(crate) unsafe fn futex(
209+
pub(crate) unsafe fn futex_val2(
210+
uaddr: *const AtomicU32,
211+
op: FutexOperation,
212+
flags: FutexFlags,
213+
val: u32,
214+
val2: u32,
215+
uaddr2: *const AtomicU32,
216+
val3: u32,
217+
) -> io::Result<usize> {
218+
// the least significant four bytes of the timeout pointer are used as `val2`.
219+
// ["the kernel casts the timeout value first to unsigned long, then to uint32_t"](https://man7.org/linux/man-pages/man2/futex.2.html),
220+
// so we perform that exact conversion in reverse to create the pointer.
221+
let utime = val2 as usize as *const Timespec;
222+
223+
#[cfg(target_pointer_width = "32")]
224+
{
225+
ret_usize(syscall!(
226+
__NR_futex_time64,
227+
uaddr,
228+
(op, flags),
229+
c_uint(val),
230+
utime,
231+
uaddr2,
232+
c_uint(val3)
233+
))
234+
}
235+
#[cfg(target_pointer_width = "64")]
236+
ret_usize(syscall!(
237+
__NR_futex,
238+
uaddr,
239+
(op, flags),
240+
c_uint(val),
241+
utime,
242+
uaddr2,
243+
c_uint(val3)
244+
))
245+
}
246+
247+
#[inline]
248+
pub(crate) unsafe fn futex_timespec(
211249
uaddr: *const AtomicU32,
212250
op: FutexOperation,
213251
flags: FutexFlags,
@@ -231,7 +269,7 @@ pub(crate) unsafe fn futex(
231269
// See the comments in `rustix_clock_gettime_via_syscall` about
232270
// emulation.
233271
if err == io::Errno::NOSYS {
234-
futex_old(uaddr, op, flags, val, utime, uaddr2, val3)
272+
futex_old_timespec(uaddr, op, flags, val, utime, uaddr2, val3)
235273
} else {
236274
Err(err)
237275
}
@@ -250,7 +288,7 @@ pub(crate) unsafe fn futex(
250288
}
251289

252290
#[cfg(target_pointer_width = "32")]
253-
unsafe fn futex_old(
291+
unsafe fn futex_old_timespec(
254292
uaddr: *const AtomicU32,
255293
op: FutexOperation,
256294
flags: FutexFlags,
@@ -259,16 +297,23 @@ unsafe fn futex_old(
259297
uaddr2: *const AtomicU32,
260298
val3: u32,
261299
) -> io::Result<usize> {
262-
let old_utime = __kernel_old_timespec {
263-
tv_sec: (*utime).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
264-
tv_nsec: (*utime).tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
300+
let old_utime = if utime.is_null() {
301+
None
302+
} else {
303+
Some(__kernel_old_timespec {
304+
tv_sec: (*utime).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
305+
tv_nsec: (*utime).tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
306+
})
265307
};
266308
ret_usize(syscall!(
267309
__NR_futex,
268310
uaddr,
269311
(op, flags),
270312
c_uint(val),
271-
by_ref(&old_utime),
313+
old_utime
314+
.as_ref()
315+
.map(|r| r as *const __kernel_old_timespec)
316+
.unwrap_or(core::ptr::null()),
272317
uaddr2,
273318
c_uint(val3)
274319
))

0 commit comments

Comments
 (0)