Use futex-based locks and thread parker on DragonFlyBSD.

This commit is contained in:
Mara Bos 2022-04-28 11:28:40 +02:00
parent 2dfad1e3f8
commit 69f0bcb26d
4 changed files with 44 additions and 1 deletions

View file

@ -4,6 +4,7 @@
all(target_os = "emscripten", target_feature = "atomics"),
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
))]
use crate::sync::atomic::AtomicU32;
@ -158,6 +159,35 @@ pub fn futex_wake_all(futex: &AtomicU32) {
}
}
#[cfg(target_os = "dragonfly")]
pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
use crate::convert::TryFrom;
let r = unsafe {
libc::umtx_sleep(
futex as *const AtomicU32 as *const i32,
expected as i32,
// A timeout of 0 means infinite, so we round smaller timeouts up to 1 millisecond.
// Timeouts larger than i32::MAX milliseconds saturate.
timeout.map_or(0, |d| {
i32::try_from(d.as_millis()).map_or(i32::MAX, |millis| millis.max(1))
}),
)
};
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.
#[cfg(target_os = "dragonfly")]
pub fn futex_wake(futex: &AtomicU32) {
unsafe { libc::umtx_wakeup(futex as *const AtomicU32 as *const i32, 1) };
}
#[cfg(target_os = "dragonfly")]
pub fn futex_wake_all(futex: &AtomicU32) {
unsafe { libc::umtx_wakeup(futex as *const AtomicU32 as *const i32, i32::MAX) };
}
#[cfg(target_os = "emscripten")]
extern "C" {
fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;

View file

@ -283,8 +283,19 @@ impl RwLock {
/// writer that was about to go to sleep.
fn wake_writer(&self) -> bool {
self.writer_notify.fetch_add(1, Release);
cfg_if::cfg_if! {
if #[cfg(target_os = "dragonfly")] {
// DragonFlyBSD doesn't tell us whether it woke up any threads or not.
// So, we always return `false` here, as that still results in correct behaviour.
// The downside is an extra syscall 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.
fn spin_until(&self, f: impl Fn(u32) -> bool) -> u32 {

View file

@ -5,6 +5,7 @@ cfg_if::cfg_if! {
all(target_os = "emscripten", target_feature = "atomics"),
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
))] {
mod futex;
mod futex_rwlock;

View file

@ -5,6 +5,7 @@ cfg_if::cfg_if! {
all(target_arch = "wasm32", target_feature = "atomics"),
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
))] {
mod futex;
pub use futex::Parker;