summaryrefslogtreecommitdiff
path: root/src/futex/windows.rs
blob: 153d9efd1a2f57f9222002e44cd4871daf440f58 (plain)
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
	}
}