From 12dc3b65d8c08139d193f8ace1ad7ae1b8fc0682 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Mon, 20 Feb 2017 22:32:03 +0100 Subject: [PATCH] shm: mmap logic --- Cargo.toml | 1 + src/lib.rs | 1 + src/shm/mod.rs | 27 ++++++++++++--- src/shm/pool.rs | 88 +++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 106 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0e4ddf7..40217c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,4 @@ authors = ["Victor Berger "] [dependencies] wayland-server = "0.8.4" +nix = "0.7.0" diff --git a/src/lib.rs b/src/lib.rs index f6df6e7..8ac17eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,5 +2,6 @@ #[macro_use] extern crate wayland_server; +extern crate nix; pub mod shm; diff --git a/src/shm/mod.rs b/src/shm/mod.rs index ee9a7bd..3624c54 100644 --- a/src/shm/mod.rs +++ b/src/shm/mod.rs @@ -32,7 +32,7 @@ use std::sync::Arc; use wayland_server::{GlobalHandler, EventLoopHandle, Client, Init, Resource, Destroy, resource_is_registered}; use wayland_server::protocol::{wl_shm, wl_shm_pool, wl_buffer}; -use self::pool::Pool; +use self::pool::{Pool, ResizeError}; mod pool; @@ -156,9 +156,20 @@ impl Init for ShmHandler { } impl wl_shm::Handler for ShmHandler { - fn create_pool(&mut self, evqh: &mut EventLoopHandle, _client: &Client, _shm: &wl_shm::WlShm, + fn create_pool(&mut self, evqh: &mut EventLoopHandle, _client: &Client, shm: &wl_shm::WlShm, pool: wl_shm_pool::WlShmPool, fd: RawFd, size: i32) { - let arc_pool = Box::new(Arc::new(Pool::new(fd, size))); + if size <= 0 { + shm.post_error(wl_shm::Error::InvalidFd as u32, "Invalid size for a new wl_shm_pool.".into()); + return + } + let mmap_pool = match Pool::new(fd, size as usize) { + Ok(p) => p, + Err(()) => { + shm.post_error(wl_shm::Error::InvalidFd as u32, format!("Failed mmap of fd {}.", fd)); + return + } + }; + let arc_pool = Box::new(Arc::new(mmap_pool)); evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&pool, self.my_id); pool.set_user_data(Box::into_raw(arc_pool) as *mut ()); } @@ -221,8 +232,14 @@ impl wl_shm_pool::Handler for ShmHandler { pool: &wl_shm_pool::WlShmPool, size: i32) { let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc) }; - if arc_pool.resize(size).is_err() { - pool.post_error(wl_shm::Error::InvalidFd as u32, "Invalid new size for a wl_shm_pool.".into()) + match arc_pool.resize(size) { + Ok(()) => {}, + Err(ResizeError::InvalidSize) => { + pool.post_error(wl_shm::Error::InvalidFd as u32, "Invalid new size for a wl_shm_pool.".into()); + }, + Err(ResizeError::MremapFailed) => { + pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into()); + } } } } diff --git a/src/shm/pool.rs b/src/shm/pool.rs index 07a0198..4aa07f3 100644 --- a/src/shm/pool.rs +++ b/src/shm/pool.rs @@ -1,17 +1,93 @@ use std::os::unix::io::RawFd; +use std::sync::RwLock; +use std::ptr; -pub struct Pool; +use nix::sys::mman; + +pub struct Pool { + map: RwLock +} + +pub enum ResizeError { + InvalidSize, + MremapFailed +} impl Pool { - pub fn new(fd: RawFd, size: i32) -> Pool { - unimplemented!() + pub fn new(fd: RawFd, size: usize) -> Result { + let memmap = MemMap::new(fd, size)?; + Ok(Pool { + map: RwLock::new(memmap) + }) } - pub fn resize(&self, newsize: i32) -> Result<(),()> { - unimplemented!() + pub fn resize(&self, newsize: i32) -> Result<(),ResizeError> { + let mut guard = self.map.write().unwrap(); + if newsize <= 0 || guard.size() > (newsize as usize) { + return Err(ResizeError::InvalidSize) + } + guard.remap(newsize as usize).map_err(|()| ResizeError::MremapFailed) } pub fn with_data_slice(&self, f: F) -> Result<(),()> { - unimplemented!() + // TODO: handle SIGBUS + let guard = self.map.read().unwrap(); + + let slice = guard.get_slice(); + f(slice); + + Ok(()) } } + +struct MemMap { + ptr: *mut u8, + fd: RawFd, + size: usize +} + +impl MemMap { + fn new(fd: RawFd, size: usize) -> Result { + Ok(MemMap { + ptr: map(fd, size)?, + fd: fd, + size: size + }) + } + + fn remap(&mut self, newsize: usize) -> Result<(),()> { + unmap(self.ptr, self.size)?; + self.ptr = map(self.fd, newsize)?; + self.size = newsize; + Ok(()) + } + + fn size(&self) -> usize { + self.size + } + + fn get_slice(&self) -> &[u8] { + unsafe { ::std::slice::from_raw_parts(self.ptr, self.size) } + } +} + +// mman::mmap should really be unsafe... why isn't it? +#[allow(unused_unsafe)] +fn map(fd: RawFd, size: usize) -> Result<*mut u8, ()> { + let ret = unsafe { mman::mmap( + ptr::null_mut(), + size, + mman::PROT_READ, + mman::MAP_SHARED, + fd, + 0 + ) }; + ret.map(|p| p as *mut u8).map_err(|_| ()) +} + +// mman::munmap should really be unsafe... why isn't it? +#[allow(unused_unsafe)] +fn unmap(ptr: *mut u8, size: usize) -> Result<(),()> { + let ret = unsafe { mman::munmap(ptr as *mut _, size) }; + ret.map_err(|_| ()) +}