extern crate context;
use std::panic;
use context::{Context, Transfer};
use context::stack::ProtectedFixedSizeStack;
struct Dropper;
impl Drop for Dropper {
fn drop(&mut self) {
println!("Dropping a Dropper!");
}
}
struct Carrier {
context: Option<Context>,
}
fn take_some_stack_from_transfer(t: &Transfer) -> Option<ProtectedFixedSizeStack> {
let stack_ref = unsafe { &mut *(t.data as *mut Option<ProtectedFixedSizeStack>) };
stack_ref.take()
}
fn stack_ref_from_some_stack(some_stack: &mut Option<ProtectedFixedSizeStack>) -> usize {
some_stack as *mut Option<ProtectedFixedSizeStack> as usize
}
extern "C" fn unwind_stack(t: Transfer) -> Transfer {
println!("Unwinding stack by panicking!");
let Transfer { context: ctx, data } = t;
let carrier = unsafe { &mut *(data as *mut Carrier) };
carrier.context = Some(ctx);
struct ForceUnwind;
panic::resume_unwind(Box::new(ForceUnwind));
}
extern "C" fn delete_stack(t: Transfer) -> Transfer {
println!("Deleting stack!");
let _ = take_some_stack_from_transfer(&t);
t
}
extern "C" fn context_function(t: Transfer) -> ! {
println!("Entering context_function...");
let mut some_stack = take_some_stack_from_transfer(&t);
let stack_ref = stack_ref_from_some_stack(&mut some_stack);
let (result, context) = {
let mut carrier = Carrier { context: Some(t.context) };
let carrier_ptr = &mut carrier as *mut _ as usize;
let r = panic::catch_unwind(|| {
let _dropper = Dropper;
let carrier = unsafe { &mut *(carrier_ptr as *mut Carrier) };
println!("Everything's set up!");
let context = carrier.context.take().unwrap();
let Transfer { context, .. } = unsafe { context.resume(carrier_ptr) };
carrier.context = Some(context);
for i in 0usize.. {
print!("Yielding {} => ", i);
let context = carrier.context.take().unwrap();
let Transfer { context, .. } = unsafe { context.resume(i) };
carrier.context = Some(context);
}
});
(r, carrier.context.take().unwrap())
};
match result {
Ok(..) => println!("Finished loop without panicking (this should not happen here)!"),
Err(..) => println!("Recovered from a panic!"),
}
println!("Defer stack deallocation by returning to main()!");
unsafe { context.resume_ontop(stack_ref, delete_stack) };
unreachable!();
}
pub fn run() {
let mut some_stack = Some(ProtectedFixedSizeStack::default());
let stack_ref = stack_ref_from_some_stack(&mut some_stack);
let mut ctx = unsafe { Context::new(some_stack.as_ref().unwrap(), context_function) };
let Transfer { context, data } = unsafe { ctx.resume(stack_ref) };
ctx = context;
let carrier_ptr = data;
for _ in 0..10 {
print!("Resuming => ");
let Transfer { context, data } = unsafe { ctx.resume(0) };
ctx = context;
println!("Got {}", data);
}
println!("Resuming context with unwind_stack() ontop!");
unsafe { ctx.resume_ontop(carrier_ptr, unwind_stack) };
match some_stack {
Some(..) => println!("Stack is still there (this should not happen here)!"),
None => println!("Stack has been deleted!"),
}
println!("Finished!");
}
fn main() {
run();
}