@@ -24,7 +24,7 @@ use stack::StackSegment;
2424// then misalign the regs again.
2525pub struct Context {
2626 /// The context entry point, saved here for later destruction
27- priv start : ~ Option < proc ( ) > ,
27+ priv start : Option < ~ proc ( ) > ,
2828 /// Hold the registers while the task or scheduler is suspended
2929 priv regs : ~Registers ,
3030 /// Lower bound and upper bound for the stack
@@ -34,7 +34,7 @@ pub struct Context {
3434impl Context {
3535 pub fn empty ( ) -> Context {
3636 Context {
37- start : ~ None ,
37+ start : None ,
3838 regs : new_regs ( ) ,
3939 stack_bounds : None ,
4040 }
@@ -43,8 +43,26 @@ impl Context {
4343 /// Create a new context that will resume execution by running proc()
4444 pub fn new ( start : proc ( ) , stack : & mut StackSegment ) -> Context {
4545 // 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+ }
4866 }
4967
5068 let sp: * uint = stack. end ( ) ;
@@ -60,10 +78,10 @@ impl Context {
6078 // FIXME #7767: Putting main into a ~ so it's a thin pointer and can
6179 // be passed to the spawn function. Another unfortunate
6280 // allocation
63- let box = ~Some ( start) ;
81+ let start = ~start;
6482 initialize_call_frame ( & mut * regs,
6583 task_start_wrapper as * c_void ,
66- unsafe { transmute ( & * box ) } ,
84+ unsafe { transmute ( & * start ) } ,
6785 sp) ;
6886
6987 // Scheduler tasks don't have a stack in the "we allocated it" sense,
@@ -78,7 +96,7 @@ impl Context {
7896 Some ( ( stack_base as uint , sp as uint ) )
7997 } ;
8098 return Context {
81- start : box ,
99+ start : Some ( start ) ,
82100 regs : regs,
83101 stack_bounds : bounds,
84102 }
0 commit comments