Skip to content

Commit a92c89f

Browse files
authored
Fix compatibility with older 32-bit kernels (#1374)
* Fix handling of negative timestamps in `stat` on Linux. Some Linux `stat64` structs are defined with `st_atime`, `st_mtime`, and `st_ctime` fields using unsigned types, even though they hold signed values. Convert them to signed before converting them to `i64`, so that they're signed-extended. This fixes test failures on old 32-bit Linux platforms which lack `statx`. * Fix select fallback for 32-bit platforms. * Add a "linux_5_1" feature for specializing for Linux >= 5.1. * Fix `test_vdso` to handle older kernel versions on x86 and powerpc. * Fix poll, select, epoll_wait, and futex for 32-bit platforms. Handle kernel versions that lack _time64 syscalls. And change all timeouts to `Option<&Timepsec>`, for efficiency and consistency. * Use `opt_ref` for passing optional references to syscalls. * Fix `Timespec` layout on Windows to match `Nsecs`. * Convert kernel_sigtimedwait to use timeouts like poll/etc.
1 parent 7592cd6 commit a92c89f

File tree

15 files changed

+486
-241
lines changed

15 files changed

+486
-241
lines changed

CHANGES.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,22 @@ fields are `tv_sec` which holds seconds and `tv_nsec` which holds nanoseconds.
140140
[`rustix::event::epoll`]: https://docs.rs/rustix/1.0.0/rustix/event/epoll/index.html
141141
[`Timespec`]: https://docs.rs/rustix/1.0.0/rustix/time/struct.Timespec.html
142142

143+
The timeout argument in [`rustix::thread::futex::wait`],
144+
[`rustix::thread::futex::lock_pi`], [`rustix::thread::futex::wait_bitset`],
145+
[`rustix::thread::futex::wait_requeue_pi`], and
146+
[`rustix::thread::futex::lock_pi2`] changed from `Option<Timespec>` to
147+
`Option<&Timespec>`, for consistency with the rest of rustix's API, and for
148+
low-level efficiency, as it means the implementation doesn't need to make a
149+
copy of the `Timespec` to take its address. An easy way to convert an
150+
`Option<Timespec>` to an `Option<&Timespec> is to use [`Option::as_ref`].
151+
152+
[`rustix::thread::futex::wait`]: https://docs.rs/rustix/1.0.0/rustix/thread/futex/fn.wait.html
153+
[`rustix::thread::futex::lock_pi`]: https://docs.rs/rustix/1.0.0/rustix/thread/futex/fn.lock_pi.html
154+
[`rustix::thread::futex::wait_bitset`]: https://docs.rs/rustix/1.0.0/rustix/thread/futex/fn.wait_bitset.html
155+
[`rustix::thread::futex::wait_requeue_pi`]: https://docs.rs/rustix/1.0.0/rustix/thread/futex/fn.wait_requeue_pi.html
156+
[`rustix::thread::futex::lock_pi2`]: https://docs.rs/rustix/1.0.0/rustix/thread/futex/fn.lock_pi2.html
157+
[`Option::as_ref`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.as_ref
158+
143159
Functions in [`rustix::event::port`] are renamed to remove the redundant
144160
`port_*` prefix.
145161

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,11 @@ use-explicitly-provided-auxv = []
211211
# Specialize for Linux 4.11 or later
212212
linux_4_11 = []
213213

214+
# Specialize for Linux 5.1 or later
215+
linux_5_1 = ["linux_4_11"]
216+
214217
# Specialize for Linux 5.11 or later
215-
linux_5_11 = ["linux_4_11"]
218+
linux_5_11 = ["linux_5_1"]
216219

217220
# Enable all specializations for the latest Linux versions.
218221
linux_latest = ["linux_5_11"]

src/backend/libc/event/syscalls.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -572,14 +572,12 @@ pub(crate) unsafe fn epoll_wait(
572572
// If we're on Linux >= 5.11, use `epoll_pwait2` via `libc::syscall`.
573573
#[cfg(all(linux_kernel, feature = "linux_5_11"))]
574574
{
575-
use linux_raw_sys::general::__kernel_timespec as timespec;
576-
577575
syscall! {
578576
fn epoll_pwait2(
579577
epfd: c::c_int,
580578
events: *mut c::epoll_event,
581579
maxevents: c::c_int,
582-
timeout: *const timespec,
580+
timeout: *const Timespec,
583581
sigmask: *const c::sigset_t
584582
) via SYS_epoll_pwait2 -> c::c_int
585583
}

src/backend/libc/thread/syscalls.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ pub(crate) unsafe fn futex_val2(
505505
uaddr: *const AtomicU32,
506506
futex_op: c::c_int,
507507
val: u32,
508-
timeout: *const linux_raw_sys::general::__kernel_timespec,
508+
timeout: *const Timespec,
509509
uaddr2: *const AtomicU32,
510510
val3: u32
511511
) via SYS_futex -> c::c_long
@@ -531,7 +531,7 @@ pub(crate) unsafe fn futex_timeout(
531531
op: super::futex::Operation,
532532
flags: futex::Flags,
533533
val: u32,
534-
timeout: *const Timespec,
534+
timeout: Option<&Timespec>,
535535
uaddr2: *const AtomicU32,
536536
val3: u32,
537537
) -> io::Result<usize> {
@@ -559,7 +559,7 @@ pub(crate) unsafe fn futex_timeout(
559559
uaddr,
560560
op as i32 | flags.bits() as i32,
561561
val,
562-
timeout,
562+
option_as_ptr(timeout),
563563
uaddr2,
564564
val3,
565565
))
@@ -584,7 +584,7 @@ pub(crate) unsafe fn futex_timeout(
584584
uaddr: *const AtomicU32,
585585
futex_op: c::c_int,
586586
val: u32,
587-
timeout: *const linux_raw_sys::general::__kernel_timespec,
587+
timeout: *const Timespec,
588588
uaddr2: *const AtomicU32,
589589
val3: u32
590590
) via SYS_futex -> c::c_long
@@ -594,7 +594,7 @@ pub(crate) unsafe fn futex_timeout(
594594
uaddr,
595595
op as i32 | flags.bits() as i32,
596596
val,
597-
timeout.cast(),
597+
option_as_ptr(timeout).cast(),
598598
uaddr2,
599599
val3,
600600
) as isize)
@@ -614,7 +614,7 @@ unsafe fn futex_old_timespec(
614614
op: super::futex::Operation,
615615
flags: futex::Flags,
616616
val: u32,
617-
timeout: *const Timespec,
617+
timeout: Option<&Timespec>,
618618
uaddr2: *const AtomicU32,
619619
val3: u32,
620620
) -> io::Result<usize> {
@@ -629,16 +629,16 @@ unsafe fn futex_old_timespec(
629629
) via SYS_futex -> c::c_long
630630
}
631631

632-
let old_timeout = if timeout.is_null() {
633-
None
634-
} else {
632+
let old_timeout = if let Some(timeout) = timeout {
635633
Some(linux_raw_sys::general::__kernel_old_timespec {
636634
tv_sec: (*timeout).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
637635
tv_nsec: (*timeout)
638636
.tv_nsec
639637
.try_into()
640638
.map_err(|_| io::Errno::INVAL)?,
641639
})
640+
} else {
641+
None
642642
};
643643
ret_usize(futex(
644644
uaddr,
@@ -658,22 +658,19 @@ pub(crate) fn futex_waitv(
658658
clockid: ClockId,
659659
) -> io::Result<usize> {
660660
use futex::Wait as FutexWait;
661-
use linux_raw_sys::general::{__kernel_clockid_t as clockid_t, __kernel_timespec as timespec};
661+
use linux_raw_sys::general::__kernel_clockid_t as clockid_t;
662662
syscall! {
663663
fn futex_waitv(
664664
waiters: *const FutexWait,
665665
nr_futexes: c::c_uint,
666666
flags: c::c_uint,
667-
timeout: *const timespec,
667+
timeout: *const Timespec,
668668
clockid: clockid_t
669669
) via SYS_futex_waitv -> c::c_int
670670
}
671671

672672
let nr_futexes: c::c_uint = waiters.len().try_into().map_err(|_| io::Errno::INVAL)?;
673673

674-
#[cfg(test)]
675-
assert_eq_size!(timespec, Timespec);
676-
677674
unsafe {
678675
ret_c_int(futex_waitv(
679676
waiters.as_ptr(),

src/backend/libc/winsock_c.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,6 @@ pub(crate) use WinSock::{
6262
// in its public API. So define one, and we'll convert it internally.
6363
pub struct timespec {
6464
pub tv_sec: time_t,
65-
pub tv_nsec: i64,
65+
pub tv_nsec: crate::ffi::c_long,
6666
}
6767
pub type time_t = i64;

0 commit comments

Comments
 (0)