Skip to content

Commit 04b0bc9

Browse files
committed
Use futex-based locks and thread parker on FreeBSD.
1 parent 69f0bcb commit 04b0bc9

File tree

4 files changed

+60
-4
lines changed

4 files changed

+60
-4
lines changed

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

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
target_os = "linux",
33
target_os = "android",
44
all(target_os = "emscripten", target_feature = "atomics"),
5+
target_os = "freebsd",
56
target_os = "openbsd",
67
target_os = "netbsd",
78
target_os = "dragonfly",
@@ -18,7 +19,12 @@ pub const SYS___futex: i32 = 166;
1819
/// Returns directly if the futex doesn't hold the expected value.
1920
///
2021
/// Returns false on timeout, and true in all other cases.
21-
#[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
22+
#[cfg(any(
23+
target_os = "linux",
24+
target_os = "android",
25+
target_os = "freebsd",
26+
target_os = "netbsd"
27+
))]
2228
pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
2329
use super::time::Timespec;
2430
use crate::ptr::null;
@@ -40,7 +46,26 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
4046
// absolute time rather than a relative time.
4147
let r = unsafe {
4248
cfg_if::cfg_if! {
43-
if #[cfg(target_os = "netbsd")] {
49+
if #[cfg(target_os = "freebsd")] {
50+
// FreeBSD doesn't have futex(), but it has
51+
// _umtx_op(UMTX_OP_WAIT_UINT_PRIVATE), which is nearly
52+
// identical. It supports absolute timeouts through a flag
53+
// in the _umtx_time struct.
54+
let umtx_timeout = timespec.map(|t| libc::_umtx_time {
55+
_timeout: t.t,
56+
_flags: libc::UMTX_ABSTIME,
57+
_clockid: libc::CLOCK_MONOTONIC as u32,
58+
});
59+
let umtx_timeout_ptr = umtx_timeout.as_ref().map_or(null(), |t| t as *const _);
60+
let umtx_timeout_size = umtx_timeout.as_ref().map_or(0, |t| crate::mem::size_of_val(t));
61+
libc::_umtx_op(
62+
futex as *const AtomicU32 as *mut _,
63+
libc::UMTX_OP_WAIT_UINT_PRIVATE,
64+
expected as libc::c_ulong,
65+
crate::ptr::invalid_mut(umtx_timeout_size),
66+
umtx_timeout_ptr as *mut _,
67+
)
68+
} else if #[cfg(target_os = "netbsd")] {
4469
// Netbsd's futex syscall takes addr2 and val2 as separate arguments.
4570
// (Both are unused for FUTEX_WAIT[_BITSET].)
4671
libc::syscall(
@@ -110,6 +135,35 @@ pub fn futex_wake_all(futex: &AtomicU32) {
110135
}
111136
}
112137

138+
// FreeBSD doesn't tell us how many threads are woken up, so this doesn't return a bool.
139+
#[cfg(target_os = "freebsd")]
140+
pub fn futex_wake(futex: &AtomicU32) {
141+
use crate::ptr::null_mut;
142+
unsafe {
143+
libc::_umtx_op(
144+
futex as *const AtomicU32 as *mut _,
145+
libc::UMTX_OP_WAKE_PRIVATE,
146+
1,
147+
null_mut(),
148+
null_mut(),
149+
)
150+
};
151+
}
152+
153+
#[cfg(target_os = "freebsd")]
154+
pub fn futex_wake_all(futex: &AtomicU32) {
155+
use crate::ptr::null_mut;
156+
unsafe {
157+
libc::_umtx_op(
158+
futex as *const AtomicU32 as *mut _,
159+
libc::UMTX_OP_WAKE_PRIVATE,
160+
i32::MAX as libc::c_ulong,
161+
null_mut(),
162+
null_mut(),
163+
)
164+
};
165+
}
166+
113167
#[cfg(target_os = "openbsd")]
114168
pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
115169
use crate::convert::TryInto;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,8 @@ impl RwLock {
284284
fn wake_writer(&self) -> bool {
285285
self.writer_notify.fetch_add(1, Release);
286286
cfg_if::cfg_if! {
287-
if #[cfg(target_os = "dragonfly")] {
288-
// DragonFlyBSD doesn't tell us whether it woke up any threads or not.
287+
if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] {
288+
// FreeBSD and DragonFlyBSD don't tell us whether they woke up any threads or not.
289289
// So, we always return `false` here, as that still results in correct behaviour.
290290
// The downside is an extra syscall in case both readers and writers were waiting,
291291
// and unnecessarily waking up readers when a writer is about to attempt to lock the lock.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ cfg_if::cfg_if! {
33
target_os = "linux",
44
target_os = "android",
55
all(target_os = "emscripten", target_feature = "atomics"),
6+
target_os = "freebsd",
67
target_os = "openbsd",
78
target_os = "netbsd",
89
target_os = "dragonfly",

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ cfg_if::cfg_if! {
33
target_os = "linux",
44
target_os = "android",
55
all(target_arch = "wasm32", target_feature = "atomics"),
6+
target_os = "freebsd",
67
target_os = "openbsd",
78
target_os = "netbsd",
89
target_os = "dragonfly",

0 commit comments

Comments
 (0)