core: Cleanup rt::context
This commit is contained in:
parent
087a015a72
commit
e8ddef93da
3 changed files with 35 additions and 17 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue