2015-04-16 20:06:57 +08:00
|
|
|
// This file is part of libfringe, a low-level green threading library.
|
2016-07-16 09:22:41 +08:00
|
|
|
// Copyright (c) edef <edef@edef.eu>,
|
|
|
|
// whitequark <whitequark@whitequark.org>
|
2016-08-21 05:45:01 +08:00
|
|
|
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE 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
|
|
|
|
// copied, modified, or distributed except according to those terms.
|
2015-04-16 19:06:30 +08:00
|
|
|
|
2016-08-11 09:34:53 +08:00
|
|
|
pub use self::imp::*;
|
2015-04-17 00:50:15 +08:00
|
|
|
|
2016-08-11 09:34:53 +08:00
|
|
|
#[allow(unused_attributes)] // rust-lang/rust#35584
|
2016-09-02 17:45:55 +08:00
|
|
|
#[cfg_attr(target_arch = "x86", path = "x86.rs")]
|
|
|
|
#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
|
|
|
|
#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
|
|
|
|
#[cfg_attr(target_arch = "or1k", path = "or1k.rs")]
|
2015-04-17 00:50:15 +08:00
|
|
|
mod imp;
|
2016-09-07 20:56:32 +08:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
extern crate test;
|
|
|
|
extern crate simd;
|
|
|
|
|
|
|
|
use arch::{self, StackPointer};
|
|
|
|
use ::OsStack;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn context() {
|
|
|
|
unsafe extern "C" fn adder(arg: usize, stack_ptr: StackPointer) -> ! {
|
|
|
|
println!("it's alive! arg: {}", arg);
|
|
|
|
let (arg, stack_ptr) = arch::swap(arg + 1, stack_ptr, None);
|
|
|
|
println!("still alive! arg: {}", arg);
|
|
|
|
arch::swap(arg + 1, stack_ptr, None);
|
|
|
|
panic!("i should be dead");
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let stack = OsStack::new(4 << 20).unwrap();
|
|
|
|
let stack_ptr = arch::init(&stack, adder);
|
|
|
|
|
|
|
|
let (ret, stack_ptr) = arch::swap(10, stack_ptr, Some(&stack));
|
|
|
|
assert_eq!(ret, 11);
|
|
|
|
let (ret, _) = arch::swap(50, stack_ptr, Some(&stack));
|
|
|
|
assert_eq!(ret, 51);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn context_simd() {
|
|
|
|
unsafe extern "C" fn permuter(arg: usize, stack_ptr: StackPointer) -> ! {
|
|
|
|
// 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);
|
|
|
|
let (_, stack_ptr) = arch::swap(0, stack_ptr, None);
|
|
|
|
// And try again after a context switch.
|
|
|
|
let x = simd::i32x4::splat(arg as i32);
|
|
|
|
let y = x * x;
|
|
|
|
println!("simd result: {:?}", y);
|
|
|
|
arch::swap(0, stack_ptr, None);
|
|
|
|
panic!("i should be dead");
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let stack = OsStack::new(4 << 20).unwrap();
|
|
|
|
let stack_ptr = arch::init(&stack, permuter);
|
|
|
|
|
|
|
|
let (_, stack_ptr) = arch::swap(10, stack_ptr, Some(&stack));
|
|
|
|
arch::swap(20, stack_ptr, Some(&stack));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe extern "C" fn do_panic(arg: usize, stack_ptr: StackPointer) -> ! {
|
|
|
|
match arg {
|
|
|
|
0 => panic!("arg=0"),
|
|
|
|
1 => {
|
|
|
|
arch::swap(0, stack_ptr, None);
|
|
|
|
panic!("arg=1");
|
|
|
|
}
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2017-02-25 21:24:36 +08:00
|
|
|
#[should_panic(expected = "arg=0")]
|
2016-09-07 20:56:32 +08:00
|
|
|
fn panic_after_start() {
|
|
|
|
unsafe {
|
|
|
|
let stack = OsStack::new(4 << 20).unwrap();
|
|
|
|
let stack_ptr = arch::init(&stack, do_panic);
|
|
|
|
|
|
|
|
arch::swap(0, stack_ptr, Some(&stack));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2017-02-25 21:24:36 +08:00
|
|
|
#[should_panic(expected = "arg=1")]
|
2016-09-07 20:56:32 +08:00
|
|
|
fn panic_after_swap() {
|
|
|
|
unsafe {
|
|
|
|
let stack = OsStack::new(4 << 20).unwrap();
|
|
|
|
let stack_ptr = arch::init(&stack, do_panic);
|
|
|
|
|
|
|
|
let (_, stack_ptr) = arch::swap(1, stack_ptr, Some(&stack));
|
|
|
|
arch::swap(0, stack_ptr, Some(&stack));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn swap(b: &mut test::Bencher) {
|
|
|
|
unsafe extern "C" fn loopback(mut arg: usize, mut stack_ptr: StackPointer) -> ! {
|
|
|
|
// This deliberately does not ignore arg, to measure the time it takes
|
|
|
|
// to move the return value between registers.
|
|
|
|
loop {
|
|
|
|
let data = arch::swap(arg, stack_ptr, None);
|
|
|
|
arg = data.0;
|
|
|
|
stack_ptr = data.1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let stack = OsStack::new(4 << 20).unwrap();
|
|
|
|
let mut stack_ptr = arch::init(&stack, loopback);
|
|
|
|
|
|
|
|
b.iter(|| for _ in 0..10 {
|
|
|
|
stack_ptr = arch::swap(0, stack_ptr, Some(&stack)).1;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|