Implement OwnedStack.
This commit is contained in:
parent
4b32c18f70
commit
5a77a01863
|
@ -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.
|
||||
|
|
12
README.md
12
README.md
|
@ -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
|
||||
|
||||
|
|
17
src/lib.rs
17
src/lib.rs
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
20
src/stack.rs
20
src/stack.rs
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 new_add_one() -> Generator<i32, i32, OsStack> {
|
||||
let stack = OsStack::new(0).unwrap();
|
||||
Generator::new(stack, move |yielder, mut input| {
|
||||
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, 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));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue