use crate::{os, util, Result};
#[inline]
pub fn lock<T>(address: *const T, size: usize) -> Result<LockGuard> {
let (address, size) = util::round_to_page_boundaries(address, size)?;
os::lock(address.cast(), size).map(|_| LockGuard::new(address, size))
}
#[inline]
pub fn unlock<T>(address: *const T, size: usize) -> Result<()> {
let (address, size) = util::round_to_page_boundaries(address, size)?;
os::unlock(address.cast(), size)
}
#[must_use]
pub struct LockGuard {
address: *const (),
size: usize,
}
impl LockGuard {
#[inline(always)]
fn new<T>(address: *const T, size: usize) -> Self {
Self {
address: address.cast(),
size,
}
}
}
impl Drop for LockGuard {
#[inline]
fn drop(&mut self) {
let result = os::unlock(self.address, self.size);
debug_assert!(result.is_ok(), "unlocking region: {:?}", result);
}
}
unsafe impl Send for LockGuard {}
unsafe impl Sync for LockGuard {}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::util::alloc_pages;
use crate::{page, Protection};
#[test]
fn lock_mapped_pages_succeeds() -> Result<()> {
let map = alloc_pages(&[Protection::READ_WRITE]);
let _guard = lock(map.as_ptr(), page::size())?;
Ok(())
}
#[test]
fn unlock_mapped_pages_succeeds() -> Result<()> {
let map = alloc_pages(&[Protection::READ_WRITE]);
std::mem::forget(lock(map.as_ptr(), page::size())?);
unlock(map.as_ptr(), page::size())
}
}