diff options
| author | Mara Bos <m-ou.se@m-ou.se> | 2022-03-24 09:51:48 +0100 |
|---|---|---|
| committer | Mara Bos <m-ou.se@m-ou.se> | 2022-03-24 09:51:48 +0100 |
| commit | 87299298d925af0943c94d2cc5bb8a2711d9f6b4 (patch) | |
| tree | 71dcc832b7243a62c4367410a0889119de7098bb /library/std/src/sys/unix | |
| parent | da4ef044c1d0e8e58f2ab18459208469110c04be (diff) | |
| download | rust-87299298d925af0943c94d2cc5bb8a2711d9f6b4.tar.gz rust-87299298d925af0943c94d2cc5bb8a2711d9f6b4.zip | |
Use FUTEX_WAIT_BITSET rather than FUTEX_WAIT on Linux.
Diffstat (limited to 'library/std/src/sys/unix')
| -rw-r--r-- | library/std/src/sys/unix/futex.rs | 56 | ||||
| -rw-r--r-- | library/std/src/sys/unix/time.rs | 4 |
2 files changed, 38 insertions, 22 deletions
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<Duration>) -> 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::<u32>(), // 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")] diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 59ddd1aa92f..64c249f33eb 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -299,6 +299,10 @@ mod inner { pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> { Some(Instant { t: self.t.checked_sub_duration(other)? }) } + + pub(in crate::sys::unix) fn as_timespec(&self) -> libc::timespec { + self.t.t + } } impl fmt::Debug for Instant { |
