forked from M-Labs/libfringe
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 {
|
where Item: Send, Stack: stack::Stack {
|
||||||
/// Creates a new generator.
|
/// Creates a new generator.
|
||||||
pub fn new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
|
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 {
|
where F: FnOnce(&mut Yielder<Item, Stack>) + Send {
|
||||||
unsafe extern "C" fn generator_wrapper<Item, Stack, F>(info: usize) -> !
|
unsafe extern "C" fn generator_wrapper<Item, Stack, F>(info: usize) -> !
|
||||||
where Item: Send, Stack: stack::Stack, F: FnOnce(&mut Yielder<Item, Stack>) {
|
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) }
|
loop { yielder.return_(None) }
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
let mut generator = Generator {
|
||||||
let mut generator = Generator {
|
state: State::Suspended,
|
||||||
state: State::Suspended,
|
context: context::Context::new(stack, generator_wrapper::<Item, Stack, F>),
|
||||||
context: context::Context::new(stack, generator_wrapper::<Item, Stack, F>),
|
phantom: PhantomData
|
||||||
phantom: PhantomData
|
};
|
||||||
};
|
|
||||||
|
|
||||||
// Transfer environment to the callee.
|
// Transfer environment to the callee.
|
||||||
let mut data = (Yielder::new(&mut generator.context), f);
|
let mut data = (Yielder::new(&mut generator.context), f);
|
||||||
context::Context::swap(&mut generator.context, &generator.context,
|
context::Context::swap(&mut generator.context, &generator.context,
|
||||||
&mut data as *mut (Yielder<Item, Stack>, F) as usize);
|
&mut data as *mut (Yielder<Item, Stack>, F) as usize);
|
||||||
mem::forget(data);
|
mem::forget(data);
|
||||||
|
|
||||||
generator
|
generator
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the state of the generator.
|
/// Returns the state of the generator.
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
pub use stack::Stack;
|
pub use stack::Stack;
|
||||||
|
pub use stack::GuardedStack;
|
||||||
pub use context::Context;
|
pub use context::Context;
|
||||||
pub use generator::Generator;
|
pub use generator::Generator;
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,8 @@ use stack;
|
||||||
|
|
||||||
mod sys;
|
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.
|
/// memory mapping facility.
|
||||||
///
|
|
||||||
/// The stack it provides comes with a guard page, which is not included
|
|
||||||
/// in the stack limit.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Stack {
|
pub struct Stack {
|
||||||
ptr: *mut u8,
|
ptr: *mut u8,
|
||||||
|
@ -22,9 +19,9 @@ unsafe impl Send for Stack {}
|
||||||
|
|
||||||
impl Stack {
|
impl Stack {
|
||||||
/// Allocates a new stack with at least `size` accessible bytes.
|
/// Allocates a new stack with at least `size` accessible bytes.
|
||||||
/// `size` is rounded up to an integral number of pages; `Stack::new(0)`
|
/// `size` is rounded up to an integral number of pages; `Stack::new(0)` is legal
|
||||||
/// is legal and allocates the smallest possible stack, consisting
|
/// and allocates the smallest possible stack, consisting of one data page and
|
||||||
/// of one data page and one guard page.
|
/// one guard page.
|
||||||
pub fn new(size: usize) -> Result<Stack, IoError> {
|
pub fn new(size: usize) -> Result<Stack, IoError> {
|
||||||
let page_size = sys::page_size();
|
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 {
|
impl Drop for Stack {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { sys::unmap_stack(self.ptr, self.len) }.expect("cannot unmap stack")
|
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.
|
/// so this is the lowest address.
|
||||||
fn limit(&self) -> *mut u8;
|
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