diff options
Diffstat (limited to 'src/futex')
| -rwxr-xr-x | src/futex/linux.rs | 61 | ||||
| -rwxr-xr-x | src/futex/windows.rs | 114 |
2 files changed, 175 insertions, 0 deletions
diff --git a/src/futex/linux.rs b/src/futex/linux.rs new file mode 100755 index 0000000..80ca5a6 --- /dev/null +++ b/src/futex/linux.rs @@ -0,0 +1,61 @@ +use core::ops::Deref; +use core::sync::atomic::{AtomicU32, Ordering}; + +use libc::{syscall, SYS_futex}; + +#[repr(C)] +pub struct Futex(AtomicU32); + +pub type Atomic = AtomicU32; +pub type Primitive = u32; + +pub type SmallFutex = Futex; +pub type SmallAtomic = Atomic; +pub type SmallPrimitive = Primitive; + +impl Futex { + #[inline] + pub const fn new(initial_value: u32) -> Self { + Self(AtomicU32::new(initial_value)) + } + + #[inline] + pub fn wait(&self, expected_start_value: u32) { + unsafe { + syscall( + SYS_futex, + core::ptr::from_ref(&self.0), + libc::FUTEX_WAIT_BITSET | libc::FUTEX_PRIVATE_FLAG, + expected_start_value, + core::ptr::null::<()>(), + core::ptr::null::<u32>(), // This argument is unused for FUTEX_WAIT_BITSET. + !0u32, // A full bitmask, to make it behave like a regular FUTEX_WAIT. + ); + } + } + + #[inline] + pub fn wake(&self) -> bool { + let ptr = &self.0 as *const AtomicU32; + const OP: libc::c_int = libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG; + unsafe { libc::syscall(libc::SYS_futex, ptr, OP, 1) > 0 } + } + + #[inline] + pub fn wake_all(&self) { + let ptr = &raw const self.0; + let op = libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG; + unsafe { + syscall(libc::SYS_futex, ptr, op, i32::MAX); + } + } +} + +impl Deref for Futex { + type Target = Atomic; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/src/futex/windows.rs b/src/futex/windows.rs new file mode 100755 index 0000000..153d9ef --- /dev/null +++ b/src/futex/windows.rs @@ -0,0 +1,114 @@ +use core::ffi::c_void; + +#[cfg(not(target_vendor = "win7"))] +// Use raw-dylib to import synchronization functions to workaround issues with the older mingw import library. +#[cfg_attr( + target_arch = "x86", + link( + name = "api-ms-win-core-synch-l1-2-0", + kind = "raw-dylib", + import_name_type = "undecorated" + ) +)] +#[cfg_attr( + not(target_arch = "x86"), + link(name = "api-ms-win-core-synch-l1-2-0", kind = "raw-dylib") +)] +extern "system" { + type BOOL = i32; + + pub const TRUE: BOOL = 1; + pub const INFINITE: u32 = 4294967295; + + pub fn WaitOnAddress( + address: *const c_void, + compareaddress: *const c_void, + addresssize: usize, + dwmilliseconds: u32, + ) -> BOOL; + pub fn WakeByAddressSingle(address: *const c_void); + pub fn WakeByAddressAll(address: *const c_void); +} + +pub struct Futex(AtomicU32); +pub type Primitive = u32; + +impl Futex { + #[inline] + pub const fn new(initial_value: Primitive) -> Self { + Self(AtomicU32::new(initial_value)) + } + + #[inline] + pub fn wait(&self, expected_start_value: Primitive) { + const SIZE: u32 = core::mem::size_of::<Atomic>(); + let addr = core::ptr::from_ref(&self.0).cast::<c_void>(); + let compare_addr = ptr::addr_of!(compare).cast::<c_void>(); + WaitOnAddress(addr, expected_start_value, SIZE, INFINITE); + } + + #[inline] + pub fn wake(&self) -> bool { + WakeByAddressSingle(core::ptr::from_ref(&self.0).cast::<c_void>()); + false + } + + #[inline] + pub fn wake_all(&self) { + unsafe { + let addr = core::ptr::from_ref(address).cast::<c_void>(); + WakeByAddressAll(addr); + } + } +} + +impl Deref for Futex { + type Target = Atomic; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub struct SmallFutex(AtomicU8); +pub type SmallAtomic = AtomicU8; +pub type SmallPrimitive = u8; + +impl SmallFutex { + #[inline] + pub const fn new(initial_value: SmallPrimitive) -> Self { + Self(AtomicU32::new(initial_value)) + } + + #[inline] + pub fn wait(&self, expected_start_value: SmallPrimitive) { + const SIZE: u32 = core::mem::size_of::<SmallAtomic>(); + let addr = core::ptr::from_ref(&self.0).cast::<c_void>(); + let compare_addr = ptr::addr_of!(compare).cast::<c_void>(); + WaitOnAddress(addr, expected_start_value, SIZE, INFINITE); + } + + #[inline] + pub fn wake(&self) -> bool { + WakeByAddressSingle(core::ptr::from_ref(&self.0).cast::<c_void>()); + false + } + + #[inline] + pub fn wake_all(&self) { + unsafe { + let addr = core::ptr::from_ref(address).cast::<c_void>(); + WakeByAddressAll(addr); + } + } +} + +impl Deref for SmallFutex { + type Target = SmallAtomic; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} |
