Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Void to ensure that the new thread diverges #11

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
/Cargo.lock
*~
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ build = "build.rs"
[build-dependencies]
gcc = "0.3.3"

[dependencies]
void = "0.0.5"

[features]
default = ["os", "valgrind"]
os = ["libc"]
Expand Down
1 change: 1 addition & 0 deletions examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ fn main() {
let mut ctx = Context::new(stack, move || {
println!("it's alive!");
(*ctx_slot).swap();
panic!("Do not come back!")
});

ctx_slot = &mut ctx;
Expand Down
8 changes: 6 additions & 2 deletions src/arch/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ use core::mem::{size_of, align_of};
use core::cmp::max;
use core::ptr;

use void::{self, Void};

use super::imp::STACK_ALIGN;

pub unsafe extern "C" fn rust_trampoline<F: FnOnce()>(f: *const F) {
ptr::read(f)()
pub unsafe extern "C" fn rust_trampoline<F>(f: *const F) -> !
where F: FnOnce<(), Output=Void>
{
void::unreachable(ptr::read(f)())
}

pub unsafe fn push<T>(spp: &mut *mut usize, value: T) -> *mut T {
Expand Down
3 changes: 0 additions & 3 deletions src/arch/x86/init.s
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ movl $$0, %ebp
// call the function pointer with the data pointer (top of the stack is the first argument)
call *%eax

// crash if it ever returns
ud2

1:
// save our neatly-setup new stack
xchg %esp, %eax
Expand Down
6 changes: 5 additions & 1 deletion src/arch/x86/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// See the LICENSE file included in this distribution.
use core::prelude::*;

use void::Void;

use stack::Stack;
use super::common::{push, rust_trampoline};

Expand All @@ -16,7 +18,9 @@ pub struct Registers {

impl Registers {
#[inline]
pub unsafe fn new<S, F>(stack: &mut S, f: F) -> Registers where S: Stack, F: FnOnce() {
pub unsafe fn new<S, F>(stack: &mut S, f: F) -> Registers
where S: Stack, F: FnOnce<(), Output=Void>
{
let sp_limit = stack.limit();
let mut sp = stack.top() as *mut usize;
let f_ptr = push(&mut sp, f);
Expand Down
3 changes: 0 additions & 3 deletions src/arch/x86_64/init.s
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ movq $$0, %rbp
// call the function pointer with the data pointer (rdi is the first argument)
call *%rax

// crash if it ever returns
ud2

1:
// save our neatly-setup new stack
xchg %rsp, %rdi
Expand Down
6 changes: 4 additions & 2 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// See the LICENSE file included in this distribution.
use core::prelude::*;
use core::marker::PhantomData;

use void::Void;

use arch::Registers;
use stack;
use debug::StackId;
Expand All @@ -28,10 +31,9 @@ unsafe impl<'a, Stack> Send for Context<'a, Stack>
impl<'a, Stack> Context<'a, Stack> where Stack: stack::Stack {
/// Create a new Context. When it is swapped into,
/// it will call the passed closure.
/// The closure shouldn't return - doing that will abort the process.
#[inline]
pub unsafe fn new<F>(mut stack: Stack, f: F) -> Context<'a, Stack>
where F: FnOnce() + Send + 'a {
where F: FnOnce<(), Output=Void> + Send + 'a {
let stack_id = StackId::register(&mut stack);
let regs = Registers::new(&mut stack, f);
Context {
Expand Down
33 changes: 13 additions & 20 deletions src/debug/mod.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
// This file is part of libfringe, a low-level green threading library.
// Copyright (c) 2015, Nathan Zadoks <nathan@nathan7.eu>
// See the LICENSE file included in this distribution.
use core::prelude::*;
use stack;
pub use self::imp::*;

mod valgrind;
#[cfg(feature = "valgrind")]
#[path = "valgrind/mod.rs"]
mod imp;

#[derive(Debug)]
pub struct StackId(valgrind::stack_id_t);

impl StackId {
#[inline(always)]
pub fn register<Stack: stack::Stack>(stack: &mut Stack) -> StackId {
StackId(unsafe {
valgrind::stack_register(stack.limit(), stack.top())
})
}
}

impl Drop for StackId {
#[inline(always)]
fn drop(&mut self) {
unsafe {
valgrind::stack_deregister(self.0)
#[cfg(not(feature = "valgrind"))]
mod imp {
use stack;
#[derive(Debug)]
pub struct StackId;
/// No-op since no valgrind
impl StackId {
pub unsafe fn register<Stack: stack::Stack>(_stack: &mut Stack) -> StackId {
StackId
}
}
}
50 changes: 39 additions & 11 deletions src/debug/valgrind/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,45 @@
// This file is part of libfringe, a low-level green threading library.
// Copyright (c) 2015, Nathan Zadoks <nathan@nathan7.eu>
// See the LICENSE file included in this distribution.
pub use self::imp::*;
#![allow(non_camel_case_types)]
//! In order for Valgrind to keep track of stack overflows and such, it needs
//! a little help. That help unfortunately comes in the form of a set of C
//! macros. Calling out to un-inlineable C code for this is pointlessly slow,
//! but that's the way it is for now.
use core::prelude::*;
use stack;

#[cfg(feature = "valgrind")]
#[path = "native.rs"]
mod imp;
pub type stack_id_t = u32;
extern "C" {
#[link_name = "valgrind_stack_register"]
/// Register a stack with Valgrind. Returns an integer ID that can
/// be used to deregister the stack when it's deallocated.
/// `start < end`.
pub fn stack_register(start: *const u8, end: *const u8) -> stack_id_t;

#[cfg(not(feature = "valgrind"))]
mod imp {
//! Stub for the Valgrind functions
#![allow(non_camel_case_types)]
pub type stack_id_t = ();
pub unsafe fn stack_register(_start: *const u8, _end: *const u8) -> stack_id_t {}
pub unsafe fn stack_deregister(_id: stack_id_t) {}
#[link_name = "valgrind_stack_deregister"]
/// Deregister a stack from Valgrind. Takes the integer ID that was returned
/// on registration.
pub fn stack_deregister(id: stack_id_t);
}

#[derive(Debug)]
pub struct StackId(stack_id_t);

impl StackId {
#[inline(always)]
pub fn register<Stack: stack::Stack>(stack: &mut Stack) -> StackId {
StackId(unsafe {
stack_register(stack.limit(), stack.top())
})
}
}

impl Drop for StackId {
#[inline(always)]
fn drop(&mut self) {
unsafe {
stack_deregister(self.0)
}
}
}
22 changes: 0 additions & 22 deletions src/debug/valgrind/native.rs

This file was deleted.

4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright (c) 2015, Nathan Zadoks <nathan@nathan7.eu>
// See the LICENSE file included in this distribution.
#![feature(no_std)]
#![feature(asm, core, core_prelude)]
#![feature(asm, core, core_prelude, unboxed_closures)]
#![no_std]

//! libfringe is a low-level green threading library.
Expand All @@ -15,6 +15,8 @@ extern crate core;
#[macro_use]
extern crate std;

extern crate void;

pub use context::Context;
pub use stack::Stack;

Expand Down