Skip to content

Commit 7d756e4

Browse files
committed
rustrt: Reorganize task usage
Most of the comments are available on the Task structure itself, but this commit is aimed at making FFI-style usage of Rust tasks a little nicer. Primarily, this commit enables re-use of tasks across multiple invocations. The method `run` will no longer unconditionally destroy the task itself. Rather, the task will be internally re-usable if the closure specified did not fail. Once a task has failed once it is considered poisoned and it can never be used again. Along the way I tried to document shortcomings of the current method of tearing down a task, opening a few issues as well. For now none of the behavior is a showstopper, but it's useful to acknowledge it. Also along the way I attempted to remove as much `unsafe` code as possible, opting for safer abstractions.
1 parent bab614f commit 7d756e4

File tree

9 files changed

+337
-118
lines changed

9 files changed

+337
-118
lines changed

src/libgreen/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ pub fn start(argc: int, argv: **u8,
299299
let mut ret = None;
300300
simple::task().run(|| {
301301
ret = Some(run(event_loop_factory, main.take_unwrap()));
302-
});
302+
}).destroy();
303303
// unsafe is ok b/c we're sure that the runtime is gone
304304
unsafe { rt::cleanup() }
305305
ret.unwrap()

src/libgreen/task.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ extern fn bootstrap_green_task(task: uint, code: *(), env: *()) -> ! {
110110
// requested. This is the "try/catch" block for this green task and
111111
// is the wrapper for *all* code run in the task.
112112
let mut start = Some(start);
113-
let task = task.swap().run(|| start.take_unwrap()());
113+
let task = task.swap().run(|| start.take_unwrap()()).destroy();
114114

115115
// Once the function has exited, it's time to run the termination
116116
// routine. This means we need to context switch one more time but
@@ -120,7 +120,7 @@ extern fn bootstrap_green_task(task: uint, code: *(), env: *()) -> ! {
120120
// this we could add a `terminate` function to the `Runtime` trait
121121
// in libstd, but that seems less appropriate since the coversion
122122
// method exists.
123-
GreenTask::convert(task).terminate()
123+
GreenTask::convert(task).terminate();
124124
}
125125

126126
impl GreenTask {

src/libnative/lib.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,12 @@ pub fn start(argc: int, argv: **u8, main: proc()) -> int {
134134
let mut main = Some(main);
135135
let mut task = task::new((my_stack_bottom, my_stack_top));
136136
task.name = Some(str::Slice("<main>"));
137-
let t = task.run(|| {
137+
drop(task.run(|| {
138138
unsafe {
139139
rt::stack::record_stack_bounds(my_stack_bottom, my_stack_top);
140140
}
141141
exit_code = Some(run(main.take_unwrap()));
142-
});
143-
drop(t);
142+
}).destroy());
144143
unsafe { rt::cleanup(); }
145144
// If the exit code wasn't set, then the task block must have failed.
146145
return exit_code.unwrap_or(rt::DEFAULT_ERROR_CODE);

src/libnative/task.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ pub fn spawn_opts(opts: TaskOpts, f: proc():Send) {
9292
let mut f = Some(f);
9393
let mut task = task;
9494
task.put_runtime(ops);
95-
let t = task.run(|| { f.take_unwrap()() });
96-
drop(t);
95+
drop(task.run(|| { f.take_unwrap()() }).destroy());
9796
bookkeeping::decrement();
9897
})
9998
}

src/librustrt/local_heap.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,12 @@ impl LocalHeap {
110110
self.memory_region.free(alloc);
111111
}
112112

113-
pub unsafe fn annihilate(&mut self) {
113+
/// Immortalize all pending allocations, forcing them to live forever.
114+
///
115+
/// This function will freeze all allocations to prevent all pending
116+
/// allocations from being deallocated. This is used in preparation for when
117+
/// a task is about to destroy TLD.
118+
pub unsafe fn immortalize(&mut self) {
114119
let mut n_total_boxes = 0u;
115120

116121
// Pass 1: Make all boxes immortal.
@@ -122,6 +127,17 @@ impl LocalHeap {
122127
(*alloc).ref_count = RC_IMMORTAL;
123128
});
124129

130+
if debug_mem() {
131+
// We do logging here w/o allocation.
132+
rterrln!("total boxes annihilated: {}", n_total_boxes);
133+
}
134+
}
135+
136+
/// Continues deallocation of the all pending allocations in this arena.
137+
///
138+
/// This is invoked from the destructor, and requires that `immortalize` has
139+
/// been called previously.
140+
unsafe fn annihilate(&mut self) {
125141
// Pass 2: Drop all boxes.
126142
//
127143
// In this pass, unique-managed boxes may get freed, but not
@@ -142,11 +158,6 @@ impl LocalHeap {
142158
self.each_live_alloc(true, |me, alloc| {
143159
me.free(alloc);
144160
});
145-
146-
if debug_mem() {
147-
// We do logging here w/o allocation.
148-
rterrln!("total boxes annihilated: {}", n_total_boxes);
149-
}
150161
}
151162

152163
unsafe fn each_live_alloc(&mut self, read_next_before: bool,
@@ -170,6 +181,7 @@ impl LocalHeap {
170181

171182
impl Drop for LocalHeap {
172183
fn drop(&mut self) {
184+
unsafe { self.annihilate() }
173185
assert!(self.live_allocs.is_null());
174186
}
175187
}

0 commit comments

Comments
 (0)