use libc::{c_void, ftruncate, mmap, munmap, shm_open, shm_unlink, MAP_FAILED, MAP_PRIVATE, MAP_SHARED, O_CREAT, O_EXCL, O_RDWR, PROT_READ, PROT_WRITE}; use crate::graphics::drawable::color_over; #[derive(Clone)] pub struct ShmPool { pub fd: i32, pub addr: *mut c_void, pub size: usize, } impl ShmPool { pub fn new(size: usize) -> std::io::Result { let shm_path: *const i8 = b"/chlorostart\0".as_ptr() as *const i8; let fd = unsafe { shm_open(shm_path, O_RDWR | O_EXCL | O_CREAT, 0o600) }; if fd == -1 { eprint!("shm_open in ShmPool::new() failed: "); return Err(std::io::Error::last_os_error()) } if unsafe { shm_unlink(shm_path) } == -1 { eprint!("shm_unlink in ShmPool::new() failed: "); return Err(std::io::Error::last_os_error()) } if unsafe { ftruncate(fd, size as i64) } == -1 { eprint!("ftruncate in ShmPool::new() failed: "); return Err(std::io::Error::last_os_error()) } let addr = unsafe { mmap(std::ptr::null_mut(), size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0) }; if addr == MAP_FAILED { eprint!("mmap in ShmPool::new() failed: "); return Err(std::io::Error::last_os_error()) } Ok(ShmPool { fd, addr, size, }) } pub fn from_fd(fd: i32, size: usize) -> std::io::Result { let addr = unsafe { mmap(std::ptr::null_mut(), size, PROT_READ, MAP_PRIVATE, fd, 0) }; if addr == MAP_FAILED { eprint!("mmap in ShmPool::from_fd() failed with fd {}", fd); return Err(std::io::Error::last_os_error()); } Ok(ShmPool {fd, addr, size}) } pub fn read_string(&self, offset: usize) -> std::io::Result { let mut res: Vec = Vec::new(); for i in offset..self.size { let byte = unsafe {*(self.addr.offset(i as isize) as *const u8)}; if byte == 0 { break; } res.push(byte); }; Ok(String::from_utf8(res).unwrap()) } pub fn resize(&mut self, size: usize) -> std::io::Result<()> { if unsafe { ftruncate(self.fd, size as i64) } == -1 { return Err(std::io::Error::last_os_error()) }; self.size = size; Ok(()) } pub fn write(&mut self, color: u32, offset: usize, len: usize) { if offset + len/4 >= self.size { return; } for i in offset..offset+len { unsafe { *((self.addr as *mut u32).offset(i as isize)) = color_over(color, self.read_pixel(i).unwrap()); }} } pub fn write_pixel(&mut self, color: u32, offset: usize) { // TODO: Return error if out of bounds if offset + 3 > self.size { return; } unsafe {*((self.addr as *mut u32).offset(offset as isize)) = color;} } pub fn read_pixel(&self, offset: usize) -> Option { if offset + 3 > self.size { return None; } return Some(unsafe {*(self.addr.offset(4*offset as isize) as *const u32)}); } } impl Drop for ShmPool { fn drop(&mut self) { println!("Dropping ShmPool!"); unsafe { munmap(self.addr, self.size); } } } unsafe impl Send for ShmPool {} unsafe impl Sync for ShmPool {}