diff options
| author | Mara Bos <m-ou.se@m-ou.se> | 2022-04-28 12:22:14 +0200 |
|---|---|---|
| committer | Mara Bos <m-ou.se@m-ou.se> | 2022-04-29 16:45:17 +0200 |
| commit | 04b0bc97bb84915f2487743b7dde7993ddb34e5d (patch) | |
| tree | 490ccb048c9dce0eb555e6a4a56ad9bfc075bf05 /library/std/src | |
| parent | 69f0bcb26def1bccdf3774fc487201258b746fca (diff) | |
| download | rust-04b0bc97bb84915f2487743b7dde7993ddb34e5d.tar.gz rust-04b0bc97bb84915f2487743b7dde7993ddb34e5d.zip | |
Use futex-based locks and thread parker on FreeBSD.
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/sys/unix/futex.rs | 58 | ||||
| -rw-r--r-- | library/std/src/sys/unix/locks/futex_rwlock.rs | 4 | ||||
| -rw-r--r-- | library/std/src/sys/unix/locks/mod.rs | 1 | ||||
| -rw-r--r-- | library/std/src/sys_common/thread_parker/mod.rs | 1 |
4 files changed, 60 insertions, 4 deletions
diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs index cfb2d1f07de..4f91d48f2f0 100644 --- a/library/std/src/sys/unix/futex.rs +++ b/library/std/src/sys/unix/futex.rs @@ -2,6 +2,7 @@ target_os = "linux", target_os = "android", all(target_os = "emscripten", target_feature = "atomics"), + target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly", @@ -18,7 +19,12 @@ pub const SYS___futex: i32 = 166; /// Returns directly if the futex doesn't hold the expected value. /// /// Returns false on timeout, and true in all other cases. -#[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))] +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd" +))] pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool { use super::time::Timespec; use crate::ptr::null; @@ -40,7 +46,26 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) - // absolute time rather than a relative time. let r = unsafe { cfg_if::cfg_if! { - if #[cfg(target_os = "netbsd")] { + if #[cfg(target_os = "freebsd")] { + // FreeBSD doesn't have futex(), but it has + // _umtx_op(UMTX_OP_WAIT_UINT_PRIVATE), which is nearly + // identical. It supports absolute timeouts through a flag + // in the _umtx_time struct. + let umtx_timeout = timespec.map(|t| libc::_umtx_time { + _timeout: t.t, + _flags: libc::UMTX_ABSTIME, + _clockid: libc::CLOCK_MONOTONIC as u32, + }); + let umtx_timeout_ptr = umtx_timeout.as_ref().map_or(null(), |t| t as *const _); + let umtx_timeout_size = umtx_timeout.as_ref().map_or(0, |t| crate::mem::size_of_val(t)); + libc::_umtx_op( + futex as *const AtomicU32 as *mut _, + libc::UMTX_OP_WAIT_UINT_PRIVATE, + expected as libc::c_ulong, + crate::ptr::invalid_mut(umtx_timeout_size), + umtx_timeout_ptr as *mut _, + ) + } else if #[cfg(target_os = "netbsd")] { // Netbsd's futex syscall takes addr2 and val2 as separate arguments. // (Both are unused for FUTEX_WAIT[_BITSET].) libc::syscall( @@ -110,6 +135,35 @@ 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. +#[cfg(target_os = "freebsd")] +pub fn futex_wake(futex: &AtomicU32) { + use crate::ptr::null_mut; + unsafe { + libc::_umtx_op( + futex as *const AtomicU32 as *mut _, + libc::UMTX_OP_WAKE_PRIVATE, + 1, + null_mut(), + null_mut(), + ) + }; +} + +#[cfg(target_os = "freebsd")] +pub fn futex_wake_all(futex: &AtomicU32) { + use crate::ptr::null_mut; + unsafe { + libc::_umtx_op( + futex as *const AtomicU32 as *mut _, + libc::UMTX_OP_WAKE_PRIVATE, + i32::MAX as libc::c_ulong, + null_mut(), + null_mut(), + ) + }; +} + #[cfg(target_os = "openbsd")] pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool { use crate::convert::TryInto; diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs index 8829ed4db25..9c698f89b0d 100644 --- a/library/std/src/sys/unix/locks/futex_rwlock.rs +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -284,8 +284,8 @@ impl RwLock { 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. + if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { + // FreeBSD and DragonFlyBSD don't tell us whether they 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. diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs index d39da200dda..27d007a1051 100644 --- a/library/std/src/sys/unix/locks/mod.rs +++ b/library/std/src/sys/unix/locks/mod.rs @@ -3,6 +3,7 @@ cfg_if::cfg_if! { target_os = "linux", target_os = "android", all(target_os = "emscripten", target_feature = "atomics"), + target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly", diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs index 7fd4d3610ca..5305f1f2dee 100644 --- a/library/std/src/sys_common/thread_parker/mod.rs +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -3,6 +3,7 @@ cfg_if::cfg_if! { target_os = "linux", target_os = "android", all(target_arch = "wasm32", target_feature = "atomics"), + target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly", |
