use core::cell::UnsafeCell;
use wdk_sys::{
ntddk::{
ExAcquireResourceSharedLite, ExEnterCriticalRegionAndAcquireResourceExclusive,
ExInitializeResourceLite, ExReleaseResourceAndLeaveCriticalRegion, ExReleaseResourceLite,
},
ERESOURCE, NT_SUCCESS, _ERESOURCE,
};
extern crate alloc;
pub struct ExecutionBody<T> {
resource: _ERESOURCE,
data: UnsafeCell<T>,
}
unsafe impl<T: Send> Sync for ExecutionBody<T> {}
pub struct InitExecutionBodyError {}
impl<T> ExecutionBody<T> {
pub fn new(data: T) -> Result<Self, InitExecutionBodyError> {
let mut resource = ERESOURCE::default();
let status = unsafe { ExInitializeResourceLite(&mut resource as *mut _) };
if !NT_SUCCESS(status) {
return Err(InitExecutionBodyError {});
}
let r = ExecutionBody {
resource,
data: UnsafeCell::new(data),
};
Ok(r)
}
pub fn read(&self) -> ExecutionBodyReadGuard<T> {
unsafe { ExAcquireResourceSharedLite(&self.resource as *const _ as *mut _, 1) };
ExecutionBodyReadGuard { lock: self }
}
pub fn write(&self) -> ExecutionBodyWriteGuard<T> {
unsafe {
ExEnterCriticalRegionAndAcquireResourceExclusive(&self.resource as *const _ as *mut _)
};
ExecutionBodyWriteGuard { lock: self }
}
}
pub struct ExecutionBodyReadGuard<'a, T> {
lock: &'a ExecutionBody<T>,
}
impl<'a, T> core::ops::Deref for ExecutionBodyReadGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.lock.data.get() }
}
}
impl<'a, T> Drop for ExecutionBodyReadGuard<'a, T> {
fn drop(&mut self) {
unsafe { ExReleaseResourceLite(&self.lock.resource as *const _ as *mut _) };
}
}
pub struct ExecutionBodyWriteGuard<'a, T> {
lock: &'a ExecutionBody<T>,
}
impl<'a, T> core::ops::Deref for ExecutionBodyWriteGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.lock.data.get() }
}
}
impl<'a, T> core::ops::DerefMut for ExecutionBodyWriteGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.lock.data.get() }
}
}
impl<'a, T> Drop for ExecutionBodyWriteGuard<'a, T> {
fn drop(&mut self) {
unsafe {
ExReleaseResourceAndLeaveCriticalRegion(&self.lock.resource as *const _ as *mut _)
};
}
}