88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11+ use option:: * ;
1112use super :: stack:: StackSegment ;
1213use libc:: c_void;
1314use cast:: { transmute, transmute_mut_unsafe,
@@ -16,17 +17,30 @@ use cast::{transmute, transmute_mut_unsafe,
1617// XXX: Registers is boxed so that it is 16-byte aligned, for storing
1718// SSE regs. It would be marginally better not to do this. In C++ we
1819// use an attribute on a struct.
19- pub struct Context ( ~Registers ) ;
20+ // XXX: It would be nice to define regs as `~Option<Registers>` since
21+ // the registers are sometimes empty, but the discriminant would
22+ // then misalign the regs again.
23+ pub struct Context {
24+ /// The context entry point, saved here for later destruction
25+ start : Option < ~~fn ( ) > ,
26+ /// Hold the registers while the task or scheduler is suspended
27+ regs : ~Registers
28+ }
2029
2130pub impl Context {
2231 static fn empty( ) -> Context {
23- Context ( new_regs( ) )
32+ Context {
33+ start: None ,
34+ regs : new_regs ( )
35+ }
2436 }
2537
2638 /// Create a new context that will resume execution by running ~fn()
27- /// # Safety Note
28- /// The `start` closure must remain valid for the life of the Task
29- static fn new( start: & ~fn ( ) , stack: & mut StackSegment ) -> Context {
39+ static fn new ( start : ~fn ( ) , stack : & mut StackSegment ) -> Context {
40+ // XXX: Putting main into a ~ so it's a thin pointer and can
41+ // be passed to the spawn function. Another unfortunate
42+ // allocation
43+ let start = ~start;
3044
3145 // The C-ABI function that is the task entry point
3246 extern fn task_start_wrapper ( f : & ~fn ( ) ) { ( * f) ( ) }
@@ -46,15 +60,24 @@ pub impl Context {
4660
4761 initialize_call_frame ( & mut * regs, fp, argp, sp) ;
4862
49- return Context ( regs) ;
63+ return Context {
64+ start : Some ( start) ,
65+ regs : regs
66+ }
5067 }
5168
69+ /* Switch contexts
70+
71+ Suspend the current execution context and resume another by
72+ saving the registers values of the executing thread to a Context
73+ then loading the registers from a previously saved Context.
74+ */
5275 static fn swap( out_context: & mut Context , in_context: & Context ) {
5376 let out_regs : & mut Registers = match out_context {
54- & Context ( ~ref mut r) => r
77+ & Context { regs : ~ref mut r, _ } => r
5578 } ;
5679 let in_regs: & Registers = match in_context {
57- & Context ( ~ref r) => r
80+ & Context { regs : ~ref r, _ } => r
5881 } ;
5982
6083 unsafe { swap_registers ( out_regs, in_regs) } ;
@@ -88,7 +111,7 @@ fn initialize_call_frame(regs: &mut Registers,
88111 fptr : * c_void , arg : * c_void , sp : * mut uint ) {
89112
90113 let sp = align_down ( sp) ;
91- let sp = mut_offset ( sp, -4 ) ; // XXX: -4 words? Needs this be done at all?
114+ let sp = mut_offset ( sp, -4 ) ;
92115
93116 unsafe { * sp = arg as uint ; }
94117 let sp = mut_offset ( sp, -1 ) ;
0 commit comments