std: Make box annihilator work with newsched
This commit is contained in:
parent
a09972db35
commit
5e7c5d6c3d
9 changed files with 102 additions and 132 deletions
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue