shm: mmap logic

This commit is contained in:
Victor Berger 2017-02-20 22:32:03 +01:00
parent 48424da89b
commit 12dc3b65d8
4 changed files with 106 additions and 11 deletions

View File

@ -5,3 +5,4 @@ authors = ["Victor Berger <victor.berger@thalesgroup.com>"]
[dependencies] [dependencies]
wayland-server = "0.8.4" wayland-server = "0.8.4"
nix = "0.7.0"

View File

@ -2,5 +2,6 @@
#[macro_use] #[macro_use]
extern crate wayland_server; extern crate wayland_server;
extern crate nix;
pub mod shm; pub mod shm;

View File

@ -32,7 +32,7 @@ use std::sync::Arc;
use wayland_server::{GlobalHandler, EventLoopHandle, Client, Init, Resource, Destroy, resource_is_registered}; use wayland_server::{GlobalHandler, EventLoopHandle, Client, Init, Resource, Destroy, resource_is_registered};
use wayland_server::protocol::{wl_shm, wl_shm_pool, wl_buffer}; use wayland_server::protocol::{wl_shm, wl_shm_pool, wl_buffer};
use self::pool::Pool; use self::pool::{Pool, ResizeError};
mod pool; mod pool;
@ -156,9 +156,20 @@ impl Init for ShmHandler {
} }
impl wl_shm::Handler 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) { 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); evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&pool, self.my_id);
pool.set_user_data(Box::into_raw(arc_pool) as *mut ()); 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) pool: &wl_shm_pool::WlShmPool, size: i32)
{ {
let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) }; let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
if arc_pool.resize(size).is_err() { match arc_pool.resize(size) {
pool.post_error(wl_shm::Error::InvalidFd as u32, "Invalid new size for a wl_shm_pool.".into()) 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());
}
} }
} }
} }

View File

@ -1,17 +1,93 @@
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::sync::RwLock;
use std::ptr;
pub struct Pool; use nix::sys::mman;
impl Pool { pub struct Pool {
pub fn new(fd: RawFd, size: i32) -> Pool { map: RwLock<MemMap>
unimplemented!()
} }
pub fn resize(&self, newsize: i32) -> Result<(),()> { pub enum ResizeError {
unimplemented!() InvalidSize,
MremapFailed
}
impl Pool {
pub fn new(fd: RawFd, size: usize) -> Result<Pool,()> {
let memmap = MemMap::new(fd, size)?;
Ok(Pool {
map: RwLock::new(memmap)
})
}
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<F: FnOnce(&[u8])>(&self, f: F) -> Result<(),()> { pub fn with_data_slice<F: FnOnce(&[u8])>(&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<MemMap,()> {
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(|_| ())
}