From 87299298d925af0943c94d2cc5bb8a2711d9f6b4 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Mar 2022 09:51:48 +0100 Subject: Use FUTEX_WAIT_BITSET rather than FUTEX_WAIT on Linux. --- library/std/src/sys/unix/futex.rs | 56 ++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 22 deletions(-) (limited to 'library/std/src/sys/unix/futex.rs') diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs index cc6da97ec73..adb661d877b 100644 --- a/library/std/src/sys/unix/futex.rs +++ b/library/std/src/sys/unix/futex.rs @@ -4,33 +4,45 @@ all(target_os = "emscripten", target_feature = "atomics") ))] -#[cfg(any(target_os = "linux", target_os = "android"))] -use crate::convert::TryInto; -#[cfg(any(target_os = "linux", target_os = "android"))] -use crate::ptr::null; use crate::sync::atomic::AtomicI32; use crate::time::Duration; #[cfg(any(target_os = "linux", target_os = "android"))] pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option) -> bool { - let timespec = timeout.and_then(|d| { - Some(libc::timespec { - // Sleep forever if the timeout is longer than fits in a timespec. - tv_sec: d.as_secs().try_into().ok()?, - // This conversion never truncates, as subsec_nanos is always <1e9. - tv_nsec: d.subsec_nanos() as _, - }) - }); - let r = unsafe { - libc::syscall( - libc::SYS_futex, - futex as *const AtomicI32, - libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG, - expected, - timespec.as_ref().map_or(null(), |d| d as *const libc::timespec), - ) - }; - !(r < 0 && super::os::errno() == libc::ETIMEDOUT) + use super::time::Instant; + use crate::ptr::null; + use crate::sync::atomic::Ordering::Relaxed; + + // Calculate the timeout as an absolute timespec. + let timespec = + timeout.and_then(|d| Some(Instant::now().checked_add_duration(&d)?.as_timespec())); + + loop { + // No need to wait if the value already changed. + if futex.load(Relaxed) != expected { + return true; + } + + // Use FUTEX_WAIT_BITSET rather than FUTEX_WAIT to be able to give an + // absolute time rather than a relative time. + let r = unsafe { + libc::syscall( + libc::SYS_futex, + futex as *const AtomicI32, + libc::FUTEX_WAIT_BITSET | libc::FUTEX_PRIVATE_FLAG, + expected, + timespec.as_ref().map_or(null(), |d| d as *const libc::timespec), + null::(), // This argument is unused for FUTEX_WAIT_BITSET. + !0u32, // A full bitmask, to make it behave like a regular FUTEX_WAIT. + ) + }; + + match (r < 0).then(super::os::errno) { + Some(libc::ETIMEDOUT) => return false, + Some(libc::EINTR) => continue, + _ => return true, + } + } } #[cfg(target_os = "emscripten")] -- cgit 1.4.1-3-g733a5