This commit is contained in:
Victor Berger 2017-03-13 18:12:14 +01:00
parent 38708c4ead
commit 4adea0950a
4 changed files with 114 additions and 113 deletions

11
.rustfmt.toml Normal file
View File

@ -0,0 +1,11 @@
error_on_line_overflow = false
fn_args_density = "Compressed"
fn_args_layout = "Visual"
fn_arg_intent = "Tabbed"
reorder_imports = true
reorder_imported_names = true
report_todo = "Always"
report_fixme = "Always"
normalize_comments = true
use_try_shorthand = true
max_width = 110

View File

@ -24,9 +24,9 @@ branches:
- master - master
before_script: before_script:
- export PATH=$HOME/.local/bin:$HOME/.cargo/bin:$PATH
- which rustfmt || cargo install rustfmt - which rustfmt || cargo install rustfmt
- pip install 'travis-cargo<0.2' --user - pip install 'travis-cargo<0.2' --user
- export PATH=$HOME/.local/bin:$HOME/.cargo/bin:$PATH
- mkdir $(pwd)/socket - mkdir $(pwd)/socket
- export XDG_RUNTIME_DIR="$(pwd)/socket" - export XDG_RUNTIME_DIR="$(pwd)/socket"

View File

@ -61,13 +61,13 @@
//! //!
//! If you are already using an handler for this signal, you probably don't want to use this handler. //! If you are already using an handler for this signal, you probably don't want to use this handler.
use self::pool::{Pool, ResizeError};
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::sync::Arc; use std::sync::Arc;
use wayland_server::{GlobalHandler, EventLoopHandle, Client, Init, Resource, Destroy, resource_is_registered}; use wayland_server::{Client, Destroy, EventLoopHandle, GlobalHandler, Init, Resource, resource_is_registered};
use wayland_server::protocol::{wl_shm, wl_shm_pool, wl_buffer}; use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool};
use self::pool::{Pool, ResizeError};
mod pool; mod pool;
@ -78,7 +78,7 @@ mod pool;
pub struct ShmGlobal { pub struct ShmGlobal {
formats: Vec<wl_shm::Format>, formats: Vec<wl_shm::Format>,
handler_id: Option<usize>, handler_id: Option<usize>,
log: ::slog::Logger log: ::slog::Logger,
} }
impl ShmGlobal { impl ShmGlobal {
@ -94,7 +94,7 @@ impl ShmGlobal {
where L: Into<Option<::slog::Logger>> where L: Into<Option<::slog::Logger>>
{ {
use slog::DrainExt; use slog::DrainExt;
let log = logger.into().unwrap_or(::slog::Logger::root(::slog_stdlog::StdLog.fuse(), o!())); let log = logger.into().unwrap_or_else(|| ::slog::Logger::root(::slog_stdlog::StdLog.fuse(), o!()));
// always add the mandatory formats // always add the mandatory formats
formats.push(wl_shm::Format::Argb8888); formats.push(wl_shm::Format::Argb8888);
@ -102,7 +102,7 @@ impl ShmGlobal {
ShmGlobal { ShmGlobal {
formats: formats, formats: formats,
handler_id: None, handler_id: None,
log: log.new(o!("smithay_module" => "shm_handler")) log: log.new(o!("smithay_module" => "shm_handler")),
} }
} }
@ -113,18 +113,16 @@ impl ShmGlobal {
/// ///
/// This is needed to retrieve the contents of the shm pools and buffers. /// This is needed to retrieve the contents of the shm pools and buffers.
pub fn get_token(&self) -> ShmGlobalToken { pub fn get_token(&self) -> ShmGlobalToken {
ShmGlobalToken { ShmGlobalToken { hid: self.handler_id.expect("ShmGlobal was not initialized.") }
hid: self.handler_id.clone().expect("ShmGlobal was not initialized."),
}
} }
} }
/// An SHM global token /// An SHM global token
/// ///
/// It is needed to access the contents of the buffers & pools managed by the /// It is needed to access the contents of the buffers & pools managed by the
/// associated ShmGlobal. /// associated `ShmGlobal`.
pub struct ShmGlobalToken { pub struct ShmGlobalToken {
hid: usize hid: usize,
} }
/// Error that can occur when accessing an SHM buffer /// Error that can occur when accessing an SHM buffer
@ -137,7 +135,7 @@ pub enum BufferAccessError {
/// for the memory map. /// for the memory map.
/// ///
/// If this error occurs, the client has been killed as a result. /// If this error occurs, the client has been killed as a result.
BadMap BadMap,
} }
impl ShmGlobalToken { impl ShmGlobalToken {
@ -155,14 +153,14 @@ impl ShmGlobalToken {
where F: FnOnce(&[u8], BufferData) where F: FnOnce(&[u8], BufferData)
{ {
if !resource_is_registered::<_, ShmHandler>(buffer, self.hid) { if !resource_is_registered::<_, ShmHandler>(buffer, self.hid) {
return Err(BufferAccessError::NotManaged) return Err(BufferAccessError::NotManaged);
} }
let data = unsafe { &* (buffer.get_user_data() as *mut InternalBufferData) }; let data = unsafe { &*(buffer.get_user_data() as *mut InternalBufferData) };
if data.pool.with_data_slice(|slice| f(slice, data.data.clone())).is_err() { if data.pool.with_data_slice(|slice| f(slice, data.data)).is_err() {
// SIGBUS error occured // SIGBUS error occured
buffer.post_error(wl_shm::Error::InvalidFd as u32, "Bad pool size.".into()); buffer.post_error(wl_shm::Error::InvalidFd as u32, "Bad pool size.".into());
return Err(BufferAccessError::BadMap) return Err(BufferAccessError::BadMap);
} }
Ok(()) Ok(())
} }
@ -171,17 +169,17 @@ impl ShmGlobalToken {
impl Init for ShmGlobal { impl Init for ShmGlobal {
fn init(&mut self, evqh: &mut EventLoopHandle, _index: usize) { fn init(&mut self, evqh: &mut EventLoopHandle, _index: usize) {
let id = evqh.add_handler_with_init(ShmHandler { let id = evqh.add_handler_with_init(ShmHandler {
my_id: ::std::usize::MAX, my_id: ::std::usize::MAX,
valid_formats: self.formats.clone(), valid_formats: self.formats.clone(),
log: self.log.clone() log: self.log.clone(),
}); });
self.handler_id = Some(id); self.handler_id = Some(id);
} }
} }
impl GlobalHandler<wl_shm::WlShm> for ShmGlobal { impl GlobalHandler<wl_shm::WlShm> for ShmGlobal {
fn bind(&mut self, evqh: &mut EventLoopHandle, _: &Client, global: wl_shm::WlShm) { fn bind(&mut self, evqh: &mut EventLoopHandle, _: &Client, global: wl_shm::WlShm) {
let hid = self.handler_id.clone().expect("ShmGlobal was not initialized."); let hid = self.handler_id.expect("ShmGlobal was not initialized.");
// register an handler for this shm // register an handler for this shm
evqh.register::<_, ShmHandler>(&global, hid); evqh.register::<_, ShmHandler>(&global, hid);
// and then the custom formats // and then the custom formats
@ -194,7 +192,7 @@ impl GlobalHandler<wl_shm::WlShm> for ShmGlobal {
struct ShmHandler { struct ShmHandler {
my_id: usize, my_id: usize,
valid_formats: Vec<wl_shm::Format>, valid_formats: Vec<wl_shm::Format>,
log: ::slog::Logger log: ::slog::Logger,
} }
impl Init for ShmHandler { impl Init for ShmHandler {
@ -208,8 +206,9 @@ 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) {
if size <= 0 { if size <= 0 {
shm.post_error(wl_shm::Error::InvalidFd as u32, "Invalid size for a new wl_shm_pool.".into()); shm.post_error(wl_shm::Error::InvalidFd as u32,
return "Invalid size for a new wl_shm_pool.".into());
return;
} }
let mmap_pool = match Pool::new(fd, size as usize, self.log.clone()) { let mmap_pool = match Pool::new(fd, size as usize, self.log.clone()) {
Ok(p) => p, Ok(p) => p,
@ -245,47 +244,46 @@ pub struct BufferData {
/// Stride of the buffer in bytes /// Stride of the buffer in bytes
pub stride: i32, pub stride: i32,
/// Format used by this buffer /// Format used by this buffer
pub format: wl_shm::Format pub format: wl_shm::Format,
} }
struct InternalBufferData { struct InternalBufferData {
pool: Arc<Pool>, pool: Arc<Pool>,
data: BufferData data: BufferData,
} }
impl wl_shm_pool::Handler for ShmHandler { impl wl_shm_pool::Handler for ShmHandler {
fn create_buffer(&mut self, evqh: &mut EventLoopHandle, _client: &Client, fn create_buffer(&mut self, evqh: &mut EventLoopHandle, _client: &Client,
pool: &wl_shm_pool::WlShmPool, buffer: wl_buffer::WlBuffer, offset: i32, pool: &wl_shm_pool::WlShmPool, buffer: wl_buffer::WlBuffer, offset: i32, width: i32,
width: i32, height: i32, stride: i32, format: wl_shm::Format) height: i32, stride: i32, format: wl_shm::Format) {
{
if !self.valid_formats.contains(&format) { if !self.valid_formats.contains(&format) {
buffer.post_error(wl_shm::Error::InvalidFormat as u32, String::new()); buffer.post_error(wl_shm::Error::InvalidFormat as u32, String::new());
return return;
} }
let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) }; let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
let data = Box::into_raw(Box::new(InternalBufferData { let data = Box::into_raw(Box::new(InternalBufferData {
pool: arc_pool.clone(), pool: arc_pool.clone(),
data: BufferData { data: BufferData {
offset: offset, offset: offset,
width: width, width: width,
height: height, height: height,
stride: stride, stride: stride,
format: format format: format,
} },
})); }));
evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&buffer, self.my_id); evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&buffer, self.my_id);
buffer.set_user_data(data as *mut ()); buffer.set_user_data(data as *mut ());
} }
fn resize(&mut self, _evqh: &mut EventLoopHandle, _client: &Client, fn resize(&mut self, _evqh: &mut EventLoopHandle, _client: &Client, pool: &wl_shm_pool::WlShmPool,
pool: &wl_shm_pool::WlShmPool, size: i32) 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>) };
match arc_pool.resize(size) { match arc_pool.resize(size) {
Ok(()) => {}, Ok(()) => {}
Err(ResizeError::InvalidSize) => { Err(ResizeError::InvalidSize) => {
pool.post_error(wl_shm::Error::InvalidFd as u32, "Invalid new size for a wl_shm_pool.".into()); pool.post_error(wl_shm::Error::InvalidFd as u32,
}, "Invalid new size for a wl_shm_pool.".into());
}
Err(ResizeError::MremapFailed) => { Err(ResizeError::MremapFailed) => {
pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into()); pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into());
} }
@ -302,7 +300,6 @@ impl Destroy<wl_buffer::WlBuffer> for ShmHandler {
declare_handler!(ShmHandler, wl_shm_pool::Handler, wl_shm_pool::WlShmPool); declare_handler!(ShmHandler, wl_shm_pool::Handler, wl_shm_pool::WlShmPool);
impl wl_buffer::Handler for ShmHandler { impl wl_buffer::Handler for ShmHandler {}
}
declare_handler!(ShmHandler, wl_buffer::Handler, wl_buffer::WlBuffer); declare_handler!(ShmHandler, wl_buffer::Handler, wl_buffer::WlBuffer);

View File

@ -1,11 +1,12 @@
use std::cell::Cell;
use std::os::unix::io::RawFd;
use std::sync::{RwLock, Once, ONCE_INIT};
use std::ptr;
use nix::{c_int, c_void, libc, unistd}; use nix::{c_int, c_void, libc, unistd};
use nix::sys::mman; use nix::sys::mman;
use nix::sys::signal::{self, SigAction, Signal, SigHandler}; use nix::sys::signal::{self, SigAction, SigHandler, Signal};
use std::cell::Cell;
use std::os::unix::io::RawFd;
use std::ptr;
use std::sync::{ONCE_INIT, Once, RwLock};
thread_local!(static SIGBUS_GUARD: Cell<(*const MemMap, bool)> = Cell::new((ptr::null_mut(), false))); thread_local!(static SIGBUS_GUARD: Cell<(*const MemMap, bool)> = Cell::new((ptr::null_mut(), false)));
@ -15,30 +16,30 @@ static mut OLD_SIGBUS_HANDLER: *mut SigAction = 0 as *mut SigAction;
pub struct Pool { pub struct Pool {
map: RwLock<MemMap>, map: RwLock<MemMap>,
fd: RawFd, fd: RawFd,
log: ::slog::Logger log: ::slog::Logger,
} }
pub enum ResizeError { pub enum ResizeError {
InvalidSize, InvalidSize,
MremapFailed MremapFailed,
} }
impl Pool { impl Pool {
pub fn new(fd: RawFd, size: usize, log: ::slog::Logger) -> Result<Pool,()> { pub fn new(fd: RawFd, size: usize, log: ::slog::Logger) -> Result<Pool, ()> {
let memmap = MemMap::new(fd, size)?; let memmap = MemMap::new(fd, size)?;
trace!(log, "Creating new shm pool"; "fd" => fd as i32, "size" => size); trace!(log, "Creating new shm pool"; "fd" => fd as i32, "size" => size);
Ok(Pool { Ok(Pool {
map: RwLock::new(memmap), map: RwLock::new(memmap),
fd: fd, fd: fd,
log: log log: log,
}) })
} }
pub fn resize(&self, newsize: i32) -> Result<(),ResizeError> { pub fn resize(&self, newsize: i32) -> Result<(), ResizeError> {
let mut guard = self.map.write().unwrap(); let mut guard = self.map.write().unwrap();
let oldsize = guard.size(); let oldsize = guard.size();
if newsize <= 0 || oldsize > (newsize as usize) { if newsize <= 0 || oldsize > (newsize as usize) {
return Err(ResizeError::InvalidSize) return Err(ResizeError::InvalidSize);
} }
trace!(self.log, "Resizing shm pool"; "fd" => self.fd as i32, "oldsize" => oldsize, "newsize" => newsize); trace!(self.log, "Resizing shm pool"; "fd" => self.fd as i32, "oldsize" => oldsize, "newsize" => newsize);
guard.remap(newsize as usize).map_err(|()| { guard.remap(newsize as usize).map_err(|()| {
@ -46,12 +47,12 @@ impl Pool {
ResizeError::MremapFailed 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<(), ()> {
// Place the sigbus handler // Place the sigbus handler
SIGBUS_INIT.call_once(|| { SIGBUS_INIT.call_once(|| unsafe {
unsafe { place_sigbus_handler(); } place_sigbus_handler();
}); });
let pool_guard = self.map.read().unwrap(); let pool_guard = self.map.read().unwrap();
@ -59,7 +60,7 @@ impl Pool {
// Prepare the access // Prepare the access
SIGBUS_GUARD.with(|guard| { SIGBUS_GUARD.with(|guard| {
let (p,_) = guard.get(); let (p, _) = guard.get();
if !p.is_null() { if !p.is_null() {
// Recursive call of this method is not supported // Recursive call of this method is not supported
panic!("Recursive access to a SHM pool content is not supported."); panic!("Recursive access to a SHM pool content is not supported.");
@ -87,28 +88,28 @@ impl Pool {
impl Drop for Pool { impl Drop for Pool {
fn drop(&mut self) { fn drop(&mut self) {
trace!(self.log, "Deleting SHM pool"; "fd" => self.fd); trace!(self.log, "Deleting SHM pool"; "fd" => self.fd);
let _ = unsafe { unistd::close(self.fd) }; let _ = unistd::close(self.fd);
} }
} }
struct MemMap { struct MemMap {
ptr: *mut u8, ptr: *mut u8,
fd: RawFd, fd: RawFd,
size: usize size: usize,
} }
impl MemMap { impl MemMap {
fn new(fd: RawFd, size: usize) -> Result<MemMap,()> { fn new(fd: RawFd, size: usize) -> Result<MemMap, ()> {
Ok(MemMap { Ok(MemMap {
ptr: unsafe { map(fd, size) }?, ptr: unsafe { map(fd, size) }?,
fd: fd, fd: fd,
size: size size: size,
}) })
} }
fn remap(&mut self, newsize: usize) -> Result<(),()> { fn remap(&mut self, newsize: usize) -> Result<(), ()> {
if self.ptr.is_null() { if self.ptr.is_null() {
return Err(()) return Err(());
} }
// memunmap cannot fail, as we are unmapping a pre-existing map // memunmap cannot fail, as we are unmapping a pre-existing map
let _ = unsafe { unmap(self.ptr, self.size) }; let _ = unsafe { unmap(self.ptr, self.size) };
@ -119,7 +120,7 @@ impl MemMap {
self.ptr = ptr; self.ptr = ptr;
self.size = newsize; self.size = newsize;
Ok(()) Ok(())
}, }
Err(()) => { Err(()) => {
// set ourselves in an empty state // set ourselves in an empty state
self.ptr = ptr::null_mut(); self.ptr = ptr::null_mut();
@ -144,7 +145,7 @@ impl MemMap {
ptr >= self.ptr && ptr < unsafe { self.ptr.offset(self.size as isize) } ptr >= self.ptr && ptr < unsafe { self.ptr.offset(self.size as isize) }
} }
fn nullify(&self) -> Result<(),()> { fn nullify(&self) -> Result<(), ()> {
unsafe { nullify_map(self.ptr, self.size) } unsafe { nullify_map(self.ptr, self.size) }
} }
} }
@ -159,49 +160,41 @@ impl Drop for MemMap {
// mman::mmap should really be unsafe... why isn't it? // mman::mmap should really be unsafe... why isn't it?
unsafe fn map(fd: RawFd, size: usize) -> Result<*mut u8, ()> { unsafe fn map(fd: RawFd, size: usize) -> Result<*mut u8, ()> {
let ret = mman::mmap( let ret = mman::mmap(ptr::null_mut(),
ptr::null_mut(), size,
size, mman::PROT_READ,
mman::PROT_READ, mman::MAP_SHARED,
mman::MAP_SHARED, fd,
fd, 0);
0
);
ret.map(|p| p as *mut u8).map_err(|_| ()) ret.map(|p| p as *mut u8).map_err(|_| ())
} }
// mman::munmap should really be unsafe... why isn't it? // mman::munmap should really be unsafe... why isn't it?
unsafe fn unmap(ptr: *mut u8, size: usize) -> Result<(),()> { unsafe fn unmap(ptr: *mut u8, size: usize) -> Result<(), ()> {
let ret = mman::munmap(ptr as *mut _, size); let ret = mman::munmap(ptr as *mut _, size);
ret.map_err(|_| ()) ret.map_err(|_| ())
} }
unsafe fn nullify_map(ptr: *mut u8, size: usize) -> Result<(), ()> { unsafe fn nullify_map(ptr: *mut u8, size: usize) -> Result<(), ()> {
let ret = mman::mmap( let ret = mman::mmap(ptr as *mut _,
ptr as *mut _, size,
size, mman::PROT_READ,
mman::PROT_READ, mman::MAP_ANONYMOUS | mman::MAP_PRIVATE | mman::MAP_FIXED,
mman::MAP_ANONYMOUS | mman::MAP_PRIVATE | mman::MAP_FIXED, -1,
-1, 0);
0
);
ret.map(|_| ()).map_err(|_| ()) ret.map(|_| ()).map_err(|_| ())
} }
unsafe fn place_sigbus_handler() { unsafe fn place_sigbus_handler() {
// create our sigbus handler // create our sigbus handler
let action = SigAction::new( let action = SigAction::new(SigHandler::SigAction(sigbus_handler),
SigHandler::SigAction(sigbus_handler), signal::SA_NODEFER,
signal::SA_NODEFER, signal::SigSet::empty());
signal::SigSet::empty()
);
match signal::sigaction(Signal::SIGBUS, &action) { match signal::sigaction(Signal::SIGBUS, &action) {
Ok(old_signal) => { Ok(old_signal) => {
OLD_SIGBUS_HANDLER = Box::into_raw(Box::new(old_signal)); OLD_SIGBUS_HANDLER = Box::into_raw(Box::new(old_signal));
},
Err(e) => {
panic!("sigaction failed sor SIGBUS handler: {:?}", e)
} }
Err(e) => panic!("sigaction failed sor SIGBUS handler: {:?}", e),
} }
} }
@ -225,7 +218,7 @@ extern "C" fn sigbus_handler(_signum: c_int, info: *mut libc::siginfo_t, _contex
// something terrible occured ! // something terrible occured !
unsafe { reraise_sigbus() } unsafe { reraise_sigbus() }
} }
}, }
_ => { _ => {
// something else occured, let's die honorably // something else occured, let's die honorably
unsafe { reraise_sigbus() } unsafe { reraise_sigbus() }
@ -240,16 +233,16 @@ extern "C" fn sigbus_handler(_signum: c_int, info: *mut libc::siginfo_t, _contex
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut c_void { unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut c_void {
#[repr(C)] #[repr(C)]
struct siginfo_t { struct siginfo_t {
a: [libc::c_int; 3], // si_signo, si_errno, si_code a: [libc::c_int; 3], // si_signo, si_errno, si_code
si_addr: *mut libc::c_void, si_addr: *mut libc::c_void,
} }
(*(info as *const siginfo_t)).si_addr (*(info as *const siginfo_t)).si_addr
} }
#[cfg(not(any(target_os = "linux", target_os = "android")))] #[cfg(not(any(target_os = "linux", target_os = "android")))]
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut c_void { unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> *mut c_void {
(*info).si_addr (*info).si_addr
} }