use std::cell::RefCell;
use std::ffi::c_void;
use windows_sys::Win32::Storage::FileSystem::{
FILE_FLUSH_MODE, IORING_BUFFER_INFO, IORING_BUFFER_REF, IORING_CQE, IORING_HANDLE_REF,
};
use windows_sys::core::HRESULT;
use super::real;
pub trait Responses {
unsafe fn submit(
&mut self,
ring: *mut c_void,
wait_operations: u32,
milliseconds: u32,
submitted: *mut u32,
) -> HRESULT {
unsafe { real::SubmitIoRing(ring, wait_operations, milliseconds, submitted) }
}
unsafe fn pop(&mut self, ring: *mut c_void, cqe: *mut IORING_CQE) -> HRESULT {
unsafe { real::PopIoRingCompletion(ring, cqe) }
}
#[allow(clippy::too_many_arguments)]
unsafe fn build_read(
&mut self,
ring: *mut c_void,
file: IORING_HANDLE_REF,
buffer: IORING_BUFFER_REF,
bytes: u32,
offset: u64,
user_data: usize,
flags: i32,
) -> HRESULT {
unsafe { real::BuildIoRingReadFile(ring, file, buffer, bytes, offset, user_data, flags) }
}
#[allow(clippy::too_many_arguments)]
unsafe fn build_write(
&mut self,
ring: *mut c_void,
file: IORING_HANDLE_REF,
buffer: IORING_BUFFER_REF,
bytes: u32,
offset: u64,
caching: i32,
user_data: usize,
flags: i32,
) -> HRESULT {
unsafe {
real::BuildIoRingWriteFile(ring, file, buffer, bytes, offset, caching, user_data, flags)
}
}
unsafe fn build_flush(
&mut self,
ring: *mut c_void,
file: IORING_HANDLE_REF,
mode: FILE_FLUSH_MODE,
user_data: usize,
flags: i32,
) -> HRESULT {
unsafe { real::BuildIoRingFlushFile(ring, file, mode, user_data, flags) }
}
unsafe fn build_cancel(
&mut self,
ring: *mut c_void,
file: IORING_HANDLE_REF,
cancel_user_data: usize,
user_data: usize,
) -> HRESULT {
unsafe { real::BuildIoRingCancelRequest(ring, file, cancel_user_data, user_data) }
}
unsafe fn build_register_files(
&mut self,
ring: *mut c_void,
count: u32,
handles: *const *mut c_void,
user_data: usize,
) -> HRESULT {
unsafe { real::BuildIoRingRegisterFileHandles(ring, count, handles, user_data) }
}
unsafe fn build_register_buffers(
&mut self,
ring: *mut c_void,
count: u32,
buffers: *const IORING_BUFFER_INFO,
user_data: usize,
) -> HRESULT {
unsafe { real::BuildIoRingRegisterBuffers(ring, count, buffers, user_data) }
}
unsafe fn set_completion_event(&mut self, ring: *mut c_void, event: *mut c_void) -> HRESULT {
unsafe { real::SetIoRingCompletionEvent(ring, event) }
}
}
thread_local! {
static CURRENT: RefCell<Option<Box<dyn Responses>>> = const { RefCell::new(None) };
}
pub(crate) fn with<R>(f: impl FnOnce(&mut dyn Responses) -> R) -> Option<R> {
CURRENT
.try_with(|slot| {
let Ok(mut borrow) = slot.try_borrow_mut() else {
return None;
};
borrow.as_mut().map(|responder| f(&mut **responder))
})
.ok()
.flatten()
}
#[must_use = "the responder is uninstalled when the guard drops"]
pub fn install(responder: Box<dyn Responses>) -> Installed {
CURRENT.with(|slot| {
let mut borrow = slot.borrow_mut();
assert!(
borrow.is_none(),
"a kernel responder is already installed on this thread"
);
*borrow = Some(responder);
});
Installed { _private: () }
}
#[must_use = "dropping this immediately uninstalls the responder"]
pub struct Installed {
_private: (),
}
impl Drop for Installed {
fn drop(&mut self) {
let _ = CURRENT.try_with(|slot| {
if let Ok(mut borrow) = slot.try_borrow_mut() {
*borrow = None;
}
});
}
}
#[cfg(test)]
mod tests;