Skip to content

Commit a360d54

Browse files
committed
Adds PI futex for FreeBSD
1 parent a1731ad commit a360d54

File tree

3 files changed

+161
-43
lines changed

3 files changed

+161
-43
lines changed
Lines changed: 157 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,171 @@
1-
#![cfg(any(target_os = "linux", target_os = "android"))]
1+
#[cfg(any(target_os = "linux", target_os = "android"))]
2+
mod linux {
3+
use crate::ops::Deref;
4+
use crate::sync::atomic::AtomicU32;
5+
use crate::sys::cvt;
6+
use crate::{io, ptr};
27

3-
use crate::sync::atomic::AtomicU32;
4-
use crate::sys::cvt;
5-
use crate::{io, ptr};
8+
pub type State = u32;
69

7-
pub const fn unlocked() -> u32 {
8-
0
9-
}
10+
pub struct Futex(AtomicU32);
1011

11-
pub fn locked() -> u32 {
12-
(unsafe { libc::gettid() }) as _
13-
}
12+
impl Futex {
13+
pub const fn new() -> Futex {
14+
Futex(AtomicU32::new(0))
15+
}
16+
}
1417

15-
pub fn is_contended(futex_val: u32) -> bool {
16-
(futex_val & libc::FUTEX_WAITERS) != 0
17-
}
18+
impl Deref for Futex {
19+
type Target = AtomicU32;
20+
fn deref(&self) -> &AtomicU32 {
21+
&self.0
22+
}
23+
}
1824

19-
pub fn is_owned_died(futex_val: u32) -> bool {
20-
(futex_val & libc::FUTEX_OWNER_DIED) != 0
21-
}
25+
pub const fn unlocked() -> State {
26+
0
27+
}
28+
29+
pub fn locked() -> State {
30+
(unsafe { libc::gettid() }) as _
31+
}
32+
33+
pub fn is_contended(futex_val: State) -> bool {
34+
(futex_val & libc::FUTEX_WAITERS) != 0
35+
}
2236

23-
pub fn futex_lock(futex: &AtomicU32) -> io::Result<()> {
24-
loop {
25-
match cvt(unsafe {
37+
pub fn is_owned_died(futex_val: State) -> bool {
38+
(futex_val & libc::FUTEX_OWNER_DIED) != 0
39+
}
40+
41+
pub fn futex_lock(futex: &Futex) -> io::Result<()> {
42+
loop {
43+
match cvt(unsafe {
44+
libc::syscall(
45+
libc::SYS_futex,
46+
ptr::from_ref(futex.deref()),
47+
libc::FUTEX_LOCK_PI | libc::FUTEX_PRIVATE_FLAG,
48+
0,
49+
ptr::null::<u32>(),
50+
// remaining args are unused
51+
)
52+
}) {
53+
Ok(_) => return Ok(()),
54+
Err(e) if e.raw_os_error() == Some(libc::EINTR) => continue,
55+
Err(e) => return Err(e),
56+
}
57+
}
58+
}
59+
60+
pub fn futex_unlock(futex: &Futex) -> io::Result<()> {
61+
cvt(unsafe {
2662
libc::syscall(
2763
libc::SYS_futex,
28-
ptr::from_ref(futex),
29-
libc::FUTEX_LOCK_PI | libc::FUTEX_PRIVATE_FLAG,
30-
0,
31-
ptr::null::<u32>(),
64+
ptr::from_ref(futex.deref()),
65+
libc::FUTEX_UNLOCK_PI | libc::FUTEX_PRIVATE_FLAG,
3266
// remaining args are unused
3367
)
34-
}) {
35-
Ok(_) => return Ok(()),
36-
Err(e) if e.raw_os_error() == Some(libc::EINTR) => continue,
37-
Err(e) => return Err(e),
38-
}
68+
})
69+
.map(|_| ())
3970
}
4071
}
4172

42-
pub fn futex_unlock(futex: &AtomicU32) -> io::Result<()> {
43-
cvt(unsafe {
44-
libc::syscall(
45-
libc::SYS_futex,
46-
ptr::from_ref(futex),
47-
libc::FUTEX_UNLOCK_PI | libc::FUTEX_PRIVATE_FLAG,
48-
// remaining args are unused
49-
)
50-
})
51-
.map(|_| ())
73+
#[cfg(any(target_os = "linux", target_os = "android"))]
74+
pub use linux::*;
75+
76+
#[cfg(target_os = "freebsd")]
77+
mod freebsd {
78+
use crate::mem::transmute;
79+
use crate::ops::Deref;
80+
use crate::sync::atomic::AtomicU32;
81+
use crate::sys::cvt;
82+
use crate::{io, ptr};
83+
84+
pub type State = u32;
85+
86+
#[repr(C)]
87+
pub struct umutex {
88+
m_owner: libc::lwpid_t,
89+
m_flags: u32,
90+
m_ceilings: [u32; 2],
91+
m_rb_link: libc::uintptr_t,
92+
#[cfg(target_pointer_width = "32")]
93+
m_pad: u32,
94+
m_spare: [u32; 2],
95+
}
96+
97+
pub struct Futex(umutex);
98+
99+
impl Futex {
100+
pub const fn new() -> Futex {
101+
Futex(umutex {
102+
m_owner: 0,
103+
m_flags: UMUTEX_PRIO_INHERIT,
104+
m_ceilings: [0, 0],
105+
m_rb_link: 0,
106+
#[cfg(target_pointer_width = "32")]
107+
m_pad: 0,
108+
m_spare: [0, 0],
109+
})
110+
}
111+
}
112+
113+
impl Deref for Futex {
114+
type Target = AtomicU32;
115+
fn deref(&self) -> &AtomicU32 {
116+
unsafe { transmute(&self.0.m_owner) }
117+
}
118+
}
119+
120+
const UMUTEX_PRIO_INHERIT: u32 = 0x0004;
121+
const UMUTEX_CONTESTED: u32 = 0x80000000;
122+
123+
pub const fn unlocked() -> State {
124+
0
125+
}
126+
127+
pub fn locked() -> State {
128+
let mut tid: libc::c_long = 0;
129+
let _ = unsafe { libc::thr_self(ptr::from_mut(&mut tid)) };
130+
tid as _
131+
}
132+
133+
pub fn is_contended(futex_val: State) -> bool {
134+
(futex_val & UMUTEX_CONTESTED) != 0
135+
}
136+
137+
pub fn is_owned_died(futex_val: State) -> bool {
138+
// never happens for non-robust mutex
139+
let _ = futex_val;
140+
false
141+
}
142+
143+
pub fn futex_lock(futex: &Futex) -> io::Result<()> {
144+
cvt(unsafe {
145+
libc::_umtx_op(
146+
ptr::from_ref(futex.deref()) as _,
147+
libc::UMTX_OP_MUTEX_LOCK,
148+
0,
149+
ptr::null_mut::<libc::c_void>(),
150+
ptr::null_mut::<libc::c_void>(),
151+
)
152+
})
153+
.map(|_| ())
154+
}
155+
156+
pub fn futex_unlock(futex: &Futex) -> io::Result<()> {
157+
cvt(unsafe {
158+
libc::_umtx_op(
159+
ptr::from_ref(futex.deref()) as _,
160+
libc::UMTX_OP_MUTEX_UNLOCK,
161+
0,
162+
ptr::null_mut::<libc::c_void>(),
163+
ptr::null_mut::<libc::c_void>(),
164+
)
165+
})
166+
.map(|_| ())
167+
}
52168
}
169+
170+
#[cfg(target_os = "freebsd")]
171+
pub use freebsd::*;

library/std/src/sys/sync/mutex/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ cfg_if::cfg_if! {
22
if #[cfg(any(
33
target_os = "linux",
44
target_os = "android",
5+
target_os = "freebsd",
56
))] {
67
mod pi_futex;
78
pub use pi_futex::Mutex;
89
} else if #[cfg(any(
910
all(target_os = "windows", not(target_vendor = "win7")),
10-
target_os = "freebsd",
1111
target_os = "openbsd",
1212
target_os = "dragonfly",
1313
all(target_family = "wasm", target_feature = "atomics"),

library/std/src/sys/sync/mutex/pi_futex.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
use crate::sync::atomic::AtomicU32;
21
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
32
use crate::sys::pi_futex as pi;
43

54
pub struct Mutex {
6-
futex: AtomicU32,
5+
futex: pi::Futex,
76
}
87

98
impl Mutex {
109
#[inline]
1110
pub const fn new() -> Self {
12-
Self { futex: AtomicU32::new(pi::unlocked()) }
11+
Self { futex: pi::Futex::new() }
1312
}
1413

1514
#[inline]
@@ -46,7 +45,7 @@ impl Mutex {
4645
}
4746
}
4847

49-
fn spin(&self) -> u32 {
48+
fn spin(&self) -> pi::State {
5049
let mut spin = 100;
5150
loop {
5251
// We only use `load` (and not `swap` or `compare_exchange`)

0 commit comments

Comments
 (0)