Always return false in futex_wake on {Free,DragonFly}BSD.

This commit is contained in:
Mara Bos 2022-04-29 16:44:28 +02:00
parent 0b4df22f55
commit c4c69143a9
2 changed files with 13 additions and 16 deletions

View File

@ -104,6 +104,8 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
/// ///
/// Returns true if this actually woke up such a thread, /// Returns true if this actually woke up such a thread,
/// or false if no thread was waiting on this futex. /// or false if no thread was waiting on this futex.
///
/// On some platforms, this always returns false.
#[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))] #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
pub fn futex_wake(futex: &AtomicU32) -> bool { pub fn futex_wake(futex: &AtomicU32) -> bool {
let ptr = futex as *const AtomicU32; let ptr = futex as *const AtomicU32;
@ -135,9 +137,9 @@ pub fn futex_wake_all(futex: &AtomicU32) {
} }
} }
// FreeBSD doesn't tell us how many threads are woken up, so this doesn't return a bool. // FreeBSD doesn't tell us how many threads are woken up, so this always returns false.
#[cfg(target_os = "freebsd")] #[cfg(target_os = "freebsd")]
pub fn futex_wake(futex: &AtomicU32) { pub fn futex_wake(futex: &AtomicU32) -> bool {
use crate::ptr::null_mut; use crate::ptr::null_mut;
unsafe { unsafe {
libc::_umtx_op( libc::_umtx_op(
@ -148,6 +150,7 @@ pub fn futex_wake(futex: &AtomicU32) {
null_mut(), null_mut(),
) )
}; };
false
} }
#[cfg(target_os = "freebsd")] #[cfg(target_os = "freebsd")]
@ -231,10 +234,11 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
r == 0 || super::os::errno() != libc::ETIMEDOUT r == 0 || super::os::errno() != libc::ETIMEDOUT
} }
// DragonflyBSD doesn't tell us how many threads are woken up, so this doesn't return a bool. // DragonflyBSD doesn't tell us how many threads are woken up, so this always returns false.
#[cfg(target_os = "dragonfly")] #[cfg(target_os = "dragonfly")]
pub fn futex_wake(futex: &AtomicU32) { pub fn futex_wake(futex: &AtomicU32) -> bool {
unsafe { libc::umtx_wakeup(futex as *const AtomicU32 as *const i32, 1) }; unsafe { libc::umtx_wakeup(futex as *const AtomicU32 as *const i32, 1) };
false
} }
#[cfg(target_os = "dragonfly")] #[cfg(target_os = "dragonfly")]

View File

@ -283,18 +283,11 @@ impl RwLock {
/// writer that was about to go to sleep. /// writer that was about to go to sleep.
fn wake_writer(&self) -> bool { fn wake_writer(&self) -> bool {
self.writer_notify.fetch_add(1, Release); self.writer_notify.fetch_add(1, Release);
cfg_if::cfg_if! { futex_wake(&self.writer_notify)
if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { // Note that FreeBSD and DragonFlyBSD don't tell us whether they woke
// FreeBSD and DragonFlyBSD don't tell us whether they woke up any threads or not. // up any threads or not, and always return `false` here. That still
// So, we always return `false` here, as that still results in correct behaviour. // results in correct behaviour: it just means readers get woken up as
// The downside is an extra syscall in case both readers and writers were waiting, // well in case both readers and writers were waiting.
// and unnecessarily waking up readers when a writer is about to attempt to lock the lock.
futex_wake(&self.writer_notify);
false
} else {
futex_wake(&self.writer_notify)
}
}
} }
/// Spin for a while, but stop directly at the given condition. /// Spin for a while, but stop directly at the given condition.