diff options
| author | Erick Tryzelaar <erick.tryzelaar@gmail.com> | 2013-08-06 16:18:58 -0700 |
|---|---|---|
| committer | Erick Tryzelaar <erick.tryzelaar@gmail.com> | 2013-08-06 16:18:58 -0700 |
| commit | 8567611adfa69c4488133e18d3ec4fc195afadd1 (patch) | |
| tree | 80e325db23f407d643e2ada480de23b1fb8b4fc6 /src/libstd | |
| parent | fb9b27910b41e714dfd6b3ccc48161260943c9cf (diff) | |
| parent | d89ff7eef969aee6b493bc846b64d68358fafbcd (diff) | |
| download | rust-8567611adfa69c4488133e18d3ec4fc195afadd1.tar.gz rust-8567611adfa69c4488133e18d3ec4fc195afadd1.zip | |
Merge commit 'd89ff7eef969aee6b493bc846b64d68358fafbcd' into remove-str-trailing-nulls
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/comm.rs | 110 | ||||
| -rw-r--r-- | src/libstd/gc.rs | 358 | ||||
| -rw-r--r-- | src/libstd/logging.rs | 10 | ||||
| -rw-r--r-- | src/libstd/pipes.rs | 44 | ||||
| -rw-r--r-- | src/libstd/rt/local.rs | 81 | ||||
| -rw-r--r-- | src/libstd/rt/local_ptr.rs | 26 | ||||
| -rw-r--r-- | src/libstd/rt/logging.rs | 21 | ||||
| -rw-r--r-- | src/libstd/rt/mod.rs | 10 | ||||
| -rw-r--r-- | src/libstd/rt/sched.rs | 12 | ||||
| -rw-r--r-- | src/libstd/rt/task.rs | 17 | ||||
| -rw-r--r-- | src/libstd/stackwalk.rs | 80 | ||||
| -rw-r--r-- | src/libstd/std.rs | 2 | ||||
| -rw-r--r-- | src/libstd/str.rs | 9 | ||||
| -rw-r--r-- | src/libstd/sys.rs | 4 |
14 files changed, 114 insertions, 670 deletions
diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index a0731dc3494..4356f1143da 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -14,7 +14,6 @@ Message passing #[allow(missing_doc)]; -use cast::transmute; use either::{Either, Left, Right}; use kinds::Send; use option::{Option, Some}; @@ -23,12 +22,6 @@ pub use rt::comm::SendDeferred; use rtcomm = rt::comm; use rt; -use pipes::{wait_many, PacketHeader}; - -// FIXME #5160: Making this public exposes some plumbing from -// pipes. Needs some refactoring -pub use pipes::Selectable; - /// A trait for things that can send multiple messages. pub trait GenericChan<T> { /// Sends a message. @@ -146,15 +139,6 @@ impl<T: Send> Peekable<T> for Port<T> { } } -impl<T: Send> Selectable for Port<T> { - fn header(&mut self) -> *mut PacketHeader { - match self.inner { - Left(ref mut port) => port.header(), - Right(_) => fail!("can't select on newsched ports") - } - } -} - /// A channel that can be shared between many senders. pub struct SharedChan<T> { inner: Either<Exclusive<pipesy::Chan<T>>, rtcomm::SharedChan<T>> @@ -318,8 +302,8 @@ mod pipesy { use kinds::Send; use option::{Option, Some, None}; - use pipes::{recv, try_recv, peek, PacketHeader}; - use super::{GenericChan, GenericSmartChan, GenericPort, Peekable, Selectable}; + use pipes::{recv, try_recv, peek}; + use super::{GenericChan, GenericSmartChan, GenericPort, Peekable}; use cast::transmute_mut; /*proto! oneshot ( @@ -651,80 +635,6 @@ mod pipesy { } } - impl<T: Send> Selectable for Port<T> { - fn header(&mut self) -> *mut PacketHeader { - match self.endp { - Some(ref mut endp) => endp.header(), - None => fail!("peeking empty stream") - } - } -} - -} - -/// Returns the index of an endpoint that is ready to receive. -pub fn selecti<T: Selectable>(endpoints: &mut [T]) -> uint { - wait_many(endpoints) -} - -/// Returns 0 or 1 depending on which endpoint is ready to receive -pub fn select2i<A:Selectable, B:Selectable>(a: &mut A, b: &mut B) - -> Either<(), ()> { - let mut endpoints = [ a.header(), b.header() ]; - match wait_many(endpoints) { - 0 => Left(()), - 1 => Right(()), - _ => fail!("wait returned unexpected index"), - } -} - -/// Receive a message from one of two endpoints. -pub trait Select2<T: Send, U: Send> { - /// Receive a message or return `None` if a connection closes. - fn try_select(&mut self) -> Either<Option<T>, Option<U>>; - /// Receive a message or fail if a connection closes. - fn select(&mut self) -> Either<T, U>; -} - -impl<T:Send, - U:Send, - Left:Selectable + GenericPort<T>, - Right:Selectable + GenericPort<U>> - Select2<T, U> - for (Left, Right) { - fn select(&mut self) -> Either<T, U> { - // XXX: Bad borrow check workaround. - unsafe { - let this: &(Left, Right) = transmute(self); - match *this { - (ref lp, ref rp) => { - let lp: &mut Left = transmute(lp); - let rp: &mut Right = transmute(rp); - match select2i(lp, rp) { - Left(()) => Left(lp.recv()), - Right(()) => Right(rp.recv()), - } - } - } - } - } - - fn try_select(&mut self) -> Either<Option<T>, Option<U>> { - // XXX: Bad borrow check workaround. - unsafe { - let this: &(Left, Right) = transmute(self); - match *this { - (ref lp, ref rp) => { - let lp: &mut Left = transmute(lp); - let rp: &mut Right = transmute(rp); - match select2i(lp, rp) { - Left(()) => Left (lp.try_recv()), - Right(()) => Right(rp.try_recv()), - } - } - } - } - } } #[cfg(test)] @@ -733,22 +643,6 @@ mod test { use super::{Chan, Port, oneshot, stream}; #[test] - fn test_select2() { - let (p1, c1) = stream(); - let (p2, c2) = stream(); - - c1.send(~"abc"); - - let mut tuple = (p1, p2); - match tuple.select() { - Right(_) => fail!(), - _ => (), - } - - c2.send(123); - } - - #[test] fn test_oneshot() { let (p, c) = oneshot(); diff --git a/src/libstd/gc.rs b/src/libstd/gc.rs deleted file mode 100644 index 2e27f82f6f6..00000000000 --- a/src/libstd/gc.rs +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright 2012 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(hidden)]; -#[allow(non_uppercase_statics)]; - -/*! Precise garbage collector - -The precise GC exposes two functions, gc and -cleanup_stack_for_failure. The gc function is the entry point to the -garbage collector itself. The cleanup_stack_for_failure is the entry -point for GC-based cleanup. - -Precise GC depends on changes to LLVM's GC which add support for -automatic rooting and addrspace-based metadata marking. Rather than -explicitly rooting pointers with LLVM's gcroot intrinsic, the GC -merely creates allocas for pointers, and allows an LLVM pass to -automatically infer roots based on the allocas present in a function -(and live at a given location). The compiler communicates the type of -the pointer to LLVM by setting the addrspace of the pointer type. The -compiler then emits a map from addrspace to tydesc, which LLVM then -uses to match pointers with their tydesc. The GC reads the metadata -table produced by LLVM, and uses it to determine which glue functions -to call to free objects on their respective heaps. - -GC-based cleanup is a replacement for landing pads which relies on the -GC infrastructure to find pointers on the stack to cleanup. Whereas -the normal GC needs to walk task-local heap allocations, the cleanup -code needs to walk exchange heap allocations and stack-allocations -with destructors. - -*/ - -use cast; -use container::{Set, MutableSet}; -use io; -use libc::{uintptr_t}; -use option::{None, Option, Some}; -use ptr; -use hashmap::HashSet; -use stackwalk::walk_stack; -use sys; -use unstable::intrinsics::{TyDesc}; - -pub use stackwalk::Word; - -// Mirrors rust_stack.h stk_seg -pub struct StackSegment { - prev: *StackSegment, - next: *StackSegment, - end: uintptr_t, - // And other fields which we don't care about... -} - -pub mod rustrt { - use stackwalk::Word; - use super::StackSegment; - - #[link_name = "rustrt"] - extern { - #[rust_stack] - pub fn rust_gc_metadata() -> *Word; - - pub fn rust_get_stack_segment() -> *StackSegment; - pub fn rust_get_c_stack() -> *StackSegment; - } -} - -unsafe fn bump<T, U>(ptr: *T, count: uint) -> *U { - return ptr::offset(ptr, count as int) as *U; -} - -unsafe fn align_to_pointer<T>(ptr: *T) -> *T { - let align = sys::min_align_of::<*T>(); - let ptr = ptr as uint; - let ptr = (ptr + (align - 1)) & -align; - return ptr as *T; -} - -unsafe fn get_safe_point_count() -> uint { - let module_meta = rustrt::rust_gc_metadata(); - return *module_meta; -} - -struct SafePoint { - sp_meta: *Word, - fn_meta: *Word, -} - -// Returns the safe point metadata for the given program counter, if -// any. -unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> { - let module_meta = rustrt::rust_gc_metadata(); - let num_safe_points = *module_meta; - let safe_points: *Word = bump(module_meta, 1); - - if ptr::is_null(pc) { - return None; - } - - // FIXME (#2997): Use binary rather than linear search. - let mut spi = 0; - while spi < num_safe_points { - let sp: **Word = bump(safe_points, spi*3); - let sp_loc = *sp; - if sp_loc == pc { - return Some(SafePoint { - sp_meta: *bump(sp, 1), - fn_meta: *bump(sp, 2), - }); - } - spi += 1; - } - return None; -} - -type Visitor<'self> = &'self fn(root: **Word, tydesc: *TyDesc); - -// Walks the list of roots for the given safe point, and calls visitor -// on each root. -unsafe fn _walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) { - let fp_bytes = fp as *u8; - let sp_meta = sp.sp_meta as *u32; - - let num_stack_roots = *sp_meta as uint; - let num_reg_roots = *ptr::offset(sp_meta, 1) as uint; - - let stack_roots: *u32 = bump(sp_meta, 2); - let reg_roots: *u8 = bump(stack_roots, num_stack_roots); - let addrspaces: *Word = align_to_pointer(bump(reg_roots, num_reg_roots)); - let tydescs: ***TyDesc = bump(addrspaces, num_stack_roots); - - // Stack roots - let mut sri = 0; - while sri < num_stack_roots { - if *ptr::offset(addrspaces, sri as int) >= 1 { - let root = - ptr::offset(fp_bytes, *ptr::offset(stack_roots, sri as int) as int) - as **Word; - let tydescpp = ptr::offset(tydescs, sri as int); - let tydesc = if ptr::is_not_null(tydescpp) && - ptr::is_not_null(*tydescpp) { - **tydescpp - } else { - ptr::null() - }; - visitor(root, tydesc); - } - sri += 1; - } - - // Register roots - let mut rri = 0; - while rri < num_reg_roots { - if *ptr::offset(addrspaces, (num_stack_roots + rri) as int) == 1 { - // FIXME(#2997): Need to find callee saved registers on the stack. - } - rri += 1; - } -} - -unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) { - _walk_safe_point(fp, sp, visitor) -} - -// Is fp contained in segment? -unsafe fn is_frame_in_segment(fp: *Word, segment: *StackSegment) -> bool { - let begin = segment as Word; - let end = (*segment).end as Word; - let frame = fp as Word; - - return begin <= frame && frame <= end; -} - -struct Segment { segment: *StackSegment, boundary: bool } - -// Find and return the segment containing the given frame pointer. At -// stack segment boundaries, returns true for boundary, so that the -// caller can do any special handling to identify where the correct -// return address is in the stack frame. -unsafe fn find_segment_for_frame(fp: *Word, segment: *StackSegment) - -> Segment { - // Check if frame is in either current frame or previous frame. - let in_segment = is_frame_in_segment(fp, segment); - let in_prev_segment = ptr::is_not_null((*segment).prev) && - is_frame_in_segment(fp, (*segment).prev); - - // If frame is not in either segment, walk down segment list until - // we find the segment containing this frame. - if !in_segment && !in_prev_segment { - let mut segment = segment; - while ptr::is_not_null((*segment).next) && - is_frame_in_segment(fp, (*segment).next) { - segment = (*segment).next; - } - return Segment {segment: segment, boundary: false}; - } - - // If frame is in previous frame, then we're at a boundary. - if !in_segment && in_prev_segment { - return Segment {segment: (*segment).prev, boundary: true}; - } - - // Otherwise, we're somewhere on the inside of the frame. - return Segment {segment: segment, boundary: false}; -} - -type Memory = uint; - -static task_local_heap: Memory = 1; -static exchange_heap: Memory = 2; -static stack: Memory = 4; - -static need_cleanup: Memory = exchange_heap | stack; - -// Walks stack, searching for roots of the requested type, and passes -// each root to the visitor. -unsafe fn _walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) { - let mut segment = rustrt::rust_get_stack_segment(); - let mut last_ret: *Word = ptr::null(); - // To avoid collecting memory used by the GC itself, skip stack - // frames until past the root GC stack frame. The root GC stack - // frame is marked by a sentinel, which is a box pointer stored on - // the stack. - let mut reached_sentinel = ptr::is_null(sentinel); - do walk_stack |frame| { - let pc = last_ret; - let Segment {segment: next_segment, boundary: boundary} = - find_segment_for_frame(frame.fp, segment); - segment = next_segment; - // Each stack segment is bounded by a morestack frame. The - // morestack frame includes two return addresses, one for - // morestack itself, at the normal offset from the frame - // pointer, and then a second return address for the - // function prologue (which called morestack after - // determining that it had hit the end of the stack). - // Since morestack itself takes two parameters, the offset - // for this second return address is 3 greater than the - // return address for morestack. - let ret_offset = if boundary { 4 } else { 1 }; - last_ret = *ptr::offset(frame.fp, ret_offset as int) as *Word; - - if !ptr::is_null(pc) { - - let mut delay_reached_sentinel = reached_sentinel; - let sp = is_safe_point(pc); - match sp { - Some(sp_info) => { - do walk_safe_point(frame.fp, sp_info) |root, tydesc| { - // Skip roots until we see the sentinel. - if !reached_sentinel && root == sentinel { - delay_reached_sentinel = true; - } - - // Skip null pointers, which can occur when a - // unique pointer has already been freed. - if reached_sentinel && !ptr::is_null(*root) { - if ptr::is_null(tydesc) { - // Root is a generic box. - let refcount = **root; - if mem | task_local_heap != 0 && refcount != -1 { - visitor(root, tydesc); - } else if mem | exchange_heap != 0 && refcount == -1 { - visitor(root, tydesc); - } - } else { - // Root is a non-immediate. - if mem | stack != 0 { - visitor(root, tydesc); - } - } - } - } - } - None => () - } - reached_sentinel = delay_reached_sentinel; - } - } -} - -unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) { - _walk_gc_roots(mem, sentinel, visitor) -} -pub fn gc() { - unsafe { - // Abort when GC is disabled. - if get_safe_point_count() == 0 { - return; - } - - do walk_gc_roots(task_local_heap, ptr::null()) |_root, _tydesc| { - // FIXME(#2997): Walk roots and mark them. - io::stdout().write([46]); // . - } - } -} - -#[cfg(gc)] -fn expect_sentinel() -> bool { true } - -#[cfg(nogc)] -fn expect_sentinel() -> bool { false } - -// Entry point for GC-based cleanup. Walks stack looking for exchange -// heap and stack allocations requiring drop, and runs all -// destructors. -// -// This should only be called from fail!, as it will drop the roots -// which are *live* on the stack, rather than dropping those that are -// dead. -pub fn cleanup_stack_for_failure() { - unsafe { - // Abort when GC is disabled. - if get_safe_point_count() == 0 { - return; - } - - // Leave a sentinel on the stack to mark the current frame. The - // stack walker will ignore any frames above the sentinel, thus - // avoiding collecting any memory being used by the stack walker - // itself. - // - // However, when core itself is not compiled with GC, then none of - // the functions in core will have GC metadata, which means we - // won't be able to find the sentinel root on the stack. In this - // case, we can safely skip the sentinel since we won't find our - // own stack roots on the stack anyway. - let sentinel_box = ~0; - let sentinel: **Word = if expect_sentinel() { - cast::transmute(&sentinel_box) - } else { - ptr::null() - }; - - let mut roots = HashSet::new(); - do walk_gc_roots(need_cleanup, sentinel) |root, tydesc| { - // Track roots to avoid double frees. - if !roots.contains(&*root) { - roots.insert(*root); - - if ptr::is_null(tydesc) { - // FIXME #4420: Destroy this box - // FIXME #4330: Destroy this box - } else { - ((*tydesc).drop_glue)(*root as *i8); - } - } - } - } -} diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs index c662e5997af..6e11d14aea9 100644 --- a/src/libstd/logging.rs +++ b/src/libstd/logging.rs @@ -85,16 +85,6 @@ pub fn log_type<T>(level: u32, object: &T) { fn newsched_log_str(msg: ~str) { use rt::task::Task; use rt::local::Local; - use str::StrSlice; - use container::Container; - - // Truncate the string - let buf_bytes = 256; - let msg = if msg.len() > buf_bytes { - msg.slice(0, buf_bytes) + "[...]" - } else { - msg - }; unsafe { match Local::try_unsafe_borrow::<Task>() { diff --git a/src/libstd/pipes.rs b/src/libstd/pipes.rs index 1fd534825a5..78f937e058a 100644 --- a/src/libstd/pipes.rs +++ b/src/libstd/pipes.rs @@ -868,47 +868,3 @@ pub mod rt { pub fn make_some<T>(val: T) -> Option<T> { Some(val) } pub fn make_none<T>() -> Option<T> { None } } - -#[cfg(test)] -mod test { - use either::Right; - use comm::{Chan, Port, oneshot, recv_one, stream, Select2, - GenericChan, Peekable}; - - #[test] - fn test_select2() { - let (p1, c1) = stream(); - let (p2, c2) = stream(); - - c1.send(~"abc"); - - let mut tuple = (p1, p2); - match tuple.select() { - Right(_) => fail!(), - _ => (), - } - - c2.send(123); - } - - #[test] - fn test_oneshot() { - let (p, c) = oneshot(); - - c.send(()); - - recv_one(p) - } - - #[test] - fn test_peek_terminated() { - let (port, chan): (Port<int>, Chan<int>) = stream(); - - { - // Destroy the channel - let _chan = chan; - } - - assert!(!port.peek()); - } -} diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs index 7ab63233cff..131507196b1 100644 --- a/src/libstd/rt/local.rs +++ b/src/libstd/rt/local.rs @@ -126,6 +126,7 @@ impl Local for IoFactoryObject { #[cfg(test)] mod test { + use unstable::run_in_bare_thread; use rt::test::*; use super::*; use rt::task::Task; @@ -133,56 +134,64 @@ mod test { #[test] fn thread_local_task_smoke_test() { - local_ptr::init_tls_key(); - let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); - Local::put(task); - let task: ~Task = Local::take(); - cleanup_task(task); + do run_in_bare_thread { + local_ptr::init_tls_key(); + let mut sched = ~new_test_uv_sched(); + let task = ~Task::new_root(&mut sched.stack_pool, || {}); + Local::put(task); + let task: ~Task = Local::take(); + cleanup_task(task); + } } #[test] fn thread_local_task_two_instances() { - local_ptr::init_tls_key(); - let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); - Local::put(task); - let task: ~Task = Local::take(); - cleanup_task(task); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); - Local::put(task); - let task: ~Task = Local::take(); - cleanup_task(task); + do run_in_bare_thread { + local_ptr::init_tls_key(); + let mut sched = ~new_test_uv_sched(); + let task = ~Task::new_root(&mut sched.stack_pool, || {}); + Local::put(task); + let task: ~Task = Local::take(); + cleanup_task(task); + let task = ~Task::new_root(&mut sched.stack_pool, || {}); + Local::put(task); + let task: ~Task = Local::take(); + cleanup_task(task); + } } #[test] fn borrow_smoke_test() { - local_ptr::init_tls_key(); - let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); - Local::put(task); - - unsafe { - let _task: *mut Task = Local::unsafe_borrow(); + do run_in_bare_thread { + local_ptr::init_tls_key(); + let mut sched = ~new_test_uv_sched(); + let task = ~Task::new_root(&mut sched.stack_pool, || {}); + Local::put(task); + + unsafe { + let _task: *mut Task = Local::unsafe_borrow(); + } + let task: ~Task = Local::take(); + cleanup_task(task); } - let task: ~Task = Local::take(); - cleanup_task(task); } #[test] fn borrow_with_return() { - local_ptr::init_tls_key(); - let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); - Local::put(task); - - let res = do Local::borrow::<Task,bool> |_task| { - true - }; - assert!(res) - let task: ~Task = Local::take(); - cleanup_task(task); + do run_in_bare_thread { + local_ptr::init_tls_key(); + let mut sched = ~new_test_uv_sched(); + let task = ~Task::new_root(&mut sched.stack_pool, || {}); + Local::put(task); + + let res = do Local::borrow::<Task,bool> |_task| { + true + }; + assert!(res) + let task: ~Task = Local::take(); + cleanup_task(task); + } } } diff --git a/src/libstd/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs index cd7c5daa444..652e39b05c7 100644 --- a/src/libstd/rt/local_ptr.rs +++ b/src/libstd/rt/local_ptr.rs @@ -52,7 +52,9 @@ pub unsafe fn put<T>(sched: ~T) { pub unsafe fn take<T>() -> ~T { let key = tls_key(); let void_ptr: *mut c_void = tls::get(key); - rtassert!(void_ptr.is_not_null()); + if void_ptr.is_null() { + rtabort!("thread-local pointer is null. bogus!"); + } let ptr: ~T = cast::transmute(void_ptr); tls::set(key, ptr::mut_null()); return ptr; @@ -68,8 +70,8 @@ pub fn exists() -> bool { } } -/// Borrow the thread-local scheduler from thread-local storage. -/// While the scheduler is borrowed it is not available in TLS. +/// Borrow the thread-local value from thread-local storage. +/// While the value is borrowed it is not available in TLS. /// /// # Safety note /// @@ -88,21 +90,23 @@ pub unsafe fn borrow<T>(f: &fn(&mut T)) { } } -/// Borrow a mutable reference to the thread-local Scheduler +/// Borrow a mutable reference to the thread-local value /// /// # Safety Note /// -/// Because this leaves the Scheduler in thread-local storage it is possible +/// Because this leaves the value in thread-local storage it is possible /// For the Scheduler pointer to be aliased pub unsafe fn unsafe_borrow<T>() -> *mut T { let key = tls_key(); - let mut void_sched: *mut c_void = tls::get(key); - rtassert!(void_sched.is_not_null()); + let mut void_ptr: *mut c_void = tls::get(key); + if void_ptr.is_null() { + rtabort!("thread-local pointer is null. bogus!"); + } { - let sched: *mut *mut c_void = &mut void_sched; - let sched: *mut ~T = sched as *mut ~T; - let sched: *mut T = &mut **sched; - return sched; + let ptr: *mut *mut c_void = &mut void_ptr; + let ptr: *mut ~T = ptr as *mut ~T; + let ptr: *mut T = &mut **ptr; + return ptr; } } diff --git a/src/libstd/rt/logging.rs b/src/libstd/rt/logging.rs index 76619704bee..117795f6c90 100644 --- a/src/libstd/rt/logging.rs +++ b/src/libstd/rt/logging.rs @@ -10,6 +10,7 @@ use either::*; use libc; +use str::StrSlice; pub trait Logger { fn log(&mut self, msg: Either<~str, &'static str>); @@ -35,10 +36,22 @@ impl Logger for StdErrLogger { s } }; - let dbg = ::libc::STDERR_FILENO as ::io::fd_t; - dbg.write_str(s); - dbg.write_str("\n"); - dbg.flush(); + + // Truncate the string + let buf_bytes = 256; + if s.len() > buf_bytes { + let s = s.slice(0, buf_bytes) + "[...]"; + print(s); + } else { + print(s) + }; + + fn print(s: &str) { + let dbg = ::libc::STDERR_FILENO as ::io::fd_t; + dbg.write_str(s); + dbg.write_str("\n"); + dbg.flush(); + } } } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 4cfe0efacfe..33e83fd9040 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -432,13 +432,3 @@ pub fn context() -> RuntimeContext { pub fn rust_try_get_task() -> *rust_task; } } - -#[test] -fn test_context() { - use unstable::run_in_bare_thread; - - assert_eq!(context(), OldTaskContext); - do run_in_bare_thread { - assert_eq!(context(), GlobalContext); - } -} diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 18cfeade157..1a75f2569b5 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -172,6 +172,10 @@ impl Scheduler { rtdebug!("stopping scheduler %u", stask.sched.get_ref().sched_id()); + // Should not have any messages + let message = stask.sched.get_mut_ref().message_queue.pop(); + assert!(message.is_none()); + stask.destroyed = true; } @@ -335,19 +339,24 @@ impl Scheduler { let mut this = self; match this.message_queue.pop() { Some(PinnedTask(task)) => { + this.event_loop.callback(Scheduler::run_sched_once); let mut task = task; task.give_home(Sched(this.make_handle())); this.resume_task_immediately(task); return None; } Some(TaskFromFriend(task)) => { + this.event_loop.callback(Scheduler::run_sched_once); + rtdebug!("got a task from a friend. lovely!"); return this.sched_schedule_task(task); } Some(Wake) => { + this.event_loop.callback(Scheduler::run_sched_once); this.sleepy = false; return Some(this); } Some(Shutdown) => { + this.event_loop.callback(Scheduler::run_sched_once); if this.sleepy { // There may be an outstanding handle on the // sleeper list. Pop them all to make sure that's @@ -395,6 +404,7 @@ impl Scheduler { /// Take a non-homed task we aren't allowed to run here and send /// it to the designated friend scheduler to execute. fn send_to_friend(&mut self, task: ~Task) { + rtdebug!("sending a task to friend"); match self.friend_handle { Some(ref mut handle) => { handle.send(TaskFromFriend(task)); @@ -426,12 +436,14 @@ impl Scheduler { Scheduler::send_task_home(task); return Some(this); } else { + this.event_loop.callback(Scheduler::run_sched_once); task.give_home(Sched(home_handle)); this.resume_task_immediately(task); return None; } } AnySched if this.run_anything => { + this.event_loop.callback(Scheduler::run_sched_once); task.give_home(AnySched); this.resume_task_immediately(task); return None; diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index abafe1cf209..cb949edd7bb 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -228,6 +228,19 @@ impl Task { _ => () } + // FIXME #8302: Dear diary. I'm so tired and confused. + // There's some interaction in rustc between the box + // annihilator and the TLS dtor by which TLS is + // accessed from annihilated box dtors *after* TLS is + // destroyed. Somehow setting TLS back to null, as the + // old runtime did, makes this work, but I don't currently + // understand how. I would expect that, if the annihilator + // reinvokes TLS while TLS is uninitialized, that + // TLS would be reinitialized but never destroyed, + // but somehow this works. I have no idea what's going + // on but this seems to make things magically work. FML. + self.storage = LocalStorage(ptr::null(), None); + // Destroy remaining boxes. Also may run user dtors. unsafe { cleanup::annihilate(); } } @@ -303,7 +316,7 @@ impl Task { impl Drop for Task { fn drop(&self) { rtdebug!("called drop for a task: %u", borrow::to_uint(self)); - assert!(self.destroyed) + rtassert!(self.destroyed) } } @@ -313,7 +326,7 @@ impl Drop for Task { impl Coroutine { pub fn new(stack_pool: &mut StackPool, start: ~fn()) -> Coroutine { - static MIN_STACK_SIZE: uint = 2000000; // XXX: Too much stack + static MIN_STACK_SIZE: uint = 3000000; // XXX: Too much stack let start = Coroutine::build_start_wrapper(start); let mut stack = stack_pool.take_segment(MIN_STACK_SIZE); diff --git a/src/libstd/stackwalk.rs b/src/libstd/stackwalk.rs deleted file mode 100644 index cc516fb559e..00000000000 --- a/src/libstd/stackwalk.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2012 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(missing_doc)]; - -use cast::transmute; -use unstable::intrinsics; - -pub type Word = uint; - -pub struct Frame { - fp: *Word -} - -pub fn Frame(fp: *Word) -> Frame { - Frame { - fp: fp - } -} - -pub fn walk_stack(visit: &fn(Frame)) { - - debug!("beginning stack walk"); - - do frame_address |frame_pointer| { - let mut frame_address: *Word = unsafe { - transmute(frame_pointer) - }; - loop { - let fr = Frame(frame_address); - - debug!("frame: %x", unsafe { transmute(fr.fp) }); - visit(fr); - - unsafe { - let next_fp: **Word = transmute(frame_address); - frame_address = *next_fp; - if *frame_address == 0u { - debug!("encountered task_start_wrapper. ending walk"); - // This is the task_start_wrapper_frame. There is - // no stack beneath it and it is a foreign frame. - break; - } - } - } - } -} - -#[test] -fn test_simple() { - do walk_stack |_frame| { - } -} - -#[test] -fn test_simple_deep() { - fn run(i: int) { - if i == 0 { return } - - do walk_stack |_frame| { - // Would be nice to test something here... - } - run(i - 1); - } - - run(10); -} - -fn frame_address(f: &fn(x: *u8)) { - unsafe { - intrinsics::frame_address(f) - } -} diff --git a/src/libstd/std.rs b/src/libstd/std.rs index d51f0de1d27..236103ec886 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -170,7 +170,6 @@ pub mod local_data; /* Runtime and platform support */ -pub mod gc; pub mod libc; pub mod c_str; pub mod os; @@ -197,7 +196,6 @@ pub mod unstable; mod unicode; #[path = "num/cmath.rs"] mod cmath; -mod stackwalk; // XXX: This shouldn't be pub, and it should be reexported under 'unstable' // but name resolution doesn't work without it being pub. diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 4a5fa82a226..a77371bbfc9 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -1068,7 +1068,7 @@ pub mod raw { let new_len = s.len() + 1; s.reserve_at_least(new_len); do s.as_mut_buf |buf, len| { - *ptr::mut_offset(buf, len as int) = b; + *ptr::mut_offset(buf, (len-1) as int) = b; } set_len(&mut *s, new_len); } @@ -3081,6 +3081,13 @@ mod tests { } #[test] + fn test_push_byte() { + let mut s = ~"ABC"; + unsafe{raw::push_byte(&mut s, 'D' as u8)}; + assert_eq!(s, ~"ABCD"); + } + + #[test] fn test_shift_byte() { let mut s = ~"ABC"; let b = unsafe{raw::shift_byte(&mut s)}; diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs index b40f87617a9..83ee4cf07c6 100644 --- a/src/libstd/sys.rs +++ b/src/libstd/sys.rs @@ -14,7 +14,6 @@ use c_str::ToCStr; use cast; -use gc; use io; use libc; use libc::{c_char, size_t}; @@ -147,7 +146,6 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { match context { OldTaskContext => { unsafe { - gc::cleanup_stack_for_failure(); rustrt::rust_upcall_fail(msg, file, line); cast::transmute(()) } @@ -180,8 +178,6 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { msg, file, line as int); } - gc::cleanup_stack_for_failure(); - let task = Local::unsafe_borrow::<Task>(); if (*task).unwinder.unwinding { rtabort!("unwinding again"); |
