std: Make box annihilator work with newsched

This commit is contained in:
Brian Anderson 2013-06-22 01:09:06 -07:00
parent a09972db35
commit 5e7c5d6c3d
9 changed files with 102 additions and 132 deletions

View file

@ -13,107 +13,14 @@
use libc::{c_char, c_void, intptr_t, uintptr_t};
use ptr::mut_null;
use repr::BoxRepr;
use rt;
use rt::OldTaskContext;
use sys::TypeDesc;
use cast::transmute;
#[cfg(not(test))] use rt::borrowck::clear_task_borrow_list;
#[cfg(not(test))] use ptr::to_unsafe_ptr;
/**
* Runtime structures
*
* NB: These must match the representation in the C++ runtime.
*/
type DropGlue<'self> = &'self fn(**TypeDesc, *c_void);
type FreeGlue<'self> = &'self fn(**TypeDesc, *c_void);
type TaskID = uintptr_t;
struct StackSegment { priv opaque: () }
struct Scheduler { priv opaque: () }
struct SchedulerLoop { priv opaque: () }
struct Kernel { priv opaque: () }
struct Env { priv opaque: () }
struct AllocHeader { priv opaque: () }
struct MemoryRegion { priv opaque: () }
#[cfg(target_arch="x86")]
struct Registers {
data: [u32, ..16]
}
#[cfg(target_arch="arm")]
#[cfg(target_arch="mips")]
struct Registers {
data: [u32, ..32]
}
#[cfg(target_arch="x86")]
#[cfg(target_arch="arm")]
#[cfg(target_arch="mips")]
struct Context {
regs: Registers,
next: *Context,
pad: [u32, ..3]
}
#[cfg(target_arch="x86_64")]
struct Registers {
data: [u64, ..22]
}
#[cfg(target_arch="x86_64")]
struct Context {
regs: Registers,
next: *Context,
pad: uintptr_t
}
struct BoxedRegion {
env: *Env,
backing_region: *MemoryRegion,
live_allocs: *BoxRepr
}
#[cfg(target_arch="x86")]
#[cfg(target_arch="arm")]
#[cfg(target_arch="mips")]
struct Task {
// Public fields
refcount: intptr_t, // 0
id: TaskID, // 4
pad: [u32, ..2], // 8
ctx: Context, // 16
stack_segment: *StackSegment, // 96
runtime_sp: uintptr_t, // 100
scheduler: *Scheduler, // 104
scheduler_loop: *SchedulerLoop, // 108
// Fields known only to the runtime
kernel: *Kernel, // 112
name: *c_char, // 116
list_index: i32, // 120
boxed_region: BoxedRegion // 128
}
#[cfg(target_arch="x86_64")]
struct Task {
// Public fields
refcount: intptr_t,
id: TaskID,
ctx: Context,
stack_segment: *StackSegment,
runtime_sp: uintptr_t,
scheduler: *Scheduler,
scheduler_loop: *SchedulerLoop,
// Fields known only to the runtime
kernel: *Kernel,
name: *c_char,
list_index: i32,
boxed_region: BoxedRegion
}
/*
* Box annihilation
@ -132,9 +39,9 @@ unsafe fn each_live_alloc(read_next_before: bool,
//! Walks the internal list of allocations
use managed;
use rt::local_heap;
let task: *Task = transmute(rustrt::rust_get_task());
let box = (*task).boxed_region.live_allocs;
let box = local_heap::live_allocs();
let mut box: *mut BoxRepr = transmute(copy box);
while box != mut_null() {
let next_before = transmute(copy (*box).header.next);
@ -156,7 +63,11 @@ unsafe fn each_live_alloc(read_next_before: bool,
#[cfg(unix)]
fn debug_mem() -> bool {
::rt::env::get().debug_mem
// XXX: Need to port the environment struct to newsched
match rt::context() {
OldTaskContext => ::rt::env::get().debug_mem,
_ => false
}
}
#[cfg(windows)]
@ -165,13 +76,12 @@ fn debug_mem() -> bool {
}
/// Destroys all managed memory (i.e. @ boxes) held by the current task.
#[cfg(not(test))]
#[lang="annihilate"]
pub unsafe fn annihilate() {
use unstable::lang::local_free;
use rt::local_heap::local_free;
use io::WriterUtil;
use io;
use libc;
use rt::borrowck;
use sys;
use managed;
@ -183,7 +93,7 @@ pub unsafe fn annihilate() {
// Quick hack: we need to free this list upon task exit, and this
// is a convenient place to do it.
clear_task_borrow_list();
borrowck::clear_task_borrow_list();
// Pass 1: Make all boxes immortal.
//
@ -207,7 +117,7 @@ pub unsafe fn annihilate() {
if !uniq {
let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc);
let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0));
drop_glue(to_unsafe_ptr(&tydesc), transmute(&(*box).data));
drop_glue(&tydesc, transmute(&(*box).data));
}
}

View file

@ -399,12 +399,6 @@ impl<T: Owned> GenericChan<T> for SharedChan<T> {
}
impl<T: Owned> GenericSmartChan<T> for SharedChan<T> {
#[cfg(stage0)] // odd type checking errors
fn try_send(&self, _val: T) -> bool {
fail!()
}
#[cfg(not(stage0))]
fn try_send(&self, val: T) -> bool {
unsafe {
let (next_pone, next_cone) = oneshot();
@ -448,12 +442,6 @@ impl<T: Owned> GenericPort<T> for SharedPort<T> {
}
}
#[cfg(stage0)] // odd type checking errors
fn try_recv(&self) -> Option<T> {
fail!()
}
#[cfg(not(stage0))]
fn try_recv(&self) -> Option<T> {
unsafe {
let (next_link_port, next_link_chan) = oneshot();

View file

@ -10,11 +10,24 @@
//! The local, garbage collected heap
use libc;
use libc::{c_void, uintptr_t, size_t};
use ops::Drop;
use repr::BoxRepr;
use rt;
use rt::OldTaskContext;
use rt::local::Local;
use rt::task::Task;
type MemoryRegion = c_void;
type BoxedRegion = c_void;
struct Env { priv opaque: () }
struct BoxedRegion {
env: *Env,
backing_region: *MemoryRegion,
live_allocs: *BoxRepr
}
pub type OpaqueBox = c_void;
pub type TypeDesc = c_void;
@ -71,6 +84,40 @@ impl Drop for LocalHeap {
}
}
// A little compatibility function
pub unsafe fn local_free(ptr: *libc::c_char) {
match rt::context() {
OldTaskContext => {
rust_upcall_free_noswitch(ptr);
extern {
#[fast_ffi]
unsafe fn rust_upcall_free_noswitch(ptr: *libc::c_char);
}
}
_ => {
do Local::borrow::<Task,()> |task| {
task.heap.free(ptr as *libc::c_void);
}
}
}
}
pub fn live_allocs() -> *BoxRepr {
let region = match rt::context() {
OldTaskContext => {
unsafe { rust_current_boxed_region() }
}
_ => {
do Local::borrow::<Task, *BoxedRegion> |task| {
task.heap.boxed_region
}
}
};
return unsafe { (*region).live_allocs };
}
extern {
fn rust_new_memory_region(synchronized: uintptr_t,
detailed_leaks: uintptr_t,
@ -86,4 +133,5 @@ extern {
ptr: *OpaqueBox,
size: size_t) -> *OpaqueBox;
fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox);
fn rust_current_boxed_region() -> *BoxedRegion;
}

View file

@ -124,7 +124,7 @@ mod thread;
pub mod env;
/// The local, managed heap
mod local_heap;
pub mod local_heap;
/// The Logger trait and implementations
pub mod logging;

View file

@ -15,6 +15,7 @@
use borrow;
use cast::transmute;
use cleanup;
use libc::{c_void, uintptr_t};
use ptr;
use prelude::*;
@ -118,6 +119,10 @@ impl Task {
}
_ => ()
}
// Destroy remaining boxes
unsafe { cleanup::annihilate(); }
self.destroyed = true;
}
}
@ -269,4 +274,20 @@ mod test {
assert!(res.is_err());
}
}
#[test]
fn heap_cycles() {
use option::{Option, Some, None};
do run_in_newsched_task {
struct List {
next: Option<@mut List>,
}
let a = @mut List { next: None };
let b = @mut List { next: Some(a) };
a.next = Some(b);
}
}
}

View file

@ -216,12 +216,15 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
task.logger.log(Left(outmsg.take()));
}
} else {
rtdebug!("%s", outmsg);
rterrln!("%s", outmsg);
}
gc::cleanup_stack_for_failure();
let task = Local::unsafe_borrow::<Task>();
if (*task).unwinder.unwinding {
rtabort!("unwinding again");
}
(*task).unwinder.begin_unwind();
}
}

View file

@ -43,9 +43,6 @@ pub mod rustrt {
size: uintptr_t)
-> *c_char;
#[fast_ffi]
unsafe fn rust_upcall_free_noswitch(ptr: *c_char);
#[rust_stack]
fn rust_try_get_task() -> *rust_task;
@ -105,16 +102,7 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
// problem occurs, call exit instead.
#[lang="free"]
pub unsafe fn local_free(ptr: *c_char) {
match context() {
OldTaskContext => {
rustrt::rust_upcall_free_noswitch(ptr);
}
_ => {
do Local::borrow::<Task,()> |task| {
task.heap.free(ptr as *c_void);
}
}
}
::rt::local_heap::local_free(ptr);
}
#[lang="borrow_as_imm"]
@ -162,6 +150,11 @@ pub unsafe fn strdup_uniq(ptr: *c_uchar, len: uint) -> ~str {
str::raw::from_buf_len(ptr, len)
}
#[lang="annihilate"]
pub unsafe fn annihilate() {
::cleanup::annihilate()
}
#[lang="start"]
pub fn start(main: *u8, argc: int, argv: **c_char,
crate_map: *u8) -> int {

View file

@ -882,6 +882,12 @@ rust_delete_memory_region(memory_region *region) {
delete region;
}
extern "C" CDECL boxed_region*
rust_current_boxed_region() {
rust_task *task = rust_get_current_task();
return &task->boxed;
}
extern "C" CDECL boxed_region*
rust_new_boxed_region(memory_region *region,
uintptr_t poison_on_free) {

View file

@ -244,4 +244,5 @@ rust_drop_env_lock
rust_update_log_settings
rust_running_on_valgrind
rust_get_num_cpus
rust_get_global_args_ptr
rust_get_global_args_ptr
rust_current_boxed_region