use crate::{Error, Result, non_zero_len};
pub fn lock_region(ptr: *const u8, len: usize) -> Result<()> {
region_call(ptr, len, libc::mlock, "mlock")
}
pub fn unlock_region(ptr: *const u8, len: usize) -> Result<()> {
region_call(ptr, len, libc::munlock, "munlock")
}
fn region_call(
ptr: *const u8,
len: usize,
operation: unsafe extern "C" fn(*const libc::c_void, libc::size_t) -> libc::c_int,
operation_name: &'static str,
) -> Result<()> {
if non_zero_len(len).is_none() {
return Ok(());
}
if ptr.is_null() {
return Err(Error::NullPointer);
}
let result = unsafe { operation(ptr.cast::<libc::c_void>(), len) };
if result == 0 {
Ok(())
} else {
Err(Error::System {
operation: operation_name,
source: std::io::Error::last_os_error(),
})
}
}
#[cfg(test)]
mod tests {
use super::{lock_region, unlock_region};
#[test]
fn zero_length_lock_is_a_noop() {
assert!(lock_region(std::ptr::null(), 0).is_ok());
assert!(unlock_region(std::ptr::null(), 0).is_ok());
}
#[test]
fn null_pointer_with_non_zero_length_is_rejected() {
let error = lock_region(std::ptr::null(), 4).expect_err("null pointer must fail");
assert!(matches!(error, crate::Error::NullPointer));
}
}