libfringe/src/os.rs

99 lines
2.3 KiB
Rust

extern crate libc;
extern crate std;
use self::std::prelude::v1::*;
use self::std::env;
use self::std::io::Error as IoError;
use self::libc::{c_void, size_t};
use core::ptr;
use stack;
use valgrind;
#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Stack {
ptr: *mut u8,
len: usize,
valgrind_id: valgrind::stack_id_t
}
pub struct StackSource;
impl stack::StackSource for StackSource {
type Output = Stack;
fn get_stack(size: usize) -> Stack {
Stack::new(size)
}
}
impl stack::Stack for Stack {
fn top(&mut self) -> *mut u8 {
unsafe {
self.ptr.offset(self.len as isize)
}
}
fn limit(&self) -> *const u8 {
unsafe {
self.ptr.offset(env::page_size() as isize)
}
}
}
impl Stack {
fn new(size: usize) -> Stack {
let page_size = env::page_size();
// round the page size up,
// using the fact that it is a power of two
let len = (size + page_size - 1) & !(page_size - 1);
const STACK_PROT: libc::c_int = libc::PROT_READ | libc::PROT_WRITE;
const STACK_FLAGS: libc::c_int = libc::MAP_STACK
| libc::MAP_PRIVATE
| libc::MAP_ANON;
let stack = unsafe {
let ptr = libc::mmap(ptr::null_mut(), len as size_t,
STACK_PROT, STACK_FLAGS, -1, 0);
if ptr == libc::MAP_FAILED {
panic!("mmap for stack of size {} failed: {:?}",
len, IoError::last_os_error())
}
let valgrind_id =
valgrind::stack_register(ptr as *const _,
ptr.offset(len as isize) as *const _);
Stack { ptr: ptr as *mut u8, len: len, valgrind_id: valgrind_id }
};
stack.protect();
stack
}
fn protect(&self) {
unsafe {
if libc::mprotect(self.ptr as *mut c_void,
env::page_size() as libc::size_t,
libc::PROT_NONE) != 0 {
panic!("mprotect for guard page of stack {:p} failed: {:?}",
self.ptr, IoError::last_os_error());
}
}
}
}
impl Drop for Stack {
fn drop(&mut self) {
unsafe {
valgrind::stack_deregister(self.valgrind_id);
if libc::munmap(self.ptr as *mut c_void, self.len as size_t) != 0 {
panic!("munmap for stack {:p} of size {} failed: {:?}",
self.ptr, self.len, IoError::last_os_error())
}
}
}
}