2
2
target_os = "linux" ,
3
3
target_os = "android" ,
4
4
all( target_os = "emscripten" , target_feature = "atomics" ) ,
5
+ target_os = "freebsd" ,
5
6
target_os = "openbsd" ,
6
7
target_os = "netbsd" ,
7
8
target_os = "dragonfly" ,
@@ -18,7 +19,12 @@ pub const SYS___futex: i32 = 166;
18
19
/// Returns directly if the futex doesn't hold the expected value.
19
20
///
20
21
/// 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
+ ) ) ]
22
28
pub fn futex_wait ( futex : & AtomicU32 , expected : u32 , timeout : Option < Duration > ) -> bool {
23
29
use super :: time:: Timespec ;
24
30
use crate :: ptr:: null;
@@ -40,7 +46,26 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
40
46
// absolute time rather than a relative time.
41
47
let r = unsafe {
42
48
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" ) ] {
44
69
// Netbsd's futex syscall takes addr2 and val2 as separate arguments.
45
70
// (Both are unused for FUTEX_WAIT[_BITSET].)
46
71
libc:: syscall(
@@ -110,6 +135,35 @@ pub fn futex_wake_all(futex: &AtomicU32) {
110
135
}
111
136
}
112
137
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
+
113
167
#[ cfg( target_os = "openbsd" ) ]
114
168
pub fn futex_wait ( futex : & AtomicU32 , expected : u32 , timeout : Option < Duration > ) -> bool {
115
169
use crate :: convert:: TryInto ;
0 commit comments