Implement SliceStack.

This commit is contained in:
whitequark 2016-08-19 09:18:46 +00:00 committed by edef
parent e0ad79ea0c
commit f8cf95f686
4 changed files with 48 additions and 5 deletions

View File

@ -27,6 +27,8 @@ extern crate std;
pub use stack::Stack; pub use stack::Stack;
pub use stack::GuardedStack; pub use stack::GuardedStack;
pub use stack::SliceStack;
pub use generator::Generator; pub use generator::Generator;
#[cfg(unix)] #[cfg(unix)]

View File

@ -1,7 +1,6 @@
// This file is part of libfringe, a low-level green threading library. // This file is part of libfringe, a low-level green threading library.
// Copyright (c) edef <edef@edef.eu> // Copyright (c) edef <edef@edef.eu>
// See the LICENSE file included in this distribution. // See the LICENSE file included in this distribution.
//! Traits for stacks.
/// A trait for objects that hold ownership of a stack. /// A trait for objects that hold ownership of a stack.
pub trait Stack { pub trait Stack {
@ -20,3 +19,22 @@ pub trait Stack {
/// A guarded stack must guarantee that any access of data at addresses `limit()` to /// A guarded stack must guarantee that any access of data at addresses `limit()` to
/// `limit().offset(4096)` will abnormally terminate the program. /// `limit().offset(4096)` will abnormally terminate the program.
pub unsafe trait GuardedStack {} pub unsafe trait GuardedStack {}
/// SliceStack holds a non-guarded stack allocated elsewhere and provided as a mutable
/// slice.
pub struct SliceStack<'a>(pub &'a mut [u8]);
impl<'a> Stack for SliceStack<'a> {
#[inline(always)]
fn base(&self) -> *mut u8 {
// The slice cannot wrap around the address space, so the conversion from usize
// to isize will not wrap either.
let len: isize = self.0.len() as isize;
unsafe { self.limit().offset(len) }
}
#[inline(always)]
fn limit(&self) -> *mut u8 {
self.0.as_ptr() as *mut u8
}
}

View File

@ -3,7 +3,7 @@
// See the LICENSE file included in this distribution. // See the LICENSE file included in this distribution.
extern crate fringe; extern crate fringe;
use fringe::OsStack; use fringe::{OsStack, SliceStack};
use fringe::generator::Generator; use fringe::generator::Generator;
fn new_add_one() -> Generator<i32, i32, OsStack> { fn new_add_one() -> Generator<i32, i32, OsStack> {
@ -59,3 +59,19 @@ fn panic_safety() {
let mut wrapper = Wrapper { gen: gen }; let mut wrapper = Wrapper { gen: gen };
wrapper.gen.resume(()); wrapper.gen.resume(());
} }
#[test]
fn with_slice_stack() {
let mut memory = [0; 1024];
let stack = SliceStack(&mut memory);
let mut add_one = unsafe {
Generator::unsafe_new(stack, move |yielder, mut input| {
loop {
if input == 0 { break }
input = yielder.generate(input + 1)
}
})
};
assert_eq!(add_one.resume(1), Some(2));
assert_eq!(add_one.resume(2), Some(3));
}

View File

@ -3,17 +3,24 @@
// See the LICENSE file included in this distribution. // See the LICENSE file included in this distribution.
extern crate fringe; extern crate fringe;
use fringe::{Stack, OsStack}; use fringe::{Stack, SliceStack, OsStack};
#[test] #[test]
fn default_stack() { fn slice_stack() {
let mut memory = [0; 1024];
let stack = SliceStack(&mut memory);
assert_eq!(stack.base() as isize - stack.limit() as isize, 1024);
}
#[test]
fn default_os_stack() {
let stack = OsStack::new(0).unwrap(); let stack = OsStack::new(0).unwrap();
// Make sure the topmost page of the stack, at least, is accessible. // Make sure the topmost page of the stack, at least, is accessible.
unsafe { *(stack.base().offset(-1)) = 0; } unsafe { *(stack.base().offset(-1)) = 0; }
} }
#[test] #[test]
fn one_page_stack() { fn one_page_os_stack() {
let stack = OsStack::new(4096).unwrap(); let stack = OsStack::new(4096).unwrap();
// Make sure the topmost page of the stack, at least, is accessible. // Make sure the topmost page of the stack, at least, is accessible.
unsafe { *(stack.base().offset(-1)) = 0; } unsafe { *(stack.base().offset(-1)) = 0; }