rustuv: Fix a memory leak (documented inside)

This happened because the environment of a procedure was never deallocated.
This commit is contained in:
Alex Crichton 2013-12-16 00:44:34 -08:00
parent f25c81a51a
commit 9f005866e5
1 changed files with 25 additions and 7 deletions

View File

@ -24,7 +24,7 @@ use stack::StackSegment;
// then misalign the regs again.
pub struct Context {
/// The context entry point, saved here for later destruction
priv start: ~Option<proc()>,
priv start: Option<~proc()>,
/// Hold the registers while the task or scheduler is suspended
priv regs: ~Registers,
/// Lower bound and upper bound for the stack
@ -34,7 +34,7 @@ pub struct Context {
impl Context {
pub fn empty() -> Context {
Context {
start: ~None,
start: None,
regs: new_regs(),
stack_bounds: None,
}
@ -43,8 +43,26 @@ impl Context {
/// Create a new context that will resume execution by running proc()
pub fn new(start: proc(), stack: &mut StackSegment) -> Context {
// The C-ABI function that is the task entry point
extern fn task_start_wrapper(f: &mut Option<proc()>) {
f.take_unwrap()()
//
// Note that this function is a little sketchy. We're taking a
// procedure, transmuting it to a stack-closure, and then calling to
// closure. This leverages the fact that the representation of these two
// types is the same.
//
// The reason that we're doing this is that this procedure is expected
// to never return. The codegen which frees the environment of the
// procedure occurs *after* the procedure has completed, and this means
// that we'll never actually free the procedure.
//
// To solve this, we use this transmute (to not trigger the procedure
// deallocation here), and then store a copy of the procedure in the
// `Context` structure returned. When the `Context` is deallocated, then
// the entire procedure box will be deallocated as well.
extern fn task_start_wrapper(f: &proc()) {
unsafe {
let f: &|| = transmute(f);
(*f)()
}
}
let sp: *uint = stack.end();
@ -60,10 +78,10 @@ impl Context {
// FIXME #7767: Putting main into a ~ so it's a thin pointer and can
// be passed to the spawn function. Another unfortunate
// allocation
let box = ~Some(start);
let start = ~start;
initialize_call_frame(&mut *regs,
task_start_wrapper as *c_void,
unsafe { transmute(&*box) },
unsafe { transmute(&*start) },
sp);
// Scheduler tasks don't have a stack in the "we allocated it" sense,
@ -78,7 +96,7 @@ impl Context {
Some((stack_base as uint, sp as uint))
};
return Context {
start: box,
start: Some(start),
regs: regs,
stack_bounds: bounds,
}