diff options
| author | bors <bors@rust-lang.org> | 2013-06-30 15:02:05 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-06-30 15:02:05 -0700 |
| commit | 040ac2a93270b4420c59621521d554a078e2d451 (patch) | |
| tree | 16dc8d87d4352a8e695949c906af4e5e55f2f47d /src/libstd/rt | |
| parent | ca835f482cebcd353db789e45f9cec72db1a24ed (diff) | |
| parent | 4a29d6eb3f20c2b7a05bb9c9c2f964da606e39ca (diff) | |
| download | rust-040ac2a93270b4420c59621521d554a078e2d451.tar.gz rust-040ac2a93270b4420c59621521d554a078e2d451.zip | |
auto merge of #7495 : thestinger/rust/exchange, r=cmr
With these changes, exchange allocator headers are never initialized, read or written to. Removing the header will now just involve updating the code in trans using an offset to only do it if the type contained is managed. The only thing blocking removing the initialization of the last field in the header was ~fn since it uses it to store the dynamic size/types due to captures. I temporarily switched it to a `closure_exchange_alloc` lang item (it uses the same `exchange_free`) and #7496 is filed about removing that. Since the `exchange_free` call is now inlined all over the codebase, I don't think we should have an assert for null. It doesn't currently ever happen, but it would be fine if we started generating code that did do it. The `exchange_free` function also had a comment declaring that it must not fail, but a regular assert would cause a failure. I also removed the atomic counter because valgrind can already find these leaks, and we have valgrind bots now. Note that exchange free does not currently print an error an out-of-memory when it aborts, because our `io` code may allocate. We could probably get away with a `#[rust_stack]` call to a `stdio` function but it would be better to make a write system call.
Diffstat (limited to 'src/libstd/rt')
| -rw-r--r-- | src/libstd/rt/global_heap.rs | 128 |
1 files changed, 75 insertions, 53 deletions
diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 1e9f9aab834..f669dc753d6 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -8,62 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use sys::{size_of}; -use libc::{c_void, size_t, uintptr_t}; -use c_malloc = libc::malloc; -use c_free = libc::free; +use libc::{c_char, c_void, size_t, uintptr_t, free, malloc}; use managed::raw::{BoxHeaderRepr, BoxRepr}; -use cast::transmute; -use unstable::intrinsics::{atomic_xadd,atomic_xsub,TyDesc}; -use ptr::null; +use unstable::intrinsics::TyDesc; +use sys::size_of; -pub unsafe fn malloc(td: *TyDesc, size: uint) -> *c_void { - assert!(td.is_not_null()); - - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert!(p.is_not_null()); - - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); - - let exchange_count = &mut *exchange_count_ptr(); - atomic_xadd(exchange_count, 1); - - return transmute(box); -} -/** -Thin wrapper around libc::malloc, none of the box header -stuff in exchange_alloc::malloc -*/ -pub unsafe fn malloc_raw(size: uint) -> *c_void { - let p = c_malloc(size as size_t); - if p.is_null() { - fail!("Failure in malloc_raw: result ptr is null"); - } - p -} - -pub unsafe fn free(ptr: *c_void) { - let exchange_count = &mut *exchange_count_ptr(); - atomic_xsub(exchange_count, 1); - - assert!(ptr.is_not_null()); - c_free(ptr); -} -///Thin wrapper around libc::free, as with exchange_alloc::malloc_raw -pub unsafe fn free_raw(ptr: *c_void) { - c_free(ptr); +extern { + #[rust_stack] + fn abort(); } fn get_box_size(body_size: uint, body_align: uint) -> uint { let header_size = size_of::<BoxHeaderRepr>(); // FIXME (#2699): This alignment calculation is suspicious. Is it right? let total_size = align_to(header_size, body_align) + body_size; - return total_size; + total_size } // Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power @@ -73,11 +32,74 @@ fn align_to(size: uint, align: uint) -> uint { (size + align - 1) & !(align - 1) } -fn exchange_count_ptr() -> *mut int { - // XXX: Need mutable globals - unsafe { transmute(&rust_exchange_count) } +/// A wrapper around libc::malloc, aborting on out-of-memory +pub unsafe fn malloc_raw(size: uint) -> *c_void { + let p = malloc(size as size_t); + if p.is_null() { + // we need a non-allocating way to print an error here + abort(); + } + p } -extern { - static rust_exchange_count: uintptr_t; +// FIXME #4942: Make these signatures agree with exchange_alloc's signatures +#[cfg(stage0, not(test))] +#[lang="exchange_malloc"] +#[inline] +pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + let p = malloc_raw(total_size as uint); + + let box: *mut BoxRepr = p as *mut BoxRepr; + (*box).header.ref_count = -1; + (*box).header.type_desc = td; + + box as *c_char +} + +// FIXME #4942: Make these signatures agree with exchange_alloc's signatures +#[cfg(not(stage0), not(test))] +#[lang="exchange_malloc"] +#[inline] +pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + malloc_raw(total_size as uint) as *c_char +} + +// FIXME: #7496 +#[cfg(not(test))] +#[lang="closure_exchange_malloc"] +#[inline] +pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + let p = malloc_raw(total_size as uint); + + let box: *mut BoxRepr = p as *mut BoxRepr; + (*box).header.type_desc = td; + + box as *c_char +} + +// 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. +#[cfg(not(test))] +#[lang="exchange_free"] +#[inline] +pub unsafe fn exchange_free(ptr: *c_char) { + free(ptr as *c_void); } |
