use core::{num::NonZero, ptr::NonNull};
use std::{
io,
os::fd::{AsRawFd, BorrowedFd},
};
use crate::ffi::binding;
use super::status;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Backend(
NonNull<binding::catalejo_fault_backend>,
NonZero<u32>,
);
unsafe impl Send for Backend {}
unsafe impl Sync for Backend {}
impl Backend {
#[inline]
pub unsafe fn initialize(device: BorrowedFd<'_>) -> io::Result<Self> {
let mut target_value = core::ptr::null();
let target_state = unsafe {
binding::catalejo_fault_backend_initialize(device.as_raw_fd(), &raw mut target_value)
};
Self::lift(target_state, target_value)
}
#[inline]
pub fn retrieve() -> io::Result<Self> {
let mut target_value = core::ptr::null();
let target_state =
unsafe { binding::catalejo_fault_backend_retrieve(&raw mut target_value) };
Self::lift(target_state, target_value)
}
fn lift(
target_status: core::ffi::c_int,
raw: *const binding::catalejo_fault_backend,
) -> io::Result<Self> {
status(target_status)?;
let raw = NonNull::new(raw.cast_mut())
.ok_or_else(|| io::Error::from(io::ErrorKind::InvalidData))?;
let process_id = NonZero::new(std::process::id())
.ok_or_else(|| io::Error::from(io::ErrorKind::InvalidData))?;
Ok(Self(raw, process_id))
}
#[inline]
pub fn validate(&self) -> io::Result<()> {
let &Self(_, process_id) = self;
let current_process = std::process::id();
match process_id.get() == current_process {
true => Ok(()),
false => Err(io::Error::from_raw_os_error(libc::ESTALE)),
}
}
}