1
0
Fork 0
forked from wry/wry
wry/src/pipewire/pw_mem.rs

155 lines
4 KiB
Rust

use {
crate::utils::{
copyhashmap::CopyHashMap,
mmap::{Mmapped, mmap},
oserror::OsError,
page_size::page_size,
ptr_ext::{MutPtrExt, PtrExt},
},
std::{marker::PhantomData, ops::Range, rc::Rc},
thiserror::Error,
uapi::{OwnedFd, Pod, c},
};
#[derive(Default)]
pub struct PwMemPool {
pub mems: CopyHashMap<u32, Rc<PwMem>>,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum PwMemType {
MemFd,
DmaBuf,
}
pub struct PwMem {
pub _ty: PwMemType,
pub read: bool,
pub write: bool,
pub fd: Rc<OwnedFd>,
}
pub struct PwMemMap {
pub _mem: Rc<PwMem>,
pub range: Range<usize>,
pub map: Mmapped,
}
pub struct PwMemTyped<T> {
mem: Rc<PwMemMap>,
offset: usize,
_phantom: PhantomData<T>,
}
#[expect(dead_code)]
pub struct PwMemSlice {
mem: Rc<PwMemMap>,
range: Range<usize>,
}
impl PwMemPool {
pub fn map(&self, memid: u32, offset: u32, size: u32) -> Result<Rc<PwMemMap>, PwMemError> {
match self.mems.get(&memid) {
Some(m) => m.map(offset, size),
_ => Err(PwMemError::MemidDoesNotExist(memid)),
}
}
}
impl PwMem {
pub fn map(self: &Rc<Self>, offset: u32, size: u32) -> Result<Rc<PwMemMap>, PwMemError> {
let mask = page_size() - 1;
let offset = offset as usize;
let size = size as usize;
let start = offset & !mask;
let dist = offset - start;
let len = (size + dist + mask) & !mask;
let range = dist..dist + size;
let mut prot = 0;
if self.read {
prot |= c::PROT_READ;
}
if self.write {
prot |= c::PROT_WRITE;
}
let map = match mmap(len as _, prot, c::MAP_SHARED, self.fd.raw(), start as _) {
Ok(m) => m,
Err(e) => return Err(PwMemError::MmapFailed(e)),
};
Ok(Rc::new(PwMemMap {
_mem: self.clone(),
range,
map,
}))
}
}
impl PwMemMap {
#[expect(dead_code)]
pub unsafe fn read<T: Pod>(&self) -> &T {
self.check::<T>(0);
unsafe { (self.map.ptr.cast::<u8>().add(self.range.start) as *const T).deref() }
}
#[expect(dead_code)]
pub unsafe fn write<T: Pod>(&self) -> &mut T {
self.check::<T>(0);
unsafe { (self.map.ptr.cast::<u8>().add(self.range.start) as *mut T).deref_mut() }
}
#[expect(dead_code)]
pub unsafe fn bytes_mut(&self) -> &mut [u8] {
unsafe {
std::slice::from_raw_parts_mut(
self.map.ptr.cast::<u8>().add(self.range.start) as _,
self.range.len(),
)
}
}
fn check<T>(&self, offset: usize) {
assert!(offset <= self.range.len());
assert!(size_of::<T>() <= self.range.len() - offset);
assert_eq!((align_of::<T>() - 1) & (self.range.start + offset), 0);
}
pub fn typed<T: Pod>(self: &Rc<Self>) -> Rc<PwMemTyped<T>> {
self.typed_at(0)
}
pub fn typed_at<T: Pod>(self: &Rc<Self>, offset: usize) -> Rc<PwMemTyped<T>> {
self.check::<T>(offset);
Rc::new(PwMemTyped {
mem: self.clone(),
offset: self.range.start + offset,
_phantom: Default::default(),
})
}
pub fn slice(self: &Rc<Self>, range: Range<usize>) -> Rc<PwMemSlice> {
assert!(range.start <= self.range.len());
assert!(range.len() <= self.range.len() - range.start);
Rc::new(PwMemSlice {
mem: self.clone(),
range: self.range.start + range.start..self.range.start + range.end,
})
}
}
impl<T: Pod> PwMemTyped<T> {
pub unsafe fn read(&self) -> &T {
unsafe { (self.mem.map.ptr.cast::<u8>().add(self.offset) as *const T).deref() }
}
pub unsafe fn write(&self) -> &mut T {
unsafe { (self.mem.map.ptr.cast::<u8>().add(self.offset) as *mut T).deref_mut() }
}
}
#[derive(Debug, Error)]
pub enum PwMemError {
#[error("mmap failed")]
MmapFailed(#[source] OsError),
#[error("memid {0} does not exist")]
MemidDoesNotExist(u32),
}