Implement OwnedStack.

This commit is contained in:
whitequark 2016-08-19 13:58:45 +00:00 committed by edef
parent 4b32c18f70
commit 5a77a01863
8 changed files with 109 additions and 41 deletions

View File

@ -20,7 +20,8 @@ rev = "9ef793e9549aabfd2d969615180b69d29ce28d88"
simd = "0.1"
[features]
default = ["valgrind"]
default = ["alloc", "valgrind"]
alloc = []
# These apply only to tests within this library; assembly at -O0 is completely
# unreadable, so use -O1.

View File

@ -19,6 +19,10 @@ It provides the following safe abstractions:
It also provides the necessary low-level building blocks:
* a trait that can be implemented by stack allocators,
[Stack](https://edef1c.github.io/libfringe/fringe/struct.Stack.html);
* a wrapper for using slice references as stacks,
[SliceStack](https://edef1c.github.io/libfringe/fringe/struct.SliceStack.html);
* a stack allocator based on `Box<[u8]>`,
[OwnedStack](https://edef1c.github.io/libfringe/fringe/struct.OwnedStack.html);
* a stack allocator based on anonymous memory mappings with guard pages,
[OsStack](https://edef1c.github.io/libfringe/fringe/struct.OsStack.html).
@ -136,10 +140,16 @@ no-default-features = true
libfringe provides some optional features through [Cargo's feature flags].
Currently, all of them are enabled by default.
#### `alloc`
This flag enables dependency on the `alloc` crate, which is required for
the [OwnedStack](https://edef1c.github.io/libfringe/fringe/struct.OwnedStack.html).
#### `valgrind`
This flag enables [Valgrind] integration. libfringe will register context stacks with Valgrind.
[Valgrind]: http://valgrind.org
[Valgrind] integration. libfringe will register context stacks with Valgrind.
## Internals

View File

@ -5,6 +5,7 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
#![feature(asm, naked_functions)]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(test, feature(test, thread_local, const_fn))]
#![no_std]
@ -21,6 +22,10 @@
//!
//! * a trait that can be implemented by stack allocators,
//! [Stack](struct.Stack.html);
//! * a wrapper for using slice references as stacks,
//! [SliceStack](struct.SliceStack.html);
//! * a stack allocator based on `Box<[u8]>`,
//! [OwnedStack](struct.OwnedStack.html);
//! * a stack allocator based on anonymous memory mappings with guard pages,
//! [OsStack](struct.OsStack.html).
@ -30,19 +35,25 @@ extern crate std;
pub use stack::Stack;
pub use stack::GuardedStack;
pub use stack::SliceStack;
pub use slice_stack::SliceStack;
pub use generator::Generator;
#[cfg(feature = "alloc")]
pub use owned_stack::OwnedStack;
#[cfg(unix)]
pub use os::Stack as OsStack;
mod arch;
mod debug;
mod stack;
mod context;
mod stack;
mod slice_stack;
pub mod generator;
#[cfg(feature = "alloc")]
mod owned_stack;
#[cfg(unix)]
mod os;

33
src/owned_stack.rs Normal file
View File

@ -0,0 +1,33 @@
// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// See the LICENSE file included in this distribution.
extern crate alloc;
use self::alloc::raw_vec::RawVec;
use self::alloc::boxed::Box;
/// OwnedStack allocates on heap and owns a non-guarded stack.
pub struct OwnedStack(Box<[u8]>);
impl OwnedStack {
/// Allocates a new stack with exactly `size` accessible bytes using
/// the default Rust allocator.
pub fn new(size: usize) -> OwnedStack {
OwnedStack(unsafe { RawVec::with_capacity(size).into_box() })
}
}
impl ::stack::Stack for OwnedStack {
#[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
}
}

22
src/slice_stack.rs Normal file
View File

@ -0,0 +1,22 @@
// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// See the LICENSE file included in this distribution.
/// 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::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

@ -4,6 +4,7 @@
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Traits for stacks.
/// A trait for objects that hold ownership of a stack.
pub trait Stack {
@ -22,22 +23,3 @@ pub trait Stack {
/// 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 {}
/// 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

@ -6,17 +6,19 @@
// copied, modified, or distributed except according to those terms.
extern crate fringe;
use fringe::{OsStack, SliceStack};
use fringe::generator::Generator;
use fringe::{Stack, SliceStack, OwnedStack, OsStack};
use fringe::generator::{Generator, Yielder};
fn add_one_fn<S: Stack>(yielder: &mut Yielder<i32, i32, S>, mut input: i32) {
loop {
if input == 0 { break }
input = yielder.suspend(input + 1)
}
}
fn new_add_one() -> Generator<i32, i32, OsStack> {
let stack = OsStack::new(0).unwrap();
Generator::new(stack, move |yielder, mut input| {
loop {
if input == 0 { break }
input = yielder.suspend(input + 1)
}
})
Generator::new(stack, add_one_fn)
}
#[test]
@ -67,14 +69,15 @@ fn panic_safety() {
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.suspend(input + 1)
}
})
};
let mut add_one = unsafe { Generator::unsafe_new(stack, add_one_fn) };
assert_eq!(add_one.resume(1), Some(2));
assert_eq!(add_one.resume(2), Some(3));
}
#[test]
fn with_owned_stack() {
let stack = OwnedStack::new(1024);
let mut add_one = unsafe { Generator::unsafe_new(stack, add_one_fn) };
assert_eq!(add_one.resume(1), Some(2));
assert_eq!(add_one.resume(2), Some(3));
}

View File

@ -6,7 +6,7 @@
// copied, modified, or distributed except according to those terms.
extern crate fringe;
use fringe::{Stack, SliceStack, OsStack};
use fringe::{Stack, SliceStack, OwnedStack, OsStack};
#[test]
fn slice_stack() {
@ -15,6 +15,12 @@ fn slice_stack() {
assert_eq!(stack.base() as isize - stack.limit() as isize, 1024);
}
#[test]
fn owned_stack() {
let stack = OwnedStack::new(1024);
assert_eq!(stack.base() as isize - stack.limit() as isize, 1024);
}
#[test]
fn default_os_stack() {
let stack = OsStack::new(0).unwrap();