blob: 10b23df697cfd971d836583c585c62f494c5c59c [file] [log] [blame]
use crate::Result;
use std::os::unix::io::AsRawFd;
use std::{
cmp::{max, min},
ops::Deref,
slice,
};
use nix::{
libc::{c_void, off_t, size_t},
sys::mman,
};
pub struct PlaneMapping {
// A mapping remains valid until we munmap it, that is, until the
// PlaneMapping object is deleted. Hence the static lifetime.
pub data: &'static mut [u8],
start: usize,
end: usize,
}
impl PlaneMapping {
pub fn restrict(mut self, start: usize, end: usize) -> Self {
self.start = max(self.start, start);
self.end = min(self.end, end);
self
}
}
impl AsRef<[u8]> for PlaneMapping {
fn as_ref(&self) -> &[u8] {
&self.data[self.start..self.end]
}
}
/// To provide len() and is_empty().
impl Deref for PlaneMapping {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.data[self.start..self.end]
}
}
impl Drop for PlaneMapping {
fn drop(&mut self) {
// Safe because the pointer and length were constructed in mmap() and
// are always valid.
unsafe { mman::munmap(self.data.as_mut_ptr() as *mut c_void, self.data.len()) }
.unwrap_or_else(|e| {
eprintln!("Error while unmapping plane: {}", e);
});
}
}
// TODO should be unsafe because the mapping can be used after a buffer is queued?
// Or not, since this cannot cause a crash...
pub fn mmap<F: AsRawFd>(fd: &F, mem_offset: u32, length: u32) -> Result<PlaneMapping> {
let data = unsafe {
mman::mmap(
std::ptr::null_mut::<c_void>(),
length as size_t,
mman::ProtFlags::PROT_READ | mman::ProtFlags::PROT_WRITE,
mman::MapFlags::MAP_SHARED,
fd.as_raw_fd(),
mem_offset as off_t,
)
}?;
Ok(PlaneMapping {
// Safe because we know the pointer is valid and has enough data mapped
// to cover the length.
data: unsafe { slice::from_raw_parts_mut(data as *mut u8, length as usize) },
start: 0,
end: length as usize,
})
}