use core::{ops::Deref, ptr::{drop_in_place, write}, sync::atomic::AtomicUsize};
use wdk::println;
use wdk_sys::{ntddk::{ExAllocatePool2, ExFreePool}, POOL_FLAG_NON_PAGED};
use crate::errors::DriverMutexError;
#[derive(Debug)]
pub struct ArcNP<T> {
ptr: *mut ArcInner<T>,
}
#[repr(C, align(8))]
#[derive(Debug)]
struct ArcInner<T> {
refcount: AtomicUsize,
data: T,
}
impl<T> ArcNP<T> {
pub fn new(data: T, tag: u32) -> Result<Self, DriverMutexError> {
let inner_size = size_of::<ArcInner<T>>();
let mem = unsafe {
ExAllocatePool2(POOL_FLAG_NON_PAGED, inner_size as u64, tag)
};
if mem.is_null() {
return Err(DriverMutexError::PagedPoolAllocFailed);
}
let ptr = mem as *mut ArcInner<T>;
unsafe {
write(
ptr,
ArcInner {
refcount: AtomicUsize::new(1),
data,
}
);
}
Ok(Self { ptr })
}
}
impl<T> Deref for ArcNP<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe {
&(*self.ptr).data
}
}
}
impl<T> Clone for ArcNP<T> {
fn clone(&self) -> Self {
unsafe {
let _ = &(*self.ptr).refcount.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
};
Self { ptr: self.ptr }
}
}
impl<T> Drop for ArcNP<T> {
fn drop(&mut self) {
let count_prior_to_dec = unsafe {
&(*self.ptr).refcount
}.fetch_sub(1, core::sync::atomic::Ordering::SeqCst);
println!("[wdk-mutex] Dec val: {}...", count_prior_to_dec);
if count_prior_to_dec == 1 {
println!("[wdk-mutex] Dropping underlying memory...");
unsafe {
drop_in_place(&mut (*self.ptr).data);
ExFreePool(self.ptr as *mut _);
}
}
}
}