about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMara Bos <m-ou.se@m-ou.se>2022-04-28 11:28:40 +0200
committerMara Bos <m-ou.se@m-ou.se>2022-04-29 16:30:54 +0200
commit69f0bcb26def1bccdf3774fc487201258b746fca (patch)
treebe4309b7295a8f2f31ccb446f0f86bd0e726f2f3
parent2dfad1e3f81d649124bba15f96fd8e96431cd4fc (diff)
downloadrust-69f0bcb26def1bccdf3774fc487201258b746fca.tar.gz
rust-69f0bcb26def1bccdf3774fc487201258b746fca.zip
Use futex-based locks and thread parker on DragonFlyBSD.
-rw-r--r--library/std/src/sys/unix/futex.rs30
-rw-r--r--library/std/src/sys/unix/locks/futex_rwlock.rs13
-rw-r--r--library/std/src/sys/unix/locks/mod.rs1
-rw-r--r--library/std/src/sys_common/thread_parker/mod.rs1
4 files changed, 44 insertions, 1 deletions
diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs
index 64ed146b036..cfb2d1f07de 100644
--- a/library/std/src/sys/unix/futex.rs
+++ b/library/std/src/sys/unix/futex.rs
@@ -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;
diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs
index e42edb25858..8829ed4db25 100644
--- a/library/std/src/sys/unix/locks/futex_rwlock.rs
+++ b/library/std/src/sys/unix/locks/futex_rwlock.rs
@@ -283,7 +283,18 @@ impl RwLock {
     /// writer that was about to go to sleep.
     fn wake_writer(&self) -> bool {
         self.writer_notify.fetch_add(1, Release);
-        futex_wake(&self.writer_notify)
+        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.
diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs
index 61fc0d5841d..d39da200dda 100644
--- a/library/std/src/sys/unix/locks/mod.rs
+++ b/library/std/src/sys/unix/locks/mod.rs
@@ -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;
diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs
index 4ff76aea23d..7fd4d3610ca 100644
--- a/library/std/src/sys_common/thread_parker/mod.rs
+++ b/library/std/src/sys_common/thread_parker/mod.rs
@@ -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;