use std::marker::PhantomData;
use libc::{c_int, c_void, mlock, munlock};
#[repr(transparent)]
pub struct Locker<C: AsMut<[T]>, T> {
pub buf: C,
item_type: PhantomData<T>,
}
impl<C: AsMut<[T]>, T> Locker<C, T> {
pub fn new(buf: C) -> Self {
Self {
buf,
item_type: PhantomData,
}
}
pub fn lock(&mut self) -> Result<(), LockError> {
let buf = self.buf.as_mut();
assert!(size_of_val(buf) > 0, "Zero size buffer");
let ptr = buf.as_mut_ptr() as *mut c_void;
let len = size_of_val(buf);
let result = unsafe {
mlock(ptr, len)
};
match result {
0 => Ok(()),
result => Err(LockError::from(result)),
}
}
pub fn unlock(&mut self) -> Result<(), LockError> {
let buf = self.buf.as_mut();
assert!(size_of_val(buf) > 0, "zero size buffer");
let ptr = buf.as_mut_ptr() as *mut c_void;
let len = size_of_val(buf);
let result = unsafe {
munlock(ptr, len)
};
match result {
0 => Ok(()),
result => Err(LockError::from(result)),
}
}
}
impl<C: AsMut<[T]>, T> Drop for Locker<C, T> {
fn drop(&mut self) {
self.unlock()
.expect("Cant unlock while dropping")
}
}
#[derive(Debug)]
pub enum LockError {
EPERM,
EINTR,
EIO,
EAGAIN,
ENOMEM,
EFAULT,
EBUSY,
EINVAL,
ENOSYS,
EUNIM(c_int),
}
impl From<c_int> for LockError {
fn from(err: c_int) -> Self {
match err {
1 => LockError::EPERM,
4 => LockError::EINTR,
5 => LockError::EIO,
11 => LockError::EAGAIN,
12 => LockError::ENOMEM,
14 => LockError::EFAULT,
16 => LockError::EBUSY,
22 => LockError::EINVAL,
38 => LockError::ENOSYS,
_ => LockError::EUNIM(err),
}
}
}