8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ use option:: * ;
11
12
use super :: stack:: StackSegment ;
12
13
use libc:: c_void;
13
14
use cast:: { transmute, transmute_mut_unsafe,
@@ -16,17 +17,30 @@ use cast::{transmute, transmute_mut_unsafe,
16
17
// XXX: Registers is boxed so that it is 16-byte aligned, for storing
17
18
// SSE regs. It would be marginally better not to do this. In C++ we
18
19
// 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
+ }
20
29
21
30
pub impl Context {
22
31
static fn empty( ) -> Context {
23
- Context ( new_regs( ) )
32
+ Context {
33
+ start: None ,
34
+ regs : new_regs ( )
35
+ }
24
36
}
25
37
26
38
/// 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;
30
44
31
45
// The C-ABI function that is the task entry point
32
46
extern fn task_start_wrapper ( f : & ~fn ( ) ) { ( * f) ( ) }
@@ -46,15 +60,24 @@ pub impl Context {
46
60
47
61
initialize_call_frame ( & mut * regs, fp, argp, sp) ;
48
62
49
- return Context ( regs) ;
63
+ return Context {
64
+ start : Some ( start) ,
65
+ regs : regs
66
+ }
50
67
}
51
68
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
+ */
52
75
static fn swap( out_context: & mut Context , in_context: & Context ) {
53
76
let out_regs : & mut Registers = match out_context {
54
- & Context ( ~ref mut r) => r
77
+ & Context { regs : ~ref mut r, _ } => r
55
78
} ;
56
79
let in_regs: & Registers = match in_context {
57
- & Context ( ~ref r) => r
80
+ & Context { regs : ~ref r, _ } => r
58
81
} ;
59
82
60
83
unsafe { swap_registers ( out_regs, in_regs) } ;
@@ -88,7 +111,7 @@ fn initialize_call_frame(regs: &mut Registers,
88
111
fptr : * c_void , arg : * c_void , sp : * mut uint ) {
89
112
90
113
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 ) ;
92
115
93
116
unsafe { * sp = arg as uint ; }
94
117
let sp = mut_offset ( sp, -1 ) ;
0 commit comments