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
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
- fn new ( start : & ~fn ( ) , stack : & mut StackSegment ) -> Context {
39
+ 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) ( ) }
@@ -40,21 +54,29 @@ pub impl Context {
40
54
// which we will then modify to call the given function when restored
41
55
let mut regs = new_regs ( ) ;
42
56
unsafe {
43
- swap_registers ( transmute_mut_region ( & mut * regs) ,
44
- transmute_region ( & * regs) )
57
+ swap_registers ( transmute_mut_region ( & mut * regs) , transmute_region ( & * regs) )
45
58
} ;
46
59
47
60
initialize_call_frame ( & mut * regs, fp, argp, sp) ;
48
61
49
- return Context ( regs) ;
62
+ return Context {
63
+ start : Some ( start) ,
64
+ regs : regs
65
+ }
50
66
}
51
67
68
+ /* Switch contexts
69
+
70
+ Suspend the current execution context and resume another by
71
+ saving the registers values of the executing thread to a Context
72
+ then loading the registers from a previously saved Context.
73
+ */
52
74
fn swap ( out_context : & mut Context , in_context : & Context ) {
53
75
let out_regs: & mut Registers = match out_context {
54
- & Context ( ~ref mut r) => r
76
+ & Context { regs : ~ref mut r, _ } => r
55
77
} ;
56
78
let in_regs: & Registers = match in_context {
57
- & Context ( ~ref r) => r
79
+ & Context { regs : ~ref r, _ } => r
58
80
} ;
59
81
60
82
unsafe { swap_registers ( out_regs, in_regs) } ;
@@ -84,11 +106,10 @@ fn new_regs() -> ~Registers {
84
106
}
85
107
86
108
#[ cfg( target_arch = "x86" ) ]
87
- fn initialize_call_frame ( regs : & mut Registers ,
88
- fptr : * c_void , arg : * c_void , sp : * mut uint ) {
109
+ fn initialize_call_frame ( regs : & mut Registers , fptr : * c_void , arg : * c_void , sp : * mut uint ) {
89
110
90
111
let sp = align_down ( sp) ;
91
- let sp = mut_offset ( sp, -4 ) ; // XXX: -4 words? Needs this be done at all?
112
+ let sp = mut_offset ( sp, -4 ) ;
92
113
93
114
unsafe { * sp = arg as uint ; }
94
115
let sp = mut_offset ( sp, -1 ) ;
@@ -108,8 +129,7 @@ type Registers = [uint * 22];
108
129
fn new_regs ( ) -> ~Registers { ~[ 0 , .. 22 ] }
109
130
110
131
#[ cfg( target_arch = "x86_64" ) ]
111
- fn initialize_call_frame ( regs : & mut Registers ,
112
- fptr : * c_void , arg : * c_void , sp : * mut uint ) {
132
+ fn initialize_call_frame ( regs : & mut Registers , fptr : * c_void , arg : * c_void , sp : * mut uint ) {
113
133
114
134
// Redefinitions from regs.h
115
135
static RUSTRT_ARG0 : uint = 3 ;
@@ -143,8 +163,7 @@ type Registers = [uint * 32];
143
163
fn new_regs ( ) -> ~Registers { ~[ 0 , .. 32 ] }
144
164
145
165
#[ cfg( target_arch = "arm" ) ]
146
- fn initialize_call_frame ( regs : & mut Registers ,
147
- fptr : * c_void , arg : * c_void , sp : * mut uint ) {
166
+ fn initialize_call_frame ( regs : & mut Registers , fptr : * c_void , arg : * c_void , sp : * mut uint ) {
148
167
let sp = mut_offset ( sp, -1 ) ;
149
168
150
169
// The final return address. 0 indicates the bottom of the stack
@@ -162,8 +181,7 @@ type Registers = [uint * 32];
162
181
fn new_regs ( ) -> ~Registers { ~[ 0 , .. 32 ] }
163
182
164
183
#[ cfg( target_arch = "mips" ) ]
165
- fn initialize_call_frame ( regs : & mut Registers ,
166
- fptr : * c_void , arg : * c_void , sp : * mut uint ) {
184
+ fn initialize_call_frame ( regs : & mut Registers , fptr : * c_void , arg : * c_void , sp : * mut uint ) {
167
185
let sp = mut_offset ( sp, -1 ) ;
168
186
169
187
// The final return address. 0 indicates the bottom of the stack
0 commit comments