From 2487e164aeeeedaba78f597724a137959b1fb299 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 1 Oct 2014 00:09:46 +0300 Subject: [PATCH] rustrt: remove local_heap implementation. --- src/librustrt/lib.rs | 6 +- src/librustrt/local_heap.rs | 345 ------------------------------------ src/librustrt/task.rs | 41 +---- 3 files changed, 11 insertions(+), 381 deletions(-) delete mode 100644 src/librustrt/local_heap.rs diff --git a/src/librustrt/lib.rs b/src/librustrt/lib.rs index 1183b14fb4e1..ad1eac41e4d6 100644 --- a/src/librustrt/lib.rs +++ b/src/librustrt/lib.rs @@ -58,7 +58,6 @@ pub mod c_str; pub mod exclusive; pub mod local; pub mod local_data; -pub mod local_heap; pub mod mutex; pub mod rtio; pub mod stack; @@ -105,9 +104,8 @@ pub static DEFAULT_ERROR_CODE: int = 101; /// One-time runtime initialization. /// -/// Initializes global state, including frobbing -/// the crate's logging flags, registering GC -/// metadata, and storing the process arguments. +/// Initializes global state, including frobbing the crate's logging flags, +/// and storing the process arguments. pub fn init(argc: int, argv: *const *const u8) { // FIXME: Derefing these pointers is not safe. // Need to propagate the unsafety to `start`. diff --git a/src/librustrt/local_heap.rs b/src/librustrt/local_heap.rs deleted file mode 100644 index 0e84e9c0097f..000000000000 --- a/src/librustrt/local_heap.rs +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The local, garbage collected heap - -use core::prelude::*; - -use alloc::libc_heap; -use alloc::util; -use libc::{c_void, free}; - -use core::mem; -use core::ptr; -use core::raw; -use local::Local; -use task::Task; - -static RC_IMMORTAL : uint = 0x77777777; - -pub type Box = raw::GcBox<()>; - -pub struct MemoryRegion { - live_allocations: uint, -} - -pub struct LocalHeap { - memory_region: MemoryRegion, - live_allocs: *mut raw::GcBox<()>, -} - -impl LocalHeap { - pub fn new() -> LocalHeap { - LocalHeap { - memory_region: MemoryRegion { live_allocations: 0 }, - live_allocs: ptr::null_mut(), - } - } - - #[inline] - #[allow(deprecated)] - pub fn alloc(&mut self, - drop_glue: fn(*mut u8), - size: uint, - align: uint) -> *mut Box { - let total_size = util::get_box_size(size, align); - let alloc = self.memory_region.malloc(total_size); - { - // Make sure that we can't use `mybox` outside of this scope - let mybox: &mut Box = unsafe { mem::transmute(alloc) }; - // Clear out this box, and move it to the front of the live - // allocations list - mybox.drop_glue = drop_glue; - mybox.ref_count = 1; - mybox.prev = ptr::null_mut(); - mybox.next = self.live_allocs; - if !self.live_allocs.is_null() { - unsafe { (*self.live_allocs).prev = alloc; } - } - self.live_allocs = alloc; - } - return alloc; - } - - #[inline] - pub fn realloc(&mut self, ptr: *mut Box, size: uint) -> *mut Box { - // Make sure that we can't use `mybox` outside of this scope - let total_size = size + mem::size_of::(); - let new_box = self.memory_region.realloc(ptr, total_size); - { - // Fix links because we could have moved around - let mybox: &mut Box = unsafe { mem::transmute(new_box) }; - if !mybox.prev.is_null() { - unsafe { (*mybox.prev).next = new_box; } - } - if !mybox.next.is_null() { - unsafe { (*mybox.next).prev = new_box; } - } - } - if self.live_allocs == ptr { - self.live_allocs = new_box; - } - return new_box; - } - - #[inline] - pub fn free(&mut self, alloc: *mut Box) { - { - // Make sure that we can't use `mybox` outside of this scope - let mybox: &mut Box = unsafe { mem::transmute(alloc) }; - - // Unlink it from the linked list - if !mybox.prev.is_null() { - unsafe { (*mybox.prev).next = mybox.next; } - } - if !mybox.next.is_null() { - unsafe { (*mybox.next).prev = mybox.prev; } - } - if self.live_allocs == alloc { - self.live_allocs = mybox.next; - } - } - - self.memory_region.free(alloc); - } - - /// Immortalize all pending allocations, forcing them to live forever. - /// - /// This function will freeze all allocations to prevent all pending - /// allocations from being deallocated. This is used in preparation for when - /// a task is about to destroy TLD. - pub unsafe fn immortalize(&mut self) { - let mut n_total_boxes = 0u; - - // Pass 1: Make all boxes immortal. - // - // In this pass, nothing gets freed, so it does not matter whether - // we read the next field before or after the callback. - self.each_live_alloc(true, |_, alloc| { - n_total_boxes += 1; - (*alloc).ref_count = RC_IMMORTAL; - }); - - if debug_mem() { - // We do logging here w/o allocation. - rterrln!("total boxes annihilated: {}", n_total_boxes); - } - } - - /// Continues deallocation of the all pending allocations in this arena. - /// - /// This is invoked from the destructor, and requires that `immortalize` has - /// been called previously. - unsafe fn annihilate(&mut self) { - // Pass 2: Drop all boxes. - // - // In this pass, unique-managed boxes may get freed, but not - // managed boxes, so we must read the `next` field *after* the - // callback, as the original value may have been freed. - self.each_live_alloc(false, |_, alloc| { - let drop_glue = (*alloc).drop_glue; - let data = &mut (*alloc).data as *mut (); - drop_glue(data as *mut u8); - }); - - // Pass 3: Free all boxes. - // - // In this pass, managed boxes may get freed (but not - // unique-managed boxes, though I think that none of those are - // left), so we must read the `next` field before, since it will - // not be valid after. - self.each_live_alloc(true, |me, alloc| { - me.free(alloc); - }); - } - - unsafe fn each_live_alloc(&mut self, read_next_before: bool, - f: |&mut LocalHeap, alloc: *mut raw::GcBox<()>|) { - //! Walks the internal list of allocations - - let mut alloc = self.live_allocs; - while alloc != ptr::null_mut() { - let next_before = (*alloc).next; - - f(self, alloc); - - if read_next_before { - alloc = next_before; - } else { - alloc = (*alloc).next; - } - } - } -} - -impl Drop for LocalHeap { - fn drop(&mut self) { - unsafe { self.annihilate() } - assert!(self.live_allocs.is_null()); - } -} - -struct AllocHeader; - -impl AllocHeader { - fn init(&mut self, _size: u32) {} - fn assert_sane(&self) {} - fn update_size(&mut self, _size: u32) {} - - fn as_box(&mut self) -> *mut Box { - let myaddr: uint = unsafe { mem::transmute(self) }; - (myaddr + AllocHeader::size()) as *mut Box - } - - fn size() -> uint { - // For some platforms, 16 byte alignment is required. - let ptr_size = 16; - let header_size = mem::size_of::(); - return (header_size + ptr_size - 1) / ptr_size * ptr_size; - } - - fn from(a_box: *mut Box) -> *mut AllocHeader { - (a_box as uint - AllocHeader::size()) as *mut AllocHeader - } -} - -#[cfg(unix)] -fn debug_mem() -> bool { - // FIXME: Need to port the environment struct to newsched - false -} - -#[cfg(windows)] -fn debug_mem() -> bool { - false -} - -impl MemoryRegion { - #[inline] - fn malloc(&mut self, size: uint) -> *mut Box { - let total_size = size + AllocHeader::size(); - let alloc: *mut AllocHeader = unsafe { - libc_heap::malloc_raw(total_size) as *mut AllocHeader - }; - - let alloc: &mut AllocHeader = unsafe { mem::transmute(alloc) }; - alloc.init(size as u32); - self.claim(alloc); - self.live_allocations += 1; - - return alloc.as_box(); - } - - #[inline] - fn realloc(&mut self, alloc: *mut Box, size: uint) -> *mut Box { - rtassert!(!alloc.is_null()); - let orig_alloc = AllocHeader::from(alloc); - unsafe { (*orig_alloc).assert_sane(); } - - let total_size = size + AllocHeader::size(); - let alloc: *mut AllocHeader = unsafe { - libc_heap::realloc_raw(orig_alloc as *mut u8, total_size) as *mut AllocHeader - }; - - let alloc: &mut AllocHeader = unsafe { mem::transmute(alloc) }; - alloc.assert_sane(); - alloc.update_size(size as u32); - self.update(alloc, orig_alloc as *mut AllocHeader); - return alloc.as_box(); - } - - #[inline] - fn free(&mut self, alloc: *mut Box) { - rtassert!(!alloc.is_null()); - let alloc = AllocHeader::from(alloc); - unsafe { - (*alloc).assert_sane(); - self.release(mem::transmute(alloc)); - rtassert!(self.live_allocations > 0); - self.live_allocations -= 1; - free(alloc as *mut c_void) - } - } - - #[inline] - fn claim(&mut self, _alloc: &mut AllocHeader) {} - #[inline] - fn release(&mut self, _alloc: &AllocHeader) {} - #[inline] - fn update(&mut self, _alloc: &mut AllocHeader, _orig: *mut AllocHeader) {} -} - -impl Drop for MemoryRegion { - fn drop(&mut self) { - if self.live_allocations != 0 { - rtabort!("leaked managed memory ({} objects)", self.live_allocations); - } - } -} - -#[cfg(not(test))] -#[lang="malloc"] -#[inline] -pub unsafe fn local_malloc_(drop_glue: fn(*mut u8), size: uint, - align: uint) -> *mut u8 { - local_malloc(drop_glue, size, align) -} - -#[inline] -pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, - align: uint) -> *mut u8 { - // FIXME: Unsafe borrow for speed. Lame. - let task: Option<*mut Task> = Local::try_unsafe_borrow(); - match task { - Some(task) => { - (*task).heap.alloc(drop_glue, size, align) as *mut u8 - } - None => rtabort!("local malloc outside of task") - } -} - -#[cfg(not(test))] -#[lang="free"] -#[inline] -pub unsafe fn local_free_(ptr: *mut u8) { - local_free(ptr) -} - -// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from -// inside a landing pad may corrupt the state of the exception handler. If a -// problem occurs, call exit instead. -#[inline] -pub unsafe fn local_free(ptr: *mut u8) { - // FIXME: Unsafe borrow for speed. Lame. - let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow(); - match task_ptr { - Some(task) => { - (*task).heap.free(ptr as *mut Box) - } - None => rtabort!("local free outside of task") - } -} - -#[cfg(test)] -mod bench { - extern crate test; - use self::test::Bencher; - use std::gc::GC; - - #[bench] - fn alloc_managed_small(b: &mut Bencher) { - b.iter(|| { box(GC) 10i }); - } - - #[bench] - fn alloc_managed_big(b: &mut Bencher) { - b.iter(|| { box(GC) ([10i, ..1000]) }); - } -} diff --git a/src/librustrt/task.rs b/src/librustrt/task.rs index 3d42b91fef17..9e88d05884ce 100644 --- a/src/librustrt/task.rs +++ b/src/librustrt/task.rs @@ -9,9 +9,8 @@ // except according to those terms. //! Language-level runtime services that should reasonably expected -//! to be available 'everywhere'. Local heaps, GC, unwinding, -//! local storage, and logging. Even a 'freestanding' Rust would likely want -//! to implement this. +//! to be available 'everywhere'. Unwinding, local storage, and logging. +//! Even a 'freestanding' Rust would likely want to implement this. use alloc::arc::Arc; use alloc::boxed::{BoxAny, Box}; @@ -27,7 +26,6 @@ use core::raw; use local_data; use Runtime; use local::Local; -use local_heap::LocalHeap; use rtio::LocalIo; use unwind; use unwind::Unwinder; @@ -95,8 +93,6 @@ use collections::str::SendStr; /// # } /// ``` pub struct Task { - pub heap: LocalHeap, - pub gc: GarbageCollector, pub storage: LocalStorage, pub unwinder: Unwinder, pub death: Death, @@ -132,7 +128,6 @@ pub struct TaskOpts { /// children tasks complete, recommend using a result future. pub type Result = ::core::result::Result<(), Box>; -pub struct GarbageCollector; pub struct LocalStorage(pub Option); /// A handle to a blocked task. Usually this means having the Box @@ -163,8 +158,6 @@ impl Task { /// task creation functions through libnative or libgreen. pub fn new() -> Task { Task { - heap: LocalHeap::new(), - gc: GarbageCollector, storage: LocalStorage(None), unwinder: Unwinder::new(), death: Death::new(), @@ -264,32 +257,22 @@ impl Task { /// already been destroyed and/or annihilated. fn cleanup(self: Box, result: Result) -> Box { // The first thing to do when cleaning up is to deallocate our local - // resources, such as TLD and GC data. + // resources, such as TLD. // // FIXME: there are a number of problems with this code // // 1. If any TLD object fails destruction, then all of TLD will leak. // This appears to be a consequence of #14875. // - // 2. Failing during GC annihilation aborts the runtime #14876. + // 2. Setting a TLD key while destroying TLD will abort the runtime #14807. // - // 3. Setting a TLD key while destroying TLD or while destroying GC will - // abort the runtime #14807. - // - // 4. Invoking GC in GC destructors will abort the runtime #6996. - // - // 5. The order of destruction of TLD and GC matters, but either way is - // susceptible to leaks (see 3/4) #8302. + // 3. The order of destruction of TLD matters, but either way is + // susceptible to leaks (see 2) #8302. // // That being said, there are a few upshots to this code // // 1. If TLD destruction fails, heap destruction will be attempted. - // There is a test for this at fail-during-tld-destroy.rs. Sadly the - // other way can't be tested due to point 2 above. Note that we must - // immortalize the heap first because if any deallocations are - // attempted while TLD is being dropped it will attempt to free the - // allocation from the wrong heap (because the current one has been - // replaced). + // There is a test for this at fail-during-tld-destroy.rs. // // 2. One failure in destruction is tolerable, so long as the task // didn't originally fail while it was running. @@ -301,15 +284,10 @@ impl Task { let &LocalStorage(ref mut optmap) = &mut task.storage; optmap.take() }; - let mut heap = mem::replace(&mut task.heap, LocalHeap::new()); - unsafe { heap.immortalize() } drop(task); // First, destroy task-local storage. This may run user dtors. drop(tld); - - // Destroy remaining boxes. Also may run user dtors. - drop(heap); }); // If the above `run` block failed, then it must be the case that the @@ -327,9 +305,8 @@ impl Task { Local::put(task); // FIXME: this is running in a seriously constrained context. If this - // allocates GC or allocates TLD then it will likely abort the - // runtime. Similarly, if this fails, this will also likely abort - // the runtime. + // allocates TLD then it will likely abort the runtime. Similarly, + // if this fails, this will also likely abort the runtime. // // This closure is currently limited to a channel send via the // standard library's task interface, but this needs