forked from M-Labs/libfringe
Implement OwnedStack.
This commit is contained in:
parent
4b32c18f70
commit
5a77a01863
|
@ -20,7 +20,8 @@ rev = "9ef793e9549aabfd2d969615180b69d29ce28d88"
|
||||||
simd = "0.1"
|
simd = "0.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["valgrind"]
|
default = ["alloc", "valgrind"]
|
||||||
|
alloc = []
|
||||||
|
|
||||||
# These apply only to tests within this library; assembly at -O0 is completely
|
# These apply only to tests within this library; assembly at -O0 is completely
|
||||||
# unreadable, so use -O1.
|
# 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:
|
It also provides the necessary low-level building blocks:
|
||||||
* a trait that can be implemented by stack allocators,
|
* a trait that can be implemented by stack allocators,
|
||||||
[Stack](https://edef1c.github.io/libfringe/fringe/struct.Stack.html);
|
[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,
|
* a stack allocator based on anonymous memory mappings with guard pages,
|
||||||
[OsStack](https://edef1c.github.io/libfringe/fringe/struct.OsStack.html).
|
[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].
|
libfringe provides some optional features through [Cargo's feature flags].
|
||||||
Currently, all of them are enabled by default.
|
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`
|
#### `valgrind`
|
||||||
|
|
||||||
|
This flag enables [Valgrind] integration. libfringe will register context stacks with Valgrind.
|
||||||
|
|
||||||
[Valgrind]: http://valgrind.org
|
[Valgrind]: http://valgrind.org
|
||||||
[Valgrind] integration. libfringe will register context stacks with Valgrind.
|
|
||||||
|
|
||||||
## Internals
|
## 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
|
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||||
// copied, modified, or distributed except according to those terms.
|
// copied, modified, or distributed except according to those terms.
|
||||||
#![feature(asm, naked_functions)]
|
#![feature(asm, naked_functions)]
|
||||||
|
#![cfg_attr(feature = "alloc", feature(alloc))]
|
||||||
#![cfg_attr(test, feature(test, thread_local, const_fn))]
|
#![cfg_attr(test, feature(test, thread_local, const_fn))]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -21,6 +22,10 @@
|
||||||
//!
|
//!
|
||||||
//! * a trait that can be implemented by stack allocators,
|
//! * a trait that can be implemented by stack allocators,
|
||||||
//! [Stack](struct.Stack.html);
|
//! [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,
|
//! * a stack allocator based on anonymous memory mappings with guard pages,
|
||||||
//! [OsStack](struct.OsStack.html).
|
//! [OsStack](struct.OsStack.html).
|
||||||
|
|
||||||
|
@ -30,19 +35,25 @@ 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 slice_stack::SliceStack;
|
||||||
|
|
||||||
pub use generator::Generator;
|
pub use generator::Generator;
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
pub use owned_stack::OwnedStack;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub use os::Stack as OsStack;
|
pub use os::Stack as OsStack;
|
||||||
|
|
||||||
mod arch;
|
mod arch;
|
||||||
mod debug;
|
mod debug;
|
||||||
|
|
||||||
mod stack;
|
|
||||||
mod context;
|
mod context;
|
||||||
|
mod stack;
|
||||||
|
mod slice_stack;
|
||||||
pub mod generator;
|
pub mod generator;
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
mod owned_stack;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mod os;
|
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://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
|
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||||
// copied, modified, or distributed except according to those terms.
|
// copied, modified, or distributed except according to those terms.
|
||||||
|
//! 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 {
|
||||||
|
@ -22,22 +23,3 @@ 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,17 +6,19 @@
|
||||||
// copied, modified, or distributed except according to those terms.
|
// copied, modified, or distributed except according to those terms.
|
||||||
extern crate fringe;
|
extern crate fringe;
|
||||||
|
|
||||||
use fringe::{OsStack, SliceStack};
|
use fringe::{Stack, SliceStack, OwnedStack, OsStack};
|
||||||
use fringe::generator::Generator;
|
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> {
|
fn new_add_one() -> Generator<i32, i32, OsStack> {
|
||||||
let stack = OsStack::new(0).unwrap();
|
let stack = OsStack::new(0).unwrap();
|
||||||
Generator::new(stack, move |yielder, mut input| {
|
Generator::new(stack, add_one_fn)
|
||||||
loop {
|
|
||||||
if input == 0 { break }
|
|
||||||
input = yielder.suspend(input + 1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -67,14 +69,15 @@ fn panic_safety() {
|
||||||
fn with_slice_stack() {
|
fn with_slice_stack() {
|
||||||
let mut memory = [0; 1024];
|
let mut memory = [0; 1024];
|
||||||
let stack = SliceStack(&mut memory);
|
let stack = SliceStack(&mut memory);
|
||||||
let mut add_one = unsafe {
|
let mut add_one = unsafe { Generator::unsafe_new(stack, add_one_fn) };
|
||||||
Generator::unsafe_new(stack, move |yielder, mut input| {
|
assert_eq!(add_one.resume(1), Some(2));
|
||||||
loop {
|
assert_eq!(add_one.resume(2), Some(3));
|
||||||
if input == 0 { break }
|
}
|
||||||
input = yielder.suspend(input + 1)
|
|
||||||
}
|
#[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(1), Some(2));
|
||||||
assert_eq!(add_one.resume(2), Some(3));
|
assert_eq!(add_one.resume(2), Some(3));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// copied, modified, or distributed except according to those terms.
|
// copied, modified, or distributed except according to those terms.
|
||||||
extern crate fringe;
|
extern crate fringe;
|
||||||
|
|
||||||
use fringe::{Stack, SliceStack, OsStack};
|
use fringe::{Stack, SliceStack, OwnedStack, OsStack};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn slice_stack() {
|
fn slice_stack() {
|
||||||
|
@ -15,6 +15,12 @@ fn slice_stack() {
|
||||||
assert_eq!(stack.base() as isize - stack.limit() as isize, 1024);
|
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]
|
#[test]
|
||||||
fn default_os_stack() {
|
fn default_os_stack() {
|
||||||
let stack = OsStack::new(0).unwrap();
|
let stack = OsStack::new(0).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue