diff --git a/benches/swap.rs b/benches/swap.rs deleted file mode 100644 index 170213a..0000000 --- a/benches/swap.rs +++ /dev/null @@ -1,30 +0,0 @@ -// This file is part of libfringe, a low-level green threading library. -// Copyright (c) edef , -// whitequark -// See the LICENSE file included in this distribution. -#![feature(test)] -extern crate test; -extern crate fringe; - -use fringe::Context; - -static mut ctx_slot: *mut Context = 0 as *mut Context<_>; - -#[bench] -fn swap(b: &mut test::Bencher) { - unsafe extern "C" fn loopback(mut arg: usize) -> ! { - // This deliberately does not ignore arg, to measure the time it takes - // to move the return value between registers. - let ctx_ptr = ctx_slot; - loop { arg = Context::swap(ctx_ptr, ctx_ptr, arg) } - } - - unsafe { - let stack = fringe::OsStack::new(4 << 20).unwrap(); - let mut ctx = Context::new(stack, loopback); - ctx_slot = &mut ctx; - - let ctx_ptr = &mut ctx; - b.iter(|| Context::swap(ctx_ptr, ctx_ptr, 0)); - } -} diff --git a/src/context.rs b/src/context.rs index a936a5c..6e864fd 100644 --- a/src/context.rs +++ b/src/context.rs @@ -52,3 +52,118 @@ impl Context where OldStack: stack::Stack { arch::swap(arg, &mut (*old_ctx).stack_ptr, &(*new_ctx).stack_ptr, &(*new_ctx).stack) } } + +#[cfg(test)] +mod test { + extern crate test; + extern crate simd; + + use std::ptr; + use super::Context; + use ::OsStack; + + #[thread_local] + static mut ctx_slot: *mut Context = ptr::null_mut(); + + #[test] + fn context() { + unsafe extern "C" fn adder(arg: usize) -> ! { + println!("it's alive! arg: {}", arg); + let arg = Context::swap(ctx_slot, ctx_slot, arg + 1); + println!("still alive! arg: {}", arg); + Context::swap(ctx_slot, ctx_slot, arg + 1); + panic!("i should be dead"); + } + + unsafe { + let stack = OsStack::new(4 << 20).unwrap(); + let mut ctx = Context::new(stack, adder); + ctx_slot = &mut ctx; + + let ret = Context::swap(ctx_slot, ctx_slot, 10); + assert_eq!(ret, 11); + let ret = Context::swap(ctx_slot, ctx_slot, 50); + assert_eq!(ret, 51); + } + } + + #[test] + fn context_simd() { + unsafe extern "C" fn permuter(arg: usize) -> ! { + // This will crash if the stack is not aligned properly. + let x = simd::i32x4::splat(arg as i32); + let y = x * x; + println!("simd result: {:?}", y); + Context::swap(ctx_slot, ctx_slot, 0); + // And try again after a context switch. + let x = simd::i32x4::splat(arg as i32); + let y = x * x; + println!("simd result: {:?}", y); + Context::swap(ctx_slot, ctx_slot, 0); + panic!("i should be dead"); + } + + unsafe { + let stack = OsStack::new(4 << 20).unwrap(); + let mut ctx = Context::new(stack, permuter); + ctx_slot = &mut ctx; + + Context::swap(ctx_slot, ctx_slot, 10); + Context::swap(ctx_slot, ctx_slot, 20); + } + } + + unsafe extern "C" fn do_panic(arg: usize) -> ! { + match arg { + 0 => panic!("arg=0"), + 1 => { + Context::swap(ctx_slot, ctx_slot, 0); + panic!("arg=1"); + } + _ => unreachable!() + } + } + + #[test] + #[should_panic="arg=0"] + fn panic_after_start() { + unsafe { + let stack = OsStack::new(4 << 20).unwrap(); + let mut ctx = Context::new(stack, do_panic); + + Context::swap(&mut ctx, &ctx, 0); + } + } + + #[test] + #[should_panic="arg=1"] + fn panic_after_swap() { + unsafe { + let stack = OsStack::new(4 << 20).unwrap(); + let mut ctx = Context::new(stack, do_panic); + ctx_slot = &mut ctx; + + Context::swap(&mut ctx, &ctx, 1); + Context::swap(&mut ctx, &ctx, 0); + } + } + + #[bench] + fn swap(b: &mut test::Bencher) { + unsafe extern "C" fn loopback(mut arg: usize) -> ! { + // This deliberately does not ignore arg, to measure the time it takes + // to move the return value between registers. + let ctx_ptr = ctx_slot; + loop { arg = Context::swap(ctx_ptr, ctx_ptr, arg) } + } + + unsafe { + let stack = OsStack::new(4 << 20).unwrap(); + let mut ctx = Context::new(stack, loopback); + ctx_slot = &mut ctx; + + let ctx_ptr = &mut ctx; + b.iter(|| Context::swap(ctx_ptr, ctx_ptr, 0)); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 5dd83af..13abc34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ // Copyright (c) edef // See the LICENSE file included in this distribution. #![feature(asm)] +#![cfg_attr(test, feature(test, thread_local, const_fn))] #![cfg_attr(target_arch = "x86", feature(naked_functions, core_intrinsics))] #![cfg_attr(target_arch = "x86_64", feature(naked_functions, core_intrinsics))] #![no_std] diff --git a/tests/context.rs b/tests/context.rs deleted file mode 100644 index a94ac7d..0000000 --- a/tests/context.rs +++ /dev/null @@ -1,60 +0,0 @@ -// This file is part of libfringe, a low-level green threading library. -// Copyright (c) edef , -// whitequark -// See the LICENSE file included in this distribution. -#![feature(thread_local)] -extern crate simd; -extern crate fringe; - -use fringe::Context; - -#[thread_local] -static mut ctx_slot: *mut Context = 0 as *mut Context<_>; - -#[test] -fn context() { - unsafe extern "C" fn adder(arg: usize) -> ! { - println!("it's alive! arg: {}", arg); - let arg = Context::swap(ctx_slot, ctx_slot, arg + 1); - println!("still alive! arg: {}", arg); - Context::swap(ctx_slot, ctx_slot, arg + 1); - panic!("i should be dead"); - } - - unsafe { - let stack = fringe::OsStack::new(4 << 20).unwrap(); - let mut ctx = Context::new(stack, adder); - ctx_slot = &mut ctx; - - let ret = Context::swap(ctx_slot, ctx_slot, 10); - assert_eq!(ret, 11); - let ret = Context::swap(ctx_slot, ctx_slot, 50); - assert_eq!(ret, 51); - } -} - -#[test] -fn context_simd() { - unsafe extern "C" fn permuter(arg: usize) -> ! { - // This will crash if the stack is not aligned properly. - let x = simd::i32x4::splat(arg as i32); - let y = x * x; - println!("simd result: {:?}", y); - Context::swap(ctx_slot, ctx_slot, 0); - // And try again after a context switch. - let x = simd::i32x4::splat(arg as i32); - let y = x * x; - println!("simd result: {:?}", y); - Context::swap(ctx_slot, ctx_slot, 0); - panic!("i should be dead"); - } - - unsafe { - let stack = fringe::OsStack::new(4 << 20).unwrap(); - let mut ctx = Context::new(stack, permuter); - ctx_slot = &mut ctx; - - Context::swap(ctx_slot, ctx_slot, 10); - Context::swap(ctx_slot, ctx_slot, 20); - } -} diff --git a/tests/panic.rs b/tests/panic.rs deleted file mode 100644 index 80c21cc..0000000 --- a/tests/panic.rs +++ /dev/null @@ -1,45 +0,0 @@ -// This file is part of libfringe, a low-level green threading library. -// Copyright (c) whitequark -// See the LICENSE file included in this distribution. -#![feature(thread_local)] -extern crate fringe; - -use fringe::Context; - -#[thread_local] -static mut ctx_slot: *mut Context = 0 as *mut Context<_>; - -unsafe extern "C" fn do_panic(arg: usize) -> ! { - match arg { - 0 => panic!("arg=0"), - 1 => { - Context::swap(ctx_slot, ctx_slot, 0); - panic!("arg=1"); - } - _ => unreachable!() - } -} - -#[test] -#[should_panic="arg=0"] -fn panic_after_start() { - unsafe { - let stack = fringe::OsStack::new(4 << 20).unwrap(); - let mut ctx = Context::new(stack, do_panic); - - Context::swap(&mut ctx, &ctx, 0); - } -} - -#[test] -#[should_panic="arg=1"] -fn panic_after_swap() { - unsafe { - let stack = fringe::OsStack::new(4 << 20).unwrap(); - let mut ctx = Context::new(stack, do_panic); - ctx_slot = &mut ctx; - - Context::swap(&mut ctx, &ctx, 1); - Context::swap(&mut ctx, &ctx, 0); - } -}