separate all the libc interaction out per OS

We're now handling more of this ourselves, and leaving less to libstd.
Hopefully, we'll eventually break free of libstd, leaving a
highly-focused low-level library that retains all its conveniences in
freestanding environments.
This commit is contained in:
edef 2015-04-16 02:04:06 -04:00
parent 46b2a4007b
commit 7e0b126f42
3 changed files with 58 additions and 31 deletions

View File

@ -1,6 +1,6 @@
#![feature(no_std)]
#![feature(asm, core)]
#![feature(libc, page_size)]
#![feature(libc)]
#![no_std]
#[macro_use]

View File

@ -1,13 +1,12 @@
extern crate libc;
extern crate std;
use self::std::prelude::v1::*;
use self::std::env;
use core::prelude::*;
use self::std::io::Error as IoError;
use self::libc::{c_void, size_t};
use core::ptr;
use stack;
use valgrind;
#[cfg(unix)]
#[path = "os/unix.rs"] mod sys;
#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Stack {
@ -34,32 +33,27 @@ impl stack::Stack for Stack {
fn limit(&self) -> *const u8 {
unsafe {
self.ptr.offset(env::page_size() as isize)
self.ptr.offset(sys::page_size() as isize)
}
}
}
impl Stack {
fn new(size: usize) -> Stack {
let page_size = env::page_size();
let page_size = sys::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 {
let ptr = match sys::map_stack(size) {
None => {
panic!("mmap for stack of size {} failed: {:?}",
len, IoError::last_os_error())
}
Some(ptr) => ptr
};
let valgrind_id =
valgrind::stack_register(ptr as *const _,
@ -68,28 +62,22 @@ impl Stack {
Stack { ptr: ptr as *mut u8, len: len, valgrind_id: valgrind_id }
};
stack.protect();
unsafe {
if !sys::protect_stack(stack.ptr) {
panic!("mprotect for guard page of stack {:p} failed: {:?}",
stack.ptr, IoError::last_os_error());
}
}
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 {
if !sys::unmap_stack(self.ptr, self.len) {
panic!("munmap for stack {:p} of size {} failed: {:?}",
self.ptr, self.len, IoError::last_os_error())
}

39
src/os/unix.rs Normal file
View File

@ -0,0 +1,39 @@
extern crate libc;
use core::prelude::*;
pub use self::libc::{c_void, c_int, size_t};
pub use self::libc::{mmap, mprotect, munmap};
pub use self::libc::MAP_FAILED;
use core::ptr;
pub fn page_size() -> usize {
unsafe {
libc::sysconf(libc::_SC_PAGESIZE) as usize
}
}
pub const GUARD_PROT: c_int = libc::PROT_NONE;
pub const STACK_PROT: c_int = libc::PROT_READ
| libc::PROT_WRITE;
pub const STACK_FLAGS: c_int = libc::MAP_STACK
| libc::MAP_PRIVATE
| libc::MAP_ANON;
pub unsafe fn map_stack(len: usize) -> Option<*mut u8> {
let ptr = mmap(ptr::null_mut(), len as size_t,
STACK_PROT, STACK_FLAGS, -1, 0);
if ptr != MAP_FAILED {
Some(ptr as *mut u8)
}
else {
None
}
}
pub unsafe fn protect_stack(ptr: *mut u8) -> bool {
mprotect(ptr as *mut c_void, page_size() as size_t, GUARD_PROT) == 0
}
pub unsafe fn unmap_stack(ptr: *mut u8, len: usize) -> bool {
munmap(ptr as *mut c_void, len as size_t) == 0
}