Fallout from new thread API
This commit is contained in:
parent
14c1a103bc
commit
43ae4b3301
51 changed files with 323 additions and 439 deletions
|
@ -32,7 +32,7 @@ use std::io;
|
||||||
use std::os;
|
use std::os;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::task;
|
use std::thread::Thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use test::MetricMap;
|
use test::MetricMap;
|
||||||
|
|
||||||
|
@ -445,9 +445,9 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||||
loop {
|
loop {
|
||||||
//waiting 1 second for gdbserver start
|
//waiting 1 second for gdbserver start
|
||||||
timer::sleep(Duration::milliseconds(1000));
|
timer::sleep(Duration::milliseconds(1000));
|
||||||
let result = task::try(move || {
|
let result = Thread::with_join(move || {
|
||||||
tcp::TcpStream::connect("127.0.0.1:5039").unwrap();
|
tcp::TcpStream::connect("127.0.0.1:5039").unwrap();
|
||||||
});
|
}).join();
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,16 +347,16 @@ result with an `int` field (representing a successful result) or an `Err` result
|
||||||
(representing termination with an error).
|
(representing termination with an error).
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
# use std::task;
|
# use std::thread::Thread;
|
||||||
# fn some_condition() -> bool { false }
|
# fn some_condition() -> bool { false }
|
||||||
# fn calculate_result() -> int { 0 }
|
# fn calculate_result() -> int { 0 }
|
||||||
let result: Result<int, Box<std::any::Any + Send>> = task::try(move || {
|
let result: Result<int, Box<std::any::Any + Send>> = Thread::with_join(move || {
|
||||||
if some_condition() {
|
if some_condition() {
|
||||||
calculate_result()
|
calculate_result()
|
||||||
} else {
|
} else {
|
||||||
panic!("oops!");
|
panic!("oops!");
|
||||||
}
|
}
|
||||||
});
|
}).join();
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ impl<'a, T, Sized? B> BorrowFrom<Cow<'a, T, B>> for B where B: ToOwned<T> {
|
||||||
|
|
||||||
/// Trait for moving into a `Cow`
|
/// Trait for moving into a `Cow`
|
||||||
pub trait IntoCow<'a, T, Sized? B> {
|
pub trait IntoCow<'a, T, Sized? B> {
|
||||||
/// Moves `self` into `Cow`
|
/// Moves `serlf` into `Cow`
|
||||||
fn into_cow(self) -> Cow<'a, T, B>;
|
fn into_cow(self) -> Cow<'a, T, B>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ use rustc::DIAGNOSTICS;
|
||||||
use std::any::AnyRefExt;
|
use std::any::AnyRefExt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os;
|
use std::os;
|
||||||
use std::task::TaskBuilder;
|
use std::thread;
|
||||||
|
|
||||||
use rustc::session::early_error;
|
use rustc::session::early_error;
|
||||||
|
|
||||||
|
@ -475,18 +475,22 @@ pub fn monitor<F:FnOnce()+Send>(f: F) {
|
||||||
static STACK_SIZE: uint = 32000000; // 32MB
|
static STACK_SIZE: uint = 32000000; // 32MB
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let w = io::ChanWriter::new(tx);
|
let mut w = Some(io::ChanWriter::new(tx)); // option dance
|
||||||
let mut r = io::ChanReader::new(rx);
|
let mut r = io::ChanReader::new(rx);
|
||||||
|
|
||||||
let mut task = TaskBuilder::new().named("rustc").stderr(box w);
|
let mut cfg = thread::cfg().name("rustc".to_string());
|
||||||
|
|
||||||
// FIXME: Hacks on hacks. If the env is trying to override the stack size
|
// FIXME: Hacks on hacks. If the env is trying to override the stack size
|
||||||
// then *don't* set it explicitly.
|
// then *don't* set it explicitly.
|
||||||
if os::getenv("RUST_MIN_STACK").is_none() {
|
if os::getenv("RUST_MIN_STACK").is_none() {
|
||||||
task = task.stack_size(STACK_SIZE);
|
cfg = cfg.stack_size(STACK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
match task.try(f) {
|
let f = proc() {
|
||||||
|
std::io::stdio::set_stderr(box w.take().unwrap());
|
||||||
|
f()
|
||||||
|
};
|
||||||
|
match cfg.with_join(f).join() {
|
||||||
Ok(()) => { /* fallthrough */ }
|
Ok(()) => { /* fallthrough */ }
|
||||||
Err(value) => {
|
Err(value) => {
|
||||||
// Task panicked without emitting a fatal diagnostic
|
// Task panicked without emitting a fatal diagnostic
|
||||||
|
@ -540,4 +544,3 @@ pub fn main() {
|
||||||
let result = run(args);
|
let result = run(args);
|
||||||
std::os::set_exit_status(result);
|
std::os::set_exit_status(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ use std::ptr;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::task::TaskBuilder;
|
use std::thread;
|
||||||
use libc::{c_uint, c_int, c_void};
|
use libc::{c_uint, c_int, c_void};
|
||||||
|
|
||||||
#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq)]
|
#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq)]
|
||||||
|
@ -896,7 +896,11 @@ fn run_work_multithreaded(sess: &Session,
|
||||||
let diag_emitter = diag_emitter.clone();
|
let diag_emitter = diag_emitter.clone();
|
||||||
let remark = sess.opts.cg.remark.clone();
|
let remark = sess.opts.cg.remark.clone();
|
||||||
|
|
||||||
let future = TaskBuilder::new().named(format!("codegen-{}", i)).try_future(move |:| {
|
let (tx, rx) = channel();
|
||||||
|
let mut tx = Some(tx);
|
||||||
|
futures.push(rx);
|
||||||
|
|
||||||
|
thread::cfg().name(format!("codegen-{}", i)).spawn(move |:| {
|
||||||
let diag_handler = mk_handler(box diag_emitter);
|
let diag_handler = mk_handler(box diag_emitter);
|
||||||
|
|
||||||
// Must construct cgcx inside the proc because it has non-Send
|
// Must construct cgcx inside the proc because it has non-Send
|
||||||
|
@ -921,13 +925,14 @@ fn run_work_multithreaded(sess: &Session,
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tx.take().unwrap().send(());
|
||||||
});
|
});
|
||||||
futures.push(future);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut panicked = false;
|
let mut panicked = false;
|
||||||
for future in futures.into_iter() {
|
for rx in futures.into_iter() {
|
||||||
match future.into_inner() {
|
match rx.recv_opt() {
|
||||||
Ok(()) => {},
|
Ok(()) => {},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
panicked = true;
|
panicked = true;
|
||||||
|
|
|
@ -342,10 +342,11 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
|
||||||
|
|
||||||
let cr = Path::new(cratefile);
|
let cr = Path::new(cratefile);
|
||||||
info!("starting to run rustc");
|
info!("starting to run rustc");
|
||||||
let (mut krate, analysis) = std::task::try(move |:| {
|
|
||||||
|
let (mut krate, analysis) = std::thread::Thread::with_join(move |:| {
|
||||||
let cr = cr;
|
let cr = cr;
|
||||||
core::run_core(libs, cfgs, externs, &cr, triple)
|
core::run_core(libs, cfgs, externs, &cr, triple)
|
||||||
}).map_err(|_| "rustc failed").unwrap();
|
}).join().map_err(|_| "rustc failed").unwrap();
|
||||||
info!("finished with rustc");
|
info!("finished with rustc");
|
||||||
let mut analysis = Some(analysis);
|
let mut analysis = Some(analysis);
|
||||||
ANALYSISKEY.with(|s| {
|
ANALYSISKEY.with(|s| {
|
||||||
|
|
|
@ -16,6 +16,7 @@ use std::os;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::thunk::Thunk;
|
use std::thunk::Thunk;
|
||||||
|
use std::thread::Thread;
|
||||||
|
|
||||||
use std::collections::{HashSet, HashMap};
|
use std::collections::{HashSet, HashMap};
|
||||||
use testing;
|
use testing;
|
||||||
|
@ -143,7 +144,7 @@ fn runtest(test: &str, cratename: &str, libs: Vec<Path>, externs: core::Externs,
|
||||||
let w1 = io::ChanWriter::new(tx);
|
let w1 = io::ChanWriter::new(tx);
|
||||||
let w2 = w1.clone();
|
let w2 = w1.clone();
|
||||||
let old = io::stdio::set_stderr(box w1);
|
let old = io::stdio::set_stderr(box w1);
|
||||||
spawn(move |:| {
|
Thread::spawn(move |:| {
|
||||||
let mut p = io::ChanReader::new(rx);
|
let mut p = io::ChanReader::new(rx);
|
||||||
let mut err = match old {
|
let mut err = match old {
|
||||||
Some(old) => {
|
Some(old) => {
|
||||||
|
|
|
@ -536,7 +536,7 @@ pub unsafe fn from_c_multistring<F>(buf: *const libc::c_char,
|
||||||
mod tests {
|
mod tests {
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
use ptr;
|
use ptr;
|
||||||
use task;
|
use thread::Thread;
|
||||||
use libc;
|
use libc;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -637,7 +637,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_to_c_str_fail() {
|
fn test_to_c_str_fail() {
|
||||||
assert!(task::try(move|| { "he\x00llo".to_c_str() }).is_err());
|
assert!(Thread::with_join(move|| { "he\x00llo".to_c_str() }).join().is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub struct WaitToken {
|
||||||
no_send: NoSend,
|
no_send: NoSend,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token() -> (WaitToken, SignalToken) {
|
pub fn tokens() -> (WaitToken, SignalToken) {
|
||||||
let inner = Arc::new(Inner {
|
let inner = Arc::new(Inner {
|
||||||
thread: Thread::current(),
|
thread: Thread::current(),
|
||||||
woken: INIT_ATOMIC_BOOL,
|
woken: INIT_ATOMIC_BOOL,
|
||||||
|
@ -48,7 +48,7 @@ fn token() -> (WaitToken, SignalToken) {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignalToken {
|
impl SignalToken {
|
||||||
fn signal(&self) -> bool {
|
pub fn signal(&self) -> bool {
|
||||||
let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst);
|
let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst);
|
||||||
if wake {
|
if wake {
|
||||||
self.inner.thread.unpark();
|
self.inner.thread.unpark();
|
||||||
|
@ -73,7 +73,7 @@ impl SignalToken {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WaitToken {
|
impl WaitToken {
|
||||||
fn wait(self) {
|
pub fn wait(self) {
|
||||||
while !self.inner.woken.load(Ordering::SeqCst) {
|
while !self.inner.woken.load(Ordering::SeqCst) {
|
||||||
Thread::park()
|
Thread::park()
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,8 +317,10 @@ use core::kinds::marker;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
|
|
||||||
pub use comm::select::{Select, Handle};
|
pub use self::select::{Select, Handle};
|
||||||
use comm::select::StartResult::*;
|
use self::select::StartResult;
|
||||||
|
use self::select::StartResult::*;
|
||||||
|
use self::blocking::SignalToken;
|
||||||
|
|
||||||
macro_rules! test {
|
macro_rules! test {
|
||||||
{ fn $name:ident() $b:block $(#[$a:meta])*} => (
|
{ fn $name:ident() $b:block $(#[$a:meta])*} => (
|
||||||
|
@ -330,7 +332,7 @@ macro_rules! test {
|
||||||
|
|
||||||
use comm::*;
|
use comm::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use task;
|
use thread::Thread;
|
||||||
|
|
||||||
$(#[$a])* #[test] fn f() { $b }
|
$(#[$a])* #[test] fn f() { $b }
|
||||||
}
|
}
|
||||||
|
@ -593,12 +595,12 @@ impl<T: Send> Sender<T> {
|
||||||
(a, ret)
|
(a, ret)
|
||||||
}
|
}
|
||||||
oneshot::UpDisconnected => (a, Err(t)),
|
oneshot::UpDisconnected => (a, Err(t)),
|
||||||
oneshot::UpWoke(task) => {
|
oneshot::UpWoke(token) => {
|
||||||
// This send cannot panic because the task is
|
// This send cannot panic because the thread is
|
||||||
// asleep (we're looking at it), so the receiver
|
// asleep (we're looking at it), so the receiver
|
||||||
// can't go away.
|
// can't go away.
|
||||||
(*a.get()).send(t).ok().unwrap();
|
(*a.get()).send(t).ok().unwrap();
|
||||||
task.wake().map(|t| t.reawaken());
|
token.signal();
|
||||||
(a, Ok(()))
|
(a, Ok(()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -937,7 +939,7 @@ impl<T: Send> select::Packet for Receiver<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_selection(&self, mut token: SignalToken) -> bool {
|
fn start_selection(&self, mut token: SignalToken) -> StartResult {
|
||||||
loop {
|
loop {
|
||||||
let (t, new_port) = match *unsafe { self.inner() } {
|
let (t, new_port) = match *unsafe { self.inner() } {
|
||||||
Oneshot(ref p) => {
|
Oneshot(ref p) => {
|
||||||
|
@ -1240,11 +1242,11 @@ mod test {
|
||||||
|
|
||||||
test! { fn oneshot_single_thread_recv_chan_close() {
|
test! { fn oneshot_single_thread_recv_chan_close() {
|
||||||
// Receiving on a closed chan will panic
|
// Receiving on a closed chan will panic
|
||||||
let res = task::try(move|| {
|
let res = Thread::with_join(move|| {
|
||||||
let (tx, rx) = channel::<int>();
|
let (tx, rx) = channel::<int>();
|
||||||
drop(tx);
|
drop(tx);
|
||||||
rx.recv();
|
rx.recv();
|
||||||
});
|
}).join();
|
||||||
// What is our res?
|
// What is our res?
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
} }
|
} }
|
||||||
|
@ -1312,9 +1314,9 @@ mod test {
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
drop(tx);
|
drop(tx);
|
||||||
});
|
});
|
||||||
let res = task::try(move|| {
|
let res = Thread::with_join(move|| {
|
||||||
assert!(rx.recv() == box 10);
|
assert!(rx.recv() == box 10);
|
||||||
});
|
}).join();
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
@ -1334,19 +1336,19 @@ mod test {
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
drop(rx);
|
drop(rx);
|
||||||
});
|
});
|
||||||
let _ = task::try(move|| {
|
let _ = Thread::with_join(move|| {
|
||||||
tx.send(1);
|
tx.send(1);
|
||||||
});
|
}).join();
|
||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
|
|
||||||
test! { fn oneshot_multi_thread_recv_close_stress() {
|
test! { fn oneshot_multi_thread_recv_close_stress() {
|
||||||
for _ in range(0, stress_factor()) {
|
for _ in range(0, stress_factor()) {
|
||||||
let (tx, rx) = channel::<int>();
|
let (tx, rx) = channel::<int>();
|
||||||
spawn(move|| {
|
spawn(proc() {
|
||||||
let res = task::try(move|| {
|
let res = Thread::with_join(move|| {
|
||||||
rx.recv();
|
rx.recv();
|
||||||
});
|
}).join();
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
});
|
});
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
|
@ -1495,7 +1497,7 @@ mod test {
|
||||||
tx2.send(());
|
tx2.send(());
|
||||||
});
|
});
|
||||||
// make sure the other task has gone to sleep
|
// make sure the other task has gone to sleep
|
||||||
for _ in range(0u, 5000) { task::deschedule(); }
|
for _ in range(0u, 5000) { Thread::yield_now(); }
|
||||||
|
|
||||||
// upgrade to a shared chan and send a message
|
// upgrade to a shared chan and send a message
|
||||||
let t = tx.clone();
|
let t = tx.clone();
|
||||||
|
@ -1504,45 +1506,7 @@ mod test {
|
||||||
|
|
||||||
// wait for the child task to exit before we exit
|
// wait for the child task to exit before we exit
|
||||||
rx2.recv();
|
rx2.recv();
|
||||||
} }
|
})
|
||||||
|
|
||||||
test! { fn sends_off_the_runtime() {
|
|
||||||
use rt::thread::Thread;
|
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
let t = Thread::start(move|| {
|
|
||||||
for _ in range(0u, 1000) {
|
|
||||||
tx.send(());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for _ in range(0u, 1000) {
|
|
||||||
rx.recv();
|
|
||||||
}
|
|
||||||
t.join();
|
|
||||||
} }
|
|
||||||
|
|
||||||
test! { fn try_recvs_off_the_runtime() {
|
|
||||||
use rt::thread::Thread;
|
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
let (cdone, pdone) = channel();
|
|
||||||
let t = Thread::start(move|| {
|
|
||||||
let mut hits = 0u;
|
|
||||||
while hits < 10 {
|
|
||||||
match rx.try_recv() {
|
|
||||||
Ok(()) => { hits += 1; }
|
|
||||||
Err(Empty) => { Thread::yield_now(); }
|
|
||||||
Err(Disconnected) => return,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cdone.send(());
|
|
||||||
});
|
|
||||||
for _ in range(0u, 10) {
|
|
||||||
tx.send(());
|
|
||||||
}
|
|
||||||
t.join();
|
|
||||||
pdone.recv();
|
|
||||||
} }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1700,11 +1664,11 @@ mod sync_tests {
|
||||||
|
|
||||||
test! { fn oneshot_single_thread_recv_chan_close() {
|
test! { fn oneshot_single_thread_recv_chan_close() {
|
||||||
// Receiving on a closed chan will panic
|
// Receiving on a closed chan will panic
|
||||||
let res = task::try(move|| {
|
let res = Thread::with_join(move|| {
|
||||||
let (tx, rx) = sync_channel::<int>(0);
|
let (tx, rx) = sync_channel::<int>(0);
|
||||||
drop(tx);
|
drop(tx);
|
||||||
rx.recv();
|
rx.recv();
|
||||||
});
|
}).join();
|
||||||
// What is our res?
|
// What is our res?
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
} }
|
} }
|
||||||
|
@ -1777,9 +1741,9 @@ mod sync_tests {
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
drop(tx);
|
drop(tx);
|
||||||
});
|
});
|
||||||
let res = task::try(move|| {
|
let res = Thread::with_join(move|| {
|
||||||
assert!(rx.recv() == box 10);
|
assert!(rx.recv() == box 10);
|
||||||
});
|
}).join();
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
@ -1799,19 +1763,19 @@ mod sync_tests {
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
drop(rx);
|
drop(rx);
|
||||||
});
|
});
|
||||||
let _ = task::try(move|| {
|
let _ = Thread::with_join(move || {
|
||||||
tx.send(1);
|
tx.send(1);
|
||||||
});
|
}).join();
|
||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
|
|
||||||
test! { fn oneshot_multi_thread_recv_close_stress() {
|
test! { fn oneshot_multi_thread_recv_close_stress() {
|
||||||
for _ in range(0, stress_factor()) {
|
for _ in range(0, stress_factor()) {
|
||||||
let (tx, rx) = sync_channel::<int>(0);
|
let (tx, rx) = sync_channel::<int>(0);
|
||||||
spawn(move|| {
|
spawn(proc() {
|
||||||
let res = task::try(move|| {
|
let res = Thread::with_join(move|| {
|
||||||
rx.recv();
|
rx.recv();
|
||||||
});
|
}).join();
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
});
|
});
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
|
@ -1960,7 +1924,7 @@ mod sync_tests {
|
||||||
tx2.send(());
|
tx2.send(());
|
||||||
});
|
});
|
||||||
// make sure the other task has gone to sleep
|
// make sure the other task has gone to sleep
|
||||||
for _ in range(0u, 5000) { task::deschedule(); }
|
for _ in range(0u, 5000) { Thread::yield_now(); }
|
||||||
|
|
||||||
// upgrade to a shared chan and send a message
|
// upgrade to a shared chan and send a message
|
||||||
let t = tx.clone();
|
let t = tx.clone();
|
||||||
|
@ -1971,29 +1935,6 @@ mod sync_tests {
|
||||||
rx2.recv();
|
rx2.recv();
|
||||||
} }
|
} }
|
||||||
|
|
||||||
test! { fn try_recvs_off_the_runtime() {
|
|
||||||
use rt::thread::Thread;
|
|
||||||
|
|
||||||
let (tx, rx) = sync_channel::<()>(0);
|
|
||||||
let (cdone, pdone) = channel();
|
|
||||||
let t = Thread::start(move|| {
|
|
||||||
let mut hits = 0u;
|
|
||||||
while hits < 10 {
|
|
||||||
match rx.try_recv() {
|
|
||||||
Ok(()) => { hits += 1; }
|
|
||||||
Err(Empty) => { Thread::yield_now(); }
|
|
||||||
Err(Disconnected) => return,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cdone.send(());
|
|
||||||
});
|
|
||||||
for _ in range(0u, 10) {
|
|
||||||
tx.send(());
|
|
||||||
}
|
|
||||||
t.join();
|
|
||||||
pdone.recv();
|
|
||||||
} }
|
|
||||||
|
|
||||||
test! { fn send_opt1() {
|
test! { fn send_opt1() {
|
||||||
let (tx, rx) = sync_channel::<int>(0);
|
let (tx, rx) = sync_channel::<int>(0);
|
||||||
spawn(move|| { rx.recv(); });
|
spawn(move|| { rx.recv(); });
|
||||||
|
@ -2052,7 +1993,7 @@ mod sync_tests {
|
||||||
test! { fn try_send4() {
|
test! { fn try_send4() {
|
||||||
let (tx, rx) = sync_channel::<int>(0);
|
let (tx, rx) = sync_channel::<int>(0);
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
for _ in range(0u, 1000) { task::deschedule(); }
|
for _ in range(0u, 1000) { Thread::yield_now(); }
|
||||||
assert_eq!(tx.try_send(1), Ok(()));
|
assert_eq!(tx.try_send(1), Ok(()));
|
||||||
});
|
});
|
||||||
assert_eq!(rx.recv(), 1);
|
assert_eq!(rx.recv(), 1);
|
||||||
|
|
|
@ -39,9 +39,8 @@ use self::MyUpgrade::*;
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
use comm::Receiver;
|
use comm::Receiver;
|
||||||
use comm::blocking::{mod, WaitToken, SignalToken};
|
use comm::blocking::{mod, SignalToken};
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use sync::atomic;
|
use sync::atomic;
|
||||||
|
|
||||||
|
@ -143,7 +142,7 @@ impl<T: Send> Packet<T> {
|
||||||
// Attempt to not block the task (it's a little expensive). If it looks
|
// Attempt to not block the task (it's a little expensive). If it looks
|
||||||
// like we're not empty, then immediately go through to `try_recv`.
|
// like we're not empty, then immediately go through to `try_recv`.
|
||||||
if self.state.load(atomic::SeqCst) == EMPTY {
|
if self.state.load(atomic::SeqCst) == EMPTY {
|
||||||
let (wait_token, signal_token) = blocking::token();
|
let (wait_token, signal_token) = blocking::tokens();
|
||||||
let ptr = unsafe { signal_token.cast_to_uint() };
|
let ptr = unsafe { signal_token.cast_to_uint() };
|
||||||
|
|
||||||
// race with senders to enter the blocking state
|
// race with senders to enter the blocking state
|
||||||
|
@ -332,7 +331,7 @@ impl<T: Send> Packet<T> {
|
||||||
|
|
||||||
// If we've got a blocked task, then use an atomic to gain ownership
|
// If we've got a blocked task, then use an atomic to gain ownership
|
||||||
// of it (may fail)
|
// of it (may fail)
|
||||||
BLOCKED => self.state.compare_and_swap(BLOCKED, EMPTY, atomic::SeqCst)
|
ptr => self.state.compare_and_swap(ptr, EMPTY, atomic::SeqCst)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Now that we've got ownership of our state, figure out what to do
|
// Now that we've got ownership of our state, figure out what to do
|
||||||
|
|
|
@ -54,7 +54,6 @@
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use core::kinds::marker;
|
use core::kinds::marker;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
@ -63,8 +62,6 @@ use core::uint;
|
||||||
use comm::Receiver;
|
use comm::Receiver;
|
||||||
use comm::blocking::{mod, SignalToken};
|
use comm::blocking::{mod, SignalToken};
|
||||||
|
|
||||||
use self::StartResult::*;
|
|
||||||
|
|
||||||
/// The "receiver set" of the select interface. This structure is used to manage
|
/// The "receiver set" of the select interface. This structure is used to manage
|
||||||
/// a set of receivers which are being selected over.
|
/// a set of receivers which are being selected over.
|
||||||
pub struct Select {
|
pub struct Select {
|
||||||
|
@ -190,8 +187,8 @@ impl Select {
|
||||||
let (wait_token, signal_token) = blocking::tokens();
|
let (wait_token, signal_token) = blocking::tokens();
|
||||||
for (i, handle) in self.iter().enumerate() {
|
for (i, handle) in self.iter().enumerate() {
|
||||||
match (*handle).packet.start_selection(signal_token.clone()) {
|
match (*handle).packet.start_selection(signal_token.clone()) {
|
||||||
Installed => {}
|
StartResult::Installed => {}
|
||||||
Abort => {
|
StartResult::Abort => {
|
||||||
// Go back and abort the already-begun selections
|
// Go back and abort the already-begun selections
|
||||||
for handle in self.iter().take(i) {
|
for handle in self.iter().take(i) {
|
||||||
(*handle).packet.abort_selection();
|
(*handle).packet.abort_selection();
|
||||||
|
@ -417,10 +414,10 @@ mod test {
|
||||||
let (tx3, rx3) = channel::<int>();
|
let (tx3, rx3) = channel::<int>();
|
||||||
|
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
for _ in range(0u, 20) { task::deschedule(); }
|
for _ in range(0u, 20) { Thread::yield_now(); }
|
||||||
tx1.send(1);
|
tx1.send(1);
|
||||||
rx3.recv();
|
rx3.recv();
|
||||||
for _ in range(0u, 20) { task::deschedule(); }
|
for _ in range(0u, 20) { Thread::yield_now(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
select! {
|
select! {
|
||||||
|
@ -440,7 +437,7 @@ mod test {
|
||||||
let (tx3, rx3) = channel::<()>();
|
let (tx3, rx3) = channel::<()>();
|
||||||
|
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
for _ in range(0u, 20) { task::deschedule(); }
|
for _ in range(0u, 20) { Thread::yield_now(); }
|
||||||
tx1.send(1);
|
tx1.send(1);
|
||||||
tx2.send(2);
|
tx2.send(2);
|
||||||
rx3.recv();
|
rx3.recv();
|
||||||
|
@ -541,7 +538,7 @@ mod test {
|
||||||
tx3.send(());
|
tx3.send(());
|
||||||
});
|
});
|
||||||
|
|
||||||
for _ in range(0u, 1000) { task::deschedule(); }
|
for _ in range(0u, 1000) { Thread::yield_now(); }
|
||||||
drop(tx1.clone());
|
drop(tx1.clone());
|
||||||
tx2.send(());
|
tx2.send(());
|
||||||
rx3.recv();
|
rx3.recv();
|
||||||
|
@ -644,7 +641,7 @@ mod test {
|
||||||
tx2.send(());
|
tx2.send(());
|
||||||
});
|
});
|
||||||
|
|
||||||
for _ in range(0u, 100) { task::deschedule() }
|
for _ in range(0u, 100) { Thread::yield_now() }
|
||||||
tx1.send(());
|
tx1.send(());
|
||||||
rx2.recv();
|
rx2.recv();
|
||||||
} }
|
} }
|
||||||
|
@ -663,7 +660,7 @@ mod test {
|
||||||
tx2.send(());
|
tx2.send(());
|
||||||
});
|
});
|
||||||
|
|
||||||
for _ in range(0u, 100) { task::deschedule() }
|
for _ in range(0u, 100) { Thread::yield_now() }
|
||||||
tx1.send(());
|
tx1.send(());
|
||||||
rx2.recv();
|
rx2.recv();
|
||||||
} }
|
} }
|
||||||
|
@ -681,7 +678,7 @@ mod test {
|
||||||
tx2.send(());
|
tx2.send(());
|
||||||
});
|
});
|
||||||
|
|
||||||
for _ in range(0u, 100) { task::deschedule() }
|
for _ in range(0u, 100) { Thread::yield_now() }
|
||||||
tx1.send(());
|
tx1.send(());
|
||||||
rx2.recv();
|
rx2.recv();
|
||||||
} }
|
} }
|
||||||
|
@ -697,7 +694,7 @@ mod test {
|
||||||
test! { fn sync2() {
|
test! { fn sync2() {
|
||||||
let (tx, rx) = sync_channel::<int>(0);
|
let (tx, rx) = sync_channel::<int>(0);
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
for _ in range(0u, 100) { task::deschedule() }
|
for _ in range(0u, 100) { Thread::yield_now() }
|
||||||
tx.send(1);
|
tx.send(1);
|
||||||
});
|
});
|
||||||
select! {
|
select! {
|
||||||
|
|
|
@ -22,7 +22,6 @@ pub use self::Failure::*;
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::int;
|
use core::int;
|
||||||
|
|
||||||
|
@ -31,6 +30,7 @@ use comm::mpsc_queue as mpsc;
|
||||||
use comm::blocking::{mod, SignalToken};
|
use comm::blocking::{mod, SignalToken};
|
||||||
use comm::select::StartResult;
|
use comm::select::StartResult;
|
||||||
use comm::select::StartResult::*;
|
use comm::select::StartResult::*;
|
||||||
|
use thread::Thread;
|
||||||
|
|
||||||
const DISCONNECTED: int = int::MIN;
|
const DISCONNECTED: int = int::MIN;
|
||||||
const FUDGE: int = 1024;
|
const FUDGE: int = 1024;
|
||||||
|
|
|
@ -24,7 +24,6 @@ use self::Message::*;
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::int;
|
use core::int;
|
||||||
use thread::Thread;
|
use thread::Thread;
|
||||||
|
@ -32,7 +31,7 @@ use thread::Thread;
|
||||||
use sync::atomic;
|
use sync::atomic;
|
||||||
use comm::spsc_queue as spsc;
|
use comm::spsc_queue as spsc;
|
||||||
use comm::Receiver;
|
use comm::Receiver;
|
||||||
use comm::blocking::{mod, WaitToken, SignalToken};
|
use comm::blocking::{mod, SignalToken};
|
||||||
|
|
||||||
const DISCONNECTED: int = int::MIN;
|
const DISCONNECTED: int = int::MIN;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -147,7 +146,7 @@ impl<T: Send> Packet<T> {
|
||||||
let ptr = self.to_wake.load(atomic::SeqCst);
|
let ptr = self.to_wake.load(atomic::SeqCst);
|
||||||
self.to_wake.store(0, atomic::SeqCst);
|
self.to_wake.store(0, atomic::SeqCst);
|
||||||
assert!(ptr != 0);
|
assert!(ptr != 0);
|
||||||
unsafe { SignaToken::cast_from_uint(ptr) }
|
unsafe { SignalToken::cast_from_uint(ptr) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrements the count on the channel for a sleeper, returning the sleeper
|
// Decrements the count on the channel for a sleeper, returning the sleeper
|
||||||
|
|
|
@ -38,10 +38,8 @@ use core::prelude::*;
|
||||||
pub use self::Failure::*;
|
pub use self::Failure::*;
|
||||||
use self::Blocker::*;
|
use self::Blocker::*;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
use vec::Vec;
|
use vec::Vec;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::cell::UnsafeCell;
|
|
||||||
|
|
||||||
use sync::{atomic, Mutex, MutexGuard};
|
use sync::{atomic, Mutex, MutexGuard};
|
||||||
use comm::blocking::{mod, WaitToken, SignalToken};
|
use comm::blocking::{mod, WaitToken, SignalToken};
|
||||||
|
@ -105,9 +103,9 @@ pub enum Failure {
|
||||||
|
|
||||||
/// Atomically blocks the current thread, placing it into `slot`, unlocking `lock`
|
/// Atomically blocks the current thread, placing it into `slot`, unlocking `lock`
|
||||||
/// in the meantime. This re-locks the mutex upon returning.
|
/// in the meantime. This re-locks the mutex upon returning.
|
||||||
fn wait<'a, 'b, T>(lock: &'a Mutex<State<T>>,
|
fn wait<'a, 'b, T: Send>(lock: &'a Mutex<State<T>>,
|
||||||
guard: MutexGuard<'b, State<T>>,
|
mut guard: MutexGuard<'b, State<T>>,
|
||||||
f: fn(BlockedTask) -> Blocker)
|
f: fn(SignalToken) -> Blocker)
|
||||||
-> MutexGuard<'a, State<T>>
|
-> MutexGuard<'a, State<T>>
|
||||||
{
|
{
|
||||||
let me: Box<Task> = Local::take();
|
let me: Box<Task> = Local::take();
|
||||||
|
@ -170,7 +168,7 @@ impl<T: Send> Packet<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(&self, t: T) -> Result<(), T> {
|
pub fn send(&self, t: T) -> Result<(), T> {
|
||||||
let guard = self.acquire_send_slot();
|
let mut guard = self.acquire_send_slot();
|
||||||
if guard.disconnected { return Err(t) }
|
if guard.disconnected { return Err(t) }
|
||||||
guard.buf.enqueue(t);
|
guard.buf.enqueue(t);
|
||||||
|
|
||||||
|
@ -183,7 +181,7 @@ impl<T: Send> Packet<T> {
|
||||||
let mut canceled = false;
|
let mut canceled = false;
|
||||||
assert!(guard.canceled.is_none());
|
assert!(guard.canceled.is_none());
|
||||||
guard.canceled = Some(unsafe { mem::transmute(&mut canceled) });
|
guard.canceled = Some(unsafe { mem::transmute(&mut canceled) });
|
||||||
let guard = wait(&self.lock, guard, BlockedSender);
|
let mut guard = wait(&self.lock, guard, BlockedSender);
|
||||||
if canceled {Err(guard.buf.dequeue())} else {Ok(())}
|
if canceled {Err(guard.buf.dequeue())} else {Ok(())}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +196,7 @@ impl<T: Send> Packet<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_send(&self, t: T) -> Result<(), super::TrySendError<T>> {
|
pub fn try_send(&self, t: T) -> Result<(), super::TrySendError<T>> {
|
||||||
let guard = self.lock.lock();
|
let mut guard = self.lock.lock();
|
||||||
if guard.disconnected {
|
if guard.disconnected {
|
||||||
Err(super::RecvDisconnected(t))
|
Err(super::RecvDisconnected(t))
|
||||||
} else if guard.buf.size() == guard.buf.cap() {
|
} else if guard.buf.size() == guard.buf.cap() {
|
||||||
|
@ -235,13 +233,13 @@ impl<T: Send> Packet<T> {
|
||||||
// When reading this, remember that there can only ever be one receiver at
|
// When reading this, remember that there can only ever be one receiver at
|
||||||
// time.
|
// time.
|
||||||
pub fn recv(&self) -> Result<T, ()> {
|
pub fn recv(&self) -> Result<T, ()> {
|
||||||
let guard = self.lock.lock();
|
let mut guard = self.lock.lock();
|
||||||
|
|
||||||
// Wait for the buffer to have something in it. No need for a while loop
|
// Wait for the buffer to have something in it. No need for a while loop
|
||||||
// because we're the only receiver.
|
// because we're the only receiver.
|
||||||
let mut waited = false;
|
let mut waited = false;
|
||||||
if !guard.disconnected && guard.buf.size() == 0 {
|
if !guard.disconnected && guard.buf.size() == 0 {
|
||||||
wait(&mut guard.blocker, BlockedReceiver, &self.lock);
|
guard = wait(&self.lock, guard, BlockedReceiver);
|
||||||
waited = true;
|
waited = true;
|
||||||
}
|
}
|
||||||
if guard.disconnected && guard.buf.size() == 0 { return Err(()) }
|
if guard.disconnected && guard.buf.size() == 0 { return Err(()) }
|
||||||
|
@ -249,12 +247,12 @@ impl<T: Send> Packet<T> {
|
||||||
// Pick up the data, wake up our neighbors, and carry on
|
// Pick up the data, wake up our neighbors, and carry on
|
||||||
assert!(guard.buf.size() > 0);
|
assert!(guard.buf.size() > 0);
|
||||||
let ret = guard.buf.dequeue();
|
let ret = guard.buf.dequeue();
|
||||||
self.wakeup_senders(waited, guard, state);
|
self.wakeup_senders(waited, guard);
|
||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_recv(&self) -> Result<T, Failure> {
|
pub fn try_recv(&self) -> Result<T, Failure> {
|
||||||
let guard = self.lock();
|
let mut guard = self.lock.lock();
|
||||||
|
|
||||||
// Easy cases first
|
// Easy cases first
|
||||||
if guard.disconnected { return Err(Disconnected) }
|
if guard.disconnected { return Err(Disconnected) }
|
||||||
|
@ -262,7 +260,7 @@ impl<T: Send> Packet<T> {
|
||||||
|
|
||||||
// Be sure to wake up neighbors
|
// Be sure to wake up neighbors
|
||||||
let ret = Ok(guard.buf.dequeue());
|
let ret = Ok(guard.buf.dequeue());
|
||||||
self.wakeup_senders(false, guard, state);
|
self.wakeup_senders(false, guard);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +270,7 @@ impl<T: Send> Packet<T> {
|
||||||
// * `waited` - flag if the receiver blocked to receive some data, or if it
|
// * `waited` - flag if the receiver blocked to receive some data, or if it
|
||||||
// just picked up some data on the way out
|
// just picked up some data on the way out
|
||||||
// * `guard` - the lock guard that is held over this channel's lock
|
// * `guard` - the lock guard that is held over this channel's lock
|
||||||
fn wakeup_senders(&self, waited: bool, guard: MutexGuard<State<T>>) {
|
fn wakeup_senders(&self, waited: bool, mut guard: MutexGuard<State<T>>) {
|
||||||
let pending_sender1: Option<SignalToken> = guard.queue.dequeue();
|
let pending_sender1: Option<SignalToken> = guard.queue.dequeue();
|
||||||
|
|
||||||
// If this is a no-buffer channel (cap == 0), then if we didn't wait we
|
// If this is a no-buffer channel (cap == 0), then if we didn't wait we
|
||||||
|
@ -311,7 +309,7 @@ impl<T: Send> Packet<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not much to do other than wake up a receiver if one's there
|
// Not much to do other than wake up a receiver if one's there
|
||||||
let guard = self.lock();
|
let mut guard = self.lock.lock();
|
||||||
if guard.disconnected { return }
|
if guard.disconnected { return }
|
||||||
guard.disconnected = true;
|
guard.disconnected = true;
|
||||||
match mem::replace(&mut guard.blocker, NoneBlocked) {
|
match mem::replace(&mut guard.blocker, NoneBlocked) {
|
||||||
|
@ -322,7 +320,7 @@ impl<T: Send> Packet<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drop_port(&self) {
|
pub fn drop_port(&self) {
|
||||||
let guard = self.lock();
|
let mut guard = self.lock.lock();
|
||||||
|
|
||||||
if guard.disconnected { return }
|
if guard.disconnected { return }
|
||||||
guard.disconnected = true;
|
guard.disconnected = true;
|
||||||
|
@ -368,14 +366,14 @@ impl<T: Send> Packet<T> {
|
||||||
// If Ok, the value is whether this port has data, if Err, then the upgraded
|
// If Ok, the value is whether this port has data, if Err, then the upgraded
|
||||||
// port needs to be checked instead of this one.
|
// port needs to be checked instead of this one.
|
||||||
pub fn can_recv(&self) -> bool {
|
pub fn can_recv(&self) -> bool {
|
||||||
let guard = self.lock();
|
let guard = self.lock.lock();
|
||||||
guard.disconnected || guard.buf.size() > 0
|
guard.disconnected || guard.buf.size() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to start selection on this port. This can either succeed or fail
|
// Attempts to start selection on this port. This can either succeed or fail
|
||||||
// because there is data waiting.
|
// because there is data waiting.
|
||||||
pub fn start_selection(&self, token: SignalToken) -> StartResult {
|
pub fn start_selection(&self, token: SignalToken) -> StartResult {
|
||||||
let guard = self.lock();
|
let mut guard = self.lock.lock();
|
||||||
if guard.disconnected || guard.buf.size() > 0 {
|
if guard.disconnected || guard.buf.size() > 0 {
|
||||||
Abort
|
Abort
|
||||||
} else {
|
} else {
|
||||||
|
@ -393,7 +391,7 @@ impl<T: Send> Packet<T> {
|
||||||
//
|
//
|
||||||
// The return value indicates whether there's data on this port.
|
// The return value indicates whether there's data on this port.
|
||||||
pub fn abort_selection(&self) -> bool {
|
pub fn abort_selection(&self) -> bool {
|
||||||
let guard = self.lock();
|
let mut guard = self.lock.lock();
|
||||||
match mem::replace(&mut guard.blocker, NoneBlocked) {
|
match mem::replace(&mut guard.blocker, NoneBlocked) {
|
||||||
NoneBlocked => true,
|
NoneBlocked => true,
|
||||||
BlockedSender(token) => {
|
BlockedSender(token) => {
|
||||||
|
@ -409,7 +407,7 @@ impl<T: Send> Packet<T> {
|
||||||
impl<T: Send> Drop for Packet<T> {
|
impl<T: Send> Drop for Packet<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
assert_eq!(self.channels.load(atomic::SeqCst), 0);
|
assert_eq!(self.channels.load(atomic::SeqCst), 0);
|
||||||
let guard = self.lock();
|
let mut guard = self.lock.lock();
|
||||||
assert!(guard.queue.dequeue().is_none());
|
assert!(guard.queue.dequeue().is_none());
|
||||||
assert!(guard.canceled.is_none());
|
assert!(guard.canceled.is_none());
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,10 @@ use option::Option::{Some, None};
|
||||||
use result::Result::Ok;
|
use result::Result::Ok;
|
||||||
use rt::backtrace;
|
use rt::backtrace;
|
||||||
use rt::util::{Stderr, Stdio};
|
use rt::util::{Stderr, Stdio};
|
||||||
use rt::local::Local;
|
|
||||||
use rt::task::Task;
|
|
||||||
use str::Str;
|
use str::Str;
|
||||||
use string::String;
|
use string::String;
|
||||||
|
use thread::Thread;
|
||||||
|
use sys_common::thread_info;
|
||||||
|
|
||||||
// Defined in this module instead of io::stdio so that the unwinding
|
// Defined in this module instead of io::stdio so that the unwinding
|
||||||
thread_local! {
|
thread_local! {
|
||||||
|
@ -52,41 +52,15 @@ pub fn on_fail(obj: &(Any+Send), file: &'static str, line: uint) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut err = Stderr;
|
let mut err = Stderr;
|
||||||
|
let thread = Thread::current();
|
||||||
// It is assumed that all reasonable rust code will have a local task at
|
let name = thread.name().unwrap_or("<unnamed>");
|
||||||
// all times. This means that this `exists` will return true almost all of
|
|
||||||
// the time. There are border cases, however, when the runtime has
|
|
||||||
// *almost* set up the local task, but hasn't quite gotten there yet. In
|
|
||||||
// order to get some better diagnostics, we print on panic and
|
|
||||||
// immediately abort the whole process if there is no local task
|
|
||||||
// available.
|
|
||||||
if !Local::exists(None::<Task>) {
|
|
||||||
let _ = writeln!(&mut err, "panicked at '{}', {}:{}", msg, file, line);
|
|
||||||
if backtrace::log_enabled() {
|
|
||||||
let _ = backtrace::write(&mut err);
|
|
||||||
} else {
|
|
||||||
let _ = writeln!(&mut err, "run with `RUST_BACKTRACE=1` to \
|
|
||||||
see a backtrace");
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Peel the name out of local task so we can print it. We've got to be sure
|
|
||||||
// that the local task is in TLS while we're printing as I/O may occur.
|
|
||||||
let (name, unwinding) = {
|
|
||||||
let mut t = Local::borrow(None::<Task>);
|
|
||||||
(t.name.take(), t.unwinder.unwinding())
|
|
||||||
};
|
|
||||||
{
|
|
||||||
let n = name.as_ref().map(|n| n.as_slice()).unwrap_or("<unnamed>");
|
|
||||||
|
|
||||||
let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
|
let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
|
||||||
match prev {
|
match prev {
|
||||||
Some(mut stderr) => {
|
Some(mut stderr) => {
|
||||||
// FIXME: what to do when the task printing panics?
|
// FIXME: what to do when the thread printing panics?
|
||||||
let _ = writeln!(stderr,
|
let _ = writeln!(stderr,
|
||||||
"task '{}' panicked at '{}', {}:{}\n",
|
"thread '{}' panicked at '{}', {}:{}\n",
|
||||||
n, msg, file, line);
|
name, msg, file, line);
|
||||||
if backtrace::log_enabled() {
|
if backtrace::log_enabled() {
|
||||||
let _ = backtrace::write(&mut *stderr);
|
let _ = backtrace::write(&mut *stderr);
|
||||||
}
|
}
|
||||||
|
@ -96,8 +70,8 @@ pub fn on_fail(obj: &(Any+Send), file: &'static str, line: uint) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let _ = writeln!(&mut err, "task '{}' panicked at '{}', {}:{}",
|
let _ = writeln!(&mut err, "thread '{}' panicked at '{}', {}:{}",
|
||||||
n, msg, file, line);
|
name, msg, file, line);
|
||||||
if backtrace::log_enabled() {
|
if backtrace::log_enabled() {
|
||||||
let _ = backtrace::write(&mut err);
|
let _ = backtrace::write(&mut err);
|
||||||
}
|
}
|
||||||
|
@ -106,9 +80,7 @@ pub fn on_fail(obj: &(Any+Send), file: &'static str, line: uint) {
|
||||||
|
|
||||||
// If this is a double panic, make sure that we printed a backtrace
|
// If this is a double panic, make sure that we printed a backtrace
|
||||||
// for this panic.
|
// for this panic.
|
||||||
if unwinding && !backtrace::log_enabled() {
|
if thread_info::panicking() && !backtrace::log_enabled() {
|
||||||
let _ = backtrace::write(&mut err);
|
let _ = backtrace::write(&mut err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Local::borrow(None::<Task>).name = name;
|
|
||||||
}
|
|
||||||
|
|
|
@ -156,12 +156,12 @@ mod test {
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use io;
|
use io;
|
||||||
use task;
|
use thread::Thread;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rx_reader() {
|
fn test_rx_reader() {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
task::spawn(move|| {
|
Thread::spawn(move|| {
|
||||||
tx.send(vec![1u8, 2u8]);
|
tx.send(vec![1u8, 2u8]);
|
||||||
tx.send(vec![]);
|
tx.send(vec![]);
|
||||||
tx.send(vec![3u8, 4u8]);
|
tx.send(vec![3u8, 4u8]);
|
||||||
|
@ -203,7 +203,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rx_buffer() {
|
fn test_rx_buffer() {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
task::spawn(move|| {
|
Thread::spawn(move|| {
|
||||||
tx.send(b"he".to_vec());
|
tx.send(b"he".to_vec());
|
||||||
tx.send(b"llo wo".to_vec());
|
tx.send(b"llo wo".to_vec());
|
||||||
tx.send(b"".to_vec());
|
tx.send(b"".to_vec());
|
||||||
|
@ -229,7 +229,11 @@ mod test {
|
||||||
writer.write_be_u32(42).unwrap();
|
writer.write_be_u32(42).unwrap();
|
||||||
|
|
||||||
let wanted = vec![0u8, 0u8, 0u8, 42u8];
|
let wanted = vec![0u8, 0u8, 0u8, 42u8];
|
||||||
|
<<<<<<< HEAD
|
||||||
let got = match task::try(move|| { rx.recv() }) {
|
let got = match task::try(move|| { rx.recv() }) {
|
||||||
|
=======
|
||||||
|
let got = match Thread::with_join(proc() { rx.recv() }).join() {
|
||||||
|
>>>>>>> Fallout from new thread API
|
||||||
Ok(got) => got,
|
Ok(got) => got,
|
||||||
Err(_) => panic!(),
|
Err(_) => panic!(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -549,7 +549,7 @@ mod tests {
|
||||||
Err(ref e) if e.kind == TimedOut => {}
|
Err(ref e) if e.kind == TimedOut => {}
|
||||||
Err(e) => panic!("error: {}", e),
|
Err(e) => panic!("error: {}", e),
|
||||||
}
|
}
|
||||||
::task::deschedule();
|
::thread::Thread::yield_now();
|
||||||
if i == 1000 { panic!("should have a pending connection") }
|
if i == 1000 { panic!("should have a pending connection") }
|
||||||
}
|
}
|
||||||
drop(l);
|
drop(l);
|
||||||
|
|
|
@ -1155,7 +1155,7 @@ mod test {
|
||||||
Err(ref e) if e.kind == TimedOut => {}
|
Err(ref e) if e.kind == TimedOut => {}
|
||||||
Err(e) => panic!("error: {}", e),
|
Err(e) => panic!("error: {}", e),
|
||||||
}
|
}
|
||||||
::task::deschedule();
|
::thread::Thread::yield_now();
|
||||||
if i == 1000 { panic!("should have a pending connection") }
|
if i == 1000 { panic!("should have a pending connection") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1378,7 +1378,7 @@ mod test {
|
||||||
|
|
||||||
// Try to ensure that the reading clone is indeed reading
|
// Try to ensure that the reading clone is indeed reading
|
||||||
for _ in range(0i, 50) {
|
for _ in range(0i, 50) {
|
||||||
::task::deschedule();
|
::thread::Thread::yield_now();
|
||||||
}
|
}
|
||||||
|
|
||||||
// clone the handle again while it's reading, then let it finish the
|
// clone the handle again while it's reading, then let it finish the
|
||||||
|
|
|
@ -30,6 +30,7 @@ use hash::Hash;
|
||||||
use std::hash::sip::SipState;
|
use std::hash::sip::SipState;
|
||||||
use io::pipe::{PipeStream, PipePair};
|
use io::pipe::{PipeStream, PipePair};
|
||||||
use path::BytesContainer;
|
use path::BytesContainer;
|
||||||
|
use thread::Thread;
|
||||||
|
|
||||||
use sys;
|
use sys;
|
||||||
use sys::fs::FileDesc;
|
use sys::fs::FileDesc;
|
||||||
|
@ -693,10 +694,12 @@ impl Process {
|
||||||
fn read(stream: Option<io::PipeStream>) -> Receiver<IoResult<Vec<u8>>> {
|
fn read(stream: Option<io::PipeStream>) -> Receiver<IoResult<Vec<u8>>> {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
match stream {
|
match stream {
|
||||||
Some(stream) => spawn(move |:| {
|
Some(stream) => {
|
||||||
|
Thread::spawn(move |:| {
|
||||||
let mut stream = stream;
|
let mut stream = stream;
|
||||||
tx.send(stream.read_to_end())
|
tx.send(stream.read_to_end())
|
||||||
}),
|
});
|
||||||
|
}
|
||||||
None => tx.send(Ok(Vec::new()))
|
None => tx.send(Ok(Vec::new()))
|
||||||
}
|
}
|
||||||
rx
|
rx
|
||||||
|
|
|
@ -41,9 +41,6 @@ use option::Option;
|
||||||
use option::Option::{Some, None};
|
use option::Option::{Some, None};
|
||||||
use ops::{Deref, DerefMut, FnOnce};
|
use ops::{Deref, DerefMut, FnOnce};
|
||||||
use result::Result::{Ok, Err};
|
use result::Result::{Ok, Err};
|
||||||
use rt;
|
|
||||||
use rt::local::Local;
|
|
||||||
use rt::task::Task;
|
|
||||||
use slice::SliceExt;
|
use slice::SliceExt;
|
||||||
use str::StrPrelude;
|
use str::StrPrelude;
|
||||||
use string::String;
|
use string::String;
|
||||||
|
@ -328,10 +325,7 @@ pub fn set_stderr(stderr: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
|
||||||
// // io1 aliases io2
|
// // io1 aliases io2
|
||||||
// })
|
// })
|
||||||
// })
|
// })
|
||||||
fn with_task_stdout<F>(f: F) where
|
fn with_task_stdout(f: |&mut Writer| -> IoResult<()>) {
|
||||||
F: FnOnce(&mut Writer) -> IoResult<()>,
|
|
||||||
{
|
|
||||||
let result = if Local::exists(None::<Task>) {
|
|
||||||
let mut my_stdout = LOCAL_STDOUT.with(|slot| {
|
let mut my_stdout = LOCAL_STDOUT.with(|slot| {
|
||||||
slot.borrow_mut().take()
|
slot.borrow_mut().take()
|
||||||
}).unwrap_or_else(|| {
|
}).unwrap_or_else(|| {
|
||||||
|
@ -342,11 +336,6 @@ fn with_task_stdout<F>(f: F) where
|
||||||
LOCAL_STDOUT.with(|slot| {
|
LOCAL_STDOUT.with(|slot| {
|
||||||
*slot.borrow_mut() = var.take();
|
*slot.borrow_mut() = var.take();
|
||||||
});
|
});
|
||||||
result
|
|
||||||
} else {
|
|
||||||
let mut io = rt::util::Stdout;
|
|
||||||
f(&mut io as &mut Writer)
|
|
||||||
};
|
|
||||||
match result {
|
match result {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(e) => panic!("failed printing to stdout: {}", e),
|
Err(e) => panic!("failed printing to stdout: {}", e),
|
||||||
|
|
|
@ -229,6 +229,8 @@ pub mod hash;
|
||||||
|
|
||||||
/* Threads and communication */
|
/* Threads and communication */
|
||||||
|
|
||||||
|
pub mod task;
|
||||||
|
#[allow(missing_docs)]
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod comm;
|
pub mod comm;
|
||||||
|
|
|
@ -49,7 +49,7 @@ use ptr::RawPtr;
|
||||||
use ptr;
|
use ptr;
|
||||||
use result::Result;
|
use result::Result;
|
||||||
use result::Result::{Err, Ok};
|
use result::Result::{Err, Ok};
|
||||||
use slice::{AsSlice, SliceExt, PartialEqSliceExt};
|
use slice::{AsSlice, SliceExt};
|
||||||
use slice::CloneSliceExt;
|
use slice::CloneSliceExt;
|
||||||
use str::{Str, StrPrelude, StrAllocating};
|
use str::{Str, StrPrelude, StrAllocating};
|
||||||
use string::{String, ToString};
|
use string::{String, ToString};
|
||||||
|
|
|
@ -514,20 +514,20 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_null_byte() {
|
fn test_null_byte() {
|
||||||
use task;
|
use thread::Thread;
|
||||||
let result = task::try(move|| {
|
let result = Thread::with_join(move|| {
|
||||||
Path::new(b"foo/bar\0")
|
Path::new(b"foo/bar\0")
|
||||||
});
|
}).join();
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
||||||
let result = task::try(move|| {
|
let result = Thread::with_join(move|| {
|
||||||
Path::new("test").set_filename(b"f\0o")
|
Path::new("test").set_filename(b"f\0o")
|
||||||
});
|
}).join();
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
||||||
let result = task::try(move|| {
|
let result = Thread::with_join(move|| {
|
||||||
Path::new("test").push(b"f\0o");
|
Path::new("test").push(b"f\0o");
|
||||||
});
|
}).join();
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1298,20 +1298,20 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_null_byte() {
|
fn test_null_byte() {
|
||||||
use task;
|
use thread::Thread;
|
||||||
let result = task::try(move|| {
|
let result = Thread::with_join(move|| {
|
||||||
Path::new(b"foo/bar\0")
|
Path::new(b"foo/bar\0")
|
||||||
});
|
}).join();
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
||||||
let result = task::try(move|| {
|
let result = Thread::with_join(move|| {
|
||||||
Path::new("test").set_filename(b"f\0o")
|
Path::new("test").set_filename(b"f\0o")
|
||||||
});
|
}).join();
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
||||||
let result = task::try(move|| {
|
let result = Thread::with_join(move|| {
|
||||||
Path::new("test").push(b"f\0o");
|
Path::new("test").push(b"f\0o");
|
||||||
});
|
}).join();
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -340,7 +340,7 @@ mod test {
|
||||||
|
|
||||||
use super::OsRng;
|
use super::OsRng;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use task;
|
use thread::Thread;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_os_rng() {
|
fn test_os_rng() {
|
||||||
|
@ -360,25 +360,26 @@ mod test {
|
||||||
for _ in range(0u, 20) {
|
for _ in range(0u, 20) {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
txs.push(tx);
|
txs.push(tx);
|
||||||
task::spawn(move|| {
|
|
||||||
|
Thread::spawn(move|| {
|
||||||
// wait until all the tasks are ready to go.
|
// wait until all the tasks are ready to go.
|
||||||
rx.recv();
|
rx.recv();
|
||||||
|
|
||||||
// deschedule to attempt to interleave things as much
|
// deschedule to attempt to interleave things as much
|
||||||
// as possible (XXX: is this a good test?)
|
// as possible (XXX: is this a good test?)
|
||||||
let mut r = OsRng::new().unwrap();
|
let mut r = OsRng::new().unwrap();
|
||||||
task::deschedule();
|
Thread::yield_now();
|
||||||
let mut v = [0u8, .. 1000];
|
let mut v = [0u8, .. 1000];
|
||||||
|
|
||||||
for _ in range(0u, 100) {
|
for _ in range(0u, 100) {
|
||||||
r.next_u32();
|
r.next_u32();
|
||||||
task::deschedule();
|
Thread::yield_now();
|
||||||
r.next_u64();
|
r.next_u64();
|
||||||
task::deschedule();
|
Thread::yield_now();
|
||||||
r.fill_bytes(&mut v);
|
r.fill_bytes(&mut v);
|
||||||
task::deschedule();
|
Thread::yield_now();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// start all the tasks
|
// start all the tasks
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use libc;
|
|
||||||
use boxed::Box;
|
use boxed::Box;
|
||||||
use vec::Vec;
|
use vec::Vec;
|
||||||
use sync::{Mutex, atomic, Once, ONCE_INIT};
|
use sync::{Mutex, atomic, Once, ONCE_INIT};
|
||||||
|
@ -25,31 +24,30 @@ type Queue = Mutex<Vec<Thunk>>;
|
||||||
|
|
||||||
static INIT: Once = ONCE_INIT;
|
static INIT: Once = ONCE_INIT;
|
||||||
static QUEUE: atomic::AtomicUint = atomic::INIT_ATOMIC_UINT;
|
static QUEUE: atomic::AtomicUint = atomic::INIT_ATOMIC_UINT;
|
||||||
static RUNNING: atomic::AtomicBool = atomic::INIT_ATOMIC_BOOL;
|
|
||||||
|
|
||||||
fn init() {
|
fn init() {
|
||||||
let state: Box<Queue> = box Mutex::new(Vec::new());
|
let state: Box<Queue> = box Mutex::new(Vec::new());
|
||||||
unsafe {
|
unsafe {
|
||||||
QUEUE.store(mem::transmute(state), atomic::SeqCst);
|
QUEUE.store(mem::transmute(state), atomic::SeqCst);
|
||||||
libc::atexit(run);
|
|
||||||
|
// FIXME: switch this to use atexit as below. Currently this
|
||||||
|
// segfaults (the queue's memory is mysteriously gone), so
|
||||||
|
// instead the cleanup is tied to the `std::rt` entry point.
|
||||||
|
//
|
||||||
|
// ::libc::atexit(cleanup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this is private and so can only be called via atexit above,
|
pub fn cleanup() {
|
||||||
// which guarantees initialization.
|
unsafe {
|
||||||
extern fn run() {
|
|
||||||
let cur = unsafe {
|
|
||||||
rtassert!(!RUNNING.load(atomic::SeqCst));
|
|
||||||
let queue = QUEUE.swap(0, atomic::SeqCst);
|
let queue = QUEUE.swap(0, atomic::SeqCst);
|
||||||
rtassert!(queue != 0);
|
if queue != 0 {
|
||||||
|
|
||||||
let queue: Box<Queue> = mem::transmute(queue);
|
let queue: Box<Queue> = mem::transmute(queue);
|
||||||
let v = mem::replace(&mut *queue.lock(), Vec::new());
|
let v = mem::replace(&mut *queue.lock(), Vec::new());
|
||||||
v
|
for to_run in v.into_iter() {
|
||||||
};
|
to_run.invoke();
|
||||||
|
}
|
||||||
for to_run in cur.into_iter() {
|
}
|
||||||
to_run.invoke(());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +58,6 @@ pub fn push(f: Thunk) {
|
||||||
// all with respect to `run`, meaning that this could theoretically be a
|
// all with respect to `run`, meaning that this could theoretically be a
|
||||||
// use-after-free. There's not much we can do to protect against that,
|
// use-after-free. There's not much we can do to protect against that,
|
||||||
// however. Let's just assume a well-behaved runtime and go from there!
|
// however. Let's just assume a well-behaved runtime and go from there!
|
||||||
rtassert!(!RUNNING.load(atomic::SeqCst));
|
|
||||||
let queue = QUEUE.load(atomic::SeqCst);
|
let queue = QUEUE.load(atomic::SeqCst);
|
||||||
rtassert!(queue != 0);
|
rtassert!(queue != 0);
|
||||||
(*(queue as *const Queue)).lock().push(f);
|
(*(queue as *const Queue)).lock().push(f);
|
||||||
|
|
|
@ -12,12 +12,8 @@
|
||||||
|
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
use io::{IoResult, Writer};
|
|
||||||
use iter::{Iterator, IteratorExt};
|
|
||||||
use option::Option::{Some, None};
|
use option::Option::{Some, None};
|
||||||
use os;
|
use os;
|
||||||
use result::Result::{Ok, Err};
|
|
||||||
use str::{StrPrelude, from_str};
|
|
||||||
use sync::atomic;
|
use sync::atomic;
|
||||||
|
|
||||||
pub use sys::backtrace::write;
|
pub use sys::backtrace::write;
|
||||||
|
|
|
@ -48,14 +48,14 @@
|
||||||
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use borrow::IntoCow;
|
|
||||||
use failure;
|
use failure;
|
||||||
use os;
|
use os;
|
||||||
use thunk::Thunk;
|
use thunk::Thunk;
|
||||||
use kinds::Send;
|
use kinds::Send;
|
||||||
use thread::Thread;
|
use thread::Thread;
|
||||||
|
use sys;
|
||||||
use sys_common;
|
use sys_common;
|
||||||
use sys_common::thread::{mod, NewThread};
|
use sys_common::thread_info::{mod, NewThread};
|
||||||
|
|
||||||
// Reexport some of our utilities which are expected by other crates.
|
// Reexport some of our utilities which are expected by other crates.
|
||||||
pub use self::util::{default_sched_threads, min_stack, running_on_valgrind};
|
pub use self::util::{default_sched_threads, min_stack, running_on_valgrind};
|
||||||
|
@ -87,10 +87,9 @@ pub const DEFAULT_ERROR_CODE: int = 101;
|
||||||
/// Initializes global state, including frobbing
|
/// Initializes global state, including frobbing
|
||||||
/// the crate's logging flags, registering GC
|
/// the crate's logging flags, registering GC
|
||||||
/// metadata, and storing the process arguments.
|
/// metadata, and storing the process arguments.
|
||||||
|
// FIXME: this should be unsafe
|
||||||
#[allow(experimental)]
|
#[allow(experimental)]
|
||||||
pub fn init(argc: int, argv: *const *const u8) {
|
pub fn init(argc: int, argv: *const *const u8) {
|
||||||
// FIXME: Derefing these pointers is not safe.
|
|
||||||
// Need to propagate the unsafety to `start`.
|
|
||||||
unsafe {
|
unsafe {
|
||||||
args::init(argc, argv);
|
args::init(argc, argv);
|
||||||
thread::init();
|
thread::init();
|
||||||
|
@ -122,8 +121,6 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
|
||||||
pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int {
|
pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int {
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
use rt;
|
use rt;
|
||||||
use rt::task::Task;
|
|
||||||
use str;
|
|
||||||
|
|
||||||
let something_around_the_top_of_the_stack = 1;
|
let something_around_the_top_of_the_stack = 1;
|
||||||
let addr = &something_around_the_top_of_the_stack as *const int;
|
let addr = &something_around_the_top_of_the_stack as *const int;
|
||||||
|
@ -153,18 +150,19 @@ pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int {
|
||||||
init(argc, argv);
|
init(argc, argv);
|
||||||
let mut exit_code = None;
|
let mut exit_code = None;
|
||||||
|
|
||||||
let thread: std::Thread = NewThread::new(Some("<main>".into_string()));
|
let thread: Thread = NewThread::new(Some("<main>".into_string()));
|
||||||
thread_info::set((my_stack_bottom, my_stack_top),
|
thread_info::set((my_stack_bottom, my_stack_top),
|
||||||
unsafe { sys::thread::guard::main() },
|
unsafe { sys::thread::guard::main() },
|
||||||
thread);
|
thread);
|
||||||
unwind::try(|| {
|
let mut main_opt = Some(main); // option dance
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let _ = unwind::try(|| {
|
||||||
sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top);
|
sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top);
|
||||||
}
|
(main_opt.take().unwrap()).invoke();
|
||||||
(main.take().unwrap()).invoke(());
|
|
||||||
exit_code = Some(os::get_exit_status());
|
exit_code = Some(os::get_exit_status());
|
||||||
});
|
});
|
||||||
unsafe { cleanup(); }
|
cleanup();
|
||||||
|
}
|
||||||
// If the exit code wasn't set, then the task block must have panicked.
|
// If the exit code wasn't set, then the task block must have panicked.
|
||||||
return exit_code.unwrap_or(rt::DEFAULT_ERROR_CODE);
|
return exit_code.unwrap_or(rt::DEFAULT_ERROR_CODE);
|
||||||
}
|
}
|
||||||
|
@ -197,14 +195,6 @@ pub fn at_exit(f: proc():Send) {
|
||||||
/// undefined behavior.
|
/// undefined behavior.
|
||||||
pub unsafe fn cleanup() {
|
pub unsafe fn cleanup() {
|
||||||
args::cleanup();
|
args::cleanup();
|
||||||
thread::cleanup();
|
sys::stack_overflow::cleanup();
|
||||||
}
|
at_exit_imp::cleanup();
|
||||||
|
|
||||||
// FIXME: these probably shouldn't be public...
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub mod shouldnt_be_public {
|
|
||||||
#[cfg(not(test))]
|
|
||||||
pub use super::local_ptr::native::maybe_tls_key;
|
|
||||||
#[cfg(all(not(windows), not(target_os = "android"), not(target_os = "ios")))]
|
|
||||||
pub use super::local_ptr::compiled::RT_TLS_PTR;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -565,7 +565,7 @@ fn begin_unwind_inner(msg: Box<Any + Send>, file_line: &(&'static str, uint)) ->
|
||||||
|
|
||||||
// Now that we've run all the necessary unwind callbacks, we actually
|
// Now that we've run all the necessary unwind callbacks, we actually
|
||||||
// perform the unwinding.
|
// perform the unwinding.
|
||||||
if thread_info::unwinding() {
|
if thread_info::panicking() {
|
||||||
// If a thread panics while it's already unwinding then we
|
// If a thread panics while it's already unwinding then we
|
||||||
// have limited options. Currently our preference is to
|
// have limited options. Currently our preference is to
|
||||||
// just abort. In the future we may consider resuming
|
// just abort. In the future we may consider resuming
|
||||||
|
|
|
@ -196,8 +196,7 @@ memory and partly incapable of presentation to others.",
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn report_overflow() {
|
pub unsafe fn report_overflow() {
|
||||||
use rt::task::Task;
|
use thread::Thread;
|
||||||
use rt::local::Local;
|
|
||||||
|
|
||||||
// See the message below for why this is not emitted to the
|
// See the message below for why this is not emitted to the
|
||||||
// ^ Where did the message below go?
|
// ^ Where did the message below go?
|
||||||
|
@ -206,11 +205,6 @@ pub unsafe fn report_overflow() {
|
||||||
// call would happen to initialized it (calling out to libuv),
|
// call would happen to initialized it (calling out to libuv),
|
||||||
// and the FFI call needs 2MB of stack when we just ran out.
|
// and the FFI call needs 2MB of stack when we just ran out.
|
||||||
|
|
||||||
let task: Option<*mut Task> = Local::try_unsafe_borrow();
|
rterrln!("\nthread '{}' has overflowed its stack",
|
||||||
|
Thread::current().name().unwrap_or("<unknown>"));
|
||||||
let name = task.and_then(|task| {
|
|
||||||
(*task).name.as_ref().map(|n| n.as_slice())
|
|
||||||
});
|
|
||||||
|
|
||||||
rterrln!("\ntask '{}' has overflowed its stack", name.unwrap_or("<unknown>"));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ use core::mem::replace;
|
||||||
|
|
||||||
use self::FutureState::*;
|
use self::FutureState::*;
|
||||||
use comm::{Receiver, channel};
|
use comm::{Receiver, channel};
|
||||||
use task::spawn;
|
|
||||||
use thunk::{Thunk};
|
use thunk::{Thunk};
|
||||||
|
use thread::Thread;
|
||||||
|
|
||||||
/// A type encapsulating the result of a computation which may not be complete
|
/// A type encapsulating the result of a computation which may not be complete
|
||||||
pub struct Future<A> {
|
pub struct Future<A> {
|
||||||
|
@ -139,7 +139,7 @@ impl<A:Send> Future<A> {
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
|
|
||||||
spawn(move |:| {
|
Thread::spawn(move |:| {
|
||||||
// Don't panic if the other end has hung up
|
// Don't panic if the other end has hung up
|
||||||
let _ = tx.send_opt(blk());
|
let _ = tx.send_opt(blk());
|
||||||
});
|
});
|
||||||
|
|
|
@ -274,7 +274,7 @@ impl Drop for StaticMutexGuard {
|
||||||
mod test {
|
mod test {
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
use task;
|
use thread::Thread;
|
||||||
use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar};
|
use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -386,10 +386,10 @@ mod test {
|
||||||
fn test_mutex_arc_poison() {
|
fn test_mutex_arc_poison() {
|
||||||
let arc = Arc::new(Mutex::new(1i));
|
let arc = Arc::new(Mutex::new(1i));
|
||||||
let arc2 = arc.clone();
|
let arc2 = arc.clone();
|
||||||
let _ = task::try(move|| {
|
let _ = Thread::with_join(move|| {
|
||||||
let lock = arc2.lock();
|
let lock = arc2.lock();
|
||||||
assert_eq!(*lock, 2);
|
assert_eq!(*lock, 2);
|
||||||
});
|
}).join();
|
||||||
let lock = arc.lock();
|
let lock = arc.lock();
|
||||||
assert_eq!(*lock, 1);
|
assert_eq!(*lock, 1);
|
||||||
}
|
}
|
||||||
|
@ -414,7 +414,7 @@ mod test {
|
||||||
fn test_mutex_arc_access_in_unwind() {
|
fn test_mutex_arc_access_in_unwind() {
|
||||||
let arc = Arc::new(Mutex::new(1i));
|
let arc = Arc::new(Mutex::new(1i));
|
||||||
let arc2 = arc.clone();
|
let arc2 = arc.clone();
|
||||||
let _ = task::try(move|| -> () {
|
let _ = Thread::with_join::<()>(move|| -> () {
|
||||||
struct Unwinder {
|
struct Unwinder {
|
||||||
i: Arc<Mutex<int>>,
|
i: Arc<Mutex<int>>,
|
||||||
}
|
}
|
||||||
|
@ -425,7 +425,7 @@ mod test {
|
||||||
}
|
}
|
||||||
let _u = Unwinder { i: arc2 };
|
let _u = Unwinder { i: arc2 };
|
||||||
panic!();
|
panic!();
|
||||||
});
|
}).join();
|
||||||
let lock = arc.lock();
|
let lock = arc.lock();
|
||||||
assert_eq!(*lock, 2);
|
assert_eq!(*lock, 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ impl Once {
|
||||||
mod test {
|
mod test {
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
use task;
|
use thread::Thread;
|
||||||
use super::{ONCE_INIT, Once};
|
use super::{ONCE_INIT, Once};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -143,7 +143,7 @@ mod test {
|
||||||
for _ in range(0u, 10) {
|
for _ in range(0u, 10) {
|
||||||
let tx = tx.clone();
|
let tx = tx.clone();
|
||||||
spawn(move|| {
|
spawn(move|| {
|
||||||
for _ in range(0u, 4) { task::deschedule() }
|
for _ in range(0u, 4) { Thread::yield_now() }
|
||||||
unsafe {
|
unsafe {
|
||||||
O.doit(|| {
|
O.doit(|| {
|
||||||
assert!(!run);
|
assert!(!run);
|
||||||
|
|
|
@ -8,21 +8,19 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use option::Option::None;
|
use thread::Thread;
|
||||||
use rustrt::task::Task;
|
|
||||||
use rustrt::local::Local;
|
|
||||||
|
|
||||||
pub struct Flag { pub failed: bool }
|
pub struct Flag { pub failed: bool }
|
||||||
|
|
||||||
impl Flag {
|
impl Flag {
|
||||||
pub fn borrow(&mut self) -> Guard {
|
pub fn borrow(&mut self) -> Guard {
|
||||||
Guard { flag: &mut self.failed, failing: failing() }
|
Guard { flag: &mut self.failed, panicking: Thread::panicking() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Guard<'a> {
|
pub struct Guard<'a> {
|
||||||
flag: &'a mut bool,
|
flag: &'a mut bool,
|
||||||
failing: bool,
|
panicking: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Guard<'a> {
|
impl<'a> Guard<'a> {
|
||||||
|
@ -33,16 +31,8 @@ impl<'a> Guard<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn done(&mut self) {
|
pub fn done(&mut self) {
|
||||||
if !self.failing && failing() {
|
if !self.panicking && Thread::panicking() {
|
||||||
*self.flag = true;
|
*self.flag = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn failing() -> bool {
|
|
||||||
if Local::exists(None::<Task>) {
|
|
||||||
Local::borrow(None::<Task>).unwinder.unwinding()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -356,7 +356,7 @@ mod tests {
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
use rand::{mod, Rng};
|
use rand::{mod, Rng};
|
||||||
use task;
|
use thread::Thread;
|
||||||
use sync::{Arc, RWLock, StaticRWLock, RWLOCK_INIT};
|
use sync::{Arc, RWLock, StaticRWLock, RWLOCK_INIT};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -409,10 +409,10 @@ mod tests {
|
||||||
fn test_rw_arc_poison_wr() {
|
fn test_rw_arc_poison_wr() {
|
||||||
let arc = Arc::new(RWLock::new(1i));
|
let arc = Arc::new(RWLock::new(1i));
|
||||||
let arc2 = arc.clone();
|
let arc2 = arc.clone();
|
||||||
let _ = task::try(move|| {
|
let _ = Thread::with_join(move|| {
|
||||||
let lock = arc2.write();
|
let lock = arc2.write();
|
||||||
assert_eq!(*lock, 2);
|
assert_eq!(*lock, 2);
|
||||||
});
|
}).join();
|
||||||
let lock = arc.read();
|
let lock = arc.read();
|
||||||
assert_eq!(*lock, 1);
|
assert_eq!(*lock, 1);
|
||||||
}
|
}
|
||||||
|
@ -422,10 +422,10 @@ mod tests {
|
||||||
fn test_rw_arc_poison_ww() {
|
fn test_rw_arc_poison_ww() {
|
||||||
let arc = Arc::new(RWLock::new(1i));
|
let arc = Arc::new(RWLock::new(1i));
|
||||||
let arc2 = arc.clone();
|
let arc2 = arc.clone();
|
||||||
let _ = task::try(move|| {
|
let _ = Thread::with_join(move|| {
|
||||||
let lock = arc2.write();
|
let lock = arc2.write();
|
||||||
assert_eq!(*lock, 2);
|
assert_eq!(*lock, 2);
|
||||||
});
|
}).join();
|
||||||
let lock = arc.write();
|
let lock = arc.write();
|
||||||
assert_eq!(*lock, 1);
|
assert_eq!(*lock, 1);
|
||||||
}
|
}
|
||||||
|
@ -434,10 +434,10 @@ mod tests {
|
||||||
fn test_rw_arc_no_poison_rr() {
|
fn test_rw_arc_no_poison_rr() {
|
||||||
let arc = Arc::new(RWLock::new(1i));
|
let arc = Arc::new(RWLock::new(1i));
|
||||||
let arc2 = arc.clone();
|
let arc2 = arc.clone();
|
||||||
let _ = task::try(move|| {
|
let _ = Thread::with_join(move|| {
|
||||||
let lock = arc2.read();
|
let lock = arc2.read();
|
||||||
assert_eq!(*lock, 2);
|
assert_eq!(*lock, 2);
|
||||||
});
|
}).join();
|
||||||
let lock = arc.read();
|
let lock = arc.read();
|
||||||
assert_eq!(*lock, 1);
|
assert_eq!(*lock, 1);
|
||||||
}
|
}
|
||||||
|
@ -445,10 +445,10 @@ mod tests {
|
||||||
fn test_rw_arc_no_poison_rw() {
|
fn test_rw_arc_no_poison_rw() {
|
||||||
let arc = Arc::new(RWLock::new(1i));
|
let arc = Arc::new(RWLock::new(1i));
|
||||||
let arc2 = arc.clone();
|
let arc2 = arc.clone();
|
||||||
let _ = task::try(move|| {
|
let _ = Thread::with_join(move|| {
|
||||||
let lock = arc2.read();
|
let lock = arc2.read();
|
||||||
assert_eq!(*lock, 2);
|
assert_eq!(*lock, 2);
|
||||||
});
|
}).join();
|
||||||
let lock = arc.write();
|
let lock = arc.write();
|
||||||
assert_eq!(*lock, 1);
|
assert_eq!(*lock, 1);
|
||||||
}
|
}
|
||||||
|
@ -459,12 +459,12 @@ mod tests {
|
||||||
let arc2 = arc.clone();
|
let arc2 = arc.clone();
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
|
|
||||||
task::spawn(move|| {
|
Thread::spawn(move|| {
|
||||||
let mut lock = arc2.write();
|
let mut lock = arc2.write();
|
||||||
for _ in range(0u, 10) {
|
for _ in range(0u, 10) {
|
||||||
let tmp = *lock;
|
let tmp = *lock;
|
||||||
*lock = -1;
|
*lock = -1;
|
||||||
task::deschedule();
|
Thread::yield_now();
|
||||||
*lock = tmp + 1;
|
*lock = tmp + 1;
|
||||||
}
|
}
|
||||||
tx.send(());
|
tx.send(());
|
||||||
|
@ -474,15 +474,15 @@ mod tests {
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
for _ in range(0u, 5) {
|
for _ in range(0u, 5) {
|
||||||
let arc3 = arc.clone();
|
let arc3 = arc.clone();
|
||||||
children.push(task::try_future(move|| {
|
children.push(Thread::with_join(move|| {
|
||||||
let lock = arc3.read();
|
let lock = arc3.read();
|
||||||
assert!(*lock >= 0);
|
assert!(*lock >= 0);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for children to pass their asserts
|
// Wait for children to pass their asserts
|
||||||
for r in children.iter_mut() {
|
for r in children.into_iter() {
|
||||||
assert!(r.get_ref().is_ok());
|
assert!(r.join().is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for writer to finish
|
// Wait for writer to finish
|
||||||
|
@ -495,7 +495,11 @@ mod tests {
|
||||||
fn test_rw_arc_access_in_unwind() {
|
fn test_rw_arc_access_in_unwind() {
|
||||||
let arc = Arc::new(RWLock::new(1i));
|
let arc = Arc::new(RWLock::new(1i));
|
||||||
let arc2 = arc.clone();
|
let arc2 = arc.clone();
|
||||||
|
<<<<<<< HEAD
|
||||||
let _ = task::try(move|| -> () {
|
let _ = task::try(move|| -> () {
|
||||||
|
=======
|
||||||
|
let _ = Thread::with_join::<()>(proc() {
|
||||||
|
>>>>>>> Fallout from new thread API
|
||||||
struct Unwinder {
|
struct Unwinder {
|
||||||
i: Arc<RWLock<int>>,
|
i: Arc<RWLock<int>>,
|
||||||
}
|
}
|
||||||
|
@ -507,7 +511,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
let _u = Unwinder { i: arc2 };
|
let _u = Unwinder { i: arc2 };
|
||||||
panic!();
|
panic!();
|
||||||
});
|
}).join();
|
||||||
let lock = arc.read();
|
let lock = arc.read();
|
||||||
assert_eq!(*lock, 2);
|
assert_eq!(*lock, 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use task::{spawn};
|
use thread::Thread;
|
||||||
use comm::{channel, Sender, Receiver};
|
use comm::{channel, Sender, Receiver};
|
||||||
use sync::{Arc, Mutex};
|
use sync::{Arc, Mutex};
|
||||||
use thunk::Thunk;
|
use thunk::Thunk;
|
||||||
|
@ -105,7 +105,7 @@ impl TaskPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_in_pool(jobs: Arc<Mutex<Receiver<Thunk>>>) {
|
fn spawn_in_pool(jobs: Arc<Mutex<Receiver<Thunk>>>) {
|
||||||
spawn(move |:| {
|
Thread::spawn(move |:| {
|
||||||
// Will spawn a new task on panic unless it is cancelled.
|
// Will spawn a new task on panic unless it is cancelled.
|
||||||
let sentinel = Sentinel::new(&jobs);
|
let sentinel = Sentinel::new(&jobs);
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ fn spawn_in_pool(jobs: Arc<Mutex<Receiver<Thunk>>>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sentinel.cancel();
|
sentinel.cancel();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -206,4 +206,3 @@ mod test {
|
||||||
waiter.wait();
|
waiter.wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use io::{IoResult, Writer};
|
use io::{IoResult, Writer};
|
||||||
use iter::Iterator;
|
use iter::{Iterator, IteratorExt};
|
||||||
use option::{Some, None};
|
use option::{Some, None};
|
||||||
use result::{Ok, Err};
|
use result::{Ok, Err};
|
||||||
use str::{StrPrelude, from_str};
|
use str::{StrPrelude, from_str};
|
||||||
|
|
|
@ -28,7 +28,7 @@ use sync::{StaticMutex, StaticCondvar};
|
||||||
use rt;
|
use rt;
|
||||||
use sys::helper_signal;
|
use sys::helper_signal;
|
||||||
|
|
||||||
use task;
|
use thread::Thread;
|
||||||
|
|
||||||
/// A structure for management of a helper thread.
|
/// A structure for management of a helper thread.
|
||||||
///
|
///
|
||||||
|
@ -82,7 +82,11 @@ impl<M: Send> Helper<M> {
|
||||||
*self.signal.get() = send as uint;
|
*self.signal.get() = send as uint;
|
||||||
|
|
||||||
let t = f();
|
let t = f();
|
||||||
|
<<<<<<< HEAD
|
||||||
task::spawn(move |:| {
|
task::spawn(move |:| {
|
||||||
|
=======
|
||||||
|
Thread::spawn(proc() {
|
||||||
|
>>>>>>> Fallout from new thread API
|
||||||
helper(receive, rx, t);
|
helper(receive, rx, t);
|
||||||
let _g = self.lock.lock();
|
let _g = self.lock.lock();
|
||||||
*self.shutdown.get() = true;
|
*self.shutdown.get() = true;
|
||||||
|
|
|
@ -27,6 +27,7 @@ pub mod net;
|
||||||
pub mod rwlock;
|
pub mod rwlock;
|
||||||
pub mod stack;
|
pub mod stack;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
|
pub mod thread_info;
|
||||||
pub mod thread_local;
|
pub mod thread_local;
|
||||||
|
|
||||||
// common error constructors
|
// common error constructors
|
||||||
|
|
|
@ -33,11 +33,11 @@ impl ThreadInfo {
|
||||||
*c.borrow_mut() = Some(ThreadInfo {
|
*c.borrow_mut() = Some(ThreadInfo {
|
||||||
stack_bounds: (0, 0),
|
stack_bounds: (0, 0),
|
||||||
stack_guard: 0,
|
stack_guard: 0,
|
||||||
unwinder: false,
|
unwinding: false,
|
||||||
thread: Thread::new(None),
|
thread: NewThread::new(None),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
f(c.borrow_mut().as_ref().unwrap())
|
f(c.borrow_mut().as_mut().unwrap())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,28 +47,25 @@ pub fn current_thread() -> Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panicking() -> bool {
|
pub fn panicking() -> bool {
|
||||||
ThreadInfo::with(|info| info.unwinder.unwinding())
|
ThreadInfo::with(|info| info.unwinding)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack_guard() -> uint {
|
pub fn stack_guard() -> uint {
|
||||||
ThreadInfo::with(|info| info.stack_guard)
|
ThreadInfo::with(|info| info.stack_guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwinding() -> bool {
|
|
||||||
ThreadInfo::with(|info| info.unwinder.unwinding)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_unwinding(unwinding: bool) {
|
pub fn set_unwinding(unwinding: bool) {
|
||||||
ThreadInfo::with(|info| info.unwinding = unwinding)
|
ThreadInfo::with(|info| info.unwinding = unwinding)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(stack_bounds: (uint, uint), stack_guard: uint, thread: Thread) {
|
pub fn set(stack_bounds: (uint, uint), stack_guard: uint, thread: Thread) {
|
||||||
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
|
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
|
||||||
|
let mut thread_opt = Some(thread); // option dance
|
||||||
THREAD_INFO.with(|c| *c.borrow_mut() = Some(ThreadInfo{
|
THREAD_INFO.with(|c| *c.borrow_mut() = Some(ThreadInfo{
|
||||||
stack_bounds: stack_bounds,
|
stack_bounds: stack_bounds,
|
||||||
stack_guard: stack_guard,
|
stack_guard: stack_guard,
|
||||||
unwinding: false,
|
unwinding: false,
|
||||||
thread: thread,
|
thread: thread_opt.take().unwrap(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,6 @@
|
||||||
|
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
use rt;
|
|
||||||
use sync::atomic::{mod, AtomicUint};
|
use sync::atomic::{mod, AtomicUint};
|
||||||
use sync::{Mutex, Once, ONCE_INIT};
|
use sync::{Mutex, Once, ONCE_INIT};
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> {
|
||||||
|
|
||||||
struct Context<'a> {
|
struct Context<'a> {
|
||||||
idx: int,
|
idx: int,
|
||||||
writer: &'a mut Writer+'a,
|
writer: &'a mut (Writer+'a),
|
||||||
last_error: Option<IoError>,
|
last_error: Option<IoError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,6 @@ mod imp {
|
||||||
use self::signal::{siginfo, sigaction, SIGBUS, SIG_DFL,
|
use self::signal::{siginfo, sigaction, SIGBUS, SIG_DFL,
|
||||||
SA_SIGINFO, SA_ONSTACK, sigaltstack,
|
SA_SIGINFO, SA_ONSTACK, sigaltstack,
|
||||||
SIGSTKSZ};
|
SIGSTKSZ};
|
||||||
use rt::local::Local;
|
|
||||||
use rt::task::Task;
|
|
||||||
use libc;
|
use libc;
|
||||||
use libc::funcs::posix88::mman::{mmap, munmap};
|
use libc::funcs::posix88::mman::{mmap, munmap};
|
||||||
use libc::consts::os::posix88::{SIGSEGV,
|
use libc::consts::os::posix88::{SIGSEGV,
|
||||||
|
@ -56,20 +54,12 @@ mod imp {
|
||||||
MAP_ANON,
|
MAP_ANON,
|
||||||
MAP_FAILED};
|
MAP_FAILED};
|
||||||
|
|
||||||
|
use sys_common::thread_info;
|
||||||
|
|
||||||
|
|
||||||
// This is initialized in init() and only read from after
|
// This is initialized in init() and only read from after
|
||||||
static mut PAGE_SIZE: uint = 0;
|
static mut PAGE_SIZE: uint = 0;
|
||||||
|
|
||||||
// get_task_info is called from an exception / signal handler.
|
|
||||||
// It returns the guard page of the current task or 0 if that
|
|
||||||
// guard page doesn't exist. None is returned if there's currently
|
|
||||||
// no local task.
|
|
||||||
unsafe fn get_task_guard_page() -> Option<uint> {
|
|
||||||
let task: Option<*mut Task> = Local::try_unsafe_borrow();
|
|
||||||
task.map(|task| (&*task).stack_guard().unwrap_or(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[no_stack_check]
|
#[no_stack_check]
|
||||||
unsafe extern fn signal_handler(signum: libc::c_int,
|
unsafe extern fn signal_handler(signum: libc::c_int,
|
||||||
info: *mut siginfo,
|
info: *mut siginfo,
|
||||||
|
@ -89,8 +79,7 @@ mod imp {
|
||||||
// We're calling into functions with stack checks
|
// We're calling into functions with stack checks
|
||||||
stack::record_sp_limit(0);
|
stack::record_sp_limit(0);
|
||||||
|
|
||||||
match get_task_guard_page() {
|
let guard = thread_info::stack_guard();
|
||||||
Some(guard) => {
|
|
||||||
let addr = (*info).si_addr as uint;
|
let addr = (*info).si_addr as uint;
|
||||||
|
|
||||||
if guard == 0 || addr < guard - PAGE_SIZE || addr >= guard {
|
if guard == 0 || addr < guard - PAGE_SIZE || addr >= guard {
|
||||||
|
@ -101,9 +90,6 @@ mod imp {
|
||||||
|
|
||||||
intrinsics::abort()
|
intrinsics::abort()
|
||||||
}
|
}
|
||||||
None => term(signum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static mut MAIN_ALTSTACK: *mut libc::c_void = 0 as *mut libc::c_void;
|
static mut MAIN_ALTSTACK: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||||
|
|
||||||
|
|
|
@ -8,15 +8,13 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use rt::local::Local;
|
|
||||||
use rt::task::Task;
|
|
||||||
use rt::util::report_overflow;
|
use rt::util::report_overflow;
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
use ptr;
|
use ptr;
|
||||||
use mem;
|
use mem;
|
||||||
use libc;
|
use libc;
|
||||||
use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL};
|
use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL};
|
||||||
use sys_common::stack;
|
use sys_common::{stack, thread_info};
|
||||||
|
|
||||||
pub struct Handler {
|
pub struct Handler {
|
||||||
_data: *mut libc::c_void
|
_data: *mut libc::c_void
|
||||||
|
@ -37,8 +35,7 @@ impl Drop for Handler {
|
||||||
// guard page doesn't exist. None is returned if there's currently
|
// guard page doesn't exist. None is returned if there's currently
|
||||||
// no local task.
|
// no local task.
|
||||||
unsafe fn get_task_guard_page() -> Option<uint> {
|
unsafe fn get_task_guard_page() -> Option<uint> {
|
||||||
let task: Option<*mut Task> = Local::try_unsafe_borrow();
|
thread_info::stack_guard()
|
||||||
task.map(|task| (&*task).stack_guard().unwrap_or(0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is initialized in init() and only read from after
|
// This is initialized in init() and only read from after
|
||||||
|
|
|
@ -12,8 +12,11 @@
|
||||||
|
|
||||||
#![deprecated = "use std::thread instead"]
|
#![deprecated = "use std::thread instead"]
|
||||||
|
|
||||||
|
use any::Any;
|
||||||
|
use boxed::Box;
|
||||||
use thread;
|
use thread;
|
||||||
use kinds::Send;
|
use kinds::Send;
|
||||||
|
use result::Result;
|
||||||
|
|
||||||
/// Deprecate: use `std::thread::Cfg` instead.
|
/// Deprecate: use `std::thread::Cfg` instead.
|
||||||
#[deprecated = "use std::thread::Cfg instead"]
|
#[deprecated = "use std::thread::Cfg instead"]
|
||||||
|
@ -24,3 +27,15 @@ pub type TaskBuilder = thread::Cfg;
|
||||||
pub fn spawn(f: proc(): Send) {
|
pub fn spawn(f: proc(): Send) {
|
||||||
thread::Thread::spawn(f);
|
thread::Thread::spawn(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deprecated: use `std::thread::Thread::with_join instead`.
|
||||||
|
#[deprecated = "use std::thread::Thread::with_join instead"]
|
||||||
|
pub fn try<T: Send>(f: proc(): Send -> T) -> Result<T, Box<Any + Send>> {
|
||||||
|
thread::Thread::with_join(f).join()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deprecated: use `std::thread::Thread::yield_now instead`.
|
||||||
|
#[deprecated = "use std::thread::Thread::yield_now instead"]
|
||||||
|
pub fn deschedule() {
|
||||||
|
thread::Thread::yield_now()
|
||||||
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ impl Cfg {
|
||||||
}
|
}
|
||||||
thread_info::set(
|
thread_info::set(
|
||||||
(my_stack_bottom, my_stack_top),
|
(my_stack_bottom, my_stack_top),
|
||||||
thread::current_guard_page(),
|
unsafe { imp::guard::current() },
|
||||||
their_thread
|
their_thread
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ impl Cfg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(unsafe { imp::create(stack, box main) }, my_thread)
|
(unsafe { imp::create(stack_size, box main) }, my_thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawn a detached thread, and return a handle to it.
|
/// Spawn a detached thread, and return a handle to it.
|
||||||
|
@ -278,19 +278,20 @@ impl Cfg {
|
||||||
// We need the address of the packet to fill in to be stable so when
|
// We need the address of the packet to fill in to be stable so when
|
||||||
// `main` fills it in it's still valid, so allocate an extra box to do
|
// `main` fills it in it's still valid, so allocate an extra box to do
|
||||||
// so.
|
// so.
|
||||||
let my_packet = box Err(box 0); // sentinel value
|
let any: Box<Any+Send> = box 0u8; // sentinel value
|
||||||
|
let my_packet = box Err(any);
|
||||||
let their_packet: *mut Result<T> = unsafe {
|
let their_packet: *mut Result<T> = unsafe {
|
||||||
*mem::transmute::<&Box<Result<T>>, *const *mut Result<T>>(&my_packet)
|
*mem::transmute::<&Box<Result<T>>, *const *mut Result<T>>(&my_packet)
|
||||||
};
|
};
|
||||||
|
|
||||||
let (native, thread) = self.core_spawn(f, proc(result) {
|
let (native, thread) = self.core_spawn(f, proc(result) {
|
||||||
*their_packet = result;
|
unsafe { *their_packet = result; }
|
||||||
});
|
});
|
||||||
|
|
||||||
JoinGuard {
|
JoinGuard {
|
||||||
native: native,
|
native: native,
|
||||||
joined: false,
|
joined: false,
|
||||||
packet: my_packet,
|
packet: Some(my_packet),
|
||||||
thread: thread,
|
thread: thread,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,7 +337,7 @@ impl Thread {
|
||||||
|
|
||||||
/// Gets a handle to the thread that invokes it.
|
/// Gets a handle to the thread that invokes it.
|
||||||
pub fn current() -> Thread {
|
pub fn current() -> Thread {
|
||||||
ThreadInfo::current_thread()
|
thread_info::current_thread()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cooperatively give up a timeslice to the OS scheduler.
|
/// Cooperatively give up a timeslice to the OS scheduler.
|
||||||
|
@ -346,7 +347,7 @@ impl Thread {
|
||||||
|
|
||||||
/// Determines whether the current thread is panicking.
|
/// Determines whether the current thread is panicking.
|
||||||
pub fn panicking() -> bool {
|
pub fn panicking() -> bool {
|
||||||
ThreadInfo::panicking()
|
thread_info::panicking()
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp
|
// http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp
|
||||||
|
@ -355,9 +356,9 @@ impl Thread {
|
||||||
/// See the module doc for more detail.
|
/// See the module doc for more detail.
|
||||||
pub fn park() {
|
pub fn park() {
|
||||||
let thread = Thread::current();
|
let thread = Thread::current();
|
||||||
let guard = thread.inner.lock.lock();
|
let mut guard = thread.inner.lock.lock();
|
||||||
while !*guard {
|
while !*guard {
|
||||||
thread.inner.cvar.wait(guard);
|
thread.inner.cvar.wait(&guard);
|
||||||
}
|
}
|
||||||
*guard = false;
|
*guard = false;
|
||||||
}
|
}
|
||||||
|
@ -366,7 +367,7 @@ impl Thread {
|
||||||
///
|
///
|
||||||
/// See the module doc for more detail.
|
/// See the module doc for more detail.
|
||||||
pub fn unpark(&self) {
|
pub fn unpark(&self) {
|
||||||
let guard = self.inner.lock();
|
let mut guard = self.inner.lock.lock();
|
||||||
if !*guard {
|
if !*guard {
|
||||||
*guard = true;
|
*guard = true;
|
||||||
self.inner.cvar.notify_one();
|
self.inner.cvar.notify_one();
|
||||||
|
@ -375,7 +376,7 @@ impl Thread {
|
||||||
|
|
||||||
/// Get the thread's name.
|
/// Get the thread's name.
|
||||||
pub fn name(&self) -> Option<&str> {
|
pub fn name(&self) -> Option<&str> {
|
||||||
self.inner.name.as_ref()
|
self.inner.name.as_ref().map(|s| s.as_slice())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +388,7 @@ impl thread_info::NewThread for Thread {
|
||||||
/// Indicates the manner in which a thread exited.
|
/// Indicates the manner in which a thread exited.
|
||||||
///
|
///
|
||||||
/// A thread that completes without panicking is considered to exit successfully.
|
/// A thread that completes without panicking is considered to exit successfully.
|
||||||
pub type Result<T> = result::Result<T, Box<Any + Send>>;
|
pub type Result<T> = ::result::Result<T, Box<Any + Send>>;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
/// An RAII guard that will block until thread termination when dropped.
|
/// An RAII guard that will block until thread termination when dropped.
|
||||||
|
@ -395,7 +396,7 @@ pub struct JoinGuard<T> {
|
||||||
native: imp::rust_thread,
|
native: imp::rust_thread,
|
||||||
thread: Thread,
|
thread: Thread,
|
||||||
joined: bool,
|
joined: bool,
|
||||||
packet: Box<Result<T>>,
|
packet: Option<Box<Result<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Send> JoinGuard<T> {
|
impl<T: Send> JoinGuard<T> {
|
||||||
|
|
|
@ -446,7 +446,7 @@ mod tests {
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
use cell::UnsafeCell;
|
use cell::UnsafeCell;
|
||||||
use rt::thread::Thread;
|
use thread::Thread;
|
||||||
|
|
||||||
struct Foo(Sender<()>);
|
struct Foo(Sender<()>);
|
||||||
|
|
||||||
|
@ -534,7 +534,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::start(move|| {
|
Thread::with_join(move|| {
|
||||||
drop(S1);
|
drop(S1);
|
||||||
}).join();
|
}).join();
|
||||||
}
|
}
|
||||||
|
@ -552,7 +552,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::start(move|| unsafe {
|
Thread::with_join(move|| unsafe {
|
||||||
K1.with(|s| *s.get() = Some(S1));
|
K1.with(|s| *s.get() = Some(S1));
|
||||||
}).join();
|
}).join();
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ use std::num::{Float, FloatMath, Int};
|
||||||
use std::os;
|
use std::os;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::task::TaskBuilder;
|
use std::thread::{mod, Thread};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::thunk::{Thunk, Invoke};
|
use std::thunk::{Thunk, Invoke};
|
||||||
|
|
||||||
|
@ -1121,28 +1121,27 @@ pub fn run_test(opts: &TestOpts,
|
||||||
monitor_ch: Sender<MonitorMsg>,
|
monitor_ch: Sender<MonitorMsg>,
|
||||||
nocapture: bool,
|
nocapture: bool,
|
||||||
testfn: Thunk) {
|
testfn: Thunk) {
|
||||||
spawn(move || {
|
Thread::spawn(move || {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let mut reader = ChanReader::new(rx);
|
let mut reader = ChanReader::new(rx);
|
||||||
let stdout = ChanWriter::new(tx.clone());
|
let stdout = ChanWriter::new(tx.clone());
|
||||||
let stderr = ChanWriter::new(tx);
|
let stderr = ChanWriter::new(tx);
|
||||||
let mut task = TaskBuilder::new().named(match desc.name {
|
let mut cfg = thread::cfg().name(match desc.name {
|
||||||
DynTestName(ref name) => name.clone().to_string(),
|
DynTestName(ref name) => name.clone().to_string(),
|
||||||
StaticTestName(name) => name.to_string(),
|
StaticTestName(name) => name.to_string(),
|
||||||
});
|
});
|
||||||
if nocapture {
|
if nocapture {
|
||||||
drop((stdout, stderr));
|
drop((stdout, stderr));
|
||||||
} else {
|
} else {
|
||||||
task = task.stdout(box stdout as Box<Writer + Send>);
|
cfg = cfg.stdout(box stdout as Box<Writer + Send>);
|
||||||
task = task.stderr(box stderr as Box<Writer + Send>);
|
cfg = cfg.stderr(box stderr as Box<Writer + Send>);
|
||||||
}
|
}
|
||||||
let result_future = task.try_future(move || testfn.invoke(()));
|
|
||||||
|
|
||||||
|
let result_guard = cfg.with_join(testfn);
|
||||||
let stdout = reader.read_to_end().unwrap().into_iter().collect();
|
let stdout = reader.read_to_end().unwrap().into_iter().collect();
|
||||||
let task_result = result_future.into_inner();
|
let test_result = calc_result(&desc, result_guard.join());
|
||||||
let test_result = calc_result(&desc, task_result);
|
|
||||||
monitor_ch.send((desc.clone(), test_result, stdout));
|
monitor_ch.send((desc.clone(), test_result, stdout));
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
match testfn {
|
match testfn {
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
// It's unclear how likely such a bug is to recur, but it seems like a
|
// It's unclear how likely such a bug is to recur, but it seems like a
|
||||||
// scenario worth testing.
|
// scenario worth testing.
|
||||||
|
|
||||||
use std::task;
|
use std::thread::Thread;
|
||||||
|
|
||||||
enum Conzabble {
|
enum Conzabble {
|
||||||
Bickwick(Foo)
|
Bickwick(Foo)
|
||||||
|
@ -45,5 +45,5 @@ pub fn fails() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
task::try(fails);
|
Thread::with_join(fails).join();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,16 +9,16 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use std::io::{ChanReader, ChanWriter};
|
use std::io::{ChanReader, ChanWriter};
|
||||||
use std::task::TaskBuilder;
|
use std::thread;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let mut reader = ChanReader::new(rx);
|
let mut reader = ChanReader::new(rx);
|
||||||
let stderr = ChanWriter::new(tx);
|
let stderr = ChanWriter::new(tx);
|
||||||
|
|
||||||
let res = TaskBuilder::new().stderr(box stderr as Box<Writer + Send>).try(move|| -> () {
|
let res = thread::cfg().stderr(box stderr as Box<Writer + Send>).with_join(move|| -> () {
|
||||||
panic!("Hello, world!")
|
panic!("Hello, world!")
|
||||||
});
|
}).join();
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
|
|
||||||
let output = reader.read_to_string().unwrap();
|
let output = reader.read_to_string().unwrap();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue