Use futex-based locks and thread parker on FreeBSD.
This commit is contained in:
parent
69f0bcb26d
commit
04b0bc97bb
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user