summaryrefslogtreecommitdiff
path: root/src/windows7.rs
blob: 2007d059697ce42325d9b416cb63b246e4d3e4cf (plain)
use core::cell::UnsafeCell;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct SrwLock {
	ptr: *mut core::ffi::c_void,
}

const SRWLOCK_INIT: SrwLock = SrwLock {
	ptr: core::ptr::null_mut(),
};

type Boolean = u8;

#[link(name = "kernel32")]
extern "system" {
	pub fn AcquireSRWLockShared(srwlock: *mut SrwLock);
	pub fn AcquireSRWLockExclusive(srwlock: *mut SrwLock);
	pub fn TryAcquireSRWLockShared(srwlock: *mut SrwLock) -> Boolean;
	pub fn TryAcquireSRWLockExclusive(srwlock: *mut SrwLock) -> Boolean;
	pub fn ReleaseSRWLockShared(srwlock: *mut SrwLock);
	pub fn ReleaseSRWLockExclusive(srwlock: *mut SrwLock);
}

pub struct Mutex(UnsafeCell<SrwLock>);

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

impl Mutex {
	#[inline]
	pub const fn new() -> Self {
		Self(UnsafeCell::new(SRWLOCK_INIT))
	}

	/// Locks the mutex
	///
	/// # Safety
	///
	/// UB occurs if the mutex is already locked by the current thread and the
	/// `unsafe_lock` feature is enabled.
	#[inline]
	pub unsafe fn lock(&self) {
		unsafe {
			AcquireSRWLockExclusive(self.0.get());
		}
	}

	/// If the mutex is unlocked, it is locked, and this function returns
	/// `true'. Otherwise, `false` is returned.
	#[inline]
	pub unsafe fn try_lock(&self) -> bool {
		unsafe { TryAcquireSRWLockExclusive(self.0.get()) != 0 }
	}

	/// Unlocks the mutex
	///
	/// # Safety
	///
	/// UB occurs if the mutex is already unlocked or if it has been locked on
	/// a different thread.
	#[inline]
	pub unsafe fn unlock(&self) {
		unsafe {
			ReleaseSRWLockExclusive(self.0.get());
		}
	}

	pub unsafe fn is_locked(&self) -> bool {
		if self.try_lock() {
			unsafe {
				self.unlock();
			}
			false
		} else {
			true
		}
	}
}

pub struct RwLock {
	inner: UnsafeCell<c::SRWLOCK>,
}

unsafe impl Send for RwLock {}
unsafe impl Sync for RwLock {}

impl RwLock {
	#[inline]
	pub const fn new() -> RwLock {
		RwLock {
			inner: UnsafeCell::new(c::SRWLOCK_INIT),
		}
	}
	#[inline]
	pub fn read(&self) {
		unsafe { c::AcquireSRWLockShared(self.inner.get()) }
	}
	#[inline]
	pub fn try_read(&self) -> bool {
		unsafe { c::TryAcquireSRWLockShared(self.inner.get()) != 0 }
	}
	#[inline]
	pub fn write(&self) {
		unsafe { c::AcquireSRWLockExclusive(self.inner.get()) }
	}
	#[inline]
	pub fn try_write(&self) -> bool {
		unsafe { c::TryAcquireSRWLockExclusive(self.inner.get()) != 0 }
	}
	#[inline]
	pub unsafe fn read_unlock(&self) {
		c::ReleaseSRWLockShared(self.inner.get())
	}
	#[inline]
	pub unsafe fn write_unlock(&self) {
		c::ReleaseSRWLockExclusive(self.inner.get())
	}
}