#![allow(unsafe_code)]
use std::sync::Arc;
use parking_lot::Mutex;
use crate::Result;
use crate::errors::PagedbError;
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE};
use windows_sys::Win32::System::IO::{
CreateIoCompletionPort, GetQueuedCompletionStatus, OVERLAPPED,
};
const NULL_HANDLE: HANDLE = std::ptr::null_mut();
pub(crate) struct PortHandle {
handle: HANDLE,
}
impl PortHandle {
fn create() -> Result<Self> {
let handle = unsafe { CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL_HANDLE, 0, 0) };
if handle == NULL_HANDLE {
return Err(PagedbError::Io(std::io::Error::last_os_error()));
}
Ok(Self { handle })
}
pub(crate) fn raw(&self) -> HANDLE {
self.handle
}
}
impl Drop for PortHandle {
fn drop(&mut self) {
unsafe {
CloseHandle(self.handle);
}
}
}
unsafe impl Send for PortHandle {}
unsafe impl Sync for PortHandle {}
pub struct Port {
pub(crate) inner: Arc<PortInner>,
}
pub(crate) struct PortInner {
pub(crate) handle: PortHandle,
pub(crate) lock: Mutex<()>,
}
impl Port {
pub fn new() -> Result<Self> {
Ok(Self {
inner: Arc::new(PortInner {
handle: PortHandle::create()?,
lock: Mutex::new(()),
}),
})
}
pub(crate) fn associate(&self, file_handle: HANDLE, key: usize) -> Result<()> {
let rc = unsafe { CreateIoCompletionPort(file_handle, self.inner.handle.raw(), key, 0) };
if rc == NULL_HANDLE {
return Err(PagedbError::Io(std::io::Error::last_os_error()));
}
Ok(())
}
pub(crate) unsafe fn dequeue(&self) -> std::io::Result<(u32, usize, *mut OVERLAPPED)> {
let mut bytes: u32 = 0;
let mut key: usize = 0;
let mut overlapped: *mut OVERLAPPED = std::ptr::null_mut();
let rc = unsafe {
GetQueuedCompletionStatus(
self.inner.handle.raw(),
&mut bytes,
&mut key,
&mut overlapped,
u32::MAX,
)
};
if rc == 0 {
let err = std::io::Error::last_os_error();
if overlapped.is_null() {
return Err(err);
}
return Err(err);
}
Ok((bytes, key, overlapped))
}
pub(crate) fn lock(&self) -> parking_lot::MutexGuard<'_, ()> {
self.inner.lock.lock()
}
}