core: Cleanup rt::context

This commit is contained in:
Brian Anderson 2013-03-12 00:48:41 -07:00
parent 087a015a72
commit e8ddef93da
3 changed files with 35 additions and 17 deletions

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use option::*;
use super::stack::StackSegment;
use libc::c_void;
use cast::{transmute, transmute_mut_unsafe,
@ -16,17 +17,30 @@ use cast::{transmute, transmute_mut_unsafe,
// XXX: Registers is boxed so that it is 16-byte aligned, for storing
// SSE regs. It would be marginally better not to do this. In C++ we
// use an attribute on a struct.
pub struct Context(~Registers);
// XXX: It would be nice to define regs as `~Option<Registers>` since
// the registers are sometimes empty, but the discriminant would
// then misalign the regs again.
pub struct Context {
/// The context entry point, saved here for later destruction
start: Option<~~fn()>,
/// Hold the registers while the task or scheduler is suspended
regs: ~Registers
}
pub impl Context {
static fn empty() -> Context {
Context(new_regs())
Context {
start: None,
regs: new_regs()
}
}
/// Create a new context that will resume execution by running ~fn()
/// # Safety Note
/// The `start` closure must remain valid for the life of the Task
static fn new(start: &~fn(), stack: &mut StackSegment) -> Context {
static fn new(start: ~fn(), stack: &mut StackSegment) -> Context {
// XXX: Putting main into a ~ so it's a thin pointer and can
// be passed to the spawn function. Another unfortunate
// allocation
let start = ~start;
// The C-ABI function that is the task entry point
extern fn task_start_wrapper(f: &~fn()) { (*f)() }
@ -46,15 +60,24 @@ pub impl Context {
initialize_call_frame(&mut *regs, fp, argp, sp);
return Context(regs);
return Context {
start: Some(start),
regs: regs
}
}
/* Switch contexts
Suspend the current execution context and resume another by
saving the registers values of the executing thread to a Context
then loading the registers from a previously saved Context.
*/
static fn swap(out_context: &mut Context, in_context: &Context) {
let out_regs: &mut Registers = match out_context {
&Context(~ref mut r) => r
&Context { regs: ~ref mut r, _ } => r
};
let in_regs: &Registers = match in_context {
&Context(~ref r) => r
&Context { regs: ~ref r, _ } => r
};
unsafe { swap_registers(out_regs, in_regs) };
@ -88,7 +111,7 @@ fn initialize_call_frame(regs: &mut Registers,
fptr: *c_void, arg: *c_void, sp: *mut uint) {
let sp = align_down(sp);
let sp = mut_offset(sp, -4); // XXX: -4 words? Needs this be done at all?
let sp = mut_offset(sp, -4);
unsafe { *sp = arg as uint; }
let sp = mut_offset(sp, -1);

View file

@ -285,8 +285,6 @@ pub impl Scheduler {
const TASK_MIN_STACK_SIZE: uint = 10000000; // XXX: Too much stack
pub struct Task {
/// The task entry point, saved here for later destruction
priv start: ~~fn(),
/// The segment of stack on which the task is currently running or,
/// if the task is blocked, on which the task will resume execution
priv current_stack_segment: StackSegment,
@ -297,15 +295,11 @@ pub struct Task {
impl Task {
static fn new(stack_pool: &mut StackPool, start: ~fn()) -> Task {
// XXX: Putting main into a ~ so it's a thin pointer and can
// be passed to the spawn function. Another unfortunate
// allocation
let start = ~Task::build_start_wrapper(start);
let start = Task::build_start_wrapper(start);
let mut stack = stack_pool.take_segment(TASK_MIN_STACK_SIZE);
// NB: Context holds a pointer to that ~fn
let initial_context = Context::new(&*start, &mut stack);
let initial_context = Context::new(start, &mut stack);
return Task {
start: start,
current_stack_segment: stack,
saved_context: initial_context,
};

View file

@ -27,6 +27,7 @@ pub impl StackSegment {
}
}
/// Point one word beyond the high end of the allocated stack
fn end(&self) -> *uint {
unsafe {
vec::raw::to_ptr(self.buf).offset(self.buf.len()) as *uint