Implement the GuardedStack marker trait.

master
whitequark 2016-07-17 03:45:50 +00:00 committed by edef
parent 7ffad26cfd
commit 16c674b4f4
4 changed files with 34 additions and 20 deletions

View File

@ -68,6 +68,16 @@ impl<Item, Stack> Generator<Item, Stack>
where Item: Send, Stack: stack::Stack {
/// Creates a new generator.
pub fn new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
where Stack: stack::GuardedStack, F: FnOnce(&mut Yielder<Item, Stack>) + Send {
unsafe { Generator::unsafe_new(stack, f) }
}
/// Same as `new`, but does not require `stack` to have a guard page.
///
/// This function is unsafe because the generator function can easily violate
/// memory safety by overflowing the stack. It is useful in environments where
/// guarded stacks do not exist, e.g. in absence of an MMU.
pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
where F: FnOnce(&mut Yielder<Item, Stack>) + Send {
unsafe extern "C" fn generator_wrapper<Item, Stack, F>(info: usize) -> !
where Item: Send, Stack: stack::Stack, F: FnOnce(&mut Yielder<Item, Stack>) {
@ -82,21 +92,19 @@ impl<Item, Stack> Generator<Item, Stack>
loop { yielder.return_(None) }
}
unsafe {
let mut generator = Generator {
state: State::Suspended,
context: context::Context::new(stack, generator_wrapper::<Item, Stack, F>),
phantom: PhantomData
};
let mut generator = Generator {
state: State::Suspended,
context: context::Context::new(stack, generator_wrapper::<Item, Stack, F>),
phantom: PhantomData
};
// Transfer environment to the callee.
let mut data = (Yielder::new(&mut generator.context), f);
context::Context::swap(&mut generator.context, &generator.context,
&mut data as *mut (Yielder<Item, Stack>, F) as usize);
mem::forget(data);
// Transfer environment to the callee.
let mut data = (Yielder::new(&mut generator.context), f);
context::Context::swap(&mut generator.context, &generator.context,
&mut data as *mut (Yielder<Item, Stack>, F) as usize);
mem::forget(data);
generator
}
generator
}
/// Returns the state of the generator.

View File

@ -30,6 +30,7 @@
extern crate std;
pub use stack::Stack;
pub use stack::GuardedStack;
pub use context::Context;
pub use generator::Generator;

View File

@ -7,11 +7,8 @@ use stack;
mod sys;
/// OsStack holds a stack allocated using the operating system's anonymous
/// OsStack holds a guarded stack allocated using the operating system's anonymous
/// memory mapping facility.
///
/// The stack it provides comes with a guard page, which is not included
/// in the stack limit.
#[derive(Debug)]
pub struct Stack {
ptr: *mut u8,
@ -22,9 +19,9 @@ unsafe impl Send for Stack {}
impl Stack {
/// Allocates a new stack with at least `size` accessible bytes.
/// `size` is rounded up to an integral number of pages; `Stack::new(0)`
/// is legal and allocates the smallest possible stack, consisting
/// of one data page and one guard page.
/// `size` is rounded up to an integral number of pages; `Stack::new(0)` is legal
/// and allocates the smallest possible stack, consisting of one data page and
/// one guard page.
pub fn new(size: usize) -> Result<Stack, IoError> {
let page_size = sys::page_size();
@ -66,6 +63,8 @@ impl stack::Stack for Stack {
}
}
unsafe impl stack::GuardedStack for Stack {}
impl Drop for Stack {
fn drop(&mut self) {
unsafe { sys::unmap_stack(self.ptr, self.len) }.expect("cannot unmap stack")

View File

@ -14,3 +14,9 @@ pub trait Stack {
/// so this is the lowest address.
fn limit(&self) -> *mut u8;
}
/// A marker trait for `Stack` objects with a guard page.
///
/// A guarded stack must guarantee that any access of data at addresses `limit()` to
/// `limit().offset(4096)` will abnormally terminate the program.
pub unsafe trait GuardedStack {}