Implement the GuardedStack marker trait.
This commit is contained in:
parent
7ffad26cfd
commit
16c674b4f4
|
@ -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.
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
extern crate std;
|
||||
|
||||
pub use stack::Stack;
|
||||
pub use stack::GuardedStack;
|
||||
pub use context::Context;
|
||||
pub use generator::Generator;
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 {}
|
||||
|
|
Loading…
Reference in New Issue