Skip to content

Commit 69f0bcb

Browse files
committed
Use futex-based locks and thread parker on DragonFlyBSD.
1 parent 2dfad1e commit 69f0bcb

File tree

4 files changed

+44
-1
lines changed

4 files changed

+44
-1
lines changed

library/std/src/sys/unix/futex.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
all(target_os = "emscripten", target_feature = "atomics"),
55
target_os = "openbsd",
66
target_os = "netbsd",
7+
target_os = "dragonfly",
78
))]
89

910
use crate::sync::atomic::AtomicU32;
@@ -158,6 +159,35 @@ pub fn futex_wake_all(futex: &AtomicU32) {
158159
}
159160
}
160161

162+
#[cfg(target_os = "dragonfly")]
163+
pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
164+
use crate::convert::TryFrom;
165+
let r = unsafe {
166+
libc::umtx_sleep(
167+
futex as *const AtomicU32 as *const i32,
168+
expected as i32,
169+
// A timeout of 0 means infinite, so we round smaller timeouts up to 1 millisecond.
170+
// Timeouts larger than i32::MAX milliseconds saturate.
171+
timeout.map_or(0, |d| {
172+
i32::try_from(d.as_millis()).map_or(i32::MAX, |millis| millis.max(1))
173+
}),
174+
)
175+
};
176+
177+
r == 0 || super::os::errno() != libc::ETIMEDOUT
178+
}
179+
180+
// DragonflyBSD doesn't tell us how many threads are woken up, so this doesn't return a bool.
181+
#[cfg(target_os = "dragonfly")]
182+
pub fn futex_wake(futex: &AtomicU32) {
183+
unsafe { libc::umtx_wakeup(futex as *const AtomicU32 as *const i32, 1) };
184+
}
185+
186+
#[cfg(target_os = "dragonfly")]
187+
pub fn futex_wake_all(futex: &AtomicU32) {
188+
unsafe { libc::umtx_wakeup(futex as *const AtomicU32 as *const i32, i32::MAX) };
189+
}
190+
161191
#[cfg(target_os = "emscripten")]
162192
extern "C" {
163193
fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;

library/std/src/sys/unix/locks/futex_rwlock.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,18 @@ impl RwLock {
283283
/// writer that was about to go to sleep.
284284
fn wake_writer(&self) -> bool {
285285
self.writer_notify.fetch_add(1, Release);
286-
futex_wake(&self.writer_notify)
286+
cfg_if::cfg_if! {
287+
if #[cfg(target_os = "dragonfly")] {
288+
// DragonFlyBSD doesn't tell us whether it woke up any threads or not.
289+
// So, we always return `false` here, as that still results in correct behaviour.
290+
// The downside is an extra syscall in case both readers and writers were waiting,
291+
// and unnecessarily waking up readers when a writer is about to attempt to lock the lock.
292+
futex_wake(&self.writer_notify);
293+
false
294+
} else {
295+
futex_wake(&self.writer_notify)
296+
}
297+
}
287298
}
288299

289300
/// Spin for a while, but stop directly at the given condition.

library/std/src/sys/unix/locks/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ cfg_if::cfg_if! {
55
all(target_os = "emscripten", target_feature = "atomics"),
66
target_os = "openbsd",
77
target_os = "netbsd",
8+
target_os = "dragonfly",
89
))] {
910
mod futex;
1011
mod futex_rwlock;

library/std/src/sys_common/thread_parker/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ cfg_if::cfg_if! {
55
all(target_arch = "wasm32", target_feature = "atomics"),
66
target_os = "openbsd",
77
target_os = "netbsd",
8+
target_os = "dragonfly",
89
))] {
910
mod futex;
1011
pub use futex::Parker;

0 commit comments

Comments
 (0)