@@ -24,7 +24,7 @@ use stack::StackSegment;
24
24
// then misalign the regs again.
25
25
pub struct Context {
26
26
/// The context entry point, saved here for later destruction
27
- priv start : ~ Option < proc ( ) > ,
27
+ priv start : Option < ~ proc ( ) > ,
28
28
/// Hold the registers while the task or scheduler is suspended
29
29
priv regs : ~Registers ,
30
30
/// Lower bound and upper bound for the stack
@@ -34,7 +34,7 @@ pub struct Context {
34
34
impl Context {
35
35
pub fn empty ( ) -> Context {
36
36
Context {
37
- start : ~ None ,
37
+ start : None ,
38
38
regs : new_regs ( ) ,
39
39
stack_bounds : None ,
40
40
}
@@ -43,8 +43,26 @@ impl Context {
43
43
/// Create a new context that will resume execution by running proc()
44
44
pub fn new ( start : proc ( ) , stack : & mut StackSegment ) -> Context {
45
45
// The C-ABI function that is the task entry point
46
- extern fn task_start_wrapper ( f : & mut Option < proc ( ) > ) {
47
- f. take_unwrap ( ) ( )
46
+ //
47
+ // Note that this function is a little sketchy. We're taking a
48
+ // procedure, transmuting it to a stack-closure, and then calling to
49
+ // closure. This leverages the fact that the representation of these two
50
+ // types is the same.
51
+ //
52
+ // The reason that we're doing this is that this procedure is expected
53
+ // to never return. The codegen which frees the environment of the
54
+ // procedure occurs *after* the procedure has completed, and this means
55
+ // that we'll never actually free the procedure.
56
+ //
57
+ // To solve this, we use this transmute (to not trigger the procedure
58
+ // deallocation here), and then store a copy of the procedure in the
59
+ // `Context` structure returned. When the `Context` is deallocated, then
60
+ // the entire procedure box will be deallocated as well.
61
+ extern fn task_start_wrapper ( f : & proc ( ) ) {
62
+ unsafe {
63
+ let f: & || = transmute ( f ) ;
64
+ ( * f) ( )
65
+ }
48
66
}
49
67
50
68
let sp: * uint = stack. end ( ) ;
@@ -60,10 +78,10 @@ impl Context {
60
78
// FIXME #7767: Putting main into a ~ so it's a thin pointer and can
61
79
// be passed to the spawn function. Another unfortunate
62
80
// allocation
63
- let box = ~Some ( start) ;
81
+ let start = ~start;
64
82
initialize_call_frame ( & mut * regs,
65
83
task_start_wrapper as * c_void ,
66
- unsafe { transmute ( & * box ) } ,
84
+ unsafe { transmute ( & * start ) } ,
67
85
sp) ;
68
86
69
87
// Scheduler tasks don't have a stack in the "we allocated it" sense,
@@ -78,7 +96,7 @@ impl Context {
78
96
Some ( ( stack_base as uint , sp as uint ) )
79
97
} ;
80
98
return Context {
81
- start : box ,
99
+ start : Some ( start ) ,
82
100
regs : regs,
83
101
stack_bounds : bounds,
84
102
}
0 commit comments