blob: 4af90e4cdd15e06cafe9b82e9dd92907893f2223 [file] [log] [blame]
use std::io::{self, Error, ErrorKind};
use std::os::windows::io::{AsHandle, AsRawHandle};
use windows_sys::Win32::Foundation::ERROR_LOCK_VIOLATION;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Storage::FileSystem::{
LockFileEx, LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY,
};
use super::utils::{syscall, Overlapped};
use super::{RwLockReadGuard, RwLockWriteGuard};
#[derive(Debug)]
pub struct RwLock<T: AsHandle> {
pub(crate) inner: T,
}
impl<T: AsHandle> RwLock<T> {
#[inline]
pub fn new(inner: T) -> Self {
RwLock { inner }
}
#[inline]
pub fn read(&self) -> io::Result<RwLockReadGuard<'_, T>> {
// See: https://stackoverflow.com/a/9186532, https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfileex
let handle = self.inner.as_handle().as_raw_handle() as HANDLE;
let overlapped = Overlapped::zero();
let flags = 0;
syscall(unsafe { LockFileEx(handle, flags, 0, 1, 0, overlapped.raw()) })?;
Ok(RwLockReadGuard { lock: self })
}
#[inline]
pub fn try_read(&self) -> io::Result<RwLockReadGuard<'_, T>> {
let handle = self.inner.as_handle().as_raw_handle() as HANDLE;
let overlapped = Overlapped::zero();
let flags = LOCKFILE_FAIL_IMMEDIATELY;
syscall(unsafe { LockFileEx(handle, flags, 0, 1, 0, overlapped.raw()) }).map_err(
|error| match error.raw_os_error().map(|error_code| error_code as u32) {
Some(ERROR_LOCK_VIOLATION) => Error::from(ErrorKind::WouldBlock),
_ => error,
},
)?;
Ok(RwLockReadGuard { lock: self })
}
#[inline]
pub fn write(&mut self) -> io::Result<RwLockWriteGuard<'_, T>> {
// See: https://stackoverflow.com/a/9186532, https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfileex
let handle = self.inner.as_handle().as_raw_handle() as HANDLE;
let overlapped = Overlapped::zero();
let flags = LOCKFILE_EXCLUSIVE_LOCK;
syscall(unsafe { LockFileEx(handle, flags, 0, 1, 0, overlapped.raw()) })?;
Ok(RwLockWriteGuard { lock: self })
}
#[inline]
pub fn try_write(&mut self) -> io::Result<RwLockWriteGuard<'_, T>> {
let handle = self.inner.as_handle().as_raw_handle() as HANDLE;
let overlapped = Overlapped::zero();
let flags = LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK;
syscall(unsafe { LockFileEx(handle, flags, 0, 1, 0, overlapped.raw()) }).map_err(
|error| match error.raw_os_error().map(|error_code| error_code as u32) {
Some(ERROR_LOCK_VIOLATION) => Error::from(ErrorKind::WouldBlock),
_ => error,
},
)?;
Ok(RwLockWriteGuard { lock: self })
}
#[inline]
pub fn into_inner(self) -> T
where
T: Sized,
{
self.inner
}
}