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+ ) ) ]
2228pub 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" ) ]
114168pub fn futex_wait ( futex : & AtomicU32 , expected : u32 , timeout : Option < Duration > ) -> bool {
115169 use crate :: convert:: TryInto ;
0 commit comments