summaryrefslogtreecommitdiff
path: root/src/futex/windows.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/futex/windows.rs')
-rwxr-xr-xsrc/futex/windows.rs114
1 files changed, 114 insertions, 0 deletions
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
+ }
+}