use std::io;
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering};
use winapi::shared::minwindef::*;
use winapi::shared::ntdef::NULL;
use winapi::um::handleapi::*;
use winapi::um::synchapi::CreateEventW;
use winapi::um::winnt::HANDLE;
#[derive(Debug)]
pub enum CacheType {
Read,
Write,
}
#[derive(Debug)]
pub struct EventCache {
handle: AtomicUsize,
cache_type: CacheType,
}
impl EventCache {
pub fn new(cache_type: CacheType) -> Self {
EventCache {
handle: AtomicUsize::new(NULL as usize),
cache_type,
}
}
pub fn take_or_create(&self) -> io::Result<HandleGuard> {
let existing = self.handle.swap(NULL as usize, Ordering::Relaxed) as HANDLE;
if existing != NULL {
return Ok(HandleGuard {
cache: self,
handle: existing,
});
}
let event_result = match self.cache_type {
CacheType::Read => unsafe { CreateEventW(ptr::null_mut(), TRUE, FALSE, ptr::null_mut()) },
CacheType::Write => unsafe { CreateEventW(ptr::null_mut(), FALSE, FALSE, ptr::null_mut()) },
};
match event_result {
NULL => Err(io::Error::last_os_error()),
new_handle => Ok(HandleGuard {
cache: self,
handle: new_handle,
}),
}
}
fn return_or_deallocate(&self, handle: HANDLE) {
if self
.handle
.compare_exchange_weak(
NULL as usize,
handle as usize,
Ordering::Relaxed,
Ordering::Relaxed,
)
.is_err()
{
unsafe { CloseHandle(handle) };
}
}
}
impl Drop for EventCache {
fn drop(&mut self) {
let handle = (*self.handle.get_mut()) as HANDLE;
if handle != NULL {
unsafe { CloseHandle(handle) };
}
}
}
pub struct HandleGuard<'a> {
cache: &'a EventCache,
handle: HANDLE,
}
impl<'a> HandleGuard<'a> {
pub fn handle(&self) -> HANDLE {
self.handle
}
}
impl<'a> Drop for HandleGuard<'a> {
fn drop(&mut self) {
self.cache.return_or_deallocate(self.handle);
}
}