Merge commit 'd89ff7eef969aee6b493bc846b64d68358fafbcd' into remove-str-trailing-nulls
This commit is contained in:
commit
8567611adf
@ -241,7 +241,7 @@ CFG_RUN_TARG_i686-apple-darwin=$(call CFG_RUN_i686-apple-darwin,,$(2))
|
||||
# arm-linux-androideabi configuration
|
||||
CC_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-gcc
|
||||
CXX_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-g++
|
||||
CPP_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-gcc
|
||||
CPP_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-gcc -E
|
||||
AR_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-ar
|
||||
CFG_LIB_NAME_arm-linux-androideabi=lib$(1).so
|
||||
CFG_LIB_GLOB_arm-linux-androideabi=lib$(1)-*.so
|
||||
@ -272,7 +272,7 @@ AR_arm-unknown-linux-gnueabihf=arm-linux-gnueabihf-ar
|
||||
CFG_LIB_NAME_arm-unknown-linux-gnueabihf=lib$(1).so
|
||||
CFG_LIB_GLOB_arm-unknown-linux-gnueabihf=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_arm-unknown-linux-gnueabihf=lib$(1)-*.dylib.dSYM
|
||||
CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC
|
||||
CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC -D__arm__
|
||||
CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabihf := -fno-rtti
|
||||
CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabihf := -shared -fPIC -g
|
||||
CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabihf := -Wl,--export-dynamic,--dynamic-list=
|
||||
@ -290,6 +290,32 @@ CFG_RUN_arm-unknown-linux-gnueabihf=
|
||||
CFG_RUN_TARG_arm-unknown-linux-gnueabihf=
|
||||
RUSTC_FLAGS_arm-unknown-linux-gnueabihf := --linker=$(CC_arm-unknown-linux-gnueabihf)
|
||||
|
||||
# arm-unknown-linux-gnueabi configuration
|
||||
CC_arm-unknown-linux-gnueabi=arm-linux-gnueabi-gcc
|
||||
CXX_arm-unknown-linux-gnueabi=arm-linux-gnueabi-g++
|
||||
CPP_arm-unknown-linux-gnueabi=arm-linux-gnueabi-gcc -E
|
||||
AR_arm-unknown-linux-gnueabi=arm-linux-gnueabi-ar
|
||||
CFG_LIB_NAME_arm-unknown-linux-gnueabi=lib$(1).so
|
||||
CFG_LIB_GLOB_arm-unknown-linux-gnueabi=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_arm-unknown-linux-gnueabi=lib$(1)-*.dylib.dSYM
|
||||
CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__
|
||||
CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabi := -fno-rtti
|
||||
CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabi := -shared -fPIC -g
|
||||
CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_arm-unknown-linux-gnueabi := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_arm-unknown-linux-gnueabi := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_arm-unknown-linux-gnueabi := .linux.def
|
||||
CFG_INSTALL_NAME_ar,-unknown-linux-gnueabi =
|
||||
CFG_LIBUV_LINK_FLAGS_arm-unknown-linux-gnueabi =
|
||||
CFG_EXE_SUFFIX_arm-unknown-linux-gnueabi :=
|
||||
CFG_WINDOWSY_arm-unknown-linux-gnueabi :=
|
||||
CFG_UNIXY_arm-unknown-linux-gnueabi := 1
|
||||
CFG_PATH_MUNGE_arm-unknown-linux-gnueabi := true
|
||||
CFG_LDPATH_arm-unknown-linux-gnueabi :=
|
||||
CFG_RUN_arm-unknown-linux-gnueabi=
|
||||
CFG_RUN_TARG_arm-unknown-linux-gnueabi=
|
||||
RUSTC_FLAGS_arm-unknown-linux-gnueabi := --linker=$(CC_arm-unknown-linux-gnueabi)
|
||||
|
||||
# mips-unknown-linux-gnu configuration
|
||||
CC_mips-unknown-linux-gnu=mips-linux-gnu-gcc
|
||||
CXX_mips-unknown-linux-gnu=mips-linux-gnu-g++
|
||||
@ -450,7 +476,7 @@ define CFG_MAKE_TOOLCHAIN
|
||||
$$(CFG_GCCISH_DEF_FLAG_$(1))$$(3) $$(2) \
|
||||
$$(call CFG_INSTALL_NAME_$(1),$$(4))
|
||||
|
||||
ifneq ($(1),arm-linux-androideabi)
|
||||
ifneq ($(HOST_$(1)),arm)
|
||||
|
||||
# We're using llvm-mc as our assembler because it supports
|
||||
# .cfi pseudo-ops on mac
|
||||
@ -462,9 +488,9 @@ define CFG_MAKE_TOOLCHAIN
|
||||
-o=$$(1)
|
||||
else
|
||||
|
||||
# For the Android cross, use the Android assembler
|
||||
# For the ARM crosses, use the toolchain assembler
|
||||
# XXX: We should be able to use the LLVM assembler
|
||||
CFG_ASSEMBLE_$(1)=$$(CPP_$(1)) $$(CFG_DEPEND_FLAGS) $$(2) -c -o $$(1)
|
||||
CFG_ASSEMBLE_$(1)=$$(CC_$(1)) $$(CFG_DEPEND_FLAGS) $$(2) -c -o $$(1)
|
||||
|
||||
endif
|
||||
|
||||
|
@ -67,17 +67,16 @@ pub struct Arena {
|
||||
priv chunks: @mut MutList<Chunk>,
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl Drop for Arena {
|
||||
fn drop(&self) {
|
||||
unsafe {
|
||||
destroy_chunk(&self.head);
|
||||
do self.chunks.each |chunk| {
|
||||
if !chunk.is_pod {
|
||||
destroy_chunk(chunk);
|
||||
}
|
||||
true
|
||||
};
|
||||
impl Arena {
|
||||
pub fn new() -> Arena {
|
||||
Arena::new_with_size(32u)
|
||||
}
|
||||
|
||||
pub fn new_with_size(initial_size: uint) -> Arena {
|
||||
Arena {
|
||||
head: chunk(initial_size, false),
|
||||
pod_head: chunk(initial_size, true),
|
||||
chunks: @mut MutNil,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,18 +91,21 @@ fn chunk(size: uint, is_pod: bool) -> Chunk {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arena_with_size(initial_size: uint) -> Arena {
|
||||
Arena {
|
||||
head: chunk(initial_size, false),
|
||||
pod_head: chunk(initial_size, true),
|
||||
chunks: @mut MutNil,
|
||||
#[unsafe_destructor]
|
||||
impl Drop for Arena {
|
||||
fn drop(&self) {
|
||||
unsafe {
|
||||
destroy_chunk(&self.head);
|
||||
do self.chunks.each |chunk| {
|
||||
if !chunk.is_pod {
|
||||
destroy_chunk(chunk);
|
||||
}
|
||||
true
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn Arena() -> Arena {
|
||||
arena_with_size(32u)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn round_up_to(base: uint, align: uint) -> uint {
|
||||
(base + (align - 1)) & !(align - 1)
|
||||
@ -276,7 +278,7 @@ impl Arena {
|
||||
|
||||
#[test]
|
||||
fn test_arena_destructors() {
|
||||
let arena = Arena();
|
||||
let arena = Arena::new();
|
||||
for i in range(0u, 10) {
|
||||
// Arena allocate something with drop glue to make sure it
|
||||
// doesn't leak.
|
||||
@ -291,7 +293,7 @@ fn test_arena_destructors() {
|
||||
#[should_fail]
|
||||
#[ignore(cfg(windows))]
|
||||
fn test_arena_destructors_fail() {
|
||||
let arena = Arena();
|
||||
let arena = Arena::new();
|
||||
// Put some stuff in the arena.
|
||||
for i in range(0u, 10) {
|
||||
// Arena allocate something with drop glue to make sure it
|
||||
|
@ -18,9 +18,8 @@ Higher level communication abstractions.
|
||||
|
||||
|
||||
use std::comm::{GenericChan, GenericSmartChan, GenericPort};
|
||||
use std::comm::{Chan, Port, Selectable, Peekable};
|
||||
use std::comm::{Chan, Port, Peekable};
|
||||
use std::comm;
|
||||
use std::pipes;
|
||||
|
||||
/// An extension of `pipes::stream` that allows both sending and receiving.
|
||||
pub struct DuplexStream<T, U> {
|
||||
@ -75,12 +74,6 @@ impl<T:Send,U:Send> Peekable<U> for DuplexStream<T, U> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Send,U:Send> Selectable for DuplexStream<T, U> {
|
||||
fn header(&mut self) -> *mut pipes::PacketHeader {
|
||||
self.port.header()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a bidirectional stream.
|
||||
pub fn DuplexStream<T:Send,U:Send>()
|
||||
-> (DuplexStream<T, U>, DuplexStream<U, T>)
|
||||
|
@ -92,6 +92,11 @@ impl<T> Rawlink<T> {
|
||||
Some(unsafe { cast::transmute(self.p) })
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the `Rawlink` and replace with `Rawlink::none()`
|
||||
fn take(&mut self) -> Rawlink<T> {
|
||||
util::replace(self, Rawlink::none())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Rawlink<T> {
|
||||
@ -280,13 +285,16 @@ impl<T> DList<T> {
|
||||
/// Add all elements from `other` to the end of the list
|
||||
///
|
||||
/// O(1)
|
||||
pub fn append(&mut self, other: DList<T>) {
|
||||
pub fn append(&mut self, mut other: DList<T>) {
|
||||
match self.list_tail.resolve() {
|
||||
None => *self = other,
|
||||
Some(tail) => {
|
||||
match other {
|
||||
DList{list_head: None, _} => return,
|
||||
DList{list_head: Some(node), list_tail: o_tail, length: o_length} => {
|
||||
// Carefully empty `other`.
|
||||
let o_tail = other.list_tail.take();
|
||||
let o_length = other.length;
|
||||
match other.list_head.take() {
|
||||
None => return,
|
||||
Some(node) => {
|
||||
tail.next = link_with_prev(node, self.list_tail);
|
||||
self.list_tail = o_tail;
|
||||
self.length += o_length;
|
||||
@ -404,6 +412,32 @@ impl<T: Ord> DList<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<T> Drop for DList<T> {
|
||||
fn drop(&self) {
|
||||
let mut_self = unsafe {
|
||||
cast::transmute_mut(self)
|
||||
};
|
||||
// Dissolve the dlist in backwards direction
|
||||
// Just dropping the list_head can lead to stack exhaustion
|
||||
// when length is >> 1_000_000
|
||||
let mut tail = mut_self.list_tail;
|
||||
loop {
|
||||
match tail.resolve() {
|
||||
None => break,
|
||||
Some(prev) => {
|
||||
prev.next.take(); // release ~Node<T>
|
||||
tail = prev.prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
mut_self.length = 0;
|
||||
mut_self.list_head = None;
|
||||
mut_self.list_tail = Rawlink::none();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'self, A> Iterator<&'self A> for DListIterator<'self, A> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'self A> {
|
||||
|
@ -184,7 +184,68 @@ impl<K: TotalOrd, V> TreeMap<K, V> {
|
||||
/// Get a lazy iterator over the key-value pairs in the map.
|
||||
/// Requires that it be frozen (immutable).
|
||||
pub fn iter<'a>(&'a self) -> TreeMapIterator<'a, K, V> {
|
||||
TreeMapIterator{stack: ~[], node: &self.root, remaining: self.length}
|
||||
TreeMapIterator {
|
||||
stack: ~[],
|
||||
node: &self.root,
|
||||
remaining_min: self.length,
|
||||
remaining_max: self.length
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a lazy iterator that should be initialized using
|
||||
/// `iter_traverse_left`/`iter_traverse_right`/`iter_traverse_complete`.
|
||||
fn iter_for_traversal<'a>(&'a self) -> TreeMapIterator<'a, K, V> {
|
||||
TreeMapIterator {
|
||||
stack: ~[],
|
||||
node: &self.root,
|
||||
remaining_min: 0,
|
||||
remaining_max: self.length
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a lazy iterator to the first key-value pair whose key is not less than `k`
|
||||
/// If all keys in map are less than `k` an empty iterator is returned.
|
||||
pub fn lower_bound_iter<'a>(&'a self, k: &K) -> TreeMapIterator<'a, K, V> {
|
||||
let mut iter: TreeMapIterator<'a, K, V> = self.iter_for_traversal();
|
||||
loop {
|
||||
match *iter.node {
|
||||
Some(ref r) => {
|
||||
match k.cmp(&r.key) {
|
||||
Less => iter_traverse_left(&mut iter),
|
||||
Greater => iter_traverse_right(&mut iter),
|
||||
Equal => {
|
||||
iter_traverse_complete(&mut iter);
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
iter_traverse_complete(&mut iter);
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a lazy iterator to the first key-value pair whose key is greater than `k`
|
||||
/// If all keys in map are not greater than `k` an empty iterator is returned.
|
||||
pub fn upper_bound_iter<'a>(&'a self, k: &K) -> TreeMapIterator<'a, K, V> {
|
||||
let mut iter: TreeMapIterator<'a, K, V> = self.iter_for_traversal();
|
||||
loop {
|
||||
match *iter.node {
|
||||
Some(ref r) => {
|
||||
match k.cmp(&r.key) {
|
||||
Less => iter_traverse_left(&mut iter),
|
||||
Greater => iter_traverse_right(&mut iter),
|
||||
Equal => iter_traverse_right(&mut iter)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
iter_traverse_complete(&mut iter);
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a lazy iterator that consumes the treemap.
|
||||
@ -205,7 +266,8 @@ impl<K: TotalOrd, V> TreeMap<K, V> {
|
||||
pub struct TreeMapIterator<'self, K, V> {
|
||||
priv stack: ~[&'self ~TreeNode<K, V>],
|
||||
priv node: &'self Option<~TreeNode<K, V>>,
|
||||
priv remaining: uint
|
||||
priv remaining_min: uint,
|
||||
priv remaining_max: uint
|
||||
}
|
||||
|
||||
impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> {
|
||||
@ -222,7 +284,10 @@ impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V
|
||||
None => {
|
||||
let res = self.stack.pop();
|
||||
self.node = &res.right;
|
||||
self.remaining -= 1;
|
||||
self.remaining_max -= 1;
|
||||
if self.remaining_min > 0 {
|
||||
self.remaining_min -= 1;
|
||||
}
|
||||
return Some((&res.key, &res.value));
|
||||
}
|
||||
}
|
||||
@ -232,7 +297,46 @@ impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (uint, Option<uint>) {
|
||||
(self.remaining, Some(self.remaining))
|
||||
(self.remaining_min, Some(self.remaining_max))
|
||||
}
|
||||
}
|
||||
|
||||
/// iter_traverse_left, iter_traverse_right and iter_traverse_complete are used to
|
||||
/// initialize TreeMapIterator pointing to element inside tree structure.
|
||||
///
|
||||
/// They should be used in following manner:
|
||||
/// - create iterator using TreeMap::iter_for_traversal
|
||||
/// - find required node using `iter_traverse_left`/`iter_traverse_right`
|
||||
/// (current node is `TreeMapIterator::node` field)
|
||||
/// - complete initialization with `iter_traverse_complete`
|
||||
#[inline]
|
||||
fn iter_traverse_left<'a, K, V>(it: &mut TreeMapIterator<'a, K, V>) {
|
||||
let node = it.node.get_ref();
|
||||
it.stack.push(node);
|
||||
it.node = &node.left;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn iter_traverse_right<'a, K, V>(it: &mut TreeMapIterator<'a, K, V>) {
|
||||
it.node = &(it.node.get_ref().right);
|
||||
}
|
||||
|
||||
/// iter_traverse_left, iter_traverse_right and iter_traverse_complete are used to
|
||||
/// initialize TreeMapIterator pointing to element inside tree structure.
|
||||
///
|
||||
/// Completes traversal. Should be called before using iterator.
|
||||
/// Iteration will start from `self.node`.
|
||||
/// If `self.node` is None iteration will start from last node from which we
|
||||
/// traversed left.
|
||||
#[inline]
|
||||
fn iter_traverse_complete<'a, K, V>(it: &mut TreeMapIterator<'a, K, V>) {
|
||||
static none: Option<~TreeNode<K, V>> = None;
|
||||
match *it.node {
|
||||
Some(ref n) => {
|
||||
it.stack.push(n);
|
||||
it.node = &none;
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,6 +521,20 @@ impl<T: TotalOrd> TreeSet<T> {
|
||||
TreeSetIterator{iter: self.map.iter()}
|
||||
}
|
||||
|
||||
/// Get a lazy iterator pointing to the first value not less than `v` (greater or equal).
|
||||
/// If all elements in the set are less than `v` empty iterator is returned.
|
||||
#[inline]
|
||||
pub fn lower_bound_iter<'a>(&'a self, v: &T) -> TreeSetIterator<'a, T> {
|
||||
TreeSetIterator{iter: self.map.lower_bound_iter(v)}
|
||||
}
|
||||
|
||||
/// Get a lazy iterator pointing to the first value greater than `v`.
|
||||
/// If all elements in the set are not greater than `v` empty iterator is returned.
|
||||
#[inline]
|
||||
pub fn upper_bound_iter<'a>(&'a self, v: &T) -> TreeSetIterator<'a, T> {
|
||||
TreeSetIterator{iter: self.map.upper_bound_iter(v)}
|
||||
}
|
||||
|
||||
/// Visit all values in reverse order
|
||||
#[inline]
|
||||
pub fn each_reverse(&self, f: &fn(&T) -> bool) -> bool {
|
||||
@ -983,6 +1101,31 @@ mod test_treemap {
|
||||
assert_eq!(*v, n * 2);
|
||||
n += 1;
|
||||
}
|
||||
assert_eq!(n, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_interval_iteration() {
|
||||
let mut m = TreeMap::new();
|
||||
for i in range(1, 100) {
|
||||
assert!(m.insert(i * 2, i * 4));
|
||||
}
|
||||
|
||||
for i in range(1, 198) {
|
||||
let mut lb_it = m.lower_bound_iter(&i);
|
||||
let (&k, &v) = lb_it.next().unwrap();
|
||||
let lb = i + i % 2;
|
||||
assert_eq!(lb, k);
|
||||
assert_eq!(lb * 2, v);
|
||||
|
||||
let mut ub_it = m.upper_bound_iter(&i);
|
||||
let (&k, &v) = ub_it.next().unwrap();
|
||||
let ub = i + 2 - i % 2;
|
||||
assert_eq!(ub, k);
|
||||
assert_eq!(ub * 2, v);
|
||||
}
|
||||
let mut end_it = m.lower_bound_iter(&199);
|
||||
assert_eq!(end_it.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1256,7 +1399,6 @@ mod test_set {
|
||||
|
||||
let mut n = 0;
|
||||
for x in m.iter() {
|
||||
printfln!(x);
|
||||
assert_eq!(*x, n);
|
||||
n += 1
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[forbid(deprecated_mode)];
|
||||
#[allow(missing_doc)];
|
||||
|
||||
pub mod icu {
|
||||
@ -159,7 +158,10 @@ pub mod icu {
|
||||
pub static UCHAR_INVALID_CODE : UProperty = -1;
|
||||
|
||||
pub mod libicu {
|
||||
#[link_name = "icuuc"]
|
||||
use unicode::icu::*;
|
||||
|
||||
// #[link_name = "icuuc"]
|
||||
#[link_args = "-licuuc"]
|
||||
#[abi = "cdecl"]
|
||||
extern {
|
||||
pub fn u_hasBinaryProperty(c: UChar32, which: UProperty) -> UBool;
|
||||
@ -174,13 +176,17 @@ pub mod icu {
|
||||
}
|
||||
|
||||
pub fn is_XID_start(c: char) -> bool {
|
||||
return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START)
|
||||
== icu::TRUE;
|
||||
unsafe {
|
||||
return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START)
|
||||
== icu::TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_XID_continue(c: char) -> bool {
|
||||
return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START)
|
||||
== icu::TRUE;
|
||||
unsafe {
|
||||
return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START)
|
||||
== icu::TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -189,7 +195,9 @@ Function: is_digit
|
||||
Returns true if a character is a digit.
|
||||
*/
|
||||
pub fn is_digit(c: char) -> bool {
|
||||
return icu::libicu::u_isdigit(c) == icu::TRUE;
|
||||
unsafe {
|
||||
return icu::libicu::u_isdigit(c) == icu::TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -198,7 +206,9 @@ Function: is_lower
|
||||
Returns true if a character is a lowercase letter.
|
||||
*/
|
||||
pub fn is_lower(c: char) -> bool {
|
||||
return icu::libicu::u_islower(c) == icu::TRUE;
|
||||
unsafe {
|
||||
return icu::libicu::u_islower(c) == icu::TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -207,7 +217,9 @@ Function: is_space
|
||||
Returns true if a character is space.
|
||||
*/
|
||||
pub fn is_space(c: char) -> bool {
|
||||
return icu::libicu::u_isspace(c) == icu::TRUE;
|
||||
unsafe {
|
||||
return icu::libicu::u_isspace(c) == icu::TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -216,33 +228,36 @@ Function: is_upper
|
||||
Returns true if a character is an uppercase letter.
|
||||
*/
|
||||
pub fn is_upper(c: char) -> bool {
|
||||
return icu::libicu::u_isupper(c) == icu::TRUE;
|
||||
unsafe {
|
||||
return icu::libicu::u_isupper(c) == icu::TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use unicode::*;
|
||||
|
||||
#[test]
|
||||
fn test_is_digit() {
|
||||
assert!((unicode::icu::is_digit('0')));
|
||||
assert!((!unicode::icu::is_digit('m')));
|
||||
assert!((is_digit('0')));
|
||||
assert!((!is_digit('m')));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_lower() {
|
||||
assert!((unicode::icu::is_lower('m')));
|
||||
assert!((!unicode::icu::is_lower('M')));
|
||||
assert!((is_lower('m')));
|
||||
assert!((!is_lower('M')));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_space() {
|
||||
assert!((unicode::icu::is_space(' ')));
|
||||
assert!((!unicode::icu::is_space('m')));
|
||||
assert!((is_space(' ')));
|
||||
assert!((!is_space('m')));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_upper() {
|
||||
assert!((unicode::icu::is_upper('M')));
|
||||
assert!((!unicode::icu::is_upper('m')));
|
||||
assert!((is_upper('M')));
|
||||
assert!((!is_upper('m')));
|
||||
}
|
||||
}
|
||||
|
@ -335,7 +335,7 @@ pub fn phase_5_run_llvm_passes(sess: Session,
|
||||
outputs: &OutputFilenames) {
|
||||
|
||||
// NB: Android hack
|
||||
if sess.targ_cfg.arch == abi::Arm &&
|
||||
if sess.targ_cfg.os == session::os_android &&
|
||||
(sess.opts.output_type == link::output_type_object ||
|
||||
sess.opts.output_type == link::output_type_exe) {
|
||||
let output_type = link::output_type_assembly;
|
||||
|
@ -179,7 +179,8 @@ pub struct crate_metadata {
|
||||
#[deriving(Eq)]
|
||||
pub enum EntryFnType {
|
||||
EntryMain,
|
||||
EntryStart
|
||||
EntryStart,
|
||||
EntryNone,
|
||||
}
|
||||
|
||||
pub struct Session_ {
|
||||
|
@ -50,6 +50,12 @@ pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map)
|
||||
return;
|
||||
}
|
||||
|
||||
// If the user wants no main function at all, then stop here.
|
||||
if attr::contains_name(crate.attrs, "no_main") {
|
||||
*session.entry_type = Some(session::EntryNone);
|
||||
return
|
||||
}
|
||||
|
||||
let ctxt = @mut EntryContext {
|
||||
session: session,
|
||||
ast_map: ast_map,
|
||||
|
@ -2269,13 +2269,16 @@ pub fn is_entry_fn(sess: &Session, node_id: ast::NodeId) -> bool {
|
||||
// Create a _rust_main(args: ~[str]) function which will be called from the
|
||||
// runtime rust_start function
|
||||
pub fn create_entry_wrapper(ccx: @mut CrateContext,
|
||||
_sp: span, main_llfn: ValueRef) {
|
||||
_sp: span,
|
||||
main_llfn: ValueRef) {
|
||||
let et = ccx.sess.entry_type.unwrap();
|
||||
if et == session::EntryMain {
|
||||
let llfn = create_main(ccx, main_llfn);
|
||||
create_entry_fn(ccx, llfn, true);
|
||||
} else {
|
||||
create_entry_fn(ccx, main_llfn, false);
|
||||
match et {
|
||||
session::EntryMain => {
|
||||
let llfn = create_main(ccx, main_llfn);
|
||||
create_entry_fn(ccx, llfn, true);
|
||||
}
|
||||
session::EntryStart => create_entry_fn(ccx, main_llfn, false),
|
||||
session::EntryNone => {} // Do nothing.
|
||||
}
|
||||
|
||||
fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
|
||||
|
@ -408,9 +408,10 @@ fn check_for_entry_fn(ccx: &CrateCtxt) {
|
||||
Some((id, sp)) => match *tcx.sess.entry_type {
|
||||
Some(session::EntryMain) => check_main_fn_ty(ccx, id, sp),
|
||||
Some(session::EntryStart) => check_start_fn_ty(ccx, id, sp),
|
||||
Some(session::EntryNone) => {}
|
||||
None => tcx.sess.bug("entry function without a type")
|
||||
},
|
||||
None => tcx.sess.bug("type checking without entry function")
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
@ -732,22 +642,6 @@ mod test {
|
||||
use either::Right;
|
||||
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();
|
||||
|
358
src/libstd/gc.rs
358
src/libstd/gc.rs
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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>() {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
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();
|
||||
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);
|
||||
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);
|
||||
let res = do Local::borrow::<Task,bool> |_task| {
|
||||
true
|
||||
};
|
||||
assert!(res)
|
||||
let task: ~Task = Local::take();
|
||||
cleanup_task(task);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
@ -3080,6 +3080,13 @@ mod tests {
|
||||
assert!(!" _ ".is_whitespace());
|
||||
}
|
||||
|
||||
#[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";
|
||||
|
@ -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");
|
||||
|
@ -14,22 +14,36 @@
|
||||
.globl get_sp
|
||||
|
||||
record_sp_limit:
|
||||
// First, try to read TLS address from coprocessor
|
||||
mrc p15, #0, r3, c13, c0, #3
|
||||
cmp r3, #0
|
||||
// Otherwise, try to read from magic address 0xFFFF0FF0
|
||||
mvneq r3, #0xF000
|
||||
ldreq r3, [r3, #-15]
|
||||
|
||||
#if __ANDROID__
|
||||
add r3, r3, #252
|
||||
#elif __linux__
|
||||
add r3, r3, #4
|
||||
#endif
|
||||
|
||||
str r0, [r3]
|
||||
mov pc, lr
|
||||
|
||||
get_sp_limit:
|
||||
// First, try to read TLS address from coprocessor
|
||||
mrc p15, #0, r3, c13, c0, #3
|
||||
cmp r3, #0
|
||||
// Otherwise, try to read from magic address 0xFFFF0FF0
|
||||
mvneq r3, #0xF000
|
||||
ldreq r3, [r3, #-15]
|
||||
|
||||
#if __ANDROID__
|
||||
add r3, r3, #252
|
||||
#elif __linux__
|
||||
add r3, r3, #4
|
||||
#endif
|
||||
|
||||
ldr r0, [r3]
|
||||
mov pc, lr
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
extern mod extra;
|
||||
use extra::arena;
|
||||
use extra::arena::Arena;
|
||||
|
||||
enum Tree<'self> {
|
||||
Nil,
|
||||
@ -25,7 +25,7 @@ fn item_check(t: &Tree) -> int {
|
||||
}
|
||||
}
|
||||
|
||||
fn bottom_up_tree<'r>(arena: &'r arena::Arena, item: int, depth: int)
|
||||
fn bottom_up_tree<'r>(arena: &'r Arena, item: int, depth: int)
|
||||
-> &'r Tree<'r> {
|
||||
if depth > 0 {
|
||||
return arena.alloc(
|
||||
@ -57,7 +57,7 @@ fn main() {
|
||||
max_depth = n;
|
||||
}
|
||||
|
||||
let stretch_arena = arena::Arena();
|
||||
let stretch_arena = Arena::new();
|
||||
let stretch_depth = max_depth + 1;
|
||||
let stretch_tree = bottom_up_tree(&stretch_arena, 0, stretch_depth);
|
||||
|
||||
@ -65,7 +65,7 @@ fn main() {
|
||||
stretch_depth,
|
||||
item_check(stretch_tree));
|
||||
|
||||
let long_lived_arena = arena::Arena();
|
||||
let long_lived_arena = Arena::new();
|
||||
let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth);
|
||||
let mut depth = min_depth;
|
||||
while depth <= max_depth {
|
||||
|
@ -1,39 +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.
|
||||
|
||||
// xfail-fast
|
||||
// xfail-win32 #7999
|
||||
|
||||
use std::comm::{Select2, Selectable};
|
||||
use std::comm;
|
||||
use std::task;
|
||||
|
||||
pub fn main() {
|
||||
let (p,c) = comm::stream();
|
||||
do task::try || {
|
||||
let (p2,c2) = comm::stream();
|
||||
do task::spawn || {
|
||||
p2.recv();
|
||||
error!("sibling fails");
|
||||
fail!();
|
||||
}
|
||||
let (p3,c3) = comm::stream();
|
||||
c.send(c3);
|
||||
c2.send(());
|
||||
error!("child blocks");
|
||||
let (p, c) = comm::stream();
|
||||
let mut tuple = (p, p3);
|
||||
tuple.select();
|
||||
c.send(());
|
||||
};
|
||||
error!("parent tries");
|
||||
assert!(!p.recv().try_send(()));
|
||||
error!("all done!");
|
||||
}
|
@ -11,10 +11,10 @@
|
||||
// except according to those terms.
|
||||
|
||||
extern mod extra;
|
||||
use extra::arena;
|
||||
use extra::arena::Arena;
|
||||
|
||||
pub fn main() {
|
||||
let mut arena = arena::Arena();
|
||||
let mut arena = Arena::new();
|
||||
let p = &mut arena;
|
||||
let x = p.alloc(|| 4u);
|
||||
printf!("%u", *x);
|
||||
|
Loading…
x
Reference in New Issue
Block a user